github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/terminal/command.go (about)

     1  // Package terminal implements functions for responding to user
     2  // input and dispatching to appropriate backend commands.
     3  package terminal
     4  
     5  //lint:file-ignore ST1005 errors here can be capitalized
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"errors"
    11  	"fmt"
    12  	"go/parser"
    13  	"go/scanner"
    14  	"io"
    15  	"io/ioutil"
    16  	"math"
    17  	"os"
    18  	"os/exec"
    19  	"path/filepath"
    20  	"reflect"
    21  	"regexp"
    22  	"runtime"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"text/tabwriter"
    27  	"time"
    28  
    29  	"github.com/cosiner/argv"
    30  	"github.com/go-delve/delve/pkg/config"
    31  	"github.com/go-delve/delve/pkg/locspec"
    32  	"github.com/go-delve/delve/pkg/proc/debuginfod"
    33  	"github.com/go-delve/delve/service"
    34  	"github.com/go-delve/delve/service/api"
    35  	"github.com/go-delve/delve/service/rpc2"
    36  )
    37  
    38  const optimizedFunctionWarning = "Warning: debugging optimized function"
    39  
    40  type cmdPrefix int
    41  
    42  const (
    43  	noPrefix = cmdPrefix(0)
    44  	onPrefix = cmdPrefix(1 << iota)
    45  	deferredPrefix
    46  	revPrefix
    47  )
    48  
    49  type callContext struct {
    50  	Prefix     cmdPrefix
    51  	Scope      api.EvalScope
    52  	Breakpoint *api.Breakpoint
    53  }
    54  
    55  func (ctx *callContext) scoped() bool {
    56  	return ctx.Scope.GoroutineID >= 0 || ctx.Scope.Frame > 0
    57  }
    58  
    59  type frameDirection int
    60  
    61  const (
    62  	frameSet frameDirection = iota
    63  	frameUp
    64  	frameDown
    65  )
    66  
    67  type cmdfunc func(t *Term, ctx callContext, args string) error
    68  
    69  type command struct {
    70  	aliases         []string
    71  	builtinAliases  []string
    72  	group           commandGroup
    73  	allowedPrefixes cmdPrefix
    74  	helpMsg         string
    75  	cmdFn           cmdfunc
    76  }
    77  
    78  // Returns true if the command string matches one of the aliases for this command
    79  func (c command) match(cmdstr string) bool {
    80  	for _, v := range c.aliases {
    81  		if v == cmdstr {
    82  			return true
    83  		}
    84  	}
    85  	return false
    86  }
    87  
    88  // Commands represents the commands for Delve terminal process.
    89  type Commands struct {
    90  	cmds   []command
    91  	client service.Client
    92  	frame  int // Current frame as set by frame/up/down commands.
    93  }
    94  
    95  var (
    96  	// longLoadConfig loads more information:
    97  	// * Follows pointers
    98  	// * Loads more array values
    99  	// * Does not limit struct fields
   100  	longLoadConfig = api.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1}
   101  	// ShortLoadConfig loads less information, not following pointers
   102  	// and limiting struct fields loaded to 3.
   103  	ShortLoadConfig = api.LoadConfig{MaxStringLen: 64, MaxStructFields: 3}
   104  )
   105  
   106  // byFirstAlias will sort by the first
   107  // alias of a command.
   108  type byFirstAlias []command
   109  
   110  func (a byFirstAlias) Len() int           { return len(a) }
   111  func (a byFirstAlias) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   112  func (a byFirstAlias) Less(i, j int) bool { return a[i].aliases[0] < a[j].aliases[0] }
   113  
   114  // DebugCommands returns a Commands struct with default commands defined.
   115  func DebugCommands(client service.Client) *Commands {
   116  	c := &Commands{client: client}
   117  
   118  	c.cmds = []command{
   119  		{aliases: []string{"help", "h"}, cmdFn: c.help, helpMsg: `Prints the help message.
   120  
   121  	help [command]
   122  
   123  Type "help" followed by the name of a command for more information about it.`},
   124  		{aliases: []string{"break", "b"}, group: breakCmds, cmdFn: breakpoint, helpMsg: `Sets a breakpoint.
   125  
   126  	break [name] [locspec]
   127  
   128  See Documentation/cli/locspec.md for the syntax of locspec. If locspec is omitted a breakpoint will be set on the current line.
   129  
   130  See also: "help on", "help cond" and "help clear"`},
   131  		{aliases: []string{"trace", "t"}, group: breakCmds, cmdFn: tracepoint, allowedPrefixes: onPrefix, helpMsg: `Set tracepoint.
   132  
   133  	trace [name] [locspec]
   134  
   135  A tracepoint is a breakpoint that does not stop the execution of the program, instead when the tracepoint is hit a notification is displayed. See Documentation/cli/locspec.md for the syntax of locspec. If locspec is omitted a tracepoint will be set on the current line.
   136  
   137  See also: "help on", "help cond" and "help clear"`},
   138  		{aliases: []string{"watch"}, group: breakCmds, cmdFn: watchpoint, helpMsg: `Set watchpoint.
   139  	
   140  	watch [-r|-w|-rw] <expr>
   141  	
   142  	-r	stops when the memory location is read
   143  	-w	stops when the memory location is written
   144  	-rw	stops when the memory location is read or written
   145  
   146  The memory location is specified with the same expression language used by 'print', for example:
   147  
   148  	watch v
   149  	watch -w *(*int)(0x1400007c018)
   150  
   151  will watch the address of variable 'v' and writes to an int at addr '0x1400007c018'.
   152  
   153  Note that writes that do not change the value of the watched memory address might not be reported.
   154  
   155  See also: "help print".`},
   156  		{aliases: []string{"restart", "r"}, group: runCmds, cmdFn: restart, helpMsg: `Restart process.
   157  
   158  For recorded targets the command takes the following forms:
   159  
   160  	restart					resets to the start of the recording
   161  	restart [checkpoint]			resets the recording to the given checkpoint
   162  	restart -r [newargv...]	[redirects...]	re-records the target process
   163  	
   164  For live targets the command takes the following forms:
   165  
   166  	restart [newargv...] [redirects...]	restarts the process
   167  
   168  If newargv is omitted the process is restarted (or re-recorded) with the same argument vector.
   169  If -noargs is specified instead, the argument vector is cleared.
   170  
   171  A list of file redirections can be specified after the new argument list to override the redirections defined using the '--redirect' command line option. A syntax similar to Unix shells is used:
   172  
   173  	<input.txt	redirects the standard input of the target process from input.txt
   174  	>output.txt	redirects the standard output of the target process to output.txt
   175  	2>error.txt	redirects the standard error of the target process to error.txt
   176  `},
   177  		{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."},
   178  		{aliases: []string{"continue", "c"}, group: runCmds, cmdFn: c.cont, allowedPrefixes: revPrefix, helpMsg: `Run until breakpoint or program termination.
   179  
   180  	continue [<locspec>]
   181  
   182  Optional locspec 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.
   183  
   184  For example:
   185  
   186  	continue main.main
   187  	continue encoding/json.Marshal
   188  `},
   189  		{aliases: []string{"step", "s"}, group: runCmds, cmdFn: c.step, allowedPrefixes: revPrefix, helpMsg: "Single step through program."},
   190  		{aliases: []string{"step-instruction", "si"}, group: runCmds, allowedPrefixes: revPrefix, cmdFn: c.stepInstruction, helpMsg: "Single step a single cpu instruction."},
   191  		{aliases: []string{"next", "n"}, group: runCmds, cmdFn: c.next, allowedPrefixes: revPrefix, helpMsg: `Step over to next source line.
   192  
   193  	next [count]
   194  
   195  Optional [count] argument allows you to skip multiple lines.
   196  `},
   197  		{aliases: []string{"stepout", "so"}, group: runCmds, allowedPrefixes: revPrefix, cmdFn: c.stepout, helpMsg: "Step out of the current function."},
   198  		{aliases: []string{"call"}, group: runCmds, cmdFn: c.call, helpMsg: `Resumes process, injecting a function call (EXPERIMENTAL!!!)
   199  	
   200  	call [-unsafe] <function call expression>
   201  	
   202  Current limitations:
   203  - only pointers to stack-allocated objects can be passed as argument.
   204  - only some automatic type conversions are supported.
   205  - functions can only be called on running goroutines that are not
   206    executing the runtime.
   207  - the current goroutine needs to have at least 256 bytes of free space on
   208    the stack.
   209  - functions can only be called when the goroutine is stopped at a safe
   210    point.
   211  - calling a function will resume execution of all goroutines.
   212  - only supported on linux's native backend.
   213  `},
   214  		{aliases: []string{"threads"}, group: goroutineCmds, cmdFn: threads, helpMsg: "Print out info for every traced thread."},
   215  		{aliases: []string{"thread", "tr"}, group: goroutineCmds, cmdFn: thread, helpMsg: `Switch to the specified thread.
   216  
   217  	thread <id>`},
   218  		{aliases: []string{"clear"}, group: breakCmds, cmdFn: clear, helpMsg: `Deletes breakpoint.
   219  
   220  	clear <breakpoint name or id>`},
   221  		{aliases: []string{"clearall"}, group: breakCmds, cmdFn: clearAll, helpMsg: `Deletes multiple breakpoints.
   222  
   223  	clearall [<locspec>]
   224  
   225  If called with the locspec argument it will delete all the breakpoints matching the locspec. If locspec is omitted all breakpoints are deleted.`},
   226  		{aliases: []string{"toggle"}, group: breakCmds, cmdFn: toggle, helpMsg: `Toggles on or off a breakpoint.
   227  
   228  toggle <breakpoint name or id>`},
   229  		{aliases: []string{"goroutines", "grs"}, group: goroutineCmds, cmdFn: c.goroutines, helpMsg: `List program goroutines.
   230  
   231  	goroutines [-u|-r|-g|-s] [-t [depth]] [-l] [-with loc expr] [-without loc expr] [-group argument] [-chan expr] [-exec command]
   232  
   233  Print out info for every goroutine. The flag controls what information is shown along with each goroutine:
   234  
   235  	-u	displays location of topmost stackframe in user code (default)
   236  	-r	displays location of topmost stackframe (including frames inside private runtime functions)
   237  	-g	displays location of go instruction that created the goroutine
   238  	-s	displays location of the start function
   239  	-t	displays goroutine's stacktrace (an optional depth value can be specified, default: 10)
   240  	-l	displays goroutine's labels
   241  
   242  If no flag is specified the default is -u, i.e. the first frame within the first 30 frames that is not executing a runtime private function.
   243  
   244  FILTERING
   245  
   246  If -with or -without are specified only goroutines that match the given condition are returned.
   247  
   248  To only display goroutines where the specified location contains (or does not contain, for -without and -wo) expr as a substring, use:
   249  
   250  	goroutines -with (userloc|curloc|goloc|startloc) expr
   251  	goroutines -w (userloc|curloc|goloc|startloc) expr
   252  	goroutines -without (userloc|curloc|goloc|startloc) expr
   253  	goroutines -wo (userloc|curloc|goloc|startloc) expr
   254  
   255  	Where:
   256  	userloc: filter by the location of the topmost stackframe in user code
   257  	curloc: filter by the location of the topmost stackframe (including frames inside private runtime functions)
   258  	goloc: filter by the location of the go instruction that created the goroutine
   259  	startloc: filter by the location of the start function
   260  	
   261  To only display goroutines that have (or do not have) the specified label key and value, use:
   262  
   263  	goroutines -with label key=value
   264  	goroutines -without label key=value
   265  	
   266  To only display goroutines that have (or do not have) the specified label key, use:
   267  
   268  	goroutines -with label key
   269  	goroutines -without label key
   270  	
   271  To only display goroutines that are running (or are not running) on a OS thread, use:
   272  
   273  
   274  	goroutines -with running
   275  	goroutines -without running
   276  	
   277  To only display user (or runtime) goroutines, use:
   278  
   279  	goroutines -with user
   280  	goroutines -without user
   281  
   282  CHANNELS
   283  	
   284  To only show goroutines waiting to send to or receive from a specific channel use:
   285  
   286  	goroutines -chan expr
   287  	
   288  Note that 'expr' must not contain spaces.
   289  
   290  GROUPING
   291  
   292  	goroutines -group (userloc|curloc|goloc|startloc|running|user)
   293  
   294  	Where:
   295  	userloc: groups goroutines by the location of the topmost stackframe in user code
   296  	curloc: groups goroutines by the location of the topmost stackframe
   297  	goloc: groups goroutines by the location of the go instruction that created the goroutine
   298  	startloc: groups goroutines by the location of the start function
   299  	running: groups goroutines by whether they are running or not
   300  	user: groups goroutines by weather they are user or runtime goroutines
   301  
   302  
   303  Groups goroutines by the given location, running status or user classification, up to 5 goroutines per group will be displayed as well as the total number of goroutines in the group.
   304  
   305  	goroutines -group label key
   306  
   307  Groups goroutines by the value of the label with the specified key.
   308  
   309  EXEC
   310  
   311  	goroutines -exec <command>
   312  
   313  Runs the command on every goroutine.
   314  `},
   315  		{aliases: []string{"goroutine", "gr"}, group: goroutineCmds, allowedPrefixes: onPrefix, cmdFn: c.goroutine, helpMsg: `Shows or changes current goroutine
   316  
   317  	goroutine
   318  	goroutine <id>
   319  	goroutine <id> <command>
   320  
   321  Called without arguments it will show information about the current goroutine.
   322  Called with a single argument it will switch to the specified goroutine.
   323  Called with more arguments it will execute a command on the specified goroutine.`},
   324  		{aliases: []string{"breakpoints", "bp"}, group: breakCmds, cmdFn: breakpoints, helpMsg: `Print out info for active breakpoints.
   325  	
   326  	breakpoints [-a]
   327  
   328  Specifying -a prints all physical breakpoint, including internal breakpoints.`},
   329  		{aliases: []string{"print", "p"}, group: dataCmds, allowedPrefixes: onPrefix | deferredPrefix, cmdFn: c.printVar, helpMsg: `Evaluate an expression.
   330  
   331  	[goroutine <n>] [frame <m>] print [%format] <expression>
   332  
   333  See Documentation/cli/expr.md for a description of supported expressions.
   334  
   335  The optional format argument is a format specifier, like the ones used by the fmt package. For example "print %x v" will print v as an hexadecimal number.`},
   336  		{aliases: []string{"whatis"}, group: dataCmds, cmdFn: whatisCommand, helpMsg: `Prints type of an expression.
   337  
   338  	whatis <expression>`},
   339  		{aliases: []string{"set"}, group: dataCmds, cmdFn: setVar, helpMsg: `Changes the value of a variable.
   340  
   341  	[goroutine <n>] [frame <m>] set <variable> = <value>
   342  
   343  See Documentation/cli/expr.md for a description of supported expressions. Only numerical variables and pointers can be changed.`},
   344  		{aliases: []string{"sources"}, cmdFn: sources, helpMsg: `Print list of source files.
   345  
   346  	sources [<regex>]
   347  
   348  If regex is specified only the source files matching it will be returned.`},
   349  		{aliases: []string{"funcs"}, cmdFn: funcs, helpMsg: `Print list of functions.
   350  
   351  	funcs [<regex>]
   352  
   353  If regex is specified only the functions matching it will be returned.`},
   354  		{aliases: []string{"types"}, cmdFn: types, helpMsg: `Print list of types
   355  
   356  	types [<regex>]
   357  
   358  If regex is specified only the types matching it will be returned.`},
   359  		{aliases: []string{"args"}, allowedPrefixes: onPrefix | deferredPrefix, group: dataCmds, cmdFn: args, helpMsg: `Print function arguments.
   360  
   361  	[goroutine <n>] [frame <m>] args [-v] [<regex>]
   362  
   363  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.`},
   364  		{aliases: []string{"locals"}, allowedPrefixes: onPrefix | deferredPrefix, group: dataCmds, cmdFn: locals, helpMsg: `Print local variables.
   365  
   366  	[goroutine <n>] [frame <m>] locals [-v] [<regex>]
   367  
   368  The name of variables that are shadowed in the current scope will be shown in parenthesis.
   369  
   370  If regex is specified only local variables with a name matching it will be returned. If -v is specified more information about each local variable will be shown.`},
   371  		{aliases: []string{"vars"}, cmdFn: vars, group: dataCmds, helpMsg: `Print package variables.
   372  
   373  	vars [-v] [<regex>]
   374  
   375  If regex is specified only package variables with a name matching it will be returned. If -v is specified more information about each package variable will be shown.`},
   376  		{aliases: []string{"regs"}, cmdFn: regs, group: dataCmds, helpMsg: `Print contents of CPU registers.
   377  
   378  	regs [-a]
   379  
   380  Argument -a shows more registers. Individual registers can also be displayed by 'print' and 'display'. See Documentation/cli/expr.md.`},
   381  		{aliases: []string{"exit", "quit", "q"}, cmdFn: exitCommand, helpMsg: `Exit the debugger.
   382  		
   383  	exit [-c]
   384  	
   385  When connected to a headless instance started with the --accept-multiclient, pass -c to resume the execution of the target process before disconnecting.`},
   386  		{aliases: []string{"list", "ls", "l"}, cmdFn: listCommand, helpMsg: `Show source code.
   387  
   388  	[goroutine <n>] [frame <m>] list [<locspec>]
   389  
   390  Show source around current point or provided locspec.
   391  
   392  For example:
   393  
   394  	frame 1 list 69
   395  	list testvariables.go:10000
   396  	list main.main:30
   397  	list 40`},
   398  		{aliases: []string{"stack", "bt"}, allowedPrefixes: onPrefix, group: stackCmds, cmdFn: stackCommand, helpMsg: `Print stack trace.
   399  
   400  	[goroutine <n>] [frame <m>] stack [<depth>] [-full] [-offsets] [-defer] [-a <n>] [-adepth <depth>] [-mode <mode>]
   401  
   402  	-full		every stackframe is decorated with the value of its local variables and arguments.
   403  	-offsets	prints frame offset of each frame.
   404  	-defer		prints deferred function call stack for each frame.
   405  	-a <n>		prints stacktrace of n ancestors of the selected goroutine (target process must have tracebackancestors enabled)
   406  	-adepth <depth>	configures depth of ancestor stacktrace
   407  	-mode <mode>	specifies the stacktrace mode, possible values are:
   408  			normal	- attempts to automatically switch between cgo frames and go frames
   409  			simple	- disables automatic switch between cgo and go
   410  			fromg	- starts from the registers stored in the runtime.g struct
   411  `},
   412  		{aliases: []string{"frame"},
   413  			group: stackCmds,
   414  			cmdFn: func(t *Term, ctx callContext, arg string) error {
   415  				return c.frameCommand(t, ctx, arg, frameSet)
   416  			},
   417  			helpMsg: `Set the current frame, or execute command on a different frame.
   418  
   419  	frame <m>
   420  	frame <m> <command>
   421  
   422  The first form sets frame used by subsequent commands such as "print" or "set".
   423  The second form runs the command on the given frame.`},
   424  		{aliases: []string{"up"},
   425  			group: stackCmds,
   426  			cmdFn: func(t *Term, ctx callContext, arg string) error {
   427  				return c.frameCommand(t, ctx, arg, frameUp)
   428  			},
   429  			helpMsg: `Move the current frame up.
   430  
   431  	up [<m>]
   432  	up [<m>] <command>
   433  
   434  Move the current frame up by <m>. The second form runs the command on the given frame.`},
   435  		{aliases: []string{"down"},
   436  			group: stackCmds,
   437  			cmdFn: func(t *Term, ctx callContext, arg string) error {
   438  				return c.frameCommand(t, ctx, arg, frameDown)
   439  			},
   440  			helpMsg: `Move the current frame down.
   441  
   442  	down [<m>]
   443  	down [<m>] <command>
   444  
   445  Move the current frame down by <m>. The second form runs the command on the given frame.`},
   446  		{aliases: []string{"deferred"}, group: stackCmds, cmdFn: c.deferredCommand, helpMsg: `Executes command in the context of a deferred call.
   447  
   448  	deferred <n> <command>
   449  
   450  Executes the specified command (print, args, locals) in the context of the n-th deferred call in the current frame.`},
   451  		{aliases: []string{"source"}, cmdFn: c.sourceCommand, helpMsg: `Executes a file containing a list of delve commands
   452  
   453  	source <path>
   454  	
   455  If path ends with the .star extension it will be interpreted as a starlark script. See Documentation/cli/starlark.md for the syntax.
   456  
   457  If path is a single '-' character an interactive starlark interpreter will start instead. Type 'exit' to exit.`},
   458  		{aliases: []string{"disassemble", "disass"}, cmdFn: disassCommand, helpMsg: `Disassembler.
   459  
   460  	[goroutine <n>] [frame <m>] disassemble [-a <start> <end>] [-l <locspec>]
   461  
   462  If no argument is specified the function being executed in the selected stack frame will be executed.
   463  
   464  	-a <start> <end>	disassembles the specified address range
   465  	-l <locspec>		disassembles the specified function`},
   466  		{aliases: []string{"on"}, group: breakCmds, cmdFn: c.onCmd, helpMsg: `Executes a command when a breakpoint is hit.
   467  
   468  	on <breakpoint name or id> <command>
   469  	on <breakpoint name or id> -edit
   470  	
   471  
   472  Supported commands: print, stack, goroutine, trace and cond. 
   473  To convert a breakpoint into a tracepoint use:
   474  	
   475  	on <breakpoint name or id> trace
   476  
   477  The command 'on <bp> cond <cond-arguments>' is equivalent to 'cond <bp> <cond-arguments>'.
   478  
   479  The command 'on x -edit' can be used to edit the list of commands executed when the breakpoint is hit.`},
   480  		{aliases: []string{"condition", "cond"}, group: breakCmds, cmdFn: conditionCmd, allowedPrefixes: onPrefix, helpMsg: `Set breakpoint condition.
   481  
   482  	condition <breakpoint name or id> <boolean expression>.
   483  	condition -hitcount <breakpoint name or id> <operator> <argument>.
   484  	condition -per-g-hitcount <breakpoint name or id> <operator> <argument>.
   485  	condition -clear <breakpoint name or id>.
   486  
   487  Specifies that the breakpoint, tracepoint or watchpoint should break only if the boolean expression is true.
   488  
   489  See Documentation/cli/expr.md for a description of supported expressions.
   490  
   491  With the -hitcount option a condition on the breakpoint hit count can be set, the following operators are supported
   492  
   493  	condition -hitcount bp > n
   494  	condition -hitcount bp >= n
   495  	condition -hitcount bp < n
   496  	condition -hitcount bp <= n
   497  	condition -hitcount bp == n
   498  	condition -hitcount bp != n
   499  	condition -hitcount bp % n
   500  
   501  The -per-g-hitcount option works like -hitcount, but use per goroutine hitcount to compare with n.
   502  
   503  With the -clear option a condition on the breakpoint can removed.
   504  	
   505  The '% n' form means we should stop at the breakpoint when the hitcount is a multiple of n.
   506  
   507  Examples:
   508  
   509  	cond 2 i == 10				breakpoint 2 will stop when variable i equals 10
   510  	cond name runtime.curg.goid == 5	breakpoint 'name' will stop only on goroutine 5
   511  	cond -clear 2				the condition on breakpoint 2 will be removed
   512  `},
   513  		{aliases: []string{"config"}, cmdFn: configureCmd, helpMsg: `Changes configuration parameters.
   514  
   515  	config -list
   516  
   517  Show all configuration parameters.
   518  
   519  	config -save
   520  
   521  Saves the configuration file to disk, overwriting the current configuration file.
   522  
   523  	config <parameter> <value>
   524  
   525  Changes the value of a configuration parameter.
   526  
   527  	config substitute-path <from> <to>
   528  	config substitute-path <from>
   529  	config substitute-path -clear
   530  
   531  Adds or removes a path substitution rule, if -clear is used all
   532  substitute-path rules are removed. Without arguments shows the current list
   533  of substitute-path rules.
   534  See also Documentation/cli/substitutepath.md for how the rules are applied.
   535  
   536  	config alias <command> <alias>
   537  	config alias <alias>
   538  
   539  Defines <alias> as an alias to <command> or removes an alias.
   540  
   541  	config debug-info-directories -add <path>
   542  	config debug-info-directories -rm <path>
   543  	config debug-info-directories -clear
   544  
   545  Adds, removes or clears debug-info-directories.`},
   546  
   547  		{aliases: []string{"edit", "ed"}, cmdFn: edit, helpMsg: `Open where you are in $DELVE_EDITOR or $EDITOR
   548  
   549  	edit [locspec]
   550  	
   551  If locspec is omitted edit will open the current source file in the editor, otherwise it will open the specified location.`},
   552  		{aliases: []string{"libraries"}, cmdFn: libraries, helpMsg: `List loaded dynamic libraries`},
   553  
   554  		{aliases: []string{"examinemem", "x"}, group: dataCmds, cmdFn: examineMemoryCmd, helpMsg: `Examine raw memory at the given address.
   555  
   556  Examine memory:
   557  
   558  	examinemem [-fmt <format>] [-count|-len <count>] [-size <size>] <address>
   559  	examinemem [-fmt <format>] [-count|-len <count>] [-size <size>] -x <expression>
   560  
   561  Format represents the data format and the value is one of this list (default hex): bin(binary), oct(octal), dec(decimal), hex(hexadecimal).
   562  Length is the number of bytes (default 1) and must be less than or equal to 1000.
   563  Address is the memory location of the target to examine. Please note '-len' is deprecated by '-count and -size'.
   564  Expression can be an integer expression or pointer value of the memory location to examine.
   565  
   566  For example:
   567  
   568      x -fmt hex -count 20 -size 1 0xc00008af38
   569      x -fmt hex -count 20 -size 1 -x 0xc00008af38 + 8
   570      x -fmt hex -count 20 -size 1 -x &myVar
   571      x -fmt hex -count 20 -size 1 -x myPtrVar`},
   572  
   573  		{aliases: []string{"display"}, group: dataCmds, cmdFn: display, helpMsg: `Print value of an expression every time the program stops.
   574  
   575  	display -a [%format] <expression>
   576  	display -d <number>
   577  
   578  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.
   579  
   580  If display is called without arguments it will print the value of all expression in the list.`},
   581  
   582  		{aliases: []string{"dump"}, cmdFn: dump, helpMsg: `Creates a core dump from the current process state
   583  
   584  	dump <output file>
   585  
   586  The core dump is always written in ELF, even on systems (windows, macOS) where this is not customary. For environments other than linux/amd64 threads and registers are dumped in a format that only Delve can read back.`},
   587  
   588  		{aliases: []string{"transcript"}, cmdFn: transcript, helpMsg: `Appends command output to a file.
   589  
   590  	transcript [-t] [-x] <output file>
   591  	transcript -off
   592  
   593  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.
   594  
   595  Using the -off option disables the transcript.`},
   596  
   597  		{aliases: []string{"target"}, cmdFn: target, helpMsg: `Manages child process debugging.
   598  
   599  	target follow-exec [-on [regex]] [-off]
   600  
   601  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.
   602  
   603  	target list
   604  
   605  List currently attached processes.
   606  
   607  	target switch [pid]
   608  
   609  Switches to the specified process.`},
   610  	}
   611  
   612  	addrecorded := client == nil
   613  	if !addrecorded {
   614  		if state, err := client.GetStateNonBlocking(); err == nil {
   615  			addrecorded = state.Recording
   616  			if !addrecorded {
   617  				addrecorded = client.Recorded()
   618  			}
   619  		}
   620  	}
   621  
   622  	if addrecorded {
   623  		c.cmds = append(c.cmds,
   624  			command{
   625  				aliases: []string{"rewind", "rw"},
   626  				group:   runCmds,
   627  				cmdFn:   c.rewind,
   628  				helpMsg: "Run backwards until breakpoint or start of recorded history.",
   629  			},
   630  			command{
   631  				aliases: []string{"check", "checkpoint"},
   632  				cmdFn:   checkpoint,
   633  				helpMsg: `Creates a checkpoint at the current position.
   634  
   635  	checkpoint [note]
   636  
   637  The "note" is arbitrary text that can be used to identify the checkpoint, if it is not specified it defaults to the current filename:line position.`,
   638  			},
   639  			command{
   640  				aliases: []string{"checkpoints"},
   641  				cmdFn:   checkpoints,
   642  				helpMsg: "Print out info for existing checkpoints.",
   643  			},
   644  			command{
   645  				aliases: []string{"clear-checkpoint", "clearcheck"},
   646  				cmdFn:   clearCheckpoint,
   647  				helpMsg: `Deletes checkpoint.
   648  
   649  	clear-checkpoint <id>`,
   650  			},
   651  			command{
   652  				aliases: []string{"rev"},
   653  				group:   runCmds,
   654  				cmdFn:   c.revCmd,
   655  				helpMsg: `Reverses the execution of the target program for the command specified.
   656  Currently, rev next, step, step-instruction and stepout commands are supported.`,
   657  			})
   658  	}
   659  
   660  	sort.Sort(byFirstAlias(c.cmds))
   661  	return c
   662  }
   663  
   664  // Register custom commands. Expects cf to be a func of type cmdfunc,
   665  // returning only an error.
   666  func (c *Commands) Register(cmdstr string, cf cmdfunc, helpMsg string) {
   667  	for _, v := range c.cmds {
   668  		if v.match(cmdstr) {
   669  			v.cmdFn = cf
   670  			return
   671  		}
   672  	}
   673  
   674  	c.cmds = append(c.cmds, command{aliases: []string{cmdstr}, cmdFn: cf, helpMsg: helpMsg})
   675  }
   676  
   677  // Find will look up the command function for the given command input.
   678  // If it cannot find the command it will default to noCmdAvailable().
   679  // If the command is an empty string it will replay the last command.
   680  func (c *Commands) Find(cmdstr string, prefix cmdPrefix) command {
   681  	// If <enter> use last command, if there was one.
   682  	if cmdstr == "" {
   683  		return command{aliases: []string{"nullcmd"}, cmdFn: nullCommand}
   684  	}
   685  
   686  	for _, v := range c.cmds {
   687  		if v.match(cmdstr) {
   688  			if prefix != noPrefix && v.allowedPrefixes&prefix == 0 {
   689  				continue
   690  			}
   691  			return v
   692  		}
   693  	}
   694  
   695  	return command{aliases: []string{"nocmd"}, cmdFn: noCmdAvailable}
   696  }
   697  
   698  // CallWithContext takes a command and a context that command should be executed in.
   699  func (c *Commands) CallWithContext(cmdstr string, t *Term, ctx callContext) error {
   700  	vals := strings.SplitN(strings.TrimSpace(cmdstr), " ", 2)
   701  	cmdname := vals[0]
   702  	var args string
   703  	if len(vals) > 1 {
   704  		args = strings.TrimSpace(vals[1])
   705  	}
   706  	return c.Find(cmdname, ctx.Prefix).cmdFn(t, ctx, args)
   707  }
   708  
   709  // Call takes a command to execute.
   710  func (c *Commands) Call(cmdstr string, t *Term) error {
   711  	ctx := callContext{Prefix: noPrefix, Scope: api.EvalScope{GoroutineID: -1, Frame: c.frame, DeferredCall: 0}}
   712  	return c.CallWithContext(cmdstr, t, ctx)
   713  }
   714  
   715  // Merge takes aliases defined in the config struct and merges them with the default aliases.
   716  func (c *Commands) Merge(allAliases map[string][]string) {
   717  	for i := range c.cmds {
   718  		if c.cmds[i].builtinAliases != nil {
   719  			c.cmds[i].aliases = append(c.cmds[i].aliases[:0], c.cmds[i].builtinAliases...)
   720  		}
   721  	}
   722  	for i := range c.cmds {
   723  		if aliases, ok := allAliases[c.cmds[i].aliases[0]]; ok {
   724  			if c.cmds[i].builtinAliases == nil {
   725  				c.cmds[i].builtinAliases = make([]string, len(c.cmds[i].aliases))
   726  				copy(c.cmds[i].builtinAliases, c.cmds[i].aliases)
   727  			}
   728  			c.cmds[i].aliases = append(c.cmds[i].aliases, aliases...)
   729  		}
   730  	}
   731  }
   732  
   733  var errNoCmd = errors.New("command not available")
   734  
   735  func noCmdAvailable(t *Term, ctx callContext, args string) error {
   736  	return errNoCmd
   737  }
   738  
   739  func nullCommand(t *Term, ctx callContext, args string) error {
   740  	return nil
   741  }
   742  
   743  func (c *Commands) help(t *Term, ctx callContext, args string) error {
   744  	if args != "" {
   745  		for _, cmd := range c.cmds {
   746  			for _, alias := range cmd.aliases {
   747  				if alias == args {
   748  					fmt.Fprintln(t.stdout, cmd.helpMsg)
   749  					return nil
   750  				}
   751  			}
   752  		}
   753  		return errNoCmd
   754  	}
   755  
   756  	fmt.Fprintln(t.stdout, "The following commands are available:")
   757  
   758  	for _, cgd := range commandGroupDescriptions {
   759  		fmt.Fprintf(t.stdout, "\n%s:\n", cgd.description)
   760  		w := new(tabwriter.Writer)
   761  		w.Init(t.stdout, 0, 8, 0, '-', 0)
   762  		for _, cmd := range c.cmds {
   763  			if cmd.group != cgd.group {
   764  				continue
   765  			}
   766  			h := cmd.helpMsg
   767  			if idx := strings.Index(h, "\n"); idx >= 0 {
   768  				h = h[:idx]
   769  			}
   770  			if len(cmd.aliases) > 1 {
   771  				fmt.Fprintf(w, "    %s (alias: %s) \t %s\n", cmd.aliases[0], strings.Join(cmd.aliases[1:], " | "), h)
   772  			} else {
   773  				fmt.Fprintf(w, "    %s \t %s\n", cmd.aliases[0], h)
   774  			}
   775  		}
   776  		if err := w.Flush(); err != nil {
   777  			return err
   778  		}
   779  	}
   780  
   781  	fmt.Fprintln(t.stdout)
   782  	fmt.Fprintln(t.stdout, "Type help followed by a command for full documentation.")
   783  	return nil
   784  }
   785  
   786  type byThreadID []*api.Thread
   787  
   788  func (a byThreadID) Len() int           { return len(a) }
   789  func (a byThreadID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   790  func (a byThreadID) Less(i, j int) bool { return a[i].ID < a[j].ID }
   791  
   792  func threads(t *Term, ctx callContext, args string) error {
   793  	threads, err := t.client.ListThreads()
   794  	if err != nil {
   795  		return err
   796  	}
   797  	state, err := t.client.GetState()
   798  	if err != nil {
   799  		return err
   800  	}
   801  	sort.Sort(byThreadID(threads))
   802  	done := false
   803  	t.stdout.pw.PageMaybe(func() { done = false })
   804  	for _, th := range threads {
   805  		if done {
   806  			break
   807  		}
   808  		prefix := "  "
   809  		if state.CurrentThread != nil && state.CurrentThread.ID == th.ID {
   810  			prefix = "* "
   811  		}
   812  		if th.Function != nil {
   813  			fmt.Fprintf(t.stdout, "%sThread %d at %#v %s:%d %s\n",
   814  				prefix, th.ID, th.PC, t.formatPath(th.File),
   815  				th.Line, th.Function.Name())
   816  		} else {
   817  			fmt.Fprintf(t.stdout, "%sThread %s\n", prefix, t.formatThread(th))
   818  		}
   819  	}
   820  	return nil
   821  }
   822  
   823  func thread(t *Term, ctx callContext, args string) error {
   824  	if len(args) == 0 {
   825  		return fmt.Errorf("you must specify a thread")
   826  	}
   827  	tid, err := strconv.Atoi(args)
   828  	if err != nil {
   829  		return err
   830  	}
   831  	oldState, err := t.client.GetState()
   832  	if err != nil {
   833  		return err
   834  	}
   835  	newState, err := t.client.SwitchThread(tid)
   836  	if err != nil {
   837  		return err
   838  	}
   839  
   840  	oldThread := "<none>"
   841  	newThread := "<none>"
   842  	if oldState.CurrentThread != nil {
   843  		oldThread = strconv.Itoa(oldState.CurrentThread.ID)
   844  	}
   845  	if newState.CurrentThread != nil {
   846  		newThread = strconv.Itoa(newState.CurrentThread.ID)
   847  	}
   848  	fmt.Fprintf(t.stdout, "Switched from %s to %s\n", oldThread, newThread)
   849  	return nil
   850  }
   851  
   852  type byGoroutineID []*api.Goroutine
   853  
   854  func (a byGoroutineID) Len() int           { return len(a) }
   855  func (a byGoroutineID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   856  func (a byGoroutineID) Less(i, j int) bool { return a[i].ID < a[j].ID }
   857  
   858  func (c *Commands) printGoroutines(t *Term, ctx callContext, indent string, gs []*api.Goroutine, fgl api.FormatGoroutineLoc, flags api.PrintGoroutinesFlags, depth int, cmd string, pdone *bool, state *api.DebuggerState) error {
   859  	for _, g := range gs {
   860  		if t.longCommandCanceled() || (pdone != nil && *pdone) {
   861  			break
   862  		}
   863  		prefix := indent + "  "
   864  		if state.SelectedGoroutine != nil && g.ID == state.SelectedGoroutine.ID {
   865  			prefix = indent + "* "
   866  		}
   867  		fmt.Fprintf(t.stdout, "%sGoroutine %s\n", prefix, t.formatGoroutine(g, fgl))
   868  		if flags&api.PrintGoroutinesLabels != 0 {
   869  			writeGoroutineLabels(t.stdout, g, indent+"\t")
   870  		}
   871  		if flags&api.PrintGoroutinesStack != 0 {
   872  			stack, err := t.client.Stacktrace(g.ID, depth, 0, nil)
   873  			if err != nil {
   874  				return err
   875  			}
   876  			printStack(t, t.stdout, stack, indent+"\t", false)
   877  		}
   878  		if cmd != "" {
   879  			ctx.Scope.GoroutineID = g.ID
   880  			if err := c.CallWithContext(cmd, t, ctx); err != nil {
   881  				return err
   882  			}
   883  		}
   884  	}
   885  	return nil
   886  }
   887  
   888  func (c *Commands) goroutines(t *Term, ctx callContext, argstr string) error {
   889  	filters, group, fgl, flags, depth, batchSize, cmd, err := api.ParseGoroutineArgs(argstr)
   890  	if err != nil {
   891  		return err
   892  	}
   893  
   894  	state, err := t.client.GetState()
   895  	if err != nil {
   896  		return err
   897  	}
   898  	var (
   899  		start         = 0
   900  		gslen         = 0
   901  		gs            []*api.Goroutine
   902  		groups        []api.GoroutineGroup
   903  		tooManyGroups bool
   904  	)
   905  	done := false
   906  	t.stdout.pw.PageMaybe(func() { done = true })
   907  	t.longCommandStart()
   908  	for start >= 0 {
   909  		if t.longCommandCanceled() || done {
   910  			fmt.Fprintf(t.stdout, "interrupted\n")
   911  			return nil
   912  		}
   913  		gs, groups, start, tooManyGroups, err = t.client.ListGoroutinesWithFilter(start, batchSize, filters, &group, &api.EvalScope{GoroutineID: -1, Frame: c.frame})
   914  		if err != nil {
   915  			return err
   916  		}
   917  		if len(groups) > 0 {
   918  			for i := range groups {
   919  				fmt.Fprintf(t.stdout, "%s\n", groups[i].Name)
   920  				err = c.printGoroutines(t, ctx, "\t", gs[groups[i].Offset:][:groups[i].Count], fgl, flags, depth, cmd, &done, state)
   921  				if err != nil {
   922  					return err
   923  				}
   924  				fmt.Fprintf(t.stdout, "\tTotal: %d\n", groups[i].Total)
   925  				if i != len(groups)-1 {
   926  					fmt.Fprintf(t.stdout, "\n")
   927  				}
   928  			}
   929  			if tooManyGroups {
   930  				fmt.Fprintf(t.stdout, "Too many groups\n")
   931  			}
   932  		} else {
   933  			sort.Sort(byGoroutineID(gs))
   934  			err = c.printGoroutines(t, ctx, "", gs, fgl, flags, depth, cmd, &done, state)
   935  			if err != nil {
   936  				return err
   937  			}
   938  			gslen += len(gs)
   939  		}
   940  	}
   941  	if gslen > 0 {
   942  		fmt.Fprintf(t.stdout, "[%d goroutines]\n", gslen)
   943  	}
   944  	return nil
   945  }
   946  
   947  func selectedGID(state *api.DebuggerState) int64 {
   948  	if state.SelectedGoroutine == nil {
   949  		return 0
   950  	}
   951  	return state.SelectedGoroutine.ID
   952  }
   953  
   954  func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error {
   955  	args := config.Split2PartsBySpace(argstr)
   956  
   957  	if ctx.Prefix == onPrefix {
   958  		if len(args) != 1 || args[0] != "" {
   959  			return errors.New("too many arguments to goroutine")
   960  		}
   961  		ctx.Breakpoint.Goroutine = true
   962  		return nil
   963  	}
   964  
   965  	if len(args) == 1 {
   966  		if args[0] == "" {
   967  			return printscope(t)
   968  		}
   969  		gid, err := strconv.ParseInt(argstr, 10, 64)
   970  		if err != nil {
   971  			return err
   972  		}
   973  
   974  		oldState, err := t.client.GetState()
   975  		if err != nil {
   976  			return err
   977  		}
   978  		newState, err := t.client.SwitchGoroutine(gid)
   979  		if err != nil {
   980  			return err
   981  		}
   982  		c.frame = 0
   983  		fmt.Fprintf(t.stdout, "Switched from %d to %d (thread %d)\n", selectedGID(oldState), gid, newState.CurrentThread.ID)
   984  		return nil
   985  	}
   986  
   987  	var err error
   988  	ctx.Scope.GoroutineID, err = strconv.ParseInt(args[0], 10, 64)
   989  	if err != nil {
   990  		return err
   991  	}
   992  	return c.CallWithContext(args[1], t, ctx)
   993  }
   994  
   995  // Handle "frame", "up", "down" commands.
   996  func (c *Commands) frameCommand(t *Term, ctx callContext, argstr string, direction frameDirection) error {
   997  	frame := 1
   998  	arg := ""
   999  	if len(argstr) == 0 {
  1000  		if direction == frameSet {
  1001  			return errors.New("not enough arguments")
  1002  		}
  1003  	} else {
  1004  		args := config.Split2PartsBySpace(argstr)
  1005  		var err error
  1006  		if frame, err = strconv.Atoi(args[0]); err != nil {
  1007  			return err
  1008  		}
  1009  		if len(args) > 1 {
  1010  			arg = args[1]
  1011  		}
  1012  	}
  1013  	switch direction {
  1014  	case frameUp:
  1015  		frame = c.frame + frame
  1016  	case frameDown:
  1017  		frame = c.frame - frame
  1018  	}
  1019  	if len(arg) > 0 {
  1020  		ctx.Scope.Frame = frame
  1021  		return c.CallWithContext(arg, t, ctx)
  1022  	}
  1023  	if frame < 0 {
  1024  		return fmt.Errorf("Invalid frame %d", frame)
  1025  	}
  1026  	stack, err := t.client.Stacktrace(ctx.Scope.GoroutineID, frame, 0, nil)
  1027  	if err != nil {
  1028  		return err
  1029  	}
  1030  	if frame >= len(stack) {
  1031  		return fmt.Errorf("Invalid frame %d", frame)
  1032  	}
  1033  	c.frame = frame
  1034  	state, err := t.client.GetState()
  1035  	if err != nil {
  1036  		return err
  1037  	}
  1038  	printcontext(t, state)
  1039  	th := stack[frame]
  1040  	fmt.Fprintf(t.stdout, "Frame %d: %s:%d (PC: %x)\n", frame, t.formatPath(th.File), th.Line, th.PC)
  1041  	printfile(t, th.File, th.Line, true)
  1042  	return nil
  1043  }
  1044  
  1045  func (c *Commands) deferredCommand(t *Term, ctx callContext, argstr string) error {
  1046  	ctx.Prefix = deferredPrefix
  1047  
  1048  	space := strings.IndexRune(argstr, ' ')
  1049  	if space < 0 {
  1050  		return errors.New("not enough arguments")
  1051  	}
  1052  
  1053  	var err error
  1054  	ctx.Scope.DeferredCall, err = strconv.Atoi(argstr[:space])
  1055  	if err != nil {
  1056  		return err
  1057  	}
  1058  	if ctx.Scope.DeferredCall <= 0 {
  1059  		return errors.New("argument of deferred must be a number greater than 0 (use 'stack -defer' to see the list of deferred calls)")
  1060  	}
  1061  	return c.CallWithContext(argstr[space:], t, ctx)
  1062  }
  1063  
  1064  func printscope(t *Term) error {
  1065  	state, err := t.client.GetState()
  1066  	if err != nil {
  1067  		return err
  1068  	}
  1069  
  1070  	fmt.Fprintf(t.stdout, "Thread %s\n", t.formatThread(state.CurrentThread))
  1071  	if state.SelectedGoroutine != nil {
  1072  		writeGoroutineLong(t, t.stdout, state.SelectedGoroutine, "")
  1073  	}
  1074  	return nil
  1075  }
  1076  
  1077  func (t *Term) formatThread(th *api.Thread) string {
  1078  	if th == nil {
  1079  		return "<nil>"
  1080  	}
  1081  	return fmt.Sprintf("%d at %s:%d", th.ID, t.formatPath(th.File), th.Line)
  1082  }
  1083  
  1084  func (t *Term) formatLocation(loc api.Location) string {
  1085  	return fmt.Sprintf("%s:%d %s (%#v)", t.formatPath(loc.File), loc.Line, loc.Function.Name(), loc.PC)
  1086  }
  1087  
  1088  func (t *Term) formatGoroutine(g *api.Goroutine, fgl api.FormatGoroutineLoc) string {
  1089  	if g == nil {
  1090  		return "<nil>"
  1091  	}
  1092  	if g.Unreadable != "" {
  1093  		return fmt.Sprintf("(unreadable %s)", g.Unreadable)
  1094  	}
  1095  	var locname string
  1096  	var loc api.Location
  1097  	switch fgl {
  1098  	case api.FglRuntimeCurrent:
  1099  		locname = "Runtime"
  1100  		loc = g.CurrentLoc
  1101  	case api.FglUserCurrent:
  1102  		locname = "User"
  1103  		loc = g.UserCurrentLoc
  1104  	case api.FglGo:
  1105  		locname = "Go"
  1106  		loc = g.GoStatementLoc
  1107  	case api.FglStart:
  1108  		locname = "Start"
  1109  		loc = g.StartLoc
  1110  	}
  1111  
  1112  	buf := new(strings.Builder)
  1113  	fmt.Fprintf(buf, "%d - %s: %s", g.ID, locname, t.formatLocation(loc))
  1114  	if g.ThreadID != 0 {
  1115  		fmt.Fprintf(buf, " (thread %d)", g.ThreadID)
  1116  	}
  1117  
  1118  	if (g.Status == api.GoroutineWaiting || g.Status == api.GoroutineSyscall) && g.WaitReason != 0 {
  1119  		var wr string
  1120  		if g.WaitReason > 0 && g.WaitReason < int64(len(waitReasonStrings)) {
  1121  			wr = waitReasonStrings[g.WaitReason]
  1122  		} else {
  1123  			wr = fmt.Sprintf("unknown wait reason %d", g.WaitReason)
  1124  		}
  1125  		fmt.Fprintf(buf, " [%s", wr)
  1126  		if g.WaitSince > 0 {
  1127  			fmt.Fprintf(buf, " %d", g.WaitSince)
  1128  		}
  1129  		fmt.Fprintf(buf, "]")
  1130  	}
  1131  
  1132  	return buf.String()
  1133  }
  1134  
  1135  var waitReasonStrings = [...]string{
  1136  	"",
  1137  	"GC assist marking",
  1138  	"IO wait",
  1139  	"chan receive (nil chan)",
  1140  	"chan send (nil chan)",
  1141  	"dumping heap",
  1142  	"garbage collection",
  1143  	"garbage collection scan",
  1144  	"panicwait",
  1145  	"select",
  1146  	"select (no cases)",
  1147  	"GC assist wait",
  1148  	"GC sweep wait",
  1149  	"GC scavenge wait",
  1150  	"chan receive",
  1151  	"chan send",
  1152  	"finalizer wait",
  1153  	"force gc (idle)",
  1154  	"semacquire",
  1155  	"sleep",
  1156  	"sync.Cond.Wait",
  1157  	"timer goroutine (idle)",
  1158  	"trace reader (blocked)",
  1159  	"wait for GC cycle",
  1160  	"GC worker (idle)",
  1161  	"preempted",
  1162  	"debug call",
  1163  }
  1164  
  1165  func writeGoroutineLong(t *Term, w io.Writer, g *api.Goroutine, prefix string) {
  1166  	fmt.Fprintf(w, "%sGoroutine %d:\n%s\tRuntime: %s\n%s\tUser: %s\n%s\tGo: %s\n%s\tStart: %s\n",
  1167  		prefix, g.ID,
  1168  		prefix, t.formatLocation(g.CurrentLoc),
  1169  		prefix, t.formatLocation(g.UserCurrentLoc),
  1170  		prefix, t.formatLocation(g.GoStatementLoc),
  1171  		prefix, t.formatLocation(g.StartLoc))
  1172  	writeGoroutineLabels(w, g, prefix+"\t")
  1173  }
  1174  
  1175  func writeGoroutineLabels(w io.Writer, g *api.Goroutine, prefix string) {
  1176  	const maxNumberOfGoroutineLabels = 5
  1177  
  1178  	if len(g.Labels) <= 0 {
  1179  		return
  1180  	}
  1181  
  1182  	keys := make([]string, 0, len(g.Labels))
  1183  	for k := range g.Labels {
  1184  		keys = append(keys, k)
  1185  	}
  1186  	sort.Strings(keys)
  1187  	more := false
  1188  	if len(keys) > maxNumberOfGoroutineLabels {
  1189  		more = true
  1190  		keys = keys[:maxNumberOfGoroutineLabels]
  1191  	}
  1192  	fmt.Fprintf(w, "%sLabels: ", prefix)
  1193  	for i, k := range keys {
  1194  		fmt.Fprintf(w, "%q:%q", k, g.Labels[k])
  1195  		if i != len(keys)-1 {
  1196  			fmt.Fprintf(w, ", ")
  1197  		} else if more {
  1198  			fmt.Fprintf(w, "... (%d more)", len(g.Labels)-maxNumberOfGoroutineLabels)
  1199  		}
  1200  	}
  1201  	fmt.Fprintf(w, "\n")
  1202  }
  1203  
  1204  func restart(t *Term, ctx callContext, args string) error {
  1205  	if t.client.Recorded() {
  1206  		return restartRecorded(t, ctx, args)
  1207  	}
  1208  
  1209  	return restartLive(t, ctx, args)
  1210  }
  1211  
  1212  func restartRecorded(t *Term, ctx callContext, args string) error {
  1213  	v := config.Split2PartsBySpace(args)
  1214  
  1215  	rerecord := false
  1216  	resetArgs := false
  1217  	newArgv := []string{}
  1218  	newRedirects := [3]string{}
  1219  	restartPos := ""
  1220  
  1221  	if len(v) > 0 {
  1222  		if v[0] == "-r" {
  1223  			rerecord = true
  1224  			if len(v) == 2 {
  1225  				var err error
  1226  				resetArgs, newArgv, newRedirects, err = parseNewArgv(v[1])
  1227  				if err != nil {
  1228  					return err
  1229  				}
  1230  			}
  1231  		} else {
  1232  			if len(v) > 1 {
  1233  				return fmt.Errorf("too many arguments to restart")
  1234  			}
  1235  			restartPos = v[0]
  1236  		}
  1237  	}
  1238  
  1239  	if err := restartIntl(t, rerecord, restartPos, resetArgs, newArgv, newRedirects); err != nil {
  1240  		return err
  1241  	}
  1242  
  1243  	state, err := t.client.GetState()
  1244  	if err != nil {
  1245  		return err
  1246  	}
  1247  	printcontext(t, state)
  1248  	printPos(t, state.CurrentThread, printPosShowArrow)
  1249  	t.onStop()
  1250  	return nil
  1251  }
  1252  
  1253  // parseOptionalCount parses an optional count argument.
  1254  // If there are not arguments, a value of 1 is returned as the default.
  1255  func parseOptionalCount(arg string) (int64, error) {
  1256  	if len(arg) == 0 {
  1257  		return 1, nil
  1258  	}
  1259  	return strconv.ParseInt(arg, 0, 64)
  1260  }
  1261  
  1262  func restartLive(t *Term, ctx callContext, args string) error {
  1263  	t.oldPid = 0
  1264  	resetArgs, newArgv, newRedirects, err := parseNewArgv(args)
  1265  	if err != nil {
  1266  		return err
  1267  	}
  1268  
  1269  	if err := restartIntl(t, false, "", resetArgs, newArgv, newRedirects); err != nil {
  1270  		return err
  1271  	}
  1272  
  1273  	fmt.Fprintln(t.stdout, "Process restarted with PID", t.client.ProcessPid())
  1274  	return nil
  1275  }
  1276  
  1277  func restartIntl(t *Term, rerecord bool, restartPos string, resetArgs bool, newArgv []string, newRedirects [3]string) error {
  1278  	discarded, err := t.client.RestartFrom(rerecord, restartPos, resetArgs, newArgv, newRedirects, false)
  1279  	if err != nil {
  1280  		return err
  1281  	}
  1282  	for i := range discarded {
  1283  		fmt.Fprintf(t.stdout, "Discarded %s at %s: %v\n", formatBreakpointName(discarded[i].Breakpoint, false), t.formatBreakpointLocation(discarded[i].Breakpoint), discarded[i].Reason)
  1284  	}
  1285  	return nil
  1286  }
  1287  
  1288  func parseNewArgv(args string) (resetArgs bool, newArgv []string, newRedirects [3]string, err error) {
  1289  	if args == "" {
  1290  		return false, nil, [3]string{}, nil
  1291  	}
  1292  	v, err := argv.Argv(args,
  1293  		func(s string) (string, error) {
  1294  			return "", fmt.Errorf("Backtick not supported in '%s'", s)
  1295  		},
  1296  		nil)
  1297  	if err != nil {
  1298  		return false, nil, [3]string{}, err
  1299  	}
  1300  	if len(v) != 1 {
  1301  		return false, nil, [3]string{}, fmt.Errorf("illegal commandline '%s'", args)
  1302  	}
  1303  	w := v[0]
  1304  	if len(w) == 0 {
  1305  		return false, nil, [3]string{}, nil
  1306  	}
  1307  	if w[0] == "-noargs" {
  1308  		if len(w) > 1 {
  1309  			return false, nil, [3]string{}, fmt.Errorf("too many arguments to restart")
  1310  		}
  1311  		return true, nil, [3]string{}, nil
  1312  	}
  1313  	redirs := [3]string{}
  1314  	for len(w) > 0 {
  1315  		var found bool
  1316  		var err error
  1317  		w, found, err = parseOneRedirect(w, &redirs)
  1318  		if err != nil {
  1319  			return false, nil, [3]string{}, err
  1320  		}
  1321  		if !found {
  1322  			break
  1323  		}
  1324  	}
  1325  	return true, w, redirs, nil
  1326  }
  1327  
  1328  func parseOneRedirect(w []string, redirs *[3]string) ([]string, bool, error) {
  1329  	prefixes := []string{"<", ">", "2>"}
  1330  	names := []string{"stdin", "stdout", "stderr"}
  1331  	if len(w) >= 2 {
  1332  		for _, prefix := range prefixes {
  1333  			if w[len(w)-2] == prefix {
  1334  				w[len(w)-2] += w[len(w)-1]
  1335  				w = w[:len(w)-1]
  1336  				break
  1337  			}
  1338  		}
  1339  	}
  1340  	for i, prefix := range prefixes {
  1341  		if strings.HasPrefix(w[len(w)-1], prefix) {
  1342  			if redirs[i] != "" {
  1343  				return nil, false, fmt.Errorf("redirect error: %s redirected twice", names[i])
  1344  			}
  1345  			redirs[i] = w[len(w)-1][len(prefix):]
  1346  			return w[:len(w)-1], true, nil
  1347  		}
  1348  	}
  1349  	return w, false, nil
  1350  }
  1351  
  1352  func printcontextNoState(t *Term) {
  1353  	state, _ := t.client.GetState()
  1354  	if state == nil || state.CurrentThread == nil {
  1355  		return
  1356  	}
  1357  	printcontext(t, state)
  1358  }
  1359  
  1360  func (c *Commands) rebuild(t *Term, ctx callContext, args string) error {
  1361  	if ctx.Prefix == revPrefix {
  1362  		return c.rewind(t, ctx, args)
  1363  	}
  1364  	defer t.onStop()
  1365  	discarded, err := t.client.Restart(true)
  1366  	if len(discarded) > 0 {
  1367  		fmt.Fprintf(t.stdout, "not all breakpoints could be restored.")
  1368  	}
  1369  	return err
  1370  }
  1371  
  1372  func (c *Commands) cont(t *Term, ctx callContext, args string) error {
  1373  	if args != "" {
  1374  		tmp, err := setBreakpoint(t, ctx, false, args)
  1375  		if err != nil {
  1376  			if !strings.Contains(err.Error(), "Breakpoint exists") {
  1377  				return err
  1378  			}
  1379  		}
  1380  		defer func() {
  1381  			for _, bp := range tmp {
  1382  				if _, err := t.client.ClearBreakpoint(bp.ID); err != nil {
  1383  					fmt.Fprintf(t.stdout, "failed to clear temporary breakpoint: %d", bp.ID)
  1384  				}
  1385  			}
  1386  		}()
  1387  	}
  1388  	if ctx.Prefix == revPrefix {
  1389  		return c.rewind(t, ctx, args)
  1390  	}
  1391  	defer t.onStop()
  1392  	c.frame = 0
  1393  	stateChan := t.client.Continue()
  1394  	var state *api.DebuggerState
  1395  	for state = range stateChan {
  1396  		if state.Err != nil {
  1397  			printcontextNoState(t)
  1398  			return state.Err
  1399  		}
  1400  		printcontext(t, state)
  1401  	}
  1402  	printPos(t, state.CurrentThread, printPosShowArrow)
  1403  	return nil
  1404  }
  1405  
  1406  func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, shouldPrintFile bool) error {
  1407  	defer t.onStop()
  1408  	if !state.NextInProgress {
  1409  		if shouldPrintFile {
  1410  			printPos(t, state.CurrentThread, printPosShowArrow)
  1411  		}
  1412  		return nil
  1413  	}
  1414  	skipBreakpoints := false
  1415  	for {
  1416  		fmt.Fprintf(t.stdout, "\tbreakpoint hit during %s", op)
  1417  		if !skipBreakpoints {
  1418  			fmt.Fprintf(t.stdout, "\n")
  1419  			answer, err := promptAutoContinue(t, op)
  1420  			switch answer {
  1421  			case "f": // finish next
  1422  				skipBreakpoints = true
  1423  				fallthrough
  1424  			case "c": // continue once
  1425  				fmt.Fprintf(t.stdout, "continuing...\n")
  1426  			case "s": // stop and cancel
  1427  				fallthrough
  1428  			default:
  1429  				t.client.CancelNext()
  1430  				printPos(t, state.CurrentThread, printPosShowArrow)
  1431  				return err
  1432  			}
  1433  		} else {
  1434  			fmt.Fprintf(t.stdout, ", continuing...\n")
  1435  		}
  1436  		stateChan := t.client.DirectionCongruentContinue()
  1437  		var state *api.DebuggerState
  1438  		for state = range stateChan {
  1439  			if state.Err != nil {
  1440  				printcontextNoState(t)
  1441  				return state.Err
  1442  			}
  1443  			printcontext(t, state)
  1444  		}
  1445  		if !state.NextInProgress {
  1446  			printPos(t, state.CurrentThread, printPosShowArrow)
  1447  			return nil
  1448  		}
  1449  	}
  1450  }
  1451  
  1452  func promptAutoContinue(t *Term, op string) (string, error) {
  1453  	for {
  1454  		answer, err := t.line.Prompt(fmt.Sprintf("[c] continue [s] stop here and cancel %s, [f] finish %s skipping all breakpoints? ", op, op))
  1455  		if err != nil {
  1456  			return "", err
  1457  		}
  1458  		answer = strings.ToLower(strings.TrimSpace(answer))
  1459  		switch answer {
  1460  		case "f", "c", "s":
  1461  			return answer, nil
  1462  		}
  1463  	}
  1464  }
  1465  
  1466  func scopePrefixSwitch(t *Term, ctx callContext) error {
  1467  	if ctx.Scope.GoroutineID > 0 {
  1468  		_, err := t.client.SwitchGoroutine(ctx.Scope.GoroutineID)
  1469  		if err != nil {
  1470  			return err
  1471  		}
  1472  	}
  1473  	return nil
  1474  }
  1475  
  1476  func exitedToError(state *api.DebuggerState, err error) (*api.DebuggerState, error) {
  1477  	if err == nil && state.Exited {
  1478  		return nil, fmt.Errorf("Process %d has exited with status %d", state.Pid, state.ExitStatus)
  1479  	}
  1480  	return state, err
  1481  }
  1482  
  1483  func (c *Commands) step(t *Term, ctx callContext, args string) error {
  1484  	if err := scopePrefixSwitch(t, ctx); err != nil {
  1485  		return err
  1486  	}
  1487  	c.frame = 0
  1488  	stepfn := t.client.Step
  1489  	if ctx.Prefix == revPrefix {
  1490  		stepfn = t.client.ReverseStep
  1491  	}
  1492  	state, err := exitedToError(stepfn())
  1493  	if err != nil {
  1494  		printcontextNoState(t)
  1495  		return err
  1496  	}
  1497  	printcontext(t, state)
  1498  	return continueUntilCompleteNext(t, state, "step", true)
  1499  }
  1500  
  1501  var errNotOnFrameZero = errors.New("not on topmost frame")
  1502  
  1503  func (c *Commands) stepInstruction(t *Term, ctx callContext, args string) error {
  1504  	if err := scopePrefixSwitch(t, ctx); err != nil {
  1505  		return err
  1506  	}
  1507  	if c.frame != 0 {
  1508  		return errNotOnFrameZero
  1509  	}
  1510  
  1511  	defer t.onStop()
  1512  
  1513  	var fn func() (*api.DebuggerState, error)
  1514  	if ctx.Prefix == revPrefix {
  1515  		fn = t.client.ReverseStepInstruction
  1516  	} else {
  1517  		fn = t.client.StepInstruction
  1518  	}
  1519  
  1520  	state, err := exitedToError(fn())
  1521  	if err != nil {
  1522  		printcontextNoState(t)
  1523  		return err
  1524  	}
  1525  	printcontext(t, state)
  1526  	printPos(t, state.CurrentThread, printPosShowArrow|printPosStepInstruction)
  1527  	return nil
  1528  }
  1529  
  1530  func (c *Commands) revCmd(t *Term, ctx callContext, args string) error {
  1531  	if len(args) == 0 {
  1532  		return errors.New("not enough arguments")
  1533  	}
  1534  
  1535  	ctx.Prefix = revPrefix
  1536  	return c.CallWithContext(args, t, ctx)
  1537  }
  1538  
  1539  func (c *Commands) next(t *Term, ctx callContext, args string) error {
  1540  	if err := scopePrefixSwitch(t, ctx); err != nil {
  1541  		return err
  1542  	}
  1543  	if c.frame != 0 {
  1544  		return errNotOnFrameZero
  1545  	}
  1546  
  1547  	nextfn := t.client.Next
  1548  	if ctx.Prefix == revPrefix {
  1549  		nextfn = t.client.ReverseNext
  1550  	}
  1551  
  1552  	var count int64
  1553  	var err error
  1554  	if count, err = parseOptionalCount(args); err != nil {
  1555  		return err
  1556  	} else if count <= 0 {
  1557  		return errors.New("Invalid next count")
  1558  	}
  1559  	for ; count > 0; count-- {
  1560  		state, err := exitedToError(nextfn())
  1561  		if err != nil {
  1562  			printcontextNoState(t)
  1563  			return err
  1564  		}
  1565  		// If we're about the exit the loop, print the context.
  1566  		finishedNext := count == 1
  1567  		if finishedNext {
  1568  			printcontext(t, state)
  1569  		}
  1570  		if err := continueUntilCompleteNext(t, state, "next", finishedNext); err != nil {
  1571  			return err
  1572  		}
  1573  	}
  1574  	return nil
  1575  }
  1576  
  1577  func (c *Commands) stepout(t *Term, ctx callContext, args string) error {
  1578  	if err := scopePrefixSwitch(t, ctx); err != nil {
  1579  		return err
  1580  	}
  1581  	if c.frame != 0 {
  1582  		return errNotOnFrameZero
  1583  	}
  1584  
  1585  	stepoutfn := t.client.StepOut
  1586  	if ctx.Prefix == revPrefix {
  1587  		stepoutfn = t.client.ReverseStepOut
  1588  	}
  1589  
  1590  	state, err := exitedToError(stepoutfn())
  1591  	if err != nil {
  1592  		printcontextNoState(t)
  1593  		return err
  1594  	}
  1595  	printcontext(t, state)
  1596  	return continueUntilCompleteNext(t, state, "stepout", true)
  1597  }
  1598  
  1599  func (c *Commands) call(t *Term, ctx callContext, args string) error {
  1600  	if err := scopePrefixSwitch(t, ctx); err != nil {
  1601  		return err
  1602  	}
  1603  	const unsafePrefix = "-unsafe "
  1604  	unsafe := false
  1605  	if strings.HasPrefix(args, unsafePrefix) {
  1606  		unsafe = true
  1607  		args = args[len(unsafePrefix):]
  1608  	}
  1609  	state, err := exitedToError(t.client.Call(ctx.Scope.GoroutineID, args, unsafe))
  1610  	c.frame = 0
  1611  	if err != nil {
  1612  		printcontextNoState(t)
  1613  		return err
  1614  	}
  1615  	printcontext(t, state)
  1616  	return continueUntilCompleteNext(t, state, "call", true)
  1617  }
  1618  
  1619  func clear(t *Term, ctx callContext, args string) error {
  1620  	if len(args) == 0 {
  1621  		return fmt.Errorf("not enough arguments")
  1622  	}
  1623  	id, err := strconv.Atoi(args)
  1624  	var bp *api.Breakpoint
  1625  	if err == nil {
  1626  		bp, err = t.client.ClearBreakpoint(id)
  1627  	} else {
  1628  		bp, err = t.client.ClearBreakpointByName(args)
  1629  	}
  1630  	if err != nil {
  1631  		return err
  1632  	}
  1633  	fmt.Fprintf(t.stdout, "%s cleared at %s\n", formatBreakpointName(bp, true), t.formatBreakpointLocation(bp))
  1634  	return nil
  1635  }
  1636  
  1637  func clearAll(t *Term, ctx callContext, args string) error {
  1638  	breakPoints, err := t.client.ListBreakpoints(false)
  1639  	if err != nil {
  1640  		return err
  1641  	}
  1642  
  1643  	var locPCs map[uint64]struct{}
  1644  	if args != "" {
  1645  		locs, _, err := t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, args, true, t.substitutePathRules())
  1646  		if err != nil {
  1647  			return err
  1648  		}
  1649  		locPCs = make(map[uint64]struct{})
  1650  		for _, loc := range locs {
  1651  			for _, pc := range loc.PCs {
  1652  				locPCs[pc] = struct{}{}
  1653  			}
  1654  			locPCs[loc.PC] = struct{}{}
  1655  		}
  1656  	}
  1657  
  1658  	for _, bp := range breakPoints {
  1659  		if locPCs != nil {
  1660  			if _, ok := locPCs[bp.Addr]; !ok {
  1661  				continue
  1662  			}
  1663  		}
  1664  
  1665  		if bp.ID < 0 {
  1666  			continue
  1667  		}
  1668  
  1669  		_, err := t.client.ClearBreakpoint(bp.ID)
  1670  		if err != nil {
  1671  			fmt.Fprintf(t.stdout, "Couldn't delete %s at %s: %s\n", formatBreakpointName(bp, false), t.formatBreakpointLocation(bp), err)
  1672  		}
  1673  		fmt.Fprintf(t.stdout, "%s cleared at %s\n", formatBreakpointName(bp, true), t.formatBreakpointLocation(bp))
  1674  	}
  1675  	return nil
  1676  }
  1677  
  1678  func toggle(t *Term, ctx callContext, args string) error {
  1679  	if args == "" {
  1680  		return fmt.Errorf("not enough arguments")
  1681  	}
  1682  	id, err := strconv.Atoi(args)
  1683  	var bp *api.Breakpoint
  1684  	if err == nil {
  1685  		bp, err = t.client.ToggleBreakpoint(id)
  1686  	} else {
  1687  		bp, err = t.client.ToggleBreakpointByName(args)
  1688  	}
  1689  	if err != nil {
  1690  		return err
  1691  	}
  1692  	fmt.Fprintf(t.stdout, "%s toggled at %s\n", formatBreakpointName(bp, true), t.formatBreakpointLocation(bp))
  1693  	return nil
  1694  }
  1695  
  1696  // byID sorts breakpoints by ID.
  1697  type byID []*api.Breakpoint
  1698  
  1699  func (a byID) Len() int           { return len(a) }
  1700  func (a byID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
  1701  func (a byID) Less(i, j int) bool { return a[i].ID < a[j].ID }
  1702  
  1703  func breakpoints(t *Term, ctx callContext, args string) error {
  1704  	breakPoints, err := t.client.ListBreakpoints(args == "-a")
  1705  	if err != nil {
  1706  		return err
  1707  	}
  1708  	sort.Sort(byID(breakPoints))
  1709  	for _, bp := range breakPoints {
  1710  		enabled := "(enabled)"
  1711  		if bp.Disabled {
  1712  			enabled = "(disabled)"
  1713  		} else if bp.ExprString != "" {
  1714  			enabled = "(suspended)"
  1715  		}
  1716  		fmt.Fprintf(t.stdout, "%s %s", formatBreakpointName(bp, true), enabled)
  1717  		if bp.ExprString != "" {
  1718  			fmt.Fprintf(t.stdout, " at %s\n", bp.ExprString)
  1719  		} else {
  1720  			fmt.Fprintf(t.stdout, " at %v (%d)\n", t.formatBreakpointLocation(bp), bp.TotalHitCount)
  1721  		}
  1722  
  1723  		attrs := formatBreakpointAttrs("\t", bp, false)
  1724  
  1725  		if len(attrs) > 0 {
  1726  			fmt.Fprintf(t.stdout, "%s\n", strings.Join(attrs, "\n"))
  1727  		}
  1728  	}
  1729  	return nil
  1730  }
  1731  
  1732  func formatBreakpointAttrs(prefix string, bp *api.Breakpoint, includeTrace bool) []string {
  1733  	var attrs []string
  1734  	if bp.Cond != "" {
  1735  		attrs = append(attrs, fmt.Sprintf("%scond %s", prefix, bp.Cond))
  1736  	}
  1737  	if bp.HitCond != "" {
  1738  		if bp.HitCondPerG {
  1739  			attrs = append(attrs, fmt.Sprintf("%scond -per-g-hitcount %s", prefix, bp.HitCond))
  1740  		} else {
  1741  			attrs = append(attrs, fmt.Sprintf("%scond -hitcount %s", prefix, bp.HitCond))
  1742  		}
  1743  	}
  1744  	if bp.Stacktrace > 0 {
  1745  		attrs = append(attrs, fmt.Sprintf("%sstack %d", prefix, bp.Stacktrace))
  1746  	}
  1747  	if bp.Goroutine {
  1748  		attrs = append(attrs, fmt.Sprintf("%sgoroutine", prefix))
  1749  	}
  1750  	if bp.LoadArgs != nil {
  1751  		if *(bp.LoadArgs) == longLoadConfig {
  1752  			attrs = append(attrs, fmt.Sprintf("%sargs -v", prefix))
  1753  		} else {
  1754  			attrs = append(attrs, fmt.Sprintf("%sargs", prefix))
  1755  		}
  1756  	}
  1757  	if bp.LoadLocals != nil {
  1758  		if *(bp.LoadLocals) == longLoadConfig {
  1759  			attrs = append(attrs, fmt.Sprintf("%slocals -v", prefix))
  1760  		} else {
  1761  			attrs = append(attrs, fmt.Sprintf("%slocals", prefix))
  1762  		}
  1763  	}
  1764  	for i := range bp.Variables {
  1765  		attrs = append(attrs, fmt.Sprintf("%sprint %s", prefix, bp.Variables[i]))
  1766  	}
  1767  	if includeTrace && bp.Tracepoint {
  1768  		attrs = append(attrs, fmt.Sprintf("%strace", prefix))
  1769  	}
  1770  	for i := range bp.VerboseDescr {
  1771  		attrs = append(attrs, fmt.Sprintf("%s%s", prefix, bp.VerboseDescr[i]))
  1772  	}
  1773  	return attrs
  1774  }
  1775  
  1776  func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) ([]*api.Breakpoint, error) {
  1777  	args := config.Split2PartsBySpace(argstr)
  1778  
  1779  	requestedBp := &api.Breakpoint{}
  1780  	spec := ""
  1781  	switch len(args) {
  1782  	case 1:
  1783  		if len(args[0]) != 0 {
  1784  			spec = argstr
  1785  		} else {
  1786  			// no arg specified
  1787  			spec = "+0"
  1788  		}
  1789  	case 2:
  1790  		if api.ValidBreakpointName(args[0]) == nil {
  1791  			requestedBp.Name = args[0]
  1792  			spec = args[1]
  1793  		} else {
  1794  			spec = argstr
  1795  		}
  1796  	default:
  1797  		return nil, fmt.Errorf("address required")
  1798  	}
  1799  
  1800  	requestedBp.Tracepoint = tracepoint
  1801  	locs, substSpec, findLocErr := t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules())
  1802  	if findLocErr != nil && requestedBp.Name != "" {
  1803  		requestedBp.Name = ""
  1804  		spec = argstr
  1805  		var err2 error
  1806  		var substSpec2 string
  1807  		locs, substSpec2, err2 = t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules())
  1808  		if err2 == nil {
  1809  			findLocErr = nil
  1810  			substSpec = substSpec2
  1811  		}
  1812  	}
  1813  	if findLocErr != nil && shouldAskToSuspendBreakpoint(t) {
  1814  		fmt.Fprintf(os.Stderr, "Command failed: %s\n", findLocErr.Error())
  1815  		question := "Set a suspended breakpoint (Delve will try to set this breakpoint when a plugin is loaded) [Y/n]?"
  1816  		if isErrProcessExited(findLocErr) {
  1817  			question = "Set a suspended breakpoint (Delve will try to set this breakpoint when the process is restarted) [Y/n]?"
  1818  		}
  1819  		answer, err := yesno(t.line, question, "yes")
  1820  		if err != nil {
  1821  			return nil, err
  1822  		}
  1823  		if !answer {
  1824  			return nil, nil
  1825  		}
  1826  		findLocErr = nil
  1827  		bp, err := t.client.CreateBreakpointWithExpr(requestedBp, spec, t.substitutePathRules(), true)
  1828  		if err != nil {
  1829  			return nil, err
  1830  		}
  1831  		fmt.Fprintf(t.stdout, "%s set at %s\n", formatBreakpointName(bp, true), t.formatBreakpointLocation(bp))
  1832  		return nil, nil
  1833  	}
  1834  	if findLocErr != nil {
  1835  		return nil, findLocErr
  1836  	}
  1837  	if substSpec != "" {
  1838  		spec = substSpec
  1839  	}
  1840  
  1841  	created := []*api.Breakpoint{}
  1842  	for _, loc := range locs {
  1843  		requestedBp.Addr = loc.PC
  1844  		requestedBp.Addrs = loc.PCs
  1845  		requestedBp.AddrPid = loc.PCPids
  1846  		if tracepoint {
  1847  			requestedBp.LoadArgs = &ShortLoadConfig
  1848  		}
  1849  
  1850  		bp, err := t.client.CreateBreakpointWithExpr(requestedBp, spec, t.substitutePathRules(), false)
  1851  		if err != nil {
  1852  			return nil, err
  1853  		}
  1854  		created = append(created, bp)
  1855  
  1856  		fmt.Fprintf(t.stdout, "%s set at %s\n", formatBreakpointName(bp, true), t.formatBreakpointLocation(bp))
  1857  	}
  1858  
  1859  	var shouldSetReturnBreakpoints bool
  1860  	loc, err := locspec.Parse(spec)
  1861  	if err != nil {
  1862  		return nil, err
  1863  	}
  1864  	switch t := loc.(type) {
  1865  	case *locspec.NormalLocationSpec:
  1866  		shouldSetReturnBreakpoints = t.LineOffset == -1 && t.FuncBase != nil
  1867  	case *locspec.RegexLocationSpec:
  1868  		shouldSetReturnBreakpoints = true
  1869  	}
  1870  	if tracepoint && shouldSetReturnBreakpoints && locs[0].Function != nil {
  1871  		for i := range locs {
  1872  			if locs[i].Function == nil {
  1873  				continue
  1874  			}
  1875  			addrs, err := t.client.(*rpc2.RPCClient).FunctionReturnLocations(locs[0].Function.Name())
  1876  			if err != nil {
  1877  				return nil, err
  1878  			}
  1879  			for j := range addrs {
  1880  				_, err = t.client.CreateBreakpoint(&api.Breakpoint{
  1881  					Addr:        addrs[j],
  1882  					TraceReturn: true,
  1883  					Line:        -1,
  1884  					LoadArgs:    &ShortLoadConfig,
  1885  				})
  1886  				if err != nil {
  1887  					return nil, err
  1888  				}
  1889  			}
  1890  		}
  1891  	}
  1892  	return created, nil
  1893  }
  1894  
  1895  func breakpoint(t *Term, ctx callContext, args string) error {
  1896  	_, err := setBreakpoint(t, ctx, false, args)
  1897  	return err
  1898  }
  1899  
  1900  func tracepoint(t *Term, ctx callContext, args string) error {
  1901  	if ctx.Prefix == onPrefix {
  1902  		if args != "" {
  1903  			return errors.New("too many arguments to trace")
  1904  		}
  1905  		ctx.Breakpoint.Tracepoint = true
  1906  		return nil
  1907  	}
  1908  	_, err := setBreakpoint(t, ctx, true, args)
  1909  	return err
  1910  }
  1911  
  1912  func runEditor(args ...string) error {
  1913  	var editor string
  1914  	if editor = os.Getenv("DELVE_EDITOR"); editor == "" {
  1915  		if editor = os.Getenv("EDITOR"); editor == "" {
  1916  			return fmt.Errorf("Neither DELVE_EDITOR or EDITOR is set")
  1917  		}
  1918  	}
  1919  
  1920  	cmd := exec.Command(editor, args...)
  1921  	cmd.Stdin = os.Stdin
  1922  	cmd.Stdout = os.Stdout
  1923  	cmd.Stderr = os.Stderr
  1924  	return cmd.Run()
  1925  }
  1926  
  1927  func edit(t *Term, ctx callContext, args string) error {
  1928  	file, lineno, _, err := getLocation(t, ctx, args, false)
  1929  	if err != nil {
  1930  		return err
  1931  	}
  1932  	return runEditor(fmt.Sprintf("+%d", lineno), file)
  1933  }
  1934  
  1935  func watchpoint(t *Term, ctx callContext, args string) error {
  1936  	v := strings.SplitN(args, " ", 2)
  1937  	if len(v) != 2 {
  1938  		return errors.New("wrong number of arguments: watch [-r|-w|-rw] <expr>")
  1939  	}
  1940  	var wtype api.WatchType
  1941  	switch v[0] {
  1942  	case "-r":
  1943  		wtype = api.WatchRead
  1944  	case "-w":
  1945  		wtype = api.WatchWrite
  1946  	case "-rw":
  1947  		wtype = api.WatchRead | api.WatchWrite
  1948  	default:
  1949  		return fmt.Errorf("wrong argument %q to watch", v[0])
  1950  	}
  1951  	bp, err := t.client.CreateWatchpoint(ctx.Scope, v[1], wtype)
  1952  	if err != nil {
  1953  		return err
  1954  	}
  1955  	fmt.Fprintf(t.stdout, "%s set at %s\n", formatBreakpointName(bp, true), t.formatBreakpointLocation(bp))
  1956  	return nil
  1957  }
  1958  
  1959  func examineMemoryCmd(t *Term, ctx callContext, argstr string) error {
  1960  	var (
  1961  		address uint64
  1962  		err     error
  1963  		ok      bool
  1964  		args    = strings.Split(argstr, " ")
  1965  	)
  1966  
  1967  	// Default value
  1968  	priFmt := byte('x')
  1969  	count := 1
  1970  	size := 1
  1971  	isExpr := false
  1972  
  1973  	// nextArg returns the next argument that is not an empty string, if any, and
  1974  	// advances the args slice to the position after that.
  1975  	nextArg := func() string {
  1976  		for len(args) > 0 {
  1977  			arg := args[0]
  1978  			args = args[1:]
  1979  			if arg != "" {
  1980  				return arg
  1981  			}
  1982  		}
  1983  		return ""
  1984  	}
  1985  
  1986  loop:
  1987  	for {
  1988  		switch cmd := nextArg(); cmd {
  1989  		case "":
  1990  			// no more arguments
  1991  			break loop
  1992  		case "-fmt":
  1993  			arg := nextArg()
  1994  			if arg == "" {
  1995  				return fmt.Errorf("expected argument after -fmt")
  1996  			}
  1997  			fmtMapToPriFmt := map[string]byte{
  1998  				"oct":         'o',
  1999  				"octal":       'o',
  2000  				"hex":         'x',
  2001  				"hexadecimal": 'x',
  2002  				"dec":         'd',
  2003  				"decimal":     'd',
  2004  				"bin":         'b',
  2005  				"binary":      'b',
  2006  			}
  2007  			priFmt, ok = fmtMapToPriFmt[arg]
  2008  			if !ok {
  2009  				return fmt.Errorf("%q is not a valid format", arg)
  2010  			}
  2011  		case "-count", "-len":
  2012  			arg := nextArg()
  2013  			if arg == "" {
  2014  				return fmt.Errorf("expected argument after -count/-len")
  2015  			}
  2016  			var err error
  2017  			count, err = strconv.Atoi(arg)
  2018  			if err != nil || count <= 0 {
  2019  				return fmt.Errorf("count/len must be a positive integer")
  2020  			}
  2021  		case "-size":
  2022  			arg := nextArg()
  2023  			if arg == "" {
  2024  				return fmt.Errorf("expected argument after -size")
  2025  			}
  2026  			var err error
  2027  			size, err = strconv.Atoi(arg)
  2028  			if err != nil || size <= 0 || size > 8 {
  2029  				return fmt.Errorf("size must be a positive integer (<=8)")
  2030  			}
  2031  		case "-x":
  2032  			isExpr = true
  2033  			break loop // remaining args are going to be interpreted as expression
  2034  		default:
  2035  			if len(args) > 0 {
  2036  				return fmt.Errorf("unknown option %q", args[0])
  2037  			}
  2038  			args = []string{cmd}
  2039  			break loop // only one arg left to be evaluated as a uint
  2040  		}
  2041  	}
  2042  
  2043  	// TODO, maybe configured by user.
  2044  	if count*size > 1000 {
  2045  		return fmt.Errorf("read memory range (count*size) must be less than or equal to 1000 bytes")
  2046  	}
  2047  
  2048  	if len(args) == 0 {
  2049  		return fmt.Errorf("no address specified")
  2050  	}
  2051  
  2052  	if isExpr {
  2053  		expr := strings.Join(args, " ")
  2054  		val, err := t.client.EvalVariable(ctx.Scope, expr, t.loadConfig())
  2055  		if err != nil {
  2056  			return err
  2057  		}
  2058  
  2059  		// "-x &myVar" or "-x myPtrVar"
  2060  		if val.Kind == reflect.Ptr {
  2061  			if len(val.Children) < 1 {
  2062  				return fmt.Errorf("bug? invalid pointer: %#v", val)
  2063  			}
  2064  			address = val.Children[0].Addr
  2065  			// "-x 0xc000079f20 + 8" or -x 824634220320 + 8
  2066  		} else if val.Kind == reflect.Int && val.Value != "" {
  2067  			address, err = strconv.ParseUint(val.Value, 0, 64)
  2068  			if err != nil {
  2069  				return fmt.Errorf("bad expression result: %q: %s", val.Value, err)
  2070  			}
  2071  		} else {
  2072  			return fmt.Errorf("unsupported expression type: %s", val.Kind)
  2073  		}
  2074  	} else {
  2075  		address, err = strconv.ParseUint(args[0], 0, 64)
  2076  		if err != nil {
  2077  			return fmt.Errorf("convert address into uintptr type failed, %s", err)
  2078  		}
  2079  	}
  2080  
  2081  	memArea, isLittleEndian, err := t.client.ExamineMemory(address, count*size)
  2082  	if err != nil {
  2083  		return err
  2084  	}
  2085  	t.stdout.pw.PageMaybe(nil)
  2086  	fmt.Fprint(t.stdout, api.PrettyExamineMemory(uintptr(address), memArea, isLittleEndian, priFmt, size))
  2087  	return nil
  2088  }
  2089  
  2090  func parseFormatArg(args string) (fmtstr, argsOut string) {
  2091  	if len(args) < 1 || args[0] != '%' {
  2092  		return "", args
  2093  	}
  2094  	v := strings.SplitN(args, " ", 2)
  2095  	if len(v) == 1 {
  2096  		return v[0], ""
  2097  	}
  2098  	return v[0], v[1]
  2099  }
  2100  
  2101  const maxPrintVarChanGoroutines = 100
  2102  
  2103  func (c *Commands) printVar(t *Term, ctx callContext, args string) error {
  2104  	if len(args) == 0 {
  2105  		return fmt.Errorf("not enough arguments")
  2106  	}
  2107  	if ctx.Prefix == onPrefix {
  2108  		ctx.Breakpoint.Variables = append(ctx.Breakpoint.Variables, args)
  2109  		return nil
  2110  	}
  2111  	fmtstr, args := parseFormatArg(args)
  2112  	val, err := t.client.EvalVariable(ctx.Scope, args, t.loadConfig())
  2113  	if err != nil {
  2114  		return err
  2115  	}
  2116  
  2117  	fmt.Fprintln(t.stdout, val.MultilineString("", fmtstr))
  2118  
  2119  	if val.Kind == reflect.Chan {
  2120  		fmt.Fprintln(t.stdout)
  2121  		gs, _, _, _, err := t.client.ListGoroutinesWithFilter(0, maxPrintVarChanGoroutines, []api.ListGoroutinesFilter{{Kind: api.GoroutineWaitingOnChannel, Arg: fmt.Sprintf("*(*%q)(%#x)", val.Type, val.Addr)}}, nil, &ctx.Scope)
  2122  		if err != nil {
  2123  			fmt.Fprintf(t.stdout, "Error reading channel wait queue: %v", err)
  2124  		} else {
  2125  			fmt.Fprintln(t.stdout, "Goroutines waiting on this channel:")
  2126  			state, err := t.client.GetState()
  2127  			if err != nil {
  2128  				fmt.Fprintf(t.stdout, "Error printing channel wait queue: %v", err)
  2129  			}
  2130  			var done bool
  2131  			c.printGoroutines(t, ctx, "", gs, api.FglUserCurrent, 0, 0, "", &done, state)
  2132  		}
  2133  	}
  2134  	return nil
  2135  }
  2136  
  2137  func whatisCommand(t *Term, ctx callContext, args string) error {
  2138  	if len(args) == 0 {
  2139  		return fmt.Errorf("not enough arguments")
  2140  	}
  2141  	val, err := t.client.EvalVariable(ctx.Scope, args, ShortLoadConfig)
  2142  	if err != nil {
  2143  		return err
  2144  	}
  2145  	if val.Flags&api.VariableCPURegister != 0 {
  2146  		fmt.Fprintln(t.stdout, "CPU Register")
  2147  		return nil
  2148  	}
  2149  	if val.Type != "" {
  2150  		fmt.Fprintln(t.stdout, val.Type)
  2151  	}
  2152  	if val.RealType != val.Type {
  2153  		fmt.Fprintf(t.stdout, "Real type: %s\n", val.RealType)
  2154  	}
  2155  	if val.Kind == reflect.Interface && len(val.Children) > 0 {
  2156  		fmt.Fprintf(t.stdout, "Concrete type: %s\n", val.Children[0].Type)
  2157  	}
  2158  	if t.conf.ShowLocationExpr && val.LocationExpr != "" {
  2159  		fmt.Fprintf(t.stdout, "location: %s\n", val.LocationExpr)
  2160  	}
  2161  	return nil
  2162  }
  2163  
  2164  func setVar(t *Term, ctx callContext, args string) error {
  2165  	// HACK: in go '=' is not an operator, we detect the error and try to recover from it by splitting the input string
  2166  	_, err := parser.ParseExpr(args)
  2167  	if err == nil {
  2168  		return fmt.Errorf("syntax error '=' not found")
  2169  	}
  2170  
  2171  	el, ok := err.(scanner.ErrorList)
  2172  	if !ok || el[0].Msg != "expected '==', found '='" {
  2173  		return err
  2174  	}
  2175  
  2176  	lexpr := args[:el[0].Pos.Offset]
  2177  	rexpr := args[el[0].Pos.Offset+1:]
  2178  	return t.client.SetVariable(ctx.Scope, lexpr, rexpr)
  2179  }
  2180  
  2181  func (t *Term) printFilteredVariables(varType string, vars []api.Variable, filter string, cfg api.LoadConfig) error {
  2182  	reg, err := regexp.Compile(filter)
  2183  	if err != nil {
  2184  		return err
  2185  	}
  2186  	match := false
  2187  	for _, v := range vars {
  2188  		if reg == nil || reg.Match([]byte(v.Name)) {
  2189  			match = true
  2190  			name := v.Name
  2191  			if v.Flags&api.VariableShadowed != 0 {
  2192  				name = "(" + name + ")"
  2193  			}
  2194  			if cfg == ShortLoadConfig {
  2195  				fmt.Fprintf(t.stdout, "%s = %s\n", name, v.SinglelineString())
  2196  			} else {
  2197  				fmt.Fprintf(t.stdout, "%s = %s\n", name, v.MultilineString("", ""))
  2198  			}
  2199  		}
  2200  	}
  2201  	if !match {
  2202  		fmt.Fprintf(t.stdout, "(no %s)\n", varType)
  2203  	}
  2204  	return nil
  2205  }
  2206  
  2207  func (t *Term) printSortedStrings(v []string, err error) error {
  2208  	if err != nil {
  2209  		return err
  2210  	}
  2211  	sort.Strings(v)
  2212  	done := false
  2213  	t.stdout.pw.PageMaybe(func() { done = false })
  2214  	for _, d := range v {
  2215  		if done {
  2216  			break
  2217  		}
  2218  		fmt.Fprintln(t.stdout, d)
  2219  	}
  2220  	return nil
  2221  }
  2222  
  2223  func sources(t *Term, ctx callContext, args string) error {
  2224  	return t.printSortedStrings(t.client.ListSources(args))
  2225  }
  2226  
  2227  func funcs(t *Term, ctx callContext, args string) error {
  2228  	return t.printSortedStrings(t.client.ListFunctions(args))
  2229  }
  2230  
  2231  func types(t *Term, ctx callContext, args string) error {
  2232  	return t.printSortedStrings(t.client.ListTypes(args))
  2233  }
  2234  
  2235  func parseVarArguments(args string, t *Term) (filter string, cfg api.LoadConfig) {
  2236  	if v := config.Split2PartsBySpace(args); len(v) >= 1 && v[0] == "-v" {
  2237  		if len(v) == 2 {
  2238  			return v[1], t.loadConfig()
  2239  		} else {
  2240  			return "", t.loadConfig()
  2241  		}
  2242  	}
  2243  	return args, ShortLoadConfig
  2244  }
  2245  
  2246  func args(t *Term, ctx callContext, args string) error {
  2247  	filter, cfg := parseVarArguments(args, t)
  2248  	if ctx.Prefix == onPrefix {
  2249  		if filter != "" {
  2250  			return fmt.Errorf("filter not supported on breakpoint")
  2251  		}
  2252  		ctx.Breakpoint.LoadArgs = &cfg
  2253  		return nil
  2254  	}
  2255  	vars, err := t.client.ListFunctionArgs(ctx.Scope, cfg)
  2256  	if err != nil {
  2257  		return err
  2258  	}
  2259  	return t.printFilteredVariables("args", vars, filter, cfg)
  2260  }
  2261  
  2262  func locals(t *Term, ctx callContext, args string) error {
  2263  	filter, cfg := parseVarArguments(args, t)
  2264  	if ctx.Prefix == onPrefix {
  2265  		if filter != "" {
  2266  			return fmt.Errorf("filter not supported on breakpoint")
  2267  		}
  2268  		ctx.Breakpoint.LoadLocals = &cfg
  2269  		return nil
  2270  	}
  2271  	locals, err := t.client.ListLocalVariables(ctx.Scope, cfg)
  2272  	if err != nil {
  2273  		return err
  2274  	}
  2275  	return t.printFilteredVariables("locals", locals, filter, cfg)
  2276  }
  2277  
  2278  func vars(t *Term, ctx callContext, args string) error {
  2279  	filter, cfg := parseVarArguments(args, t)
  2280  	vars, err := t.client.ListPackageVariables(filter, cfg)
  2281  	if err != nil {
  2282  		return err
  2283  	}
  2284  	return t.printFilteredVariables("vars", vars, filter, cfg)
  2285  }
  2286  
  2287  func regs(t *Term, ctx callContext, args string) error {
  2288  	includeFp := false
  2289  	if args == "-a" {
  2290  		includeFp = true
  2291  	}
  2292  	var regs api.Registers
  2293  	var err error
  2294  	if ctx.Scope.GoroutineID < 0 && ctx.Scope.Frame == 0 {
  2295  		regs, err = t.client.ListThreadRegisters(0, includeFp)
  2296  	} else {
  2297  		regs, err = t.client.ListScopeRegisters(ctx.Scope, includeFp)
  2298  	}
  2299  	if err != nil {
  2300  		return err
  2301  	}
  2302  	fmt.Fprintln(t.stdout, regs)
  2303  	return nil
  2304  }
  2305  
  2306  func stackCommand(t *Term, ctx callContext, args string) error {
  2307  	sa, err := parseStackArgs(args)
  2308  	if err != nil {
  2309  		return err
  2310  	}
  2311  	if ctx.Prefix == onPrefix {
  2312  		ctx.Breakpoint.Stacktrace = sa.depth
  2313  		return nil
  2314  	}
  2315  	var cfg *api.LoadConfig
  2316  	if sa.full {
  2317  		cfg = &ShortLoadConfig
  2318  	}
  2319  	stack, err := t.client.Stacktrace(ctx.Scope.GoroutineID, sa.depth, sa.opts, cfg)
  2320  	if err != nil {
  2321  		return err
  2322  	}
  2323  	t.stdout.pw.PageMaybe(nil)
  2324  	printStack(t, t.stdout, stack, "", sa.offsets)
  2325  	if sa.ancestors > 0 {
  2326  		ancestors, err := t.client.Ancestors(ctx.Scope.GoroutineID, sa.ancestors, sa.ancestorDepth)
  2327  		if err != nil {
  2328  			return err
  2329  		}
  2330  		for _, ancestor := range ancestors {
  2331  			fmt.Fprintf(t.stdout, "Created by Goroutine %d:\n", ancestor.ID)
  2332  			if ancestor.Unreadable != "" {
  2333  				fmt.Fprintf(t.stdout, "\t%s\n", ancestor.Unreadable)
  2334  				continue
  2335  			}
  2336  			printStack(t, t.stdout, ancestor.Stack, "\t", false)
  2337  		}
  2338  	}
  2339  	return nil
  2340  }
  2341  
  2342  type stackArgs struct {
  2343  	depth   int
  2344  	full    bool
  2345  	offsets bool
  2346  	opts    api.StacktraceOptions
  2347  
  2348  	ancestors     int
  2349  	ancestorDepth int
  2350  }
  2351  
  2352  func parseStackArgs(argstr string) (stackArgs, error) {
  2353  	r := stackArgs{
  2354  		depth: 50,
  2355  		full:  false,
  2356  	}
  2357  	if argstr != "" {
  2358  		args := strings.Split(argstr, " ")
  2359  		for i := 0; i < len(args); i++ {
  2360  			numarg := func(name string) (int, error) {
  2361  				if i >= len(args) {
  2362  					return 0, fmt.Errorf("expected number after %s", name)
  2363  				}
  2364  				n, err := strconv.Atoi(args[i])
  2365  				if err != nil {
  2366  					return 0, fmt.Errorf("expected number after %s: %v", name, err)
  2367  				}
  2368  				return n, nil
  2369  
  2370  			}
  2371  			switch args[i] {
  2372  			case "-full":
  2373  				r.full = true
  2374  			case "-offsets":
  2375  				r.offsets = true
  2376  			case "-defer":
  2377  				r.opts |= api.StacktraceReadDefers
  2378  			case "-mode":
  2379  				i++
  2380  				if i >= len(args) {
  2381  					return stackArgs{}, fmt.Errorf("expected normal, simple or fromg after -mode")
  2382  				}
  2383  				switch args[i] {
  2384  				case "normal":
  2385  					r.opts &^= api.StacktraceSimple
  2386  					r.opts &^= api.StacktraceG
  2387  				case "simple":
  2388  					r.opts |= api.StacktraceSimple
  2389  				case "fromg":
  2390  					r.opts |= api.StacktraceG | api.StacktraceSimple
  2391  				default:
  2392  					return stackArgs{}, fmt.Errorf("expected normal, simple or fromg after -mode")
  2393  				}
  2394  			case "-a":
  2395  				i++
  2396  				n, err := numarg("-a")
  2397  				if err != nil {
  2398  					return stackArgs{}, err
  2399  				}
  2400  				r.ancestors = n
  2401  			case "-adepth":
  2402  				i++
  2403  				n, err := numarg("-adepth")
  2404  				if err != nil {
  2405  					return stackArgs{}, err
  2406  				}
  2407  				r.ancestorDepth = n
  2408  			default:
  2409  				n, err := strconv.Atoi(args[i])
  2410  				if err != nil {
  2411  					return stackArgs{}, fmt.Errorf("depth must be a number")
  2412  				}
  2413  				r.depth = n
  2414  			}
  2415  		}
  2416  	}
  2417  	if r.ancestors > 0 && r.ancestorDepth == 0 {
  2418  		r.ancestorDepth = r.depth
  2419  	}
  2420  	return r, nil
  2421  }
  2422  
  2423  // getLocation returns the current location or the locations specified by the argument.
  2424  // getLocation is used to process the argument of list and edit commands.
  2425  func getLocation(t *Term, ctx callContext, args string, showContext bool) (file string, lineno int, showarrow bool, err error) {
  2426  	switch {
  2427  	case len(args) == 0 && !ctx.scoped():
  2428  		state, err := t.client.GetState()
  2429  		if err != nil {
  2430  			return "", 0, false, err
  2431  		}
  2432  		if showContext {
  2433  			printcontext(t, state)
  2434  		}
  2435  		if state.SelectedGoroutine != nil {
  2436  			return state.SelectedGoroutine.CurrentLoc.File, state.SelectedGoroutine.CurrentLoc.Line, true, nil
  2437  		}
  2438  		return state.CurrentThread.File, state.CurrentThread.Line, true, nil
  2439  
  2440  	case len(args) == 0 && ctx.scoped():
  2441  		locs, err := t.client.Stacktrace(ctx.Scope.GoroutineID, ctx.Scope.Frame, 0, nil)
  2442  		if err != nil {
  2443  			return "", 0, false, err
  2444  		}
  2445  		if ctx.Scope.Frame >= len(locs) {
  2446  			return "", 0, false, fmt.Errorf("Frame %d does not exist in goroutine %d", ctx.Scope.Frame, ctx.Scope.GoroutineID)
  2447  		}
  2448  		loc := locs[ctx.Scope.Frame]
  2449  		gid := ctx.Scope.GoroutineID
  2450  		if gid < 0 {
  2451  			state, err := t.client.GetState()
  2452  			if err != nil {
  2453  				return "", 0, false, err
  2454  			}
  2455  			if state.SelectedGoroutine != nil {
  2456  				gid = state.SelectedGoroutine.ID
  2457  			}
  2458  		}
  2459  		if showContext {
  2460  			fmt.Fprintf(t.stdout, "Goroutine %d frame %d at %s:%d (PC: %#x)\n", gid, ctx.Scope.Frame, loc.File, loc.Line, loc.PC)
  2461  		}
  2462  		return loc.File, loc.Line, true, nil
  2463  
  2464  	default:
  2465  		locs, _, err := t.client.FindLocation(ctx.Scope, args, false, t.substitutePathRules())
  2466  		if err != nil {
  2467  			return "", 0, false, err
  2468  		}
  2469  		if len(locs) > 1 {
  2470  			return "", 0, false, locspec.AmbiguousLocationError{Location: args, CandidatesLocation: locs}
  2471  		}
  2472  		loc := locs[0]
  2473  		if showContext {
  2474  			fmt.Fprintf(t.stdout, "Showing %s:%d (PC: %#x)\n", loc.File, loc.Line, loc.PC)
  2475  		}
  2476  		return loc.File, loc.Line, false, nil
  2477  	}
  2478  }
  2479  
  2480  func listCommand(t *Term, ctx callContext, args string) error {
  2481  	file, lineno, showarrow, err := getLocation(t, ctx, args, true)
  2482  	if err != nil {
  2483  		return err
  2484  	}
  2485  	return printfile(t, file, lineno, showarrow)
  2486  }
  2487  
  2488  func (c *Commands) sourceCommand(t *Term, ctx callContext, args string) error {
  2489  	if len(args) == 0 {
  2490  		return fmt.Errorf("wrong number of arguments: source <filename>")
  2491  	}
  2492  
  2493  	if args == "-" {
  2494  		return t.starlarkEnv.REPL()
  2495  	}
  2496  
  2497  	if runtime.GOOS != "windows" && strings.HasPrefix(args, "~") {
  2498  		home, err := os.UserHomeDir()
  2499  		if err == nil {
  2500  			if args == "~" {
  2501  				args = home
  2502  			} else if strings.HasPrefix(args, "~/") {
  2503  				args = filepath.Join(home, args[2:])
  2504  			}
  2505  		}
  2506  	}
  2507  
  2508  	if filepath.Ext(args) == ".star" {
  2509  		_, err := t.starlarkEnv.Execute(args, nil, "main", nil)
  2510  		return err
  2511  	}
  2512  
  2513  	return c.executeFile(t, args)
  2514  }
  2515  
  2516  var errDisasmUsage = errors.New("wrong number of arguments: disassemble [-a <start> <end>] [-l <locspec>]")
  2517  
  2518  func disassCommand(t *Term, ctx callContext, args string) error {
  2519  	var cmd, rest string
  2520  
  2521  	if args != "" {
  2522  		argv := config.Split2PartsBySpace(args)
  2523  		if len(argv) != 2 {
  2524  			return errDisasmUsage
  2525  		}
  2526  		cmd = argv[0]
  2527  		rest = argv[1]
  2528  	}
  2529  
  2530  	t.stdout.pw.PageMaybe(nil)
  2531  
  2532  	flavor := t.conf.GetDisassembleFlavour()
  2533  
  2534  	var disasm api.AsmInstructions
  2535  	var disasmErr error
  2536  
  2537  	switch cmd {
  2538  	case "":
  2539  		locs, _, err := t.client.FindLocation(ctx.Scope, "+0", true, t.substitutePathRules())
  2540  		if err != nil {
  2541  			return err
  2542  		}
  2543  		disasm, disasmErr = t.client.DisassemblePC(ctx.Scope, locs[0].PC, flavor)
  2544  	case "-a":
  2545  		v := config.Split2PartsBySpace(rest)
  2546  		if len(v) != 2 {
  2547  			return errDisasmUsage
  2548  		}
  2549  		startpc, err := strconv.ParseInt(v[0], 0, 64)
  2550  		if err != nil {
  2551  			return fmt.Errorf("wrong argument: %q is not a number", v[0])
  2552  		}
  2553  		endpc, err := strconv.ParseInt(v[1], 0, 64)
  2554  		if err != nil {
  2555  			return fmt.Errorf("wrong argument: %q is not a number", v[1])
  2556  		}
  2557  		disasm, disasmErr = t.client.DisassembleRange(ctx.Scope, uint64(startpc), uint64(endpc), flavor)
  2558  	case "-l":
  2559  		locs, _, err := t.client.FindLocation(ctx.Scope, rest, true, t.substitutePathRules())
  2560  		if err != nil {
  2561  			return err
  2562  		}
  2563  		if len(locs) != 1 {
  2564  			return errors.New("expression specifies multiple locations")
  2565  		}
  2566  		disasm, disasmErr = t.client.DisassemblePC(ctx.Scope, locs[0].PC, flavor)
  2567  	default:
  2568  		return errDisasmUsage
  2569  	}
  2570  
  2571  	if disasmErr != nil {
  2572  		return disasmErr
  2573  	}
  2574  
  2575  	disasmPrint(disasm, t.stdout, true)
  2576  
  2577  	return nil
  2578  }
  2579  
  2580  func libraries(t *Term, ctx callContext, args string) error {
  2581  	libs, err := t.client.ListDynamicLibraries()
  2582  	if err != nil {
  2583  		return err
  2584  	}
  2585  	d := digits(len(libs))
  2586  	for i := range libs {
  2587  		fmt.Fprintf(t.stdout, "%"+strconv.Itoa(d)+"d. %#x %s\n", i, libs[i].Address, libs[i].Path)
  2588  		if libs[i].LoadError != "" {
  2589  			fmt.Fprintf(t.stdout, "    Load error: %s", libs[i].LoadError)
  2590  		}
  2591  	}
  2592  	return nil
  2593  }
  2594  
  2595  func digits(n int) int {
  2596  	if n <= 0 {
  2597  		return 1
  2598  	}
  2599  	return int(math.Floor(math.Log10(float64(n)))) + 1
  2600  }
  2601  
  2602  func printStack(t *Term, out io.Writer, stack []api.Stackframe, ind string, offsets bool) {
  2603  	api.PrintStack(t.formatPath, out, stack, ind, offsets, func(api.Stackframe) bool { return true })
  2604  }
  2605  
  2606  func printcontext(t *Term, state *api.DebuggerState) {
  2607  	if t.IsTraceNonInteractive() {
  2608  		// If we're just running the `trace` subcommand there isn't any need
  2609  		// to print out the rest of the state below.
  2610  		for i := range state.Threads {
  2611  			if state.Threads[i].Breakpoint != nil {
  2612  				printcontextThread(t, state.Threads[i])
  2613  			}
  2614  		}
  2615  		return
  2616  	}
  2617  
  2618  	if state.Pid != t.oldPid {
  2619  		if t.oldPid != 0 {
  2620  			fmt.Fprintf(t.stdout, "Switch target process from %d to %d (%s)\n", t.oldPid, state.Pid, state.TargetCommandLine)
  2621  		}
  2622  		t.oldPid = state.Pid
  2623  	}
  2624  	for i := range state.Threads {
  2625  		if (state.CurrentThread != nil) && (state.Threads[i].ID == state.CurrentThread.ID) {
  2626  			continue
  2627  		}
  2628  		if state.Threads[i].Breakpoint != nil {
  2629  			printcontextThread(t, state.Threads[i])
  2630  		}
  2631  	}
  2632  
  2633  	if state.CurrentThread == nil {
  2634  		fmt.Fprintln(t.stdout, "No current thread available")
  2635  		return
  2636  	}
  2637  
  2638  	var th *api.Thread
  2639  	if state.SelectedGoroutine == nil {
  2640  		th = state.CurrentThread
  2641  	} else {
  2642  		for i := range state.Threads {
  2643  			if state.Threads[i].ID == state.SelectedGoroutine.ThreadID {
  2644  				th = state.Threads[i]
  2645  				break
  2646  			}
  2647  		}
  2648  		if th == nil {
  2649  			printcontextLocation(t, state.SelectedGoroutine.CurrentLoc)
  2650  			return
  2651  		}
  2652  	}
  2653  
  2654  	if th.File == "" {
  2655  		fmt.Fprintf(t.stdout, "Stopped at: 0x%x\n", state.CurrentThread.PC)
  2656  		t.stdout.ColorizePrint("", bytes.NewReader([]byte("no source available")), 1, 10, 1)
  2657  		return
  2658  	}
  2659  
  2660  	printcontextThread(t, th)
  2661  
  2662  	if state.When != "" {
  2663  		fmt.Fprintln(t.stdout, state.When)
  2664  	}
  2665  
  2666  	for _, watchpoint := range state.WatchOutOfScope {
  2667  		fmt.Fprintf(t.stdout, "%s went out of scope and was cleared\n", formatBreakpointName(watchpoint, true))
  2668  	}
  2669  }
  2670  
  2671  func printcontextLocation(t *Term, loc api.Location) {
  2672  	fmt.Fprintf(t.stdout, "> %s() %s:%d (PC: %#v)\n", loc.Function.Name(), t.formatPath(loc.File), loc.Line, loc.PC)
  2673  	if loc.Function != nil && loc.Function.Optimized {
  2674  		fmt.Fprintln(t.stdout, optimizedFunctionWarning)
  2675  	}
  2676  }
  2677  
  2678  func printReturnValues(t *Term, th *api.Thread) {
  2679  	if th.ReturnValues == nil {
  2680  		return
  2681  	}
  2682  	fmt.Fprintln(t.stdout, "Values returned:")
  2683  	for _, v := range th.ReturnValues {
  2684  		fmt.Fprintf(t.stdout, "\t%s: %s\n", v.Name, v.MultilineString("\t", ""))
  2685  	}
  2686  	fmt.Fprintln(t.stdout)
  2687  }
  2688  
  2689  func printcontextThread(t *Term, th *api.Thread) {
  2690  	fn := th.Function
  2691  
  2692  	if th.Breakpoint == nil {
  2693  		printcontextLocation(t, api.Location{PC: th.PC, File: th.File, Line: th.Line, Function: th.Function})
  2694  		printReturnValues(t, th)
  2695  		return
  2696  	}
  2697  
  2698  	args := ""
  2699  	var hasReturnValue bool
  2700  	if th.BreakpointInfo != nil && th.Breakpoint.LoadArgs != nil && *th.Breakpoint.LoadArgs == ShortLoadConfig {
  2701  		var arg []string
  2702  		for _, ar := range th.BreakpointInfo.Arguments {
  2703  			// For AI compatibility return values are included in the
  2704  			// argument list. This is a relic of the dark ages when the
  2705  			// Go debug information did not distinguish between the two.
  2706  			// Filter them out here instead, so during trace operations
  2707  			// they are not printed as an argument.
  2708  			if (ar.Flags & api.VariableArgument) != 0 {
  2709  				arg = append(arg, ar.SinglelineString())
  2710  			}
  2711  			if (ar.Flags & api.VariableReturnArgument) != 0 {
  2712  				hasReturnValue = true
  2713  			}
  2714  		}
  2715  		args = strings.Join(arg, ", ")
  2716  	}
  2717  
  2718  	bpname := ""
  2719  	if th.Breakpoint.WatchExpr != "" {
  2720  		bpname = fmt.Sprintf("watchpoint on [%s] ", th.Breakpoint.WatchExpr)
  2721  	} else if th.Breakpoint.Name != "" {
  2722  		bpname = fmt.Sprintf("[%s] ", th.Breakpoint.Name)
  2723  	}
  2724  
  2725  	if th.Breakpoint.Tracepoint || th.Breakpoint.TraceReturn {
  2726  		printTracepoint(t, th, bpname, fn, args, hasReturnValue)
  2727  		return
  2728  	}
  2729  
  2730  	if hitCount, ok := th.Breakpoint.HitCount[strconv.FormatInt(th.GoroutineID, 10)]; ok {
  2731  		fmt.Fprintf(t.stdout, "> %s%s(%s) %s:%d (hits goroutine(%d):%d total:%d) (PC: %#v)\n",
  2732  			bpname,
  2733  			fn.Name(),
  2734  			args,
  2735  			t.formatPath(th.File),
  2736  			th.Line,
  2737  			th.GoroutineID,
  2738  			hitCount,
  2739  			th.Breakpoint.TotalHitCount,
  2740  			th.PC)
  2741  	} else {
  2742  		fmt.Fprintf(t.stdout, "> %s%s(%s) %s:%d (hits total:%d) (PC: %#v)\n",
  2743  			bpname,
  2744  			fn.Name(),
  2745  			args,
  2746  			t.formatPath(th.File),
  2747  			th.Line,
  2748  			th.Breakpoint.TotalHitCount,
  2749  			th.PC)
  2750  	}
  2751  	if th.Function != nil && th.Function.Optimized {
  2752  		fmt.Fprintln(t.stdout, optimizedFunctionWarning)
  2753  	}
  2754  
  2755  	printReturnValues(t, th)
  2756  	printBreakpointInfo(t, th, false)
  2757  }
  2758  
  2759  func printBreakpointInfo(t *Term, th *api.Thread, tracepointOnNewline bool) {
  2760  	if th.BreakpointInfo == nil {
  2761  		return
  2762  	}
  2763  	bp := th.Breakpoint
  2764  	bpi := th.BreakpointInfo
  2765  
  2766  	if bp.TraceReturn {
  2767  		return
  2768  	}
  2769  
  2770  	didprintnl := tracepointOnNewline
  2771  	tracepointnl := func() {
  2772  		if !bp.Tracepoint || didprintnl {
  2773  			return
  2774  		}
  2775  		didprintnl = true
  2776  		fmt.Fprintln(t.stdout)
  2777  	}
  2778  
  2779  	if bpi.Goroutine != nil {
  2780  		tracepointnl()
  2781  		writeGoroutineLong(t, t.stdout, bpi.Goroutine, "\t")
  2782  	}
  2783  
  2784  	for _, v := range bpi.Variables {
  2785  		tracepointnl()
  2786  		fmt.Fprintf(t.stdout, "\t%s: %s\n", v.Name, v.MultilineString("\t", ""))
  2787  	}
  2788  
  2789  	for _, v := range bpi.Locals {
  2790  		tracepointnl()
  2791  		if *bp.LoadLocals == longLoadConfig {
  2792  			fmt.Fprintf(t.stdout, "\t%s: %s\n", v.Name, v.MultilineString("\t", ""))
  2793  		} else {
  2794  			fmt.Fprintf(t.stdout, "\t%s: %s\n", v.Name, v.SinglelineString())
  2795  		}
  2796  	}
  2797  
  2798  	if bp.LoadArgs != nil && *bp.LoadArgs == longLoadConfig {
  2799  		for _, v := range bpi.Arguments {
  2800  			tracepointnl()
  2801  			fmt.Fprintf(t.stdout, "\t%s: %s\n", v.Name, v.MultilineString("\t", ""))
  2802  		}
  2803  	}
  2804  
  2805  	if bpi.Stacktrace != nil {
  2806  		tracepointnl()
  2807  		fmt.Fprintf(t.stdout, "\tStack:\n")
  2808  		printStack(t, t.stdout, bpi.Stacktrace, "\t\t", false)
  2809  	}
  2810  }
  2811  
  2812  func printTracepoint(t *Term, th *api.Thread, bpname string, fn *api.Function, args string, hasReturnValue bool) {
  2813  	if t.conf.TraceShowTimestamp {
  2814  		fmt.Fprintf(t.stdout, "%s ", time.Now().Format(time.RFC3339Nano))
  2815  	}
  2816  
  2817  	if th.Breakpoint.Tracepoint {
  2818  		fmt.Fprintf(t.stdout, "> goroutine(%d): %s%s(%s)\n", th.GoroutineID, bpname, fn.Name(), args)
  2819  		printBreakpointInfo(t, th, !hasReturnValue)
  2820  	}
  2821  	if th.Breakpoint.TraceReturn {
  2822  		retVals := make([]string, 0, len(th.ReturnValues))
  2823  		for _, v := range th.ReturnValues {
  2824  			retVals = append(retVals, v.SinglelineString())
  2825  		}
  2826  		fmt.Fprintf(t.stdout, ">> goroutine(%d): => (%s)\n", th.GoroutineID, strings.Join(retVals, ","))
  2827  	}
  2828  	if th.Breakpoint.TraceReturn || !hasReturnValue {
  2829  		if th.BreakpointInfo != nil && th.BreakpointInfo.Stacktrace != nil {
  2830  			fmt.Fprintf(t.stdout, "\tStack:\n")
  2831  			printStack(t, t.stdout, th.BreakpointInfo.Stacktrace, "\t\t", false)
  2832  		}
  2833  	}
  2834  }
  2835  
  2836  type printPosFlags uint8
  2837  
  2838  const (
  2839  	printPosShowArrow printPosFlags = 1 << iota
  2840  	printPosStepInstruction
  2841  )
  2842  
  2843  func printPos(t *Term, th *api.Thread, flags printPosFlags) error {
  2844  	if flags&printPosStepInstruction != 0 {
  2845  		if t.conf.Position == config.PositionSource {
  2846  			return printfile(t, th.File, th.Line, flags&printPosShowArrow != 0)
  2847  		}
  2848  		return printdisass(t, th.PC)
  2849  	}
  2850  	if t.conf.Position == config.PositionDisassembly {
  2851  		return printdisass(t, th.PC)
  2852  	}
  2853  	return printfile(t, th.File, th.Line, flags&printPosShowArrow != 0)
  2854  }
  2855  
  2856  func printfile(t *Term, filename string, line int, showArrow bool) error {
  2857  	if filename == "" {
  2858  		return nil
  2859  	}
  2860  
  2861  	lineCount := t.conf.GetSourceListLineCount()
  2862  	arrowLine := 0
  2863  	if showArrow {
  2864  		arrowLine = line
  2865  	}
  2866  
  2867  	var file *os.File
  2868  	path := t.substitutePath(filename)
  2869  	if _, err := os.Stat(path); os.IsNotExist(err) {
  2870  		foundPath, err := debuginfod.GetSource(t.client.BuildID(), filename)
  2871  		if err == nil {
  2872  			path = foundPath
  2873  		}
  2874  	}
  2875  	file, err := os.OpenFile(path, 0, os.ModePerm)
  2876  	if err != nil {
  2877  		return err
  2878  	}
  2879  	defer file.Close()
  2880  
  2881  	fi, _ := file.Stat()
  2882  	lastModExe := t.client.LastModified()
  2883  	if fi.ModTime().After(lastModExe) {
  2884  		fmt.Fprintln(t.stdout, "Warning: listing may not match stale executable")
  2885  	}
  2886  
  2887  	return t.stdout.ColorizePrint(file.Name(), file, line-lineCount, line+lineCount+1, arrowLine)
  2888  }
  2889  
  2890  func printdisass(t *Term, pc uint64) error {
  2891  	disasm, err := t.client.DisassemblePC(api.EvalScope{GoroutineID: -1, Frame: 0, DeferredCall: 0}, pc, t.conf.GetDisassembleFlavour())
  2892  	if err != nil {
  2893  		return err
  2894  	}
  2895  
  2896  	lineCount := t.conf.GetSourceListLineCount()
  2897  
  2898  	showHeader := true
  2899  	for i := range disasm {
  2900  		if disasm[i].AtPC {
  2901  			s := i - lineCount
  2902  			if s < 0 {
  2903  				s = 0
  2904  			}
  2905  			e := i + lineCount + 1
  2906  			if e > len(disasm) {
  2907  				e = len(disasm)
  2908  			}
  2909  			showHeader = s == 0
  2910  			disasm = disasm[s:e]
  2911  			break
  2912  		}
  2913  	}
  2914  
  2915  	disasmPrint(disasm, t.stdout, showHeader)
  2916  	return nil
  2917  }
  2918  
  2919  // ExitRequestError is returned when the user
  2920  // exits Delve.
  2921  type ExitRequestError struct{}
  2922  
  2923  func (ere ExitRequestError) Error() string {
  2924  	return ""
  2925  }
  2926  
  2927  func exitCommand(t *Term, ctx callContext, args string) error {
  2928  	if args == "-c" {
  2929  		if !t.client.IsMulticlient() {
  2930  			return errors.New("not connected to an --accept-multiclient server")
  2931  		}
  2932  		bps, _ := t.client.ListBreakpoints(false)
  2933  		hasUserBreakpoints := false
  2934  		for _, bp := range bps {
  2935  			if bp.ID >= 0 {
  2936  				hasUserBreakpoints = true
  2937  				break
  2938  			}
  2939  		}
  2940  		if hasUserBreakpoints {
  2941  			yes, _ := yesno(t.line, "There are breakpoints set, do you wish to quit and continue without clearing breakpoints? [Y/n] ", "yes")
  2942  			if !yes {
  2943  				return nil
  2944  			}
  2945  		}
  2946  		t.quitContinue = true
  2947  	}
  2948  	return ExitRequestError{}
  2949  }
  2950  
  2951  func getBreakpointByIDOrName(t *Term, arg string) (*api.Breakpoint, error) {
  2952  	if id, err := strconv.Atoi(arg); err == nil {
  2953  		return t.client.GetBreakpoint(id)
  2954  	}
  2955  	return t.client.GetBreakpointByName(arg)
  2956  }
  2957  
  2958  func (c *Commands) onCmd(t *Term, ctx callContext, argstr string) error {
  2959  	args := config.Split2PartsBySpace(argstr)
  2960  
  2961  	if len(args) < 2 {
  2962  		return errors.New("not enough arguments")
  2963  	}
  2964  
  2965  	bp, err := getBreakpointByIDOrName(t, args[0])
  2966  	if err != nil {
  2967  		return err
  2968  	}
  2969  
  2970  	ctx.Prefix = onPrefix
  2971  	ctx.Breakpoint = bp
  2972  
  2973  	if args[1] == "-edit" {
  2974  		f, err := ioutil.TempFile("", "dlv-on-cmd-")
  2975  		if err != nil {
  2976  			return err
  2977  		}
  2978  		defer func() {
  2979  			_ = os.Remove(f.Name())
  2980  		}()
  2981  		attrs := formatBreakpointAttrs("", ctx.Breakpoint, true)
  2982  		_, err = f.Write([]byte(strings.Join(attrs, "\n")))
  2983  		if err != nil {
  2984  			return err
  2985  		}
  2986  		err = f.Close()
  2987  		if err != nil {
  2988  			return err
  2989  		}
  2990  
  2991  		err = runEditor(f.Name())
  2992  		if err != nil {
  2993  			return err
  2994  		}
  2995  
  2996  		fin, err := os.Open(f.Name())
  2997  		if err != nil {
  2998  			return err
  2999  		}
  3000  		defer fin.Close()
  3001  
  3002  		err = c.parseBreakpointAttrs(t, ctx, fin)
  3003  		if err != nil {
  3004  			return err
  3005  		}
  3006  	} else {
  3007  		err = c.CallWithContext(args[1], t, ctx)
  3008  		if err != nil {
  3009  			return err
  3010  		}
  3011  	}
  3012  	return t.client.AmendBreakpoint(ctx.Breakpoint)
  3013  }
  3014  
  3015  func (c *Commands) parseBreakpointAttrs(t *Term, ctx callContext, r io.Reader) error {
  3016  	ctx.Breakpoint.Tracepoint = false
  3017  	ctx.Breakpoint.Goroutine = false
  3018  	ctx.Breakpoint.Stacktrace = 0
  3019  	ctx.Breakpoint.Variables = ctx.Breakpoint.Variables[:0]
  3020  	ctx.Breakpoint.Cond = ""
  3021  	ctx.Breakpoint.HitCond = ""
  3022  
  3023  	scan := bufio.NewScanner(r)
  3024  	lineno := 0
  3025  	for scan.Scan() {
  3026  		lineno++
  3027  		err := c.CallWithContext(scan.Text(), t, ctx)
  3028  		if err != nil {
  3029  			fmt.Fprintf(t.stdout, "%d: %s\n", lineno, err.Error())
  3030  		}
  3031  	}
  3032  	return scan.Err()
  3033  }
  3034  
  3035  func conditionCmd(t *Term, ctx callContext, argstr string) error {
  3036  	args := config.Split2PartsBySpace(argstr)
  3037  
  3038  	if len(args) < 2 {
  3039  		return fmt.Errorf("not enough arguments")
  3040  	}
  3041  
  3042  	hitCondPerG := args[0] == "-per-g-hitcount"
  3043  	if args[0] == "-hitcount" || hitCondPerG {
  3044  		// hitcount breakpoint
  3045  
  3046  		if ctx.Prefix == onPrefix {
  3047  			ctx.Breakpoint.HitCond = args[1]
  3048  			ctx.Breakpoint.HitCondPerG = hitCondPerG
  3049  			return nil
  3050  		}
  3051  
  3052  		args = config.Split2PartsBySpace(args[1])
  3053  		if len(args) < 2 {
  3054  			return fmt.Errorf("not enough arguments")
  3055  		}
  3056  
  3057  		bp, err := getBreakpointByIDOrName(t, args[0])
  3058  		if err != nil {
  3059  			return err
  3060  		}
  3061  
  3062  		bp.HitCond = args[1]
  3063  		bp.HitCondPerG = hitCondPerG
  3064  
  3065  		return t.client.AmendBreakpoint(bp)
  3066  	}
  3067  
  3068  	if args[0] == "-clear" {
  3069  		bp, err := getBreakpointByIDOrName(t, args[1])
  3070  		if err != nil {
  3071  			return err
  3072  		}
  3073  		bp.Cond = ""
  3074  		return t.client.AmendBreakpoint(bp)
  3075  	}
  3076  
  3077  	if ctx.Prefix == onPrefix {
  3078  		ctx.Breakpoint.Cond = argstr
  3079  		return nil
  3080  	}
  3081  
  3082  	bp, err := getBreakpointByIDOrName(t, args[0])
  3083  	if err != nil {
  3084  		return err
  3085  	}
  3086  	bp.Cond = args[1]
  3087  
  3088  	return t.client.AmendBreakpoint(bp)
  3089  }
  3090  
  3091  func (c *Commands) executeFile(t *Term, name string) error {
  3092  	fh, err := os.Open(name)
  3093  	if err != nil {
  3094  		return err
  3095  	}
  3096  	defer fh.Close()
  3097  
  3098  	scanner := bufio.NewScanner(fh)
  3099  	lineno := 0
  3100  	for scanner.Scan() {
  3101  		line := strings.TrimSpace(scanner.Text())
  3102  		lineno++
  3103  
  3104  		if line == "" || line[0] == '#' {
  3105  			continue
  3106  		}
  3107  
  3108  		if err := c.Call(line, t); err != nil {
  3109  			if _, isExitRequest := err.(ExitRequestError); isExitRequest {
  3110  				return err
  3111  			}
  3112  			fmt.Fprintf(t.stdout, "%s:%d: %v\n", name, lineno, err)
  3113  		}
  3114  	}
  3115  
  3116  	return scanner.Err()
  3117  }
  3118  
  3119  func (c *Commands) rewind(t *Term, ctx callContext, args string) error {
  3120  	c.frame = 0
  3121  	stateChan := t.client.Rewind()
  3122  	var state *api.DebuggerState
  3123  	for state = range stateChan {
  3124  		if state.Err != nil {
  3125  			return state.Err
  3126  		}
  3127  		printcontext(t, state)
  3128  	}
  3129  	printPos(t, state.CurrentThread, printPosShowArrow)
  3130  	return nil
  3131  }
  3132  
  3133  func checkpoint(t *Term, ctx callContext, args string) error {
  3134  	if args == "" {
  3135  		state, err := t.client.GetState()
  3136  		if err != nil {
  3137  			return err
  3138  		}
  3139  		var loc api.Location = api.Location{PC: state.CurrentThread.PC, File: state.CurrentThread.File, Line: state.CurrentThread.Line, Function: state.CurrentThread.Function}
  3140  		if state.SelectedGoroutine != nil {
  3141  			loc = state.SelectedGoroutine.CurrentLoc
  3142  		}
  3143  		args = fmt.Sprintf("%s() %s:%d (%#x)", loc.Function.Name(), loc.File, loc.Line, loc.PC)
  3144  	}
  3145  
  3146  	cpid, err := t.client.Checkpoint(args)
  3147  	if err != nil {
  3148  		return err
  3149  	}
  3150  
  3151  	fmt.Fprintf(t.stdout, "Checkpoint c%d created.\n", cpid)
  3152  	return nil
  3153  }
  3154  
  3155  func checkpoints(t *Term, ctx callContext, args string) error {
  3156  	cps, err := t.client.ListCheckpoints()
  3157  	if err != nil {
  3158  		return err
  3159  	}
  3160  	w := new(tabwriter.Writer)
  3161  	w.Init(t.stdout, 4, 4, 2, ' ', 0)
  3162  	fmt.Fprintln(w, "ID\tWhen\tNote")
  3163  	for _, cp := range cps {
  3164  		fmt.Fprintf(w, "c%d\t%s\t%s\n", cp.ID, cp.When, cp.Where)
  3165  	}
  3166  	w.Flush()
  3167  	return nil
  3168  }
  3169  
  3170  func clearCheckpoint(t *Term, ctx callContext, args string) error {
  3171  	if len(args) == 0 {
  3172  		return errors.New("not enough arguments to clear-checkpoint")
  3173  	}
  3174  	if args[0] != 'c' {
  3175  		return errors.New("clear-checkpoint argument must be a checkpoint ID")
  3176  	}
  3177  	id, err := strconv.Atoi(args[1:])
  3178  	if err != nil {
  3179  		return errors.New("clear-checkpoint argument must be a checkpoint ID")
  3180  	}
  3181  	return t.client.ClearCheckpoint(id)
  3182  }
  3183  
  3184  func display(t *Term, ctx callContext, args string) error {
  3185  	const (
  3186  		addOption = "-a "
  3187  		delOption = "-d "
  3188  	)
  3189  	switch {
  3190  	case args == "":
  3191  		t.printDisplays()
  3192  
  3193  	case strings.HasPrefix(args, addOption):
  3194  		args = strings.TrimSpace(args[len(addOption):])
  3195  		fmtstr, args := parseFormatArg(args)
  3196  		if args == "" {
  3197  			return fmt.Errorf("not enough arguments")
  3198  		}
  3199  		t.addDisplay(args, fmtstr)
  3200  		t.printDisplay(len(t.displays) - 1)
  3201  
  3202  	case strings.HasPrefix(args, delOption):
  3203  		args = strings.TrimSpace(args[len(delOption):])
  3204  		n, err := strconv.Atoi(args)
  3205  		if err != nil {
  3206  			return fmt.Errorf("%q is not a number", args)
  3207  		}
  3208  		return t.removeDisplay(n)
  3209  
  3210  	default:
  3211  		return fmt.Errorf("wrong arguments")
  3212  	}
  3213  	return nil
  3214  }
  3215  
  3216  func dump(t *Term, ctx callContext, args string) error {
  3217  	if args == "" {
  3218  		return fmt.Errorf("not enough arguments")
  3219  	}
  3220  	dumpState, err := t.client.CoreDumpStart(args)
  3221  	if err != nil {
  3222  		return err
  3223  	}
  3224  	for {
  3225  		if dumpState.ThreadsDone != dumpState.ThreadsTotal {
  3226  			fmt.Fprintf(t.stdout, "\rDumping threads %d / %d...", dumpState.ThreadsDone, dumpState.ThreadsTotal)
  3227  		} else {
  3228  			fmt.Fprintf(t.stdout, "\rDumping memory %d / %d...", dumpState.MemDone, dumpState.MemTotal)
  3229  		}
  3230  		if !dumpState.Dumping {
  3231  			break
  3232  		}
  3233  		dumpState = t.client.CoreDumpWait(1000)
  3234  	}
  3235  	fmt.Fprintf(t.stdout, "\n")
  3236  	if dumpState.Err != "" {
  3237  		fmt.Fprintf(t.stdout, "error dumping: %s\n", dumpState.Err)
  3238  	} else if !dumpState.AllDone {
  3239  		fmt.Fprintf(t.stdout, "canceled\n")
  3240  	} else if dumpState.MemDone != dumpState.MemTotal {
  3241  		fmt.Fprintf(t.stdout, "Core dump could be incomplete\n")
  3242  	}
  3243  	return nil
  3244  }
  3245  
  3246  func transcript(t *Term, ctx callContext, args string) error {
  3247  	argv := strings.SplitN(args, " ", -1)
  3248  	truncate := false
  3249  	fileOnly := false
  3250  	disable := false
  3251  	path := ""
  3252  	for _, arg := range argv {
  3253  		switch arg {
  3254  		case "-x":
  3255  			fileOnly = true
  3256  		case "-t":
  3257  			truncate = true
  3258  		case "-off":
  3259  			disable = true
  3260  		default:
  3261  			if path != "" || strings.HasPrefix(arg, "-") {
  3262  				return fmt.Errorf("unrecognized option %q", arg)
  3263  			} else {
  3264  				path = arg
  3265  			}
  3266  		}
  3267  	}
  3268  
  3269  	if disable {
  3270  		if path != "" {
  3271  			return errors.New("-o option specified with an output path")
  3272  		}
  3273  		return t.stdout.CloseTranscript()
  3274  	}
  3275  
  3276  	if path == "" {
  3277  		return errors.New("no output path specified")
  3278  	}
  3279  
  3280  	flags := os.O_APPEND | os.O_WRONLY | os.O_CREATE
  3281  	if truncate {
  3282  		flags |= os.O_TRUNC
  3283  	}
  3284  	fh, err := os.OpenFile(path, flags, 0660)
  3285  	if err != nil {
  3286  		return err
  3287  	}
  3288  
  3289  	if err := t.stdout.CloseTranscript(); err != nil {
  3290  		return err
  3291  	}
  3292  
  3293  	t.stdout.TranscribeTo(fh, fileOnly)
  3294  	return nil
  3295  }
  3296  
  3297  func target(t *Term, ctx callContext, args string) error {
  3298  	argv := config.Split2PartsBySpace(args)
  3299  	switch argv[0] {
  3300  	case "list":
  3301  		tgts, err := t.client.ListTargets()
  3302  		if err != nil {
  3303  			return err
  3304  		}
  3305  		w := new(tabwriter.Writer)
  3306  		w.Init(t.stdout, 4, 4, 2, ' ', 0)
  3307  		for _, tgt := range tgts {
  3308  			selected := ""
  3309  			if tgt.Pid == t.oldPid {
  3310  				selected = "*"
  3311  			}
  3312  			fmt.Fprintf(w, "%s\t%d\t%s\n", selected, tgt.Pid, tgt.CmdLine)
  3313  		}
  3314  		w.Flush()
  3315  		return nil
  3316  	case "follow-exec":
  3317  		if len(argv) == 1 {
  3318  			if t.client.FollowExecEnabled() {
  3319  				fmt.Fprintf(t.stdout, "Follow exec is enabled.\n")
  3320  			} else {
  3321  				fmt.Fprintf(t.stdout, "Follow exec is disabled.\n")
  3322  			}
  3323  			return nil
  3324  		}
  3325  		argv = config.Split2PartsBySpace(argv[1])
  3326  		switch argv[0] {
  3327  		case "-on":
  3328  			var regex string
  3329  			if len(argv) == 2 {
  3330  				regex = argv[1]
  3331  			}
  3332  			t.client.FollowExec(true, regex)
  3333  		case "-off":
  3334  			if len(argv) > 1 {
  3335  				return errors.New("too many arguments")
  3336  			}
  3337  			t.client.FollowExec(false, "")
  3338  		default:
  3339  			return fmt.Errorf("unknown argument %q to 'target follow-exec'", argv[0])
  3340  		}
  3341  		return nil
  3342  	case "switch":
  3343  		tgts, err := t.client.ListTargets()
  3344  		if err != nil {
  3345  			return err
  3346  		}
  3347  		pid, err := strconv.Atoi(argv[1])
  3348  		if err != nil {
  3349  			return err
  3350  		}
  3351  		found := false
  3352  		for _, tgt := range tgts {
  3353  			if tgt.Pid == pid {
  3354  				found = true
  3355  				t.client.SwitchThread(tgt.CurrentThread.ID)
  3356  			}
  3357  		}
  3358  		if !found {
  3359  			return fmt.Errorf("could not find target %d", pid)
  3360  		}
  3361  		return nil
  3362  	case "":
  3363  		return errors.New("not enough arguments for 'target'")
  3364  	default:
  3365  		return fmt.Errorf("unknown command 'target %s'", argv[0])
  3366  	}
  3367  }
  3368  
  3369  func formatBreakpointName(bp *api.Breakpoint, upcase bool) string {
  3370  	thing := "breakpoint"
  3371  	if bp.Tracepoint {
  3372  		thing = "tracepoint"
  3373  	}
  3374  	if bp.WatchExpr != "" {
  3375  		thing = "watchpoint"
  3376  	}
  3377  	if upcase {
  3378  		thing = strings.Title(thing)
  3379  	}
  3380  	id := bp.Name
  3381  	if id == "" {
  3382  		id = strconv.Itoa(bp.ID)
  3383  	}
  3384  	if bp.WatchExpr != "" && bp.WatchExpr != bp.Name {
  3385  		return fmt.Sprintf("%s %s on [%s]", thing, id, bp.WatchExpr)
  3386  	}
  3387  	return fmt.Sprintf("%s %s", thing, id)
  3388  }
  3389  
  3390  func (t *Term) formatBreakpointLocation(bp *api.Breakpoint) string {
  3391  	var out bytes.Buffer
  3392  	if len(bp.Addrs) > 0 {
  3393  		for i, addr := range bp.Addrs {
  3394  			if i == 0 {
  3395  				fmt.Fprintf(&out, "%#x", addr)
  3396  			} else {
  3397  				fmt.Fprintf(&out, ",%#x", addr)
  3398  			}
  3399  		}
  3400  	} else {
  3401  		// In case we are connecting to an older version of delve that does not return the Addrs field.
  3402  		fmt.Fprintf(&out, "%#x", bp.Addr)
  3403  	}
  3404  	if bp.WatchExpr == "" {
  3405  		fmt.Fprintf(&out, " for ")
  3406  		p := t.formatPath(bp.File)
  3407  		if bp.FunctionName != "" {
  3408  			fmt.Fprintf(&out, "%s() ", bp.FunctionName)
  3409  		}
  3410  		fmt.Fprintf(&out, "%s:%d", p, bp.Line)
  3411  	}
  3412  	return out.String()
  3413  }
  3414  
  3415  func shouldAskToSuspendBreakpoint(t *Term) bool {
  3416  	fns, _ := t.client.ListFunctions(`^plugin\.Open$`)
  3417  	_, err := t.client.GetState()
  3418  	return len(fns) > 0 || isErrProcessExited(err) || t.client.FollowExecEnabled()
  3419  }