proc, terminal: stepout command

Command to step out of the currently executing function.

Implements #358
This commit is contained in:
aarzilli
2016-04-14 11:58:59 +02:00
parent 54d3eab63a
commit 0f4b5150c3
8 changed files with 192 additions and 2 deletions

View File

@ -237,6 +237,8 @@ const (
Continue = "continue"
// Step continues to next source line, entering function calls.
Step = "step"
// StepOut continues to the return address of the current function
StepOut = "stepOut"
// SingleStep continues for exactly 1 cpu instruction.
StepInstruction = "stepInstruction"
// Next continues to the next source line, not entering function calls.

View File

@ -25,6 +25,9 @@ type Client interface {
Next() (*api.DebuggerState, error)
// Step continues to the next source line, entering function calls.
Step() (*api.DebuggerState, error)
// StepOut continues to the return address of the current function
StepOut() (*api.DebuggerState, error)
// SingleStep will step a single cpu instruction.
StepInstruction() (*api.DebuggerState, error)
// SwitchThread switches the current thread context.

View File

@ -418,6 +418,9 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
case api.StepInstruction:
log.Print("single stepping")
err = d.process.StepInstruction()
case api.StepOut:
log.Print("step out")
err = d.process.StepOut()
case api.SwitchThread:
log.Printf("switching to thread %d", command.ThreadID)
err = d.process.SwitchThread(command.ThreadID)

View File

@ -103,6 +103,12 @@ func (c *RPCClient) Step() (*api.DebuggerState, error) {
return &out.State, err
}
func (c *RPCClient) StepOut() (*api.DebuggerState, error) {
var out CommandOut
err := c.call("Command", &api.DebuggerCommand{ Name: api.StepOut}, &out)
return &out.State, err
}
func (c *RPCClient) StepInstruction() (*api.DebuggerState, error) {
var out CommandOut
err := c.call("Command", api.DebuggerCommand{Name: api.StepInstruction}, &out)

View File

@ -199,6 +199,23 @@ func TestClientServer_step(t *testing.T) {
})
}
func TestClientServer_stepout(t *testing.T) {
withTestClient2("testnextprog", t, func(c service.Client) {
_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.helloworld", Line: -1})
assertNoError(err, t, "CreateBreakpoint()")
stateBefore := <-c.Continue()
assertNoError(stateBefore.Err, t, "Continue()")
if stateBefore.CurrentThread.Line != 13 {
t.Fatalf("wrong line number %s:%d, expected %d", stateBefore.CurrentThread.File, stateBefore.CurrentThread.Line, 13)
}
stateAfter, err := c.StepOut()
assertNoError(err, t, "StepOut()")
if stateAfter.CurrentThread.Line != 35 {
t.Fatalf("wrong line number %s:%d, expected %d", stateAfter.CurrentThread.File, stateAfter.CurrentThread.Line, 13)
}
})
}
func testnext2(testcases []nextTest, initialLocation string, t *testing.T) {
withTestClient2("testnextprog", t, func(c service.Client) {
bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: initialLocation, Line: -1})
@ -278,7 +295,7 @@ func TestNextGeneral(t *testing.T) {
}
}
testnext(testcases, "main.testnext", t)
testnext2(testcases, "main.testnext", t)
}
func TestNextFunctionReturn(t *testing.T) {
@ -287,7 +304,7 @@ func TestNextFunctionReturn(t *testing.T) {
{14, 15},
{15, 35},
}
testnext(testcases, "main.helloworld", t)
testnext2(testcases, "main.helloworld", t)
}
func TestClientServer_breakpointInMainThread(t *testing.T) {