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 }