gitlab.com/Raven-IO/raven-delve@v1.22.4/service/rpc2/client.go (about)

     1  package rpc2
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net"
     7  	"net/rpc"
     8  	"net/rpc/jsonrpc"
     9  	"time"
    10  
    11  	"gitlab.com/Raven-IO/raven-delve/service"
    12  	"gitlab.com/Raven-IO/raven-delve/service/api"
    13  )
    14  
    15  // RPCClient is a RPC service.Client.
    16  type RPCClient struct {
    17  	client *rpc.Client
    18  
    19  	retValLoadCfg *api.LoadConfig
    20  }
    21  
    22  // Ensure the implementation satisfies the interface.
    23  var _ service.Client = &RPCClient{}
    24  
    25  // NewClient creates a new RPCClient.
    26  func NewClient(addr string) *RPCClient {
    27  	client, err := jsonrpc.Dial("tcp", addr)
    28  	if err != nil {
    29  		log.Fatal("dialing:", err)
    30  	}
    31  	return newFromRPCClient(client)
    32  }
    33  
    34  func newFromRPCClient(client *rpc.Client) *RPCClient {
    35  	c := &RPCClient{client: client}
    36  	c.call("SetApiVersion", api.SetAPIVersionIn{APIVersion: 2}, &api.SetAPIVersionOut{})
    37  	return c
    38  }
    39  
    40  // NewClientFromConn creates a new RPCClient from the given connection.
    41  func NewClientFromConn(conn net.Conn) *RPCClient {
    42  	return newFromRPCClient(jsonrpc.NewClient(conn))
    43  }
    44  
    45  func (c *RPCClient) ProcessPid() int {
    46  	out := new(ProcessPidOut)
    47  	c.call("ProcessPid", ProcessPidIn{}, out)
    48  	return out.Pid
    49  }
    50  
    51  func (c *RPCClient) BuildID() string {
    52  	out := new(BuildIDOut)
    53  	c.call("BuildID", BuildIDIn{}, out)
    54  	return out.BuildID
    55  }
    56  
    57  func (c *RPCClient) LastModified() time.Time {
    58  	out := new(LastModifiedOut)
    59  	c.call("LastModified", LastModifiedIn{}, out)
    60  	return out.Time
    61  }
    62  
    63  func (c *RPCClient) Detach(kill bool) error {
    64  	defer c.client.Close()
    65  	out := new(DetachOut)
    66  	return c.call("Detach", DetachIn{kill}, out)
    67  }
    68  
    69  func (c *RPCClient) Restart(rebuild bool) ([]api.DiscardedBreakpoint, error) {
    70  	out := new(RestartOut)
    71  	err := c.call("Restart", RestartIn{"", false, nil, false, rebuild, [3]string{}}, out)
    72  	return out.DiscardedBreakpoints, err
    73  }
    74  
    75  func (c *RPCClient) RestartFrom(rerecord bool, pos string, resetArgs bool, newArgs []string, newRedirects [3]string, rebuild bool) ([]api.DiscardedBreakpoint, error) {
    76  	out := new(RestartOut)
    77  	err := c.call("Restart", RestartIn{pos, resetArgs, newArgs, rerecord, rebuild, newRedirects}, out)
    78  	return out.DiscardedBreakpoints, err
    79  }
    80  
    81  func (c *RPCClient) GetState() (*api.DebuggerState, error) {
    82  	var out StateOut
    83  	err := c.call("State", StateIn{NonBlocking: false}, &out)
    84  	return out.State, err
    85  }
    86  
    87  func (c *RPCClient) GetStateNonBlocking() (*api.DebuggerState, error) {
    88  	var out StateOut
    89  	err := c.call("State", StateIn{NonBlocking: true}, &out)
    90  	return out.State, err
    91  }
    92  
    93  func (c *RPCClient) Continue() <-chan *api.DebuggerState {
    94  	return c.continueDir(api.Continue)
    95  }
    96  
    97  func (c *RPCClient) Rewind() <-chan *api.DebuggerState {
    98  	return c.continueDir(api.Rewind)
    99  }
   100  
   101  func (c *RPCClient) DirectionCongruentContinue() <-chan *api.DebuggerState {
   102  	return c.continueDir(api.DirectionCongruentContinue)
   103  }
   104  
   105  func (c *RPCClient) continueDir(cmd string) <-chan *api.DebuggerState {
   106  	ch := make(chan *api.DebuggerState)
   107  	go func() {
   108  		for {
   109  			out := new(CommandOut)
   110  			err := c.call("Command", &api.DebuggerCommand{Name: cmd, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
   111  			state := out.State
   112  			if err != nil {
   113  				state.Err = err
   114  			}
   115  			if state.Exited {
   116  				// Error types apparently cannot be marshalled by Go correctly. Must reset error here.
   117  				//lint:ignore ST1005 backwards compatibility
   118  				state.Err = fmt.Errorf("Process %d has exited with status %d", c.ProcessPid(), state.ExitStatus)
   119  			}
   120  			ch <- &state
   121  			if err != nil || state.Exited {
   122  				close(ch)
   123  				return
   124  			}
   125  
   126  			isbreakpoint := false
   127  			istracepoint := true
   128  			for i := range state.Threads {
   129  				if state.Threads[i].Breakpoint != nil {
   130  					isbreakpoint = true
   131  					istracepoint = istracepoint && (state.Threads[i].Breakpoint.Tracepoint || state.Threads[i].Breakpoint.TraceReturn)
   132  				}
   133  			}
   134  
   135  			if !isbreakpoint || !istracepoint {
   136  				close(ch)
   137  				return
   138  			}
   139  		}
   140  	}()
   141  	return ch
   142  }
   143  
   144  func (c *RPCClient) Next() (*api.DebuggerState, error) {
   145  	var out CommandOut
   146  	err := c.call("Command", api.DebuggerCommand{Name: api.Next, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
   147  	return &out.State, err
   148  }
   149  
   150  func (c *RPCClient) ReverseNext() (*api.DebuggerState, error) {
   151  	var out CommandOut
   152  	err := c.call("Command", api.DebuggerCommand{Name: api.ReverseNext, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
   153  	return &out.State, err
   154  }
   155  
   156  func (c *RPCClient) Step() (*api.DebuggerState, error) {
   157  	var out CommandOut
   158  	err := c.call("Command", api.DebuggerCommand{Name: api.Step, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
   159  	return &out.State, err
   160  }
   161  
   162  func (c *RPCClient) ReverseStep() (*api.DebuggerState, error) {
   163  	var out CommandOut
   164  	err := c.call("Command", api.DebuggerCommand{Name: api.ReverseStep, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
   165  	return &out.State, err
   166  }
   167  
   168  func (c *RPCClient) StepOut() (*api.DebuggerState, error) {
   169  	var out CommandOut
   170  	err := c.call("Command", api.DebuggerCommand{Name: api.StepOut, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
   171  	return &out.State, err
   172  }
   173  
   174  func (c *RPCClient) ReverseStepOut() (*api.DebuggerState, error) {
   175  	var out CommandOut
   176  	err := c.call("Command", api.DebuggerCommand{Name: api.ReverseStepOut, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
   177  	return &out.State, err
   178  }
   179  
   180  func (c *RPCClient) Call(goroutineID int64, expr string, unsafe bool) (*api.DebuggerState, error) {
   181  	var out CommandOut
   182  	err := c.call("Command", api.DebuggerCommand{Name: api.Call, ReturnInfoLoadConfig: c.retValLoadCfg, Expr: expr, UnsafeCall: unsafe, GoroutineID: goroutineID}, &out)
   183  	return &out.State, err
   184  }
   185  
   186  func (c *RPCClient) StepInstruction(skipCalls bool) (*api.DebuggerState, error) {
   187  	var out CommandOut
   188  	name := api.StepInstruction
   189  	if skipCalls {
   190  		name = api.NextInstruction
   191  	}
   192  	err := c.call("Command", api.DebuggerCommand{Name: name}, &out)
   193  	return &out.State, err
   194  }
   195  
   196  func (c *RPCClient) ReverseStepInstruction(skipCalls bool) (*api.DebuggerState, error) {
   197  	var out CommandOut
   198  	name := api.ReverseStepInstruction
   199  	if skipCalls {
   200  		name = api.ReverseNextInstruction
   201  	}
   202  	err := c.call("Command", api.DebuggerCommand{Name: name}, &out)
   203  	return &out.State, err
   204  }
   205  
   206  func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) {
   207  	var out CommandOut
   208  	cmd := api.DebuggerCommand{
   209  		Name:     api.SwitchThread,
   210  		ThreadID: threadID,
   211  	}
   212  	err := c.call("Command", cmd, &out)
   213  	return &out.State, err
   214  }
   215  
   216  func (c *RPCClient) SwitchGoroutine(goroutineID int64) (*api.DebuggerState, error) {
   217  	var out CommandOut
   218  	cmd := api.DebuggerCommand{
   219  		Name:        api.SwitchGoroutine,
   220  		GoroutineID: goroutineID,
   221  	}
   222  	err := c.call("Command", cmd, &out)
   223  	return &out.State, err
   224  }
   225  
   226  func (c *RPCClient) Halt() (*api.DebuggerState, error) {
   227  	var out CommandOut
   228  	err := c.call("Command", api.DebuggerCommand{Name: api.Halt}, &out)
   229  	return &out.State, err
   230  }
   231  
   232  func (c *RPCClient) GetBufferedTracepoints() ([]api.TracepointResult, error) {
   233  	var out GetBufferedTracepointsOut
   234  	err := c.call("GetBufferedTracepoints", GetBufferedTracepointsIn{}, &out)
   235  	return out.TracepointResults, err
   236  }
   237  
   238  func (c *RPCClient) GetBreakpoint(id int) (*api.Breakpoint, error) {
   239  	var out GetBreakpointOut
   240  	err := c.call("GetBreakpoint", GetBreakpointIn{id, ""}, &out)
   241  	return &out.Breakpoint, err
   242  }
   243  
   244  func (c *RPCClient) GetBreakpointByName(name string) (*api.Breakpoint, error) {
   245  	var out GetBreakpointOut
   246  	err := c.call("GetBreakpoint", GetBreakpointIn{0, name}, &out)
   247  	return &out.Breakpoint, err
   248  }
   249  
   250  // CreateBreakpoint will send a request to the RPC server to create a breakpoint.
   251  // Please refer to the documentation for `Debugger.CreateBreakpoint` for a description of how
   252  // the requested breakpoint parameters are interpreted and used:
   253  // https://pkg.go.dev/gitlab.com/Raven-IO/raven-delve/service/debugger#Debugger.CreateBreakpoint
   254  func (c *RPCClient) CreateBreakpoint(breakPoint *api.Breakpoint) (*api.Breakpoint, error) {
   255  	var out CreateBreakpointOut
   256  	err := c.call("CreateBreakpoint", CreateBreakpointIn{*breakPoint, "", nil, false}, &out)
   257  	return &out.Breakpoint, err
   258  }
   259  
   260  // CreateBreakpointWithExpr is like CreateBreakpoint but will also set a
   261  // location expression to be used to restore the breakpoint after it is
   262  // disabled.
   263  func (c *RPCClient) CreateBreakpointWithExpr(breakPoint *api.Breakpoint, locExpr string, substitutePathRules [][2]string, suspended bool) (*api.Breakpoint, error) {
   264  	var out CreateBreakpointOut
   265  	err := c.call("CreateBreakpoint", CreateBreakpointIn{*breakPoint, locExpr, substitutePathRules, suspended}, &out)
   266  	return &out.Breakpoint, err
   267  }
   268  
   269  func (c *RPCClient) CreateEBPFTracepoint(fnName string) error {
   270  	var out CreateEBPFTracepointOut
   271  	return c.call("CreateEBPFTracepoint", CreateEBPFTracepointIn{FunctionName: fnName}, &out)
   272  }
   273  
   274  func (c *RPCClient) CreateWatchpoint(scope api.EvalScope, expr string, wtype api.WatchType) (*api.Breakpoint, error) {
   275  	var out CreateWatchpointOut
   276  	err := c.call("CreateWatchpoint", CreateWatchpointIn{scope, expr, wtype}, &out)
   277  	return out.Breakpoint, err
   278  }
   279  
   280  func (c *RPCClient) ListBreakpoints(all bool) ([]*api.Breakpoint, error) {
   281  	var out ListBreakpointsOut
   282  	err := c.call("ListBreakpoints", ListBreakpointsIn{all}, &out)
   283  	return out.Breakpoints, err
   284  }
   285  
   286  func (c *RPCClient) ClearBreakpoint(id int) (*api.Breakpoint, error) {
   287  	var out ClearBreakpointOut
   288  	err := c.call("ClearBreakpoint", ClearBreakpointIn{id, ""}, &out)
   289  	return out.Breakpoint, err
   290  }
   291  
   292  func (c *RPCClient) ClearBreakpointByName(name string) (*api.Breakpoint, error) {
   293  	var out ClearBreakpointOut
   294  	err := c.call("ClearBreakpoint", ClearBreakpointIn{0, name}, &out)
   295  	return out.Breakpoint, err
   296  }
   297  
   298  func (c *RPCClient) ToggleBreakpoint(id int) (*api.Breakpoint, error) {
   299  	var out ToggleBreakpointOut
   300  	err := c.call("ToggleBreakpoint", ToggleBreakpointIn{id, ""}, &out)
   301  	return out.Breakpoint, err
   302  }
   303  
   304  func (c *RPCClient) ToggleBreakpointByName(name string) (*api.Breakpoint, error) {
   305  	var out ToggleBreakpointOut
   306  	err := c.call("ToggleBreakpoint", ToggleBreakpointIn{0, name}, &out)
   307  	return out.Breakpoint, err
   308  }
   309  
   310  func (c *RPCClient) AmendBreakpoint(bp *api.Breakpoint) error {
   311  	out := new(AmendBreakpointOut)
   312  	err := c.call("AmendBreakpoint", AmendBreakpointIn{*bp}, out)
   313  	return err
   314  }
   315  
   316  func (c *RPCClient) CancelNext() error {
   317  	var out CancelNextOut
   318  	return c.call("CancelNext", CancelNextIn{}, &out)
   319  }
   320  
   321  func (c *RPCClient) ListThreads() ([]*api.Thread, error) {
   322  	var out ListThreadsOut
   323  	err := c.call("ListThreads", ListThreadsIn{}, &out)
   324  	return out.Threads, err
   325  }
   326  
   327  func (c *RPCClient) GetThread(id int) (*api.Thread, error) {
   328  	var out GetThreadOut
   329  	err := c.call("GetThread", GetThreadIn{id}, &out)
   330  	return out.Thread, err
   331  }
   332  
   333  func (c *RPCClient) EvalVariable(scope api.EvalScope, expr string, cfg api.LoadConfig) (*api.Variable, error) {
   334  	var out EvalOut
   335  	err := c.call("Eval", EvalIn{scope, expr, &cfg}, &out)
   336  	return out.Variable, err
   337  }
   338  
   339  func (c *RPCClient) SetVariable(scope api.EvalScope, symbol, value string) error {
   340  	out := new(SetOut)
   341  	return c.call("Set", SetIn{scope, symbol, value}, out)
   342  }
   343  
   344  func (c *RPCClient) ListSources(filter string) ([]string, error) {
   345  	sources := new(ListSourcesOut)
   346  	err := c.call("ListSources", ListSourcesIn{filter}, sources)
   347  	return sources.Sources, err
   348  }
   349  
   350  func (c *RPCClient) ListFunctions(filter string) ([]string, error) {
   351  	funcs := new(ListFunctionsOut)
   352  	err := c.call("ListFunctions", ListFunctionsIn{filter}, funcs)
   353  	return funcs.Funcs, err
   354  }
   355  
   356  func (c *RPCClient) ListTypes(filter string) ([]string, error) {
   357  	types := new(ListTypesOut)
   358  	err := c.call("ListTypes", ListTypesIn{filter}, types)
   359  	return types.Types, err
   360  }
   361  
   362  func (c *RPCClient) ListPackageVariables(filter string, cfg api.LoadConfig) ([]api.Variable, error) {
   363  	var out ListPackageVarsOut
   364  	err := c.call("ListPackageVars", ListPackageVarsIn{filter, cfg}, &out)
   365  	return out.Variables, err
   366  }
   367  
   368  func (c *RPCClient) ListPackagesBuildInfo(filter string, includeFiles bool) ([]api.PackageBuildInfo, error) {
   369  	var out ListPackagesBuildInfoOut
   370  	err := c.call("ListPackagesBuildInfo", ListPackagesBuildInfoIn{Filter: filter, IncludeFiles: includeFiles}, &out)
   371  	return out.List, err
   372  }
   373  
   374  func (c *RPCClient) ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) {
   375  	var out ListLocalVarsOut
   376  	err := c.call("ListLocalVars", ListLocalVarsIn{scope, cfg}, &out)
   377  	return out.Variables, err
   378  }
   379  
   380  func (c *RPCClient) ListThreadRegisters(threadID int, includeFp bool) (api.Registers, error) {
   381  	out := new(ListRegistersOut)
   382  	err := c.call("ListRegisters", ListRegistersIn{ThreadID: threadID, IncludeFp: includeFp, Scope: nil}, out)
   383  	return out.Regs, err
   384  }
   385  
   386  func (c *RPCClient) ListScopeRegisters(scope api.EvalScope, includeFp bool) (api.Registers, error) {
   387  	out := new(ListRegistersOut)
   388  	err := c.call("ListRegisters", ListRegistersIn{ThreadID: 0, IncludeFp: includeFp, Scope: &scope}, out)
   389  	return out.Regs, err
   390  }
   391  
   392  func (c *RPCClient) ListFunctionArgs(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) {
   393  	var out ListFunctionArgsOut
   394  	err := c.call("ListFunctionArgs", ListFunctionArgsIn{scope, cfg}, &out)
   395  	return out.Args, err
   396  }
   397  
   398  func (c *RPCClient) ListGoroutines(start, count int) ([]*api.Goroutine, int, error) {
   399  	var out ListGoroutinesOut
   400  	err := c.call("ListGoroutines", ListGoroutinesIn{start, count, nil, api.GoroutineGroupingOptions{}, nil}, &out)
   401  	return out.Goroutines, out.Nextg, err
   402  }
   403  
   404  func (c *RPCClient) ListGoroutinesWithFilter(start, count int, filters []api.ListGoroutinesFilter, group *api.GoroutineGroupingOptions, scope *api.EvalScope) ([]*api.Goroutine, []api.GoroutineGroup, int, bool, error) {
   405  	if group == nil {
   406  		group = &api.GoroutineGroupingOptions{}
   407  	}
   408  	var out ListGoroutinesOut
   409  	err := c.call("ListGoroutines", ListGoroutinesIn{start, count, filters, *group, scope}, &out)
   410  	return out.Goroutines, out.Groups, out.Nextg, out.TooManyGroups, err
   411  }
   412  
   413  func (c *RPCClient) Stacktrace(goroutineId int64, depth int, opts api.StacktraceOptions, cfg *api.LoadConfig) ([]api.Stackframe, error) {
   414  	var out StacktraceOut
   415  	err := c.call("Stacktrace", StacktraceIn{goroutineId, depth, false, false, opts, cfg}, &out)
   416  	return out.Locations, err
   417  }
   418  
   419  func (c *RPCClient) Ancestors(goroutineID int64, numAncestors int, depth int) ([]api.Ancestor, error) {
   420  	var out AncestorsOut
   421  	err := c.call("Ancestors", AncestorsIn{goroutineID, numAncestors, depth}, &out)
   422  	return out.Ancestors, err
   423  }
   424  
   425  func (c *RPCClient) AttachedToExistingProcess() bool {
   426  	out := new(AttachedToExistingProcessOut)
   427  	c.call("AttachedToExistingProcess", AttachedToExistingProcessIn{}, out)
   428  	return out.Answer
   429  }
   430  
   431  func (c *RPCClient) FindLocation(scope api.EvalScope, loc string, findInstructions bool, substitutePathRules [][2]string) ([]api.Location, string, error) {
   432  	var out FindLocationOut
   433  	err := c.call("FindLocation", FindLocationIn{scope, loc, !findInstructions, substitutePathRules}, &out)
   434  	return out.Locations, out.SubstituteLocExpr, err
   435  }
   436  
   437  // DisassembleRange disassembles code between startPC and endPC
   438  func (c *RPCClient) DisassembleRange(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
   439  	var out DisassembleOut
   440  	err := c.call("Disassemble", DisassembleIn{scope, startPC, endPC, flavour}, &out)
   441  	return out.Disassemble, err
   442  }
   443  
   444  // DisassemblePC disassembles function containing pc
   445  func (c *RPCClient) DisassemblePC(scope api.EvalScope, pc uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
   446  	var out DisassembleOut
   447  	err := c.call("Disassemble", DisassembleIn{scope, pc, 0, flavour}, &out)
   448  	return out.Disassemble, err
   449  }
   450  
   451  // Recorded returns true if the debugger target is a recording.
   452  func (c *RPCClient) Recorded() bool {
   453  	out := new(RecordedOut)
   454  	c.call("Recorded", RecordedIn{}, out)
   455  	return out.Recorded
   456  }
   457  
   458  // TraceDirectory returns the path to the trace directory for a recording.
   459  func (c *RPCClient) TraceDirectory() (string, error) {
   460  	var out RecordedOut
   461  	err := c.call("Recorded", RecordedIn{}, &out)
   462  	return out.TraceDirectory, err
   463  }
   464  
   465  // Checkpoint sets a checkpoint at the current position.
   466  func (c *RPCClient) Checkpoint(where string) (checkpointID int, err error) {
   467  	var out CheckpointOut
   468  	err = c.call("Checkpoint", CheckpointIn{where}, &out)
   469  	return out.ID, err
   470  }
   471  
   472  // ListCheckpoints gets all checkpoints.
   473  func (c *RPCClient) ListCheckpoints() ([]api.Checkpoint, error) {
   474  	var out ListCheckpointsOut
   475  	err := c.call("ListCheckpoints", ListCheckpointsIn{}, &out)
   476  	return out.Checkpoints, err
   477  }
   478  
   479  // ClearCheckpoint removes a checkpoint
   480  func (c *RPCClient) ClearCheckpoint(id int) error {
   481  	var out ClearCheckpointOut
   482  	err := c.call("ClearCheckpoint", ClearCheckpointIn{id}, &out)
   483  	return err
   484  }
   485  
   486  func (c *RPCClient) SetReturnValuesLoadConfig(cfg *api.LoadConfig) {
   487  	c.retValLoadCfg = cfg
   488  }
   489  
   490  func (c *RPCClient) FunctionReturnLocations(fnName string) ([]uint64, error) {
   491  	var out FunctionReturnLocationsOut
   492  	err := c.call("FunctionReturnLocations", FunctionReturnLocationsIn{fnName}, &out)
   493  	return out.Addrs, err
   494  }
   495  
   496  func (c *RPCClient) IsMulticlient() bool {
   497  	var out IsMulticlientOut
   498  	c.call("IsMulticlient", IsMulticlientIn{}, &out)
   499  	return out.IsMulticlient
   500  }
   501  
   502  func (c *RPCClient) Disconnect(cont bool) error {
   503  	if cont {
   504  		out := new(CommandOut)
   505  		c.client.Go("RPCServer.Command", &api.DebuggerCommand{Name: api.Continue, ReturnInfoLoadConfig: c.retValLoadCfg}, &out, nil)
   506  	}
   507  	return c.client.Close()
   508  }
   509  
   510  func (c *RPCClient) ListDynamicLibraries() ([]api.Image, error) {
   511  	var out ListDynamicLibrariesOut
   512  	c.call("ListDynamicLibraries", ListDynamicLibrariesIn{}, &out)
   513  	return out.List, nil
   514  }
   515  
   516  func (c *RPCClient) ExamineMemory(address uint64, count int) ([]byte, bool, error) {
   517  	out := &ExaminedMemoryOut{}
   518  
   519  	err := c.call("ExamineMemory", ExamineMemoryIn{Length: count, Address: address}, out)
   520  	if err != nil {
   521  		return nil, false, err
   522  	}
   523  	return out.Mem, out.IsLittleEndian, nil
   524  }
   525  
   526  func (c *RPCClient) StopRecording() error {
   527  	return c.call("StopRecording", StopRecordingIn{}, &StopRecordingOut{})
   528  }
   529  
   530  func (c *RPCClient) CoreDumpStart(dest string) (api.DumpState, error) {
   531  	out := &DumpStartOut{}
   532  	err := c.call("DumpStart", DumpStartIn{Destination: dest}, out)
   533  	return out.State, err
   534  }
   535  
   536  func (c *RPCClient) CoreDumpWait(msec int) api.DumpState {
   537  	out := &DumpWaitOut{}
   538  	_ = c.call("DumpWait", DumpWaitIn{Wait: msec}, out)
   539  	return out.State
   540  }
   541  
   542  func (c *RPCClient) CoreDumpCancel() error {
   543  	out := &DumpCancelOut{}
   544  	return c.call("DumpCancel", DumpCancelIn{}, out)
   545  }
   546  
   547  // ListTargets returns the current list of debug targets.
   548  func (c *RPCClient) ListTargets() ([]api.Target, error) {
   549  	out := &ListTargetsOut{}
   550  	err := c.call("ListTargets", ListTargetsIn{}, out)
   551  	return out.Targets, err
   552  }
   553  
   554  // FollowExec enabled or disabled follow exec mode. When follow exec is
   555  // enabled Delve will automatically attach to new subprocesses with a
   556  // command line matched by regex, if regex is nil all new subprocesses are
   557  // automatically debugged.
   558  func (c *RPCClient) FollowExec(v bool, regex string) error {
   559  	out := &FollowExecOut{}
   560  	err := c.call("FollowExec", FollowExecIn{Enable: v, Regex: regex}, out)
   561  	return err
   562  }
   563  
   564  // FollowExecEnabled returns true if follow exec mode is enabled.
   565  func (c *RPCClient) FollowExecEnabled() bool {
   566  	out := &FollowExecEnabledOut{}
   567  	_ = c.call("FollowExecEnabled", FollowExecEnabledIn{}, out)
   568  	return out.Enabled
   569  }
   570  
   571  func (c *RPCClient) SetDebugInfoDirectories(v []string) error {
   572  	return c.call("DebugInfoDirectories", DebugInfoDirectoriesIn{Set: true, List: v}, &DebugInfoDirectoriesOut{})
   573  }
   574  
   575  func (c *RPCClient) GetDebugInfoDirectories() ([]string, error) {
   576  	out := &DebugInfoDirectoriesOut{}
   577  	err := c.call("DebugInfoDirectories", DebugInfoDirectoriesIn{Set: false, List: nil}, out)
   578  	return out.List, err
   579  }
   580  
   581  func (c *RPCClient) call(method string, args, reply interface{}) error {
   582  	return c.client.Call("RPCServer."+method, args, reply)
   583  }
   584  
   585  func (c *RPCClient) CallAPI(method string, args, reply interface{}) error {
   586  	return c.call(method, args, reply)
   587  }