Skip to content

Commit

Permalink
terminal: add display command (go-delve#1917)
Browse files Browse the repository at this point in the history
Implements go-delve#1256
  • Loading branch information
aarzilli committed Mar 19, 2020
1 parent 4aee281 commit c6de961
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 2 deletions.
14 changes: 13 additions & 1 deletion Documentation/cli/README.md
Expand Up @@ -39,6 +39,7 @@ Command | Description
Command | Description
--------|------------
[args](#args) | Print function arguments.
[display](#display) | Print value of an expression every time the program stops.
[examinemem](#examinemem) | Examine memory:
[locals](#locals) | Print local variables.
[print](#print) | Evaluate an expression.
Expand Down Expand Up @@ -225,6 +226,17 @@ If no argument is specified the function being executed in the selected stack fr

Aliases: disass

## display
Print value of an expression every time the program stops.

display -a <expression>
display -d <number>

The '-a' option adds an expression to the list of expression printed every time the program stops. The '-d' option removes the specified expression from the list.

If display is called without arguments it will print the value of all expression in the list.


## down
Move the current frame down.

Expand All @@ -246,7 +258,7 @@ Aliases: ed
## examinemem
Examine memory:

examinemem [-fmt <format>] [-len <length>] <address>
examinemem [-fmt <format>] [-len <length>] <address>

Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal),.
Length is the number of bytes (default 1) and must be less than or equal to 1000.
Expand Down
47 changes: 46 additions & 1 deletion pkg/terminal/command.go
Expand Up @@ -375,7 +375,7 @@ If locspec is omitted edit will open the current source file in the editor, othe

{aliases: []string{"examinemem", "x"}, group: dataCmds, cmdFn: examineMemoryCmd, helpMsg: `Examine memory:
examinemem [-fmt <format>] [-len <length>] <address>
examinemem [-fmt <format>] [-len <length>] <address>
Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal),.
Length is the number of bytes (default 1) and must be less than or equal to 1000.
Expand All @@ -384,6 +384,15 @@ Address is the memory location of the target to examine.
For example:
x -fmt hex -len 20 0xc00008af38`},

{aliases: []string{"display"}, group: dataCmds, cmdFn: display, helpMsg: `Print value of an expression every time the program stops.
display -a <expression>
display -d <number>
The '-a' option adds an expression to the list of expression printed every time the program stops. The '-d' option removes the specified expression from the list.
If display is called without arguments it will print the value of all expression in the list.`},
}

if client == nil || client.Recorded() {
Expand Down Expand Up @@ -981,6 +990,7 @@ func restartRecorded(t *Term, ctx callContext, args string) error {
}
printcontext(t, state)
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
t.onStop()
return nil
}

Expand Down Expand Up @@ -1057,6 +1067,7 @@ func (c *Commands) cont(t *Term, ctx callContext, args string) error {
if ctx.Prefix == revPrefix {
return c.rewind(t, ctx, args)
}
defer t.onStop()
c.frame = 0
stateChan := t.client.Continue()
var state *api.DebuggerState
Expand All @@ -1072,6 +1083,7 @@ func (c *Commands) cont(t *Term, ctx callContext, args string) error {
}

func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, shouldPrintFile bool) error {
defer t.onStop()
if !state.NextInProgress {
if shouldPrintFile {
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
Expand Down Expand Up @@ -1141,6 +1153,8 @@ func (c *Commands) stepInstruction(t *Term, ctx callContext, args string) error
return notOnFrameZeroErr
}

defer t.onStop()

var fn func() (*api.DebuggerState, error)
if ctx.Prefix == revPrefix {
fn = t.client.ReverseStepInstruction
Expand Down Expand Up @@ -2386,6 +2400,37 @@ func clearCheckpoint(t *Term, ctx callContext, args string) error {
return t.client.ClearCheckpoint(id)
}

func display(t *Term, ctx callContext, args string) error {
const (
addOption = "-a "
delOption = "-d "
)
switch {
case args == "":
t.printDisplays()

case strings.HasPrefix(args, addOption):
args = strings.TrimSpace(args[len(addOption):])
if args == "" {
return fmt.Errorf("not enough arguments")
}
t.addDisplay(args)
t.printDisplay(len(t.displays) - 1)

case strings.HasPrefix(args, delOption):
args = strings.TrimSpace(args[len(delOption):])
n, err := strconv.Atoi(args)
if err != nil {
return fmt.Errorf("%q is not a number", args)
}
return t.removeDisplay(n)

default:
return fmt.Errorf("wrong arguments")
}
return nil
}

func formatBreakpointName(bp *api.Breakpoint, upcase bool) string {
thing := "breakpoint"
if bp.Tracepoint {
Expand Down
45 changes: 45 additions & 0 deletions pkg/terminal/terminal.go
Expand Up @@ -54,6 +54,7 @@ type Term struct {
dumb bool
stdout io.Writer
InitFile string
displays []string

starlarkEnv *starbind.Env

Expand Down Expand Up @@ -432,6 +433,50 @@ func (t *Term) loadConfig() api.LoadConfig {
return r
}

func (t *Term) removeDisplay(n int) error {
if n < 0 || n >= len(t.displays) {
return fmt.Errorf("%d is out of range", n)
}
t.displays[n] = ""
for i := len(t.displays) - 1; i >= 0; i-- {
if t.displays[i] != "" {
t.displays = t.displays[:i+1]
return nil
}
}
t.displays = t.displays[:0]
return nil
}

func (t *Term) addDisplay(expr string) {
t.displays = append(t.displays, expr)
}

func (t *Term) printDisplay(i int) {
expr := t.displays[i]
val, err := t.client.EvalVariable(api.EvalScope{GoroutineID: -1}, expr, ShortLoadConfig)
if err != nil {
if isErrProcessExited(err) {
return
}
fmt.Printf("%d: %s = error %v\n", i, expr, err)
return
}
fmt.Printf("%d: %s = %s\n", i, val.Name, val.SinglelineString())
}

func (t *Term) printDisplays() {
for i := range t.displays {
if t.displays[i] != "" {
t.printDisplay(i)
}
}
}

func (t *Term) onStop() {
t.printDisplays()
}

// isErrProcessExited returns true if `err` is an RPC error equivalent of proc.ErrProcessExited
func isErrProcessExited(err error) bool {
rpcError, ok := err.(rpc.ServerError)
Expand Down

0 comments on commit c6de961

Please sign in to comment.