From 436b9e5ec696ba51fbbde64b12da2976e329705e Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Tue, 23 Jul 2019 23:42:21 +0200 Subject: [PATCH] gdbserial: propagate signals to target while stepping (#1624) Propagate signals when stepping because debugserver will report them, from the issue: 2019-07-11T16:31:25+02:00 debug layer=gdbconn <- $z0,105525d,1#c9 2019-07-11T16:31:25+02:00 debug layer=gdbconn -> $OK#00 2019-07-11T16:31:25+02:00 debug layer=gdbconn <- $vCont;s:c41c3#50 2019-07-11T16:31:25+02:00 debug layer=gdbconn -> $T1cthread:c41c3;threads:c41c3,c41d7,c41d8,c41d9,c41da;thread-pcs:105525d,7fffc464bf46,7fffc464bbf2,7fffc464bbf2,7fffc46... 2019-07-11T16:31:25+02:00 debug layer=gdbconn <- $Z0,105525d,1#a9 2019-07-11T16:31:25+02:00 debug layer=gdbconn -> $OK#00 in this case we request a single step on thread c41c3 but debugserver reports instead a signal (in this case SIGWINCH). Fixes #1610 --- pkg/proc/gdbserial/gdbserver.go | 18 ++++++++--- pkg/proc/gdbserial/gdbserver_conn.go | 48 ++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go index 6df199000f..7271176e2f 100644 --- a/pkg/proc/gdbserial/gdbserver.go +++ b/pkg/proc/gdbserial/gdbserver.go @@ -610,8 +610,16 @@ func (p *Process) SelectedGoroutine() *proc.G { const ( interruptSignal = 0x2 breakpointSignal = 0x5 + faultSignal = 0xb childSignal = 0x11 stopSignal = 0x13 + + debugServerTargetExcBadAccess = 0x91 + debugServerTargetExcBadInstruction = 0x92 + debugServerTargetExcArithmetic = 0x93 + debugServerTargetExcEmulation = 0x94 + debugServerTargetExcSoftware = 0x95 + debugServerTargetExcBreakpoint = 0x96 ) // ContinueOnce will continue execution of the process until @@ -677,7 +685,8 @@ continueLoop: // The following are fake BSD-style signals sent by debugserver // Unfortunately debugserver can not convert them into signals for the // process so we must stop here. - case 0x91, 0x92, 0x93, 0x94, 0x95, 0x96: /* TARGET_EXC_BAD_ACCESS */ + case debugServerTargetExcBadAccess, debugServerTargetExcBadInstruction, debugServerTargetExcArithmetic, debugServerTargetExcEmulation, debugServerTargetExcSoftware, debugServerTargetExcBreakpoint: + break continueLoop // Signal 0 is returned by rr when it reaches the start of the process @@ -1274,8 +1283,7 @@ func (t *Thread) stepInstruction(tu *threadUpdater) error { } defer t.p.conn.setBreakpoint(pc) } - _, _, err := t.p.conn.step(t.strID, tu) - return err + return t.p.conn.step(t.strID, tu, false) } // StepInstruction will step exactly 1 CPU instruction. @@ -1485,7 +1493,7 @@ func (t *Thread) reloadGAtPC() error { } }() - _, _, err = t.p.conn.step(t.strID, nil) + err = t.p.conn.step(t.strID, nil, true) if err != nil { if err == threadBlockedError { t.regs.tls = 0 @@ -1538,7 +1546,7 @@ func (t *Thread) reloadGAlloc() error { } }() - _, _, err = t.p.conn.step(t.strID, nil) + err = t.p.conn.step(t.strID, nil, true) if err != nil { if err == threadBlockedError { t.regs.tls = 0 diff --git a/pkg/proc/gdbserial/gdbserver_conn.go b/pkg/proc/gdbserial/gdbserver_conn.go index 107f9d811b..1486075ba2 100644 --- a/pkg/proc/gdbserial/gdbserver_conn.go +++ b/pkg/proc/gdbserial/gdbserver_conn.go @@ -575,21 +575,51 @@ func (conn *gdbConn) resume(sig uint8, tu *threadUpdater) (string, uint8, error) } // step executes a 'vCont' command on the specified thread with 's' action. -func (conn *gdbConn) step(threadID string, tu *threadUpdater) (string, uint8, error) { - if conn.direction == proc.Forward { - conn.outbuf.Reset() - fmt.Fprintf(&conn.outbuf, "$vCont;s:%s", threadID) - } else { +func (conn *gdbConn) step(threadID string, tu *threadUpdater, ignoreFaultSignal bool) error { + if conn.direction != proc.Forward { if err := conn.selectThread('c', threadID, "step"); err != nil { - return "", 0, err + return err } conn.outbuf.Reset() fmt.Fprint(&conn.outbuf, "$bs") + if err := conn.send(conn.outbuf.Bytes()); err != nil { + return err + } + _, _, err := conn.waitForvContStop("singlestep", threadID, tu) + return err } - if err := conn.send(conn.outbuf.Bytes()); err != nil { - return "", 0, err + var sig uint8 = 0 + for { + conn.outbuf.Reset() + if sig == 0 { + fmt.Fprintf(&conn.outbuf, "$vCont;s:%s", threadID) + } else { + fmt.Fprintf(&conn.outbuf, "$vCont;S%02x:%s", sig, threadID) + } + if err := conn.send(conn.outbuf.Bytes()); err != nil { + return err + } + var err error + _, sig, err = conn.waitForvContStop("singlestep", threadID, tu) + if err != nil { + return err + } + switch sig { + case faultSignal: + if ignoreFaultSignal { // we attempting to read the TLS, a fault here should be ignored + return nil + } + case interruptSignal, breakpointSignal, stopSignal: + return nil + case childSignal: // stop on debugserver but SIGCHLD on lldb-server/linux + if conn.isDebugserver { + return nil + } + case debugServerTargetExcBadAccess, debugServerTargetExcBadInstruction, debugServerTargetExcArithmetic, debugServerTargetExcEmulation, debugServerTargetExcSoftware, debugServerTargetExcBreakpoint: + return nil + } + // any other signal is propagated to the inferior } - return conn.waitForvContStop("singlestep", threadID, tu) } var threadBlockedError = errors.New("thread blocked")