proc/gdbserial: use reverse connect feature of debugserver (#837)

Fixes #836
This commit is contained in:
Alessandro Arzilli 2017-05-11 21:34:39 +02:00 committed by Derek Parker
parent 862145f874
commit 82d142d1cd
2 changed files with 42 additions and 20 deletions

@ -86,6 +86,7 @@ const (
showLldbServerOutput = false showLldbServerOutput = false
logGdbWireMaxLen = 120 logGdbWireMaxLen = 120
maxConnectAttempts = 10 // number of connection attempts to stub
maxTransmitAttempts = 3 // number of retransmission attempts on failed checksum maxTransmitAttempts = 3 // number of retransmission attempts on failed checksum
initialInputBufferSize = 2048 // size of the input buffer for gdbConn initialInputBufferSize = 2048 // size of the input buffer for gdbConn
) )
@ -152,14 +153,24 @@ type gdbRegister struct {
regnum int regnum int
} }
// Connect creates a GdbserverProcess connected to address addr. // Connect connects to a stub and performs a handshake.
//
// If listener is not nil Connect will accept a connection from the stub
// (which should be instructed to operate in client mode), otherwise it will
// connect to addr.
//
// Path and pid are, respectively, the path to the executable of the target // Path and pid are, respectively, the path to the executable of the target
// program and the PID of the target process, both are optional, however // program and the PID of the target process, both are optional, however
// some stubs do not provide ways to determine path and pid automatically // some stubs do not provide ways to determine path and pid automatically
// and Connect will be unable to function without knowing them. // and Connect will be unable to function without knowing them.
func Connect(addr string, path string, pid int, attempts int) (*Process, error) { func Connect(listener net.Listener, addr string, path string, pid int, attempts int) (*Process, error) {
var conn net.Conn var conn net.Conn
var err error var err error
if listener != nil {
conn, err = listener.Accept()
listener.Close()
} else {
for i := 0; i < attempts; i++ { for i := 0; i < attempts; i++ {
conn, err = net.Dial("tcp", addr) conn, err = net.Dial("tcp", addr)
if err == nil { if err == nil {
@ -167,6 +178,7 @@ func Connect(addr string, path string, pid int, attempts int) (*Process, error)
} }
time.Sleep(time.Second) time.Sleep(time.Second)
} }
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -282,11 +294,7 @@ func Connect(addr string, path string, pid int, attempts int) (*Process, error)
// before reassigning one port they just assigned, unless there's heavy // before reassigning one port they just assigned, unless there's heavy
// churn in the ephemeral range this should work. // churn in the ephemeral range this should work.
func unusedPort() string { func unusedPort() string {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0") listener, err := net.Listen("tcp", "localhost:0")
if err != nil {
return ":8081"
}
listener, err := net.ListenTCP("tcp", addr)
if err != nil { if err != nil {
return ":8081" return ":8081"
} }
@ -313,19 +321,26 @@ func LLDBLaunch(cmd []string, wd string) (*Process, error) {
} }
} }
port := unusedPort()
isDebugserver := false isDebugserver := false
var listener net.Listener
var port string
var proc *exec.Cmd var proc *exec.Cmd
if _, err := os.Stat(debugserverExecutable); err == nil { if _, err := os.Stat(debugserverExecutable); err == nil {
args := make([]string, 0, len(cmd)+2) listener, err = net.Listen("tcp", "localhost:0")
args = append(args, "-F", "127.0.0.1"+port) if err != nil {
return nil, err
}
listener.(*net.TCPListener).SetDeadline(time.Now().Add(maxConnectAttempts * time.Second))
args := make([]string, 0, len(cmd)+3)
args = append(args, "-F", "-R", fmt.Sprintf("127.0.0.1:%d", listener.Addr().(*net.TCPAddr).Port))
args = append(args, cmd...) args = append(args, cmd...)
isDebugserver = true isDebugserver = true
proc = exec.Command(debugserverExecutable, args...) proc = exec.Command(debugserverExecutable, args...)
} else { } else {
port = unusedPort()
args := make([]string, 0, len(cmd)+3) args := make([]string, 0, len(cmd)+3)
args = append(args, "gdbserver") args = append(args, "gdbserver")
args = append(args, port, "--") args = append(args, port, "--")
@ -349,7 +364,7 @@ func LLDBLaunch(cmd []string, wd string) (*Process, error) {
return nil, err return nil, err
} }
p, err := Connect(port, cmd[0], 0, 10) p, err := Connect(listener, port, cmd[0], 0, maxConnectAttempts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -370,13 +385,20 @@ func LLDBAttach(pid int, path string) (*Process, error) {
return nil, ErrUnsupportedOS return nil, ErrUnsupportedOS
} }
port := unusedPort()
isDebugserver := false isDebugserver := false
var proc *exec.Cmd var proc *exec.Cmd
var listener net.Listener
var port string
if _, err := os.Stat(debugserverExecutable); err == nil { if _, err := os.Stat(debugserverExecutable); err == nil {
isDebugserver = true isDebugserver = true
proc = exec.Command(debugserverExecutable, "127.0.0.1"+port, "--attach="+strconv.Itoa(pid)) listener, err = net.Listen("tcp", "localhost:0")
if err != nil {
return nil, err
}
listener.(*net.TCPListener).SetDeadline(time.Now().Add(maxConnectAttempts * time.Second))
proc = exec.Command(debugserverExecutable, "-R", fmt.Sprintf("127.0.0.1:%d", listener.Addr().(*net.TCPAddr).Port), "--attach="+strconv.Itoa(pid))
} else { } else {
port = unusedPort()
proc = exec.Command("lldb-server", "gdbserver", "--attach", strconv.Itoa(pid), port) proc = exec.Command("lldb-server", "gdbserver", "--attach", strconv.Itoa(pid), port)
} }
@ -390,7 +412,7 @@ func LLDBAttach(pid int, path string) (*Process, error) {
return nil, err return nil, err
} }
p, err := Connect(port, path, pid, 10) p, err := Connect(listener, port, path, pid, maxConnectAttempts)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -70,7 +70,7 @@ func Replay(tracedir string, quiet bool) (*Process, error) {
rrcmd.Process.Kill() rrcmd.Process.Kill()
return nil, err return nil, err
} }
p, err := Connect(init.port, init.exe, 0, 10) p, err := Connect(nil, init.port, init.exe, 0, maxConnectAttempts)
if err != nil { if err != nil {
rrcmd.Process.Kill() rrcmd.Process.Kill()
return nil, err return nil, err