terminal: Add [linespec] argument to 'continue' command (#2376)
This change allows specifying an optional linespec after the 'continue' command which sets a temporary breakpoint. Fixes #2373
This commit is contained in:
parent
375f442949
commit
d1834df3c5
@ -206,6 +206,16 @@ Defines <alias> as an alias to <command> or removes an alias.
|
||||
## continue
|
||||
Run until breakpoint or program termination.
|
||||
|
||||
continue [<linespec>]
|
||||
|
||||
Optional linespec argument allows you to continue until a specific location is reached. The program will halt if a breakpoint is hit before reaching the specified location.
|
||||
|
||||
For example:
|
||||
|
||||
continue main.main
|
||||
continue encoding/json.Marshal
|
||||
|
||||
|
||||
Aliases: c
|
||||
|
||||
## deferred
|
||||
@ -380,7 +390,7 @@ If regex is specified only local variables with a name matching it will be retur
|
||||
## next
|
||||
Step over to next source line.
|
||||
|
||||
next [count]
|
||||
next [count]
|
||||
|
||||
Optional [count] argument allows you to skip multiple lines.
|
||||
|
||||
|
@ -152,12 +152,22 @@ A list of file redirections can be specified after the new argument list to over
|
||||
2>error.txt redirects the standard error of the target process to error.txt
|
||||
`},
|
||||
{aliases: []string{"rebuild"}, group: runCmds, cmdFn: c.rebuild, allowedPrefixes: revPrefix, helpMsg: "Rebuild the target executable and restarts it. It does not work if the executable was not built by delve."},
|
||||
{aliases: []string{"continue", "c"}, group: runCmds, cmdFn: c.cont, allowedPrefixes: revPrefix, helpMsg: "Run until breakpoint or program termination."},
|
||||
{aliases: []string{"continue", "c"}, group: runCmds, cmdFn: c.cont, allowedPrefixes: revPrefix, helpMsg: `Run until breakpoint or program termination.
|
||||
|
||||
continue [<linespec>]
|
||||
|
||||
Optional linespec argument allows you to continue until a specific location is reached. The program will halt if a breakpoint is hit before reaching the specified location.
|
||||
|
||||
For example:
|
||||
|
||||
continue main.main
|
||||
continue encoding/json.Marshal
|
||||
`},
|
||||
{aliases: []string{"step", "s"}, group: runCmds, cmdFn: c.step, allowedPrefixes: revPrefix, helpMsg: "Single step through program."},
|
||||
{aliases: []string{"step-instruction", "si"}, group: runCmds, allowedPrefixes: revPrefix, cmdFn: c.stepInstruction, helpMsg: "Single step a single cpu instruction."},
|
||||
{aliases: []string{"next", "n"}, group: runCmds, cmdFn: c.next, allowedPrefixes: revPrefix, helpMsg: `Step over to next source line.
|
||||
|
||||
next [count]
|
||||
next [count]
|
||||
|
||||
Optional [count] argument allows you to skip multiple lines.
|
||||
`},
|
||||
@ -1191,6 +1201,19 @@ func (c *Commands) rebuild(t *Term, ctx callContext, args string) error {
|
||||
}
|
||||
|
||||
func (c *Commands) cont(t *Term, ctx callContext, args string) error {
|
||||
if args != "" {
|
||||
tmp, err := setBreakpoint(t, ctx, false, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
for _, bp := range tmp {
|
||||
if _, err := t.client.ClearBreakpoint(bp.ID); err != nil {
|
||||
fmt.Printf("failed to clear temporary breakpoint: %d", bp.ID)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
if ctx.Prefix == revPrefix {
|
||||
return c.rewind(t, ctx, args)
|
||||
}
|
||||
@ -1497,7 +1520,7 @@ func breakpoints(t *Term, ctx callContext, args string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) error {
|
||||
func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) ([]*api.Breakpoint, error) {
|
||||
args := split2PartsBySpace(argstr)
|
||||
|
||||
requestedBp := &api.Breakpoint{}
|
||||
@ -1513,23 +1536,24 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) err
|
||||
spec = argstr
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("address required")
|
||||
return nil, fmt.Errorf("address required")
|
||||
}
|
||||
|
||||
requestedBp.Tracepoint = tracepoint
|
||||
locs, err := t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules())
|
||||
if err != nil {
|
||||
if requestedBp.Name == "" {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
requestedBp.Name = ""
|
||||
spec = argstr
|
||||
var err2 error
|
||||
locs, err2 = t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules())
|
||||
if err2 != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
created := []*api.Breakpoint{}
|
||||
for _, loc := range locs {
|
||||
requestedBp.Addr = loc.PC
|
||||
requestedBp.Addrs = loc.PCs
|
||||
@ -1539,8 +1563,9 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) err
|
||||
|
||||
bp, err := t.client.CreateBreakpoint(requestedBp)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
created = append(created, bp)
|
||||
|
||||
fmt.Printf("%s set at %s\n", formatBreakpointName(bp, true), t.formatBreakpointLocation(bp))
|
||||
}
|
||||
@ -1548,7 +1573,7 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) err
|
||||
var shouldSetReturnBreakpoints bool
|
||||
loc, err := locspec.Parse(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
switch t := loc.(type) {
|
||||
case *locspec.NormalLocationSpec:
|
||||
@ -1563,7 +1588,7 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) err
|
||||
}
|
||||
addrs, err := t.client.(*rpc2.RPCClient).FunctionReturnLocations(locs[0].Function.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
for j := range addrs {
|
||||
_, err = t.client.CreateBreakpoint(&api.Breakpoint{
|
||||
@ -1573,20 +1598,22 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) err
|
||||
LoadArgs: &ShortLoadConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return created, nil
|
||||
}
|
||||
|
||||
func breakpoint(t *Term, ctx callContext, args string) error {
|
||||
return setBreakpoint(t, ctx, false, args)
|
||||
_, err := setBreakpoint(t, ctx, false, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func tracepoint(t *Term, ctx callContext, args string) error {
|
||||
return setBreakpoint(t, ctx, true, args)
|
||||
_, err := setBreakpoint(t, ctx, true, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func edit(t *Term, ctx callContext, args string) error {
|
||||
|
@ -1140,3 +1140,10 @@ func TestParseNewArgv(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestContinueUntil(t *testing.T) {
|
||||
withTestTerminal("continuetestprog", t, func(term *FakeTerminal) {
|
||||
listIsAt(t, term, "continue main.main", 16, -1, -1)
|
||||
listIsAt(t, term, "continue main.sayhi", 12, -1, -1)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user