mirror of
https://github.com/go-delve/delve.git
synced 2025-10-29 17:56:45 +08:00
service/debugger,terminal: API and user interface for follow exec mode (#3286)
Updates #2551
This commit is contained in:
committed by
GitHub
parent
47481fe0ab
commit
a61ccea65a
@ -559,6 +559,20 @@ The core dump is always written in ELF, even on systems (windows, macOS) where t
|
||||
Output of Delve's command is appended to the specified output file. If '-t' is specified and the output file exists it is truncated. If '-x' is specified output to stdout is suppressed instead.
|
||||
|
||||
Using the -off option disables the transcript.`},
|
||||
|
||||
{aliases: []string{"target"}, cmdFn: target, helpMsg: `Manages child process debugging.
|
||||
|
||||
target follow-exec [-on [regex]] [-off]
|
||||
|
||||
Enables or disables follow exec mode. When follow exec mode Delve will automatically attach to new child processes executed by the target process. An optional regular expression can be passed to 'target follow-exec', only child processes with a command line matching the regular expression will be followed.
|
||||
|
||||
target list
|
||||
|
||||
List currently attached processes.
|
||||
|
||||
target switch [pid]
|
||||
|
||||
Switches to the specified process.`},
|
||||
}
|
||||
|
||||
addrecorded := client == nil
|
||||
@ -1212,6 +1226,7 @@ func parseOptionalCount(arg string) (int64, error) {
|
||||
}
|
||||
|
||||
func restartLive(t *Term, ctx callContext, args string) error {
|
||||
t.oldPid = 0
|
||||
resetArgs, newArgv, newRedirects, err := parseNewArgv(args)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -2522,6 +2537,12 @@ func printcontext(t *Term, state *api.DebuggerState) {
|
||||
return
|
||||
}
|
||||
|
||||
if state.Pid != t.oldPid {
|
||||
if t.oldPid != 0 {
|
||||
fmt.Fprintf(t.stdout, "Switch target process from %d to %d\n", t.oldPid, state.Pid)
|
||||
}
|
||||
t.oldPid = state.Pid
|
||||
}
|
||||
for i := range state.Threads {
|
||||
if (state.CurrentThread != nil) && (state.Threads[i].ID == state.CurrentThread.ID) {
|
||||
continue
|
||||
@ -3177,6 +3198,71 @@ func transcript(t *Term, ctx callContext, args string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func target(t *Term, ctx callContext, args string) error {
|
||||
argv := config.Split2PartsBySpace(args)
|
||||
switch argv[0] {
|
||||
case "list":
|
||||
tgts, err := t.client.ListTargets()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(t.stdout, 4, 4, 2, ' ', 0)
|
||||
for _, tgt := range tgts {
|
||||
selected := ""
|
||||
if tgt.Pid == t.oldPid {
|
||||
selected = "*"
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%d\t%s\n", selected, tgt.Pid, tgt.CmdLine)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
case "follow-exec":
|
||||
if len(argv) == 1 {
|
||||
return errors.New("not enough arguments")
|
||||
}
|
||||
argv = config.Split2PartsBySpace(argv[1])
|
||||
switch argv[0] {
|
||||
case "-on":
|
||||
var regex string
|
||||
if len(argv) == 2 {
|
||||
regex = argv[1]
|
||||
}
|
||||
t.client.FollowExec(true, regex)
|
||||
case "-off":
|
||||
if len(argv) > 1 {
|
||||
return errors.New("too many arguments")
|
||||
}
|
||||
t.client.FollowExec(false, "")
|
||||
default:
|
||||
return fmt.Errorf("unknown argument %q to 'target follow-exec'", argv[0])
|
||||
}
|
||||
return nil
|
||||
case "switch":
|
||||
tgts, err := t.client.ListTargets()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pid, err := strconv.Atoi(argv[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found := false
|
||||
for _, tgt := range tgts {
|
||||
if tgt.Pid == pid {
|
||||
found = true
|
||||
t.client.SwitchThread(tgt.CurrentThread.ID)
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf("could not find target %d", pid)
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown command 'target %s'", argv[0])
|
||||
}
|
||||
}
|
||||
|
||||
func formatBreakpointName(bp *api.Breakpoint, upcase bool) string {
|
||||
thing := "breakpoint"
|
||||
if bp.Tracepoint {
|
||||
@ -3226,5 +3312,5 @@ func (t *Term) formatBreakpointLocation(bp *api.Breakpoint) string {
|
||||
func shouldAskToSuspendBreakpoint(t *Term) bool {
|
||||
fns, _ := t.client.ListFunctions(`^plugin\.Open$`)
|
||||
_, err := t.client.GetState()
|
||||
return len(fns) > 0 || isErrProcessExited(err)
|
||||
return len(fns) > 0 || isErrProcessExited(err) || t.client.FollowExecEnabled()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user