mirror of
				https://github.com/go-delve/delve.git
				synced 2025-11-01 03:42:59 +08:00 
			
		
		
		
	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:
		 dpapastamos
					dpapastamos
				
			
				
					committed by
					
						 Derek Parker
						Derek Parker
					
				
			
			
				
	
			
			
			 Derek Parker
						Derek Parker
					
				
			
						parent
						
							1758823429
						
					
				
				
					commit
					c7d1692e92
				
			| @ -32,6 +32,7 @@ Command | Description | ||||
| [print](#print) | Evaluate an expression. | ||||
| [regs](#regs) | Print contents of CPU registers. | ||||
| [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. | ||||
| [set](#set) | Changes the value of a variable. | ||||
| [source](#source) | Executes a file containing a list of delve commands | ||||
| @ -329,6 +330,11 @@ Restart process from a checkpoint or event. | ||||
|  | ||||
| Aliases: r | ||||
|  | ||||
| ## rev | ||||
| Reverses the execution of the target program for the command specified. | ||||
| Currently, only the rev step-instruction command is supported. | ||||
|  | ||||
|  | ||||
| ## rewind | ||||
| Run backwards until breakpoint or program termination. | ||||
|  | ||||
|  | ||||
| @ -34,6 +34,7 @@ const ( | ||||
| 	noPrefix = cmdPrefix(0) | ||||
| 	onPrefix = cmdPrefix(1 << iota) | ||||
| 	deferredPrefix | ||||
| 	revPrefix | ||||
| ) | ||||
|  | ||||
| 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{"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{"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!!!) | ||||
| @ -379,6 +380,12 @@ The "note" is arbitrary text that can be used to identify the checkpoint, if it | ||||
| 			helpMsg: `Deletes checkpoint. | ||||
|  | ||||
| 	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 { | ||||
| 			v := &c.cmds[i] | ||||
| @ -988,7 +995,15 @@ func (c *Commands) stepInstruction(t *Term, ctx callContext, args string) error | ||||
| 	if c.frame != 0 { | ||||
| 		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 { | ||||
| 		printcontextNoState(t) | ||||
| 		return err | ||||
| @ -998,6 +1013,18 @@ func (c *Commands) stepInstruction(t *Term, ctx callContext, args string) error | ||||
| 	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 { | ||||
| 	if err := scopePrefixSwitch(t, ctx); err != nil { | ||||
| 		return err | ||||
|  | ||||
| @ -356,6 +356,8 @@ const ( | ||||
| 	StepOut = "stepOut" | ||||
| 	// StepInstruction continues for exactly 1 cpu instruction. | ||||
| 	StepInstruction = "stepInstruction" | ||||
| 	// ReverseStepInstruction reverses execution for exactly 1 cpu instruction. | ||||
| 	ReverseStepInstruction = "reverseStepInstruction" | ||||
| 	// Next continues to the next source line, not entering function calls. | ||||
| 	Next = "next" | ||||
| 	// SwitchThread switches the debugger's current thread context. | ||||
|  | ||||
| @ -43,6 +43,8 @@ type Client interface { | ||||
|  | ||||
| 	// SingleStep will step a single cpu instruction. | ||||
| 	StepInstruction() (*api.DebuggerState, error) | ||||
| 	// ReverseSingleStep will reverse step a single cpu instruction. | ||||
| 	ReverseStepInstruction() (*api.DebuggerState, error) | ||||
| 	// SwitchThread switches the current thread context. | ||||
| 	SwitchThread(threadID int) (*api.DebuggerState, error) | ||||
| 	// 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: | ||||
| 		d.log.Debug("single stepping") | ||||
| 		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: | ||||
| 		d.log.Debug("step out") | ||||
| 		err = proc.StepOut(d.target) | ||||
|  | ||||
| @ -125,6 +125,12 @@ func (c *RPCClient) StepInstruction() (*api.DebuggerState, error) { | ||||
| 	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) { | ||||
| 	state := new(api.DebuggerState) | ||||
| 	cmd := &api.DebuggerCommand{ | ||||
|  | ||||
| @ -160,6 +160,12 @@ func (c *RPCClient) StepInstruction() (*api.DebuggerState, error) { | ||||
| 	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) { | ||||
| 	var out CommandOut | ||||
| 	cmd := api.DebuggerCommand{ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user