terminal,service: Add support for rev prefix and step-instruction (#1596)
Support for rev {next,step} is not currently implemented.
This commit is contained in:
parent
1758823429
commit
c7d1692e92
@ -32,6 +32,7 @@ Command | Description
|
|||||||
[print](#print) | Evaluate an expression.
|
[print](#print) | Evaluate an expression.
|
||||||
[regs](#regs) | Print contents of CPU registers.
|
[regs](#regs) | Print contents of CPU registers.
|
||||||
[restart](#restart) | Restart process from a checkpoint or event.
|
[restart](#restart) | Restart process from a checkpoint or event.
|
||||||
|
[rev](#rev) | Reverses the execution of the target program for the command specified.
|
||||||
[rewind](#rewind) | Run backwards until breakpoint or program termination.
|
[rewind](#rewind) | Run backwards until breakpoint or program termination.
|
||||||
[set](#set) | Changes the value of a variable.
|
[set](#set) | Changes the value of a variable.
|
||||||
[source](#source) | Executes a file containing a list of delve commands
|
[source](#source) | Executes a file containing a list of delve commands
|
||||||
@ -329,6 +330,11 @@ Restart process from a checkpoint or event.
|
|||||||
|
|
||||||
Aliases: r
|
Aliases: r
|
||||||
|
|
||||||
|
## rev
|
||||||
|
Reverses the execution of the target program for the command specified.
|
||||||
|
Currently, only the rev step-instruction command is supported.
|
||||||
|
|
||||||
|
|
||||||
## rewind
|
## rewind
|
||||||
Run backwards until breakpoint or program termination.
|
Run backwards until breakpoint or program termination.
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ const (
|
|||||||
noPrefix = cmdPrefix(0)
|
noPrefix = cmdPrefix(0)
|
||||||
onPrefix = cmdPrefix(1 << iota)
|
onPrefix = cmdPrefix(1 << iota)
|
||||||
deferredPrefix
|
deferredPrefix
|
||||||
|
revPrefix
|
||||||
)
|
)
|
||||||
|
|
||||||
type callContext struct {
|
type callContext struct {
|
||||||
@ -136,7 +137,7 @@ the arguments. With -noargs, the process starts with an empty commandline.
|
|||||||
`},
|
`},
|
||||||
{aliases: []string{"continue", "c"}, cmdFn: c.cont, helpMsg: "Run until breakpoint or program termination."},
|
{aliases: []string{"continue", "c"}, cmdFn: c.cont, helpMsg: "Run until breakpoint or program termination."},
|
||||||
{aliases: []string{"step", "s"}, cmdFn: c.step, helpMsg: "Single step through program."},
|
{aliases: []string{"step", "s"}, cmdFn: c.step, helpMsg: "Single step through program."},
|
||||||
{aliases: []string{"step-instruction", "si"}, cmdFn: c.stepInstruction, helpMsg: "Single step a single cpu instruction."},
|
{aliases: []string{"step-instruction", "si"}, allowedPrefixes: revPrefix, cmdFn: c.stepInstruction, helpMsg: "Single step a single cpu instruction."},
|
||||||
{aliases: []string{"next", "n"}, cmdFn: c.next, helpMsg: "Step over to next source line."},
|
{aliases: []string{"next", "n"}, cmdFn: c.next, helpMsg: "Step over to next source line."},
|
||||||
{aliases: []string{"stepout"}, cmdFn: c.stepout, helpMsg: "Step out of the current function."},
|
{aliases: []string{"stepout"}, cmdFn: c.stepout, helpMsg: "Step out of the current function."},
|
||||||
{aliases: []string{"call"}, cmdFn: c.call, helpMsg: `Resumes process, injecting a function call (EXPERIMENTAL!!!)
|
{aliases: []string{"call"}, cmdFn: c.call, helpMsg: `Resumes process, injecting a function call (EXPERIMENTAL!!!)
|
||||||
@ -379,6 +380,12 @@ The "note" is arbitrary text that can be used to identify the checkpoint, if it
|
|||||||
helpMsg: `Deletes checkpoint.
|
helpMsg: `Deletes checkpoint.
|
||||||
|
|
||||||
clear-checkpoint <id>`,
|
clear-checkpoint <id>`,
|
||||||
|
})
|
||||||
|
c.cmds = append(c.cmds, command{
|
||||||
|
aliases: []string{"rev"},
|
||||||
|
cmdFn: c.revCmd,
|
||||||
|
helpMsg: `Reverses the execution of the target program for the command specified.
|
||||||
|
Currently, only the rev step-instruction command is supported.`,
|
||||||
})
|
})
|
||||||
for i := range c.cmds {
|
for i := range c.cmds {
|
||||||
v := &c.cmds[i]
|
v := &c.cmds[i]
|
||||||
@ -988,7 +995,15 @@ func (c *Commands) stepInstruction(t *Term, ctx callContext, args string) error
|
|||||||
if c.frame != 0 {
|
if c.frame != 0 {
|
||||||
return notOnFrameZeroErr
|
return notOnFrameZeroErr
|
||||||
}
|
}
|
||||||
state, err := exitedToError(t.client.StepInstruction())
|
|
||||||
|
var fn func() (*api.DebuggerState, error)
|
||||||
|
if ctx.Prefix == revPrefix {
|
||||||
|
fn = t.client.ReverseStepInstruction
|
||||||
|
} else {
|
||||||
|
fn = t.client.StepInstruction
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := exitedToError(fn())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printcontextNoState(t)
|
printcontextNoState(t)
|
||||||
return err
|
return err
|
||||||
@ -998,6 +1013,18 @@ func (c *Commands) stepInstruction(t *Term, ctx callContext, args string) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Commands) revCmd(t *Term, ctx callContext, args string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("not enough arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Prefix = revPrefix
|
||||||
|
if err := c.CallWithContext(args, t, ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Commands) next(t *Term, ctx callContext, args string) error {
|
func (c *Commands) next(t *Term, ctx callContext, args string) error {
|
||||||
if err := scopePrefixSwitch(t, ctx); err != nil {
|
if err := scopePrefixSwitch(t, ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -356,6 +356,8 @@ const (
|
|||||||
StepOut = "stepOut"
|
StepOut = "stepOut"
|
||||||
// StepInstruction continues for exactly 1 cpu instruction.
|
// StepInstruction continues for exactly 1 cpu instruction.
|
||||||
StepInstruction = "stepInstruction"
|
StepInstruction = "stepInstruction"
|
||||||
|
// ReverseStepInstruction reverses execution for exactly 1 cpu instruction.
|
||||||
|
ReverseStepInstruction = "reverseStepInstruction"
|
||||||
// Next continues to the next source line, not entering function calls.
|
// Next continues to the next source line, not entering function calls.
|
||||||
Next = "next"
|
Next = "next"
|
||||||
// SwitchThread switches the debugger's current thread context.
|
// SwitchThread switches the debugger's current thread context.
|
||||||
|
@ -43,6 +43,8 @@ type Client interface {
|
|||||||
|
|
||||||
// SingleStep will step a single cpu instruction.
|
// SingleStep will step a single cpu instruction.
|
||||||
StepInstruction() (*api.DebuggerState, error)
|
StepInstruction() (*api.DebuggerState, error)
|
||||||
|
// ReverseSingleStep will reverse step a single cpu instruction.
|
||||||
|
ReverseStepInstruction() (*api.DebuggerState, error)
|
||||||
// SwitchThread switches the current thread context.
|
// SwitchThread switches the current thread context.
|
||||||
SwitchThread(threadID int) (*api.DebuggerState, error)
|
SwitchThread(threadID int) (*api.DebuggerState, error)
|
||||||
// SwitchGoroutine switches the current goroutine (and the current thread as well)
|
// SwitchGoroutine switches the current goroutine (and the current thread as well)
|
||||||
|
@ -624,6 +624,15 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
|
|||||||
case api.StepInstruction:
|
case api.StepInstruction:
|
||||||
d.log.Debug("single stepping")
|
d.log.Debug("single stepping")
|
||||||
err = d.target.StepInstruction()
|
err = d.target.StepInstruction()
|
||||||
|
case api.ReverseStepInstruction:
|
||||||
|
d.log.Debug("reverse single stepping")
|
||||||
|
if err := d.target.Direction(proc.Backward); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
d.target.Direction(proc.Forward)
|
||||||
|
}()
|
||||||
|
err = d.target.StepInstruction()
|
||||||
case api.StepOut:
|
case api.StepOut:
|
||||||
d.log.Debug("step out")
|
d.log.Debug("step out")
|
||||||
err = proc.StepOut(d.target)
|
err = proc.StepOut(d.target)
|
||||||
|
@ -125,6 +125,12 @@ func (c *RPCClient) StepInstruction() (*api.DebuggerState, error) {
|
|||||||
return state, err
|
return state, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *RPCClient) ReverseStepInstruction() (*api.DebuggerState, error) {
|
||||||
|
state := new(api.DebuggerState)
|
||||||
|
err := c.call("Command", &api.DebuggerCommand{Name: api.ReverseStepInstruction}, state)
|
||||||
|
return state, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) {
|
func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) {
|
||||||
state := new(api.DebuggerState)
|
state := new(api.DebuggerState)
|
||||||
cmd := &api.DebuggerCommand{
|
cmd := &api.DebuggerCommand{
|
||||||
|
@ -160,6 +160,12 @@ func (c *RPCClient) StepInstruction() (*api.DebuggerState, error) {
|
|||||||
return &out.State, err
|
return &out.State, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *RPCClient) ReverseStepInstruction() (*api.DebuggerState, error) {
|
||||||
|
var out CommandOut
|
||||||
|
err := c.call("Command", api.DebuggerCommand{Name: api.ReverseStepInstruction}, &out)
|
||||||
|
return &out.State, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) {
|
func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) {
|
||||||
var out CommandOut
|
var out CommandOut
|
||||||
cmd := api.DebuggerCommand{
|
cmd := api.DebuggerCommand{
|
||||||
|
Loading…
Reference in New Issue
Block a user