mirror of
https://github.com/go-delve/delve.git
synced 2025-10-30 10:17:03 +08:00
proc,service,terminal: eval expressions in the scope of a deferred call
Add ability to evaluate variables on the scope of a deferred call's argument frame.
This commit is contained in:
@ -32,6 +32,7 @@ type cmdPrefix int
|
||||
const (
|
||||
noPrefix = cmdPrefix(0)
|
||||
onPrefix = cmdPrefix(1 << iota)
|
||||
deferredPrefix
|
||||
)
|
||||
|
||||
type callContext struct {
|
||||
@ -188,7 +189,7 @@ Called without arguments it will show information about the current goroutine.
|
||||
Called with a single argument it will switch to the specified goroutine.
|
||||
Called with more arguments it will execute a command on the specified goroutine.`},
|
||||
{aliases: []string{"breakpoints", "bp"}, cmdFn: breakpoints, helpMsg: "Print out info for active breakpoints."},
|
||||
{aliases: []string{"print", "p"}, allowedPrefixes: onPrefix, cmdFn: printVar, helpMsg: `Evaluate an expression.
|
||||
{aliases: []string{"print", "p"}, allowedPrefixes: onPrefix | deferredPrefix, cmdFn: printVar, helpMsg: `Evaluate an expression.
|
||||
|
||||
[goroutine <n>] [frame <m>] print <expression>
|
||||
|
||||
@ -216,12 +217,12 @@ If regex is specified only the functions matching it will be returned.`},
|
||||
types [<regex>]
|
||||
|
||||
If regex is specified only the types matching it will be returned.`},
|
||||
{aliases: []string{"args"}, allowedPrefixes: onPrefix, cmdFn: args, helpMsg: `Print function arguments.
|
||||
{aliases: []string{"args"}, allowedPrefixes: onPrefix | deferredPrefix, cmdFn: args, helpMsg: `Print function arguments.
|
||||
|
||||
[goroutine <n>] [frame <m>] args [-v] [<regex>]
|
||||
|
||||
If regex is specified only function arguments with a name matching it will be returned. If -v is specified more information about each function argument will be shown.`},
|
||||
{aliases: []string{"locals"}, allowedPrefixes: onPrefix, cmdFn: locals, helpMsg: `Print local variables.
|
||||
{aliases: []string{"locals"}, allowedPrefixes: onPrefix | deferredPrefix, cmdFn: locals, helpMsg: `Print local variables.
|
||||
|
||||
[goroutine <n>] [frame <m>] locals [-v] [<regex>]
|
||||
|
||||
@ -250,10 +251,11 @@ When connected to a headless instance started with the --accept-multiclient, pas
|
||||
Show source around current point or provided linespec.`},
|
||||
{aliases: []string{"stack", "bt"}, allowedPrefixes: onPrefix, cmdFn: stackCommand, helpMsg: `Print stack trace.
|
||||
|
||||
[goroutine <n>] [frame <m>] stack [<depth>] [-full] [-g] [-s] [-offsets]
|
||||
[goroutine <n>] [frame <m>] stack [<depth>] [-full] [-offsets] [-defer]
|
||||
|
||||
-full every stackframe is decorated with the value of its local variables and arguments.
|
||||
-offsets prints frame offset of each frame
|
||||
-offsets prints frame offset of each frame.
|
||||
-defer prints deferred function call stack for each frame.
|
||||
`},
|
||||
{aliases: []string{"frame"},
|
||||
cmdFn: func(t *Term, ctx callContext, arg string) error {
|
||||
@ -286,6 +288,11 @@ Move the current frame up by <m>. The second form runs the command on the given
|
||||
down [<m>] <command>
|
||||
|
||||
Move the current frame down by <m>. The second form runs the command on the given frame.`},
|
||||
{aliases: []string{"deferred"}, cmdFn: c.deferredCommand, helpMsg: `Executes command in the context of a deferred call.
|
||||
|
||||
deferred <n> <command>
|
||||
|
||||
Executes the specified command (print, args, locals) in the context of the n-th deferred call in the current frame.`},
|
||||
{aliases: []string{"source"}, cmdFn: c.sourceCommand, helpMsg: `Executes a file containing a list of delve commands
|
||||
|
||||
source <path>`},
|
||||
@ -428,7 +435,7 @@ func (c *Commands) CallWithContext(cmdstr string, t *Term, ctx callContext) erro
|
||||
|
||||
// Call takes a command to execute.
|
||||
func (c *Commands) Call(cmdstr string, t *Term) error {
|
||||
ctx := callContext{Prefix: noPrefix, Scope: api.EvalScope{GoroutineID: -1, Frame: c.frame}}
|
||||
ctx := callContext{Prefix: noPrefix, Scope: api.EvalScope{GoroutineID: -1, Frame: c.frame, DeferredCall: 0}}
|
||||
return c.CallWithContext(cmdstr, t, ctx)
|
||||
}
|
||||
|
||||
@ -716,6 +723,22 @@ func (c *Commands) frameCommand(t *Term, ctx callContext, argstr string, directi
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) deferredCommand(t *Term, ctx callContext, argstr string) error {
|
||||
ctx.Prefix = deferredPrefix
|
||||
|
||||
space := strings.Index(argstr, " ")
|
||||
|
||||
var err error
|
||||
ctx.Scope.DeferredCall, err = strconv.Atoi(argstr[:space])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx.Scope.DeferredCall <= 0 {
|
||||
return errors.New("argument of deferred must be a number greater than 0 (use 'stack -defer' to see the list of deferred calls)")
|
||||
}
|
||||
return c.CallWithContext(argstr[space:], t, ctx)
|
||||
}
|
||||
|
||||
func printscope(t *Term) error {
|
||||
state, err := t.client.GetState()
|
||||
if err != nil {
|
||||
@ -1573,7 +1596,7 @@ func printStack(stack []api.Stackframe, ind string, offsets bool) {
|
||||
}
|
||||
|
||||
for j, d := range stack[i].Defers {
|
||||
deferHeader := fmt.Sprintf("%s defer %d: ", s, j)
|
||||
deferHeader := fmt.Sprintf("%s defer %d: ", s, j+1)
|
||||
s2 := strings.Repeat(" ", len(deferHeader))
|
||||
if d.Unreadable != "" {
|
||||
fmt.Printf("%s(unreadable defer: %s)\n", deferHeader, d.Unreadable)
|
||||
|
||||
Reference in New Issue
Block a user