github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/service/rpc2/server.go (about) 1 package rpc2 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 "time" 8 9 "github.com/go-delve/delve/pkg/dwarf/op" 10 "github.com/go-delve/delve/pkg/proc" 11 "github.com/go-delve/delve/service" 12 "github.com/go-delve/delve/service/api" 13 "github.com/go-delve/delve/service/debugger" 14 ) 15 16 type RPCServer struct { 17 // config is all the information necessary to start the debugger and server. 18 config *service.Config 19 // debugger is a debugger service. 20 debugger *debugger.Debugger 21 } 22 23 func NewServer(config *service.Config, debugger *debugger.Debugger) *RPCServer { 24 return &RPCServer{config, debugger} 25 } 26 27 type ProcessPidIn struct { 28 } 29 30 type ProcessPidOut struct { 31 Pid int 32 } 33 34 // ProcessPid returns the pid of the process we are debugging. 35 func (s *RPCServer) ProcessPid(arg ProcessPidIn, out *ProcessPidOut) error { 36 out.Pid = s.debugger.ProcessPid() 37 return nil 38 } 39 40 type LastModifiedIn struct { 41 } 42 43 type LastModifiedOut struct { 44 Time time.Time 45 } 46 47 func (s *RPCServer) LastModified(arg LastModifiedIn, out *LastModifiedOut) error { 48 out.Time = s.debugger.LastModified() 49 return nil 50 } 51 52 type DetachIn struct { 53 Kill bool 54 } 55 56 type DetachOut struct { 57 } 58 59 // Detach detaches the debugger, optionally killing the process. 60 func (s *RPCServer) Detach(arg DetachIn, out *DetachOut) error { 61 return s.debugger.Detach(arg.Kill) 62 } 63 64 type RestartIn struct { 65 // Position to restart from, if it starts with 'c' it's a checkpoint ID, 66 // otherwise it's an event number. Only valid for recorded targets. 67 Position string 68 69 // ResetArgs tell whether NewArgs and NewRedirects should take effect. 70 ResetArgs bool 71 // NewArgs are arguments to launch a new process. They replace only the 72 // argv[1] and later. Argv[0] cannot be changed. 73 NewArgs []string 74 75 // When Rerecord is set the target will be rerecorded 76 Rerecord bool 77 78 // When Rebuild is set the process will be build again 79 Rebuild bool 80 81 NewRedirects [3]string 82 } 83 84 type RestartOut struct { 85 DiscardedBreakpoints []api.DiscardedBreakpoint 86 } 87 88 // Restart restarts program. 89 func (s *RPCServer) Restart(arg RestartIn, cb service.RPCCallback) { 90 close(cb.SetupDoneChan()) 91 if s.config.Debugger.AttachPid != 0 { 92 cb.Return(nil, errors.New("cannot restart process Delve did not create")) 93 return 94 } 95 var out RestartOut 96 var err error 97 out.DiscardedBreakpoints, err = s.debugger.Restart(arg.Rerecord, arg.Position, arg.ResetArgs, arg.NewArgs, arg.NewRedirects, arg.Rebuild) 98 cb.Return(out, err) 99 } 100 101 type StateIn struct { 102 // If NonBlocking is true State will return immediately even if the target process is running. 103 NonBlocking bool 104 } 105 106 type StateOut struct { 107 State *api.DebuggerState 108 } 109 110 // State returns the current debugger state. 111 func (s *RPCServer) State(arg StateIn, cb service.RPCCallback) { 112 close(cb.SetupDoneChan()) 113 var out StateOut 114 st, err := s.debugger.State(arg.NonBlocking) 115 if err != nil { 116 cb.Return(nil, err) 117 return 118 } 119 out.State = st 120 cb.Return(out, nil) 121 } 122 123 type CommandOut struct { 124 State api.DebuggerState 125 } 126 127 // Command interrupts, continues and steps through the program. 128 func (s *RPCServer) Command(command api.DebuggerCommand, cb service.RPCCallback) { 129 st, err := s.debugger.Command(&command, cb.SetupDoneChan()) 130 if err != nil { 131 cb.Return(nil, err) 132 return 133 } 134 var out CommandOut 135 out.State = *st 136 cb.Return(out, nil) 137 } 138 139 type GetBufferedTracepointsIn struct { 140 } 141 142 type GetBufferedTracepointsOut struct { 143 TracepointResults []api.TracepointResult 144 } 145 146 func (s *RPCServer) GetBufferedTracepoints(arg GetBufferedTracepointsIn, out *GetBufferedTracepointsOut) error { 147 out.TracepointResults = s.debugger.GetBufferedTracepoints() 148 return nil 149 } 150 151 type GetBreakpointIn struct { 152 Id int 153 Name string 154 } 155 156 type GetBreakpointOut struct { 157 Breakpoint api.Breakpoint 158 } 159 160 // GetBreakpoint gets a breakpoint by Name (if Name is not an empty string) or by ID. 161 func (s *RPCServer) GetBreakpoint(arg GetBreakpointIn, out *GetBreakpointOut) error { 162 var bp *api.Breakpoint 163 if arg.Name != "" { 164 bp = s.debugger.FindBreakpointByName(arg.Name) 165 if bp == nil { 166 return fmt.Errorf("no breakpoint with name %s", arg.Name) 167 } 168 } else { 169 bp = s.debugger.FindBreakpoint(arg.Id) 170 if bp == nil { 171 return fmt.Errorf("no breakpoint with id %d", arg.Id) 172 } 173 } 174 out.Breakpoint = *bp 175 return nil 176 } 177 178 type StacktraceIn struct { 179 Id int64 180 Depth int 181 Full bool 182 Defers bool // read deferred functions (equivalent to passing StacktraceReadDefers in Opts) 183 Opts api.StacktraceOptions 184 Cfg *api.LoadConfig 185 } 186 187 type StacktraceOut struct { 188 Locations []api.Stackframe 189 } 190 191 // Stacktrace returns stacktrace of goroutine Id up to the specified Depth. 192 // 193 // If Full is set it will also the variable of all local variables 194 // and function arguments of all stack frames. 195 func (s *RPCServer) Stacktrace(arg StacktraceIn, out *StacktraceOut) error { 196 cfg := arg.Cfg 197 if cfg == nil && arg.Full { 198 cfg = &api.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1} 199 } 200 if arg.Defers { 201 arg.Opts |= api.StacktraceReadDefers 202 } 203 var err error 204 rawlocs, err := s.debugger.Stacktrace(arg.Id, arg.Depth, arg.Opts) 205 if err != nil { 206 return err 207 } 208 out.Locations, err = s.debugger.ConvertStacktrace(rawlocs, api.LoadConfigToProc(cfg)) 209 return err 210 } 211 212 type AncestorsIn struct { 213 GoroutineID int64 214 NumAncestors int 215 Depth int 216 } 217 218 type AncestorsOut struct { 219 Ancestors []api.Ancestor 220 } 221 222 // Ancestors returns the stacktraces for the ancestors of a goroutine. 223 func (s *RPCServer) Ancestors(arg AncestorsIn, out *AncestorsOut) error { 224 var err error 225 out.Ancestors, err = s.debugger.Ancestors(arg.GoroutineID, arg.NumAncestors, arg.Depth) 226 return err 227 } 228 229 type ListBreakpointsIn struct { 230 All bool 231 } 232 233 type ListBreakpointsOut struct { 234 Breakpoints []*api.Breakpoint 235 } 236 237 // ListBreakpoints gets all breakpoints. 238 func (s *RPCServer) ListBreakpoints(arg ListBreakpointsIn, out *ListBreakpointsOut) error { 239 out.Breakpoints = s.debugger.Breakpoints(arg.All) 240 return nil 241 } 242 243 type CreateBreakpointIn struct { 244 Breakpoint api.Breakpoint 245 246 LocExpr string 247 SubstitutePathRules [][2]string 248 Suspended bool 249 } 250 251 type CreateBreakpointOut struct { 252 Breakpoint api.Breakpoint 253 } 254 255 // CreateBreakpoint creates a new breakpoint. The client is expected to populate `CreateBreakpointIn` 256 // with an `api.Breakpoint` struct describing where to set the breakpoint. For more information on 257 // how to properly request a breakpoint via the `api.Breakpoint` struct see the documentation for 258 // `debugger.CreateBreakpoint` here: https://pkg.go.dev/github.com/go-delve/delve/service/debugger#Debugger.CreateBreakpoint. 259 func (s *RPCServer) CreateBreakpoint(arg CreateBreakpointIn, out *CreateBreakpointOut) error { 260 if err := api.ValidBreakpointName(arg.Breakpoint.Name); err != nil { 261 return err 262 } 263 createdbp, err := s.debugger.CreateBreakpoint(&arg.Breakpoint, arg.LocExpr, arg.SubstitutePathRules, arg.Suspended) 264 if err != nil { 265 return err 266 } 267 out.Breakpoint = *createdbp 268 return nil 269 } 270 271 type CreateEBPFTracepointIn struct { 272 FunctionName string 273 } 274 275 type CreateEBPFTracepointOut struct { 276 Breakpoint api.Breakpoint 277 } 278 279 func (s *RPCServer) CreateEBPFTracepoint(arg CreateEBPFTracepointIn, out *CreateEBPFTracepointOut) error { 280 return s.debugger.CreateEBPFTracepoint(arg.FunctionName) 281 } 282 283 type ClearBreakpointIn struct { 284 Id int 285 Name string 286 } 287 288 type ClearBreakpointOut struct { 289 Breakpoint *api.Breakpoint 290 } 291 292 // ClearBreakpoint deletes a breakpoint by Name (if Name is not an 293 // empty string) or by ID. 294 func (s *RPCServer) ClearBreakpoint(arg ClearBreakpointIn, out *ClearBreakpointOut) error { 295 var bp *api.Breakpoint 296 if arg.Name != "" { 297 bp = s.debugger.FindBreakpointByName(arg.Name) 298 if bp == nil { 299 return fmt.Errorf("no breakpoint with name %s", arg.Name) 300 } 301 } else { 302 bp = s.debugger.FindBreakpoint(arg.Id) 303 if bp == nil { 304 return fmt.Errorf("no breakpoint with id %d", arg.Id) 305 } 306 } 307 deleted, err := s.debugger.ClearBreakpoint(bp) 308 if err != nil { 309 return err 310 } 311 out.Breakpoint = deleted 312 return nil 313 } 314 315 type ToggleBreakpointIn struct { 316 Id int 317 Name string 318 } 319 320 type ToggleBreakpointOut struct { 321 Breakpoint *api.Breakpoint 322 } 323 324 // ToggleBreakpoint toggles on or off a breakpoint by Name (if Name is not an 325 // empty string) or by ID. 326 func (s *RPCServer) ToggleBreakpoint(arg ToggleBreakpointIn, out *ToggleBreakpointOut) error { 327 var bp *api.Breakpoint 328 if arg.Name != "" { 329 bp = s.debugger.FindBreakpointByName(arg.Name) 330 if bp == nil { 331 return fmt.Errorf("no breakpoint with name %s", arg.Name) 332 } 333 } else { 334 bp = s.debugger.FindBreakpoint(arg.Id) 335 if bp == nil { 336 return fmt.Errorf("no breakpoint with id %d", arg.Id) 337 } 338 } 339 bp.Disabled = !bp.Disabled 340 if err := api.ValidBreakpointName(bp.Name); err != nil { 341 return err 342 } 343 if err := s.debugger.AmendBreakpoint(bp); err != nil { 344 return err 345 } 346 out.Breakpoint = bp 347 return nil 348 } 349 350 type AmendBreakpointIn struct { 351 Breakpoint api.Breakpoint 352 } 353 354 type AmendBreakpointOut struct { 355 } 356 357 // AmendBreakpoint allows user to update an existing breakpoint 358 // for example to change the information retrieved when the 359 // breakpoint is hit or to change, add or remove the break condition. 360 // 361 // arg.Breakpoint.ID must be a valid breakpoint ID 362 func (s *RPCServer) AmendBreakpoint(arg AmendBreakpointIn, out *AmendBreakpointOut) error { 363 if err := api.ValidBreakpointName(arg.Breakpoint.Name); err != nil { 364 return err 365 } 366 return s.debugger.AmendBreakpoint(&arg.Breakpoint) 367 } 368 369 type CancelNextIn struct { 370 } 371 372 type CancelNextOut struct { 373 } 374 375 func (s *RPCServer) CancelNext(arg CancelNextIn, out *CancelNextOut) error { 376 return s.debugger.CancelNext() 377 } 378 379 type ListThreadsIn struct { 380 } 381 382 type ListThreadsOut struct { 383 Threads []*api.Thread 384 } 385 386 // ListThreads lists all threads. 387 func (s *RPCServer) ListThreads(arg ListThreadsIn, out *ListThreadsOut) (err error) { 388 threads, err := s.debugger.Threads() 389 if err != nil { 390 return err 391 } 392 s.debugger.LockTarget() 393 defer s.debugger.UnlockTarget() 394 out.Threads = api.ConvertThreads(threads, s.debugger.ConvertThreadBreakpoint) 395 return nil 396 } 397 398 type GetThreadIn struct { 399 Id int 400 } 401 402 type GetThreadOut struct { 403 Thread *api.Thread 404 } 405 406 // GetThread gets a thread by its ID. 407 func (s *RPCServer) GetThread(arg GetThreadIn, out *GetThreadOut) error { 408 t, err := s.debugger.FindThread(arg.Id) 409 if err != nil { 410 return err 411 } 412 if t == nil { 413 return fmt.Errorf("no thread with id %d", arg.Id) 414 } 415 s.debugger.LockTarget() 416 defer s.debugger.UnlockTarget() 417 out.Thread = api.ConvertThread(t, s.debugger.ConvertThreadBreakpoint(t)) 418 return nil 419 } 420 421 type ListPackageVarsIn struct { 422 Filter string 423 Cfg api.LoadConfig 424 } 425 426 type ListPackageVarsOut struct { 427 Variables []api.Variable 428 } 429 430 // ListPackageVars lists all package variables in the context of the current thread. 431 func (s *RPCServer) ListPackageVars(arg ListPackageVarsIn, out *ListPackageVarsOut) error { 432 vars, err := s.debugger.PackageVariables(arg.Filter, *api.LoadConfigToProc(&arg.Cfg)) 433 if err != nil { 434 return err 435 } 436 out.Variables = api.ConvertVars(vars) 437 return nil 438 } 439 440 type ListRegistersIn struct { 441 ThreadID int 442 IncludeFp bool 443 Scope *api.EvalScope 444 } 445 446 type ListRegistersOut struct { 447 Registers string 448 Regs api.Registers 449 } 450 451 // ListRegisters lists registers and their values. 452 // If ListRegistersIn.Scope is not nil the registers of that eval scope will 453 // be returned, otherwise ListRegistersIn.ThreadID will be used. 454 func (s *RPCServer) ListRegisters(arg ListRegistersIn, out *ListRegistersOut) error { 455 if arg.ThreadID == 0 && arg.Scope == nil { 456 state, err := s.debugger.State(false) 457 if err != nil { 458 return err 459 } 460 arg.ThreadID = state.CurrentThread.ID 461 } 462 463 var regs *op.DwarfRegisters 464 var err error 465 466 if arg.Scope != nil { 467 regs, err = s.debugger.ScopeRegisters(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.IncludeFp) 468 } else { 469 regs, err = s.debugger.ThreadRegisters(arg.ThreadID, arg.IncludeFp) 470 } 471 if err != nil { 472 return err 473 } 474 out.Regs = api.ConvertRegisters(regs, s.debugger.DwarfRegisterToString, arg.IncludeFp) 475 out.Registers = out.Regs.String() 476 477 return nil 478 } 479 480 type ListLocalVarsIn struct { 481 Scope api.EvalScope 482 Cfg api.LoadConfig 483 } 484 485 type ListLocalVarsOut struct { 486 Variables []api.Variable 487 } 488 489 // ListLocalVars lists all local variables in scope. 490 func (s *RPCServer) ListLocalVars(arg ListLocalVarsIn, out *ListLocalVarsOut) error { 491 vars, err := s.debugger.LocalVariables(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, *api.LoadConfigToProc(&arg.Cfg)) 492 if err != nil { 493 return err 494 } 495 out.Variables = api.ConvertVars(vars) 496 return nil 497 } 498 499 type ListFunctionArgsIn struct { 500 Scope api.EvalScope 501 Cfg api.LoadConfig 502 } 503 504 type ListFunctionArgsOut struct { 505 Args []api.Variable 506 } 507 508 // ListFunctionArgs lists all arguments to the current function 509 func (s *RPCServer) ListFunctionArgs(arg ListFunctionArgsIn, out *ListFunctionArgsOut) error { 510 vars, err := s.debugger.FunctionArguments(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, *api.LoadConfigToProc(&arg.Cfg)) 511 if err != nil { 512 return err 513 } 514 out.Args = api.ConvertVars(vars) 515 return nil 516 } 517 518 type EvalIn struct { 519 Scope api.EvalScope 520 Expr string 521 Cfg *api.LoadConfig 522 } 523 524 type EvalOut struct { 525 Variable *api.Variable 526 } 527 528 // Eval returns a variable in the specified context. 529 // 530 // See https://github.com/go-delve/delve/blob/master/Documentation/cli/expr.md 531 // for a description of acceptable values of arg.Expr. 532 func (s *RPCServer) Eval(arg EvalIn, out *EvalOut) error { 533 cfg := arg.Cfg 534 if cfg == nil { 535 cfg = &api.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1} 536 } 537 pcfg := *api.LoadConfigToProc(cfg) 538 v, err := s.debugger.EvalVariableInScope(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Expr, pcfg) 539 if err != nil { 540 return err 541 } 542 out.Variable = api.ConvertVar(v) 543 return nil 544 } 545 546 type SetIn struct { 547 Scope api.EvalScope 548 Symbol string 549 Value string 550 } 551 552 type SetOut struct { 553 } 554 555 // Set sets the value of a variable. Only numerical types and 556 // pointers are currently supported. 557 func (s *RPCServer) Set(arg SetIn, out *SetOut) error { 558 return s.debugger.SetVariableInScope(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Symbol, arg.Value) 559 } 560 561 type ListSourcesIn struct { 562 Filter string 563 } 564 565 type ListSourcesOut struct { 566 Sources []string 567 } 568 569 // ListSources lists all source files in the process matching filter. 570 func (s *RPCServer) ListSources(arg ListSourcesIn, out *ListSourcesOut) error { 571 ss, err := s.debugger.Sources(arg.Filter) 572 if err != nil { 573 return err 574 } 575 out.Sources = ss 576 return nil 577 } 578 579 type ListFunctionsIn struct { 580 Filter string 581 } 582 583 type ListFunctionsOut struct { 584 Funcs []string 585 } 586 587 // ListFunctions lists all functions in the process matching filter. 588 func (s *RPCServer) ListFunctions(arg ListFunctionsIn, out *ListFunctionsOut) error { 589 fns, err := s.debugger.Functions(arg.Filter) 590 if err != nil { 591 return err 592 } 593 out.Funcs = fns 594 return nil 595 } 596 597 type ListTypesIn struct { 598 Filter string 599 } 600 601 type ListTypesOut struct { 602 Types []string 603 } 604 605 // ListTypes lists all types in the process matching filter. 606 func (s *RPCServer) ListTypes(arg ListTypesIn, out *ListTypesOut) error { 607 tps, err := s.debugger.Types(arg.Filter) 608 if err != nil { 609 return err 610 } 611 out.Types = tps 612 return nil 613 } 614 615 type ListGoroutinesIn struct { 616 Start int 617 Count int 618 619 Filters []api.ListGoroutinesFilter 620 api.GoroutineGroupingOptions 621 622 EvalScope *api.EvalScope 623 } 624 625 type ListGoroutinesOut struct { 626 Goroutines []*api.Goroutine 627 Nextg int 628 Groups []api.GoroutineGroup 629 TooManyGroups bool 630 } 631 632 // ListGoroutines lists all goroutines. 633 // If Count is specified ListGoroutines will return at the first Count 634 // goroutines and an index in Nextg, that can be passed as the Start 635 // parameter, to get more goroutines from ListGoroutines. 636 // Passing a value of Start that wasn't returned by ListGoroutines will skip 637 // an undefined number of goroutines. 638 // 639 // If arg.Filters are specified the list of returned goroutines is filtered 640 // applying the specified filters. 641 // For example: 642 // 643 // ListGoroutinesFilter{ Kind: ListGoroutinesFilterUserLoc, Negated: false, Arg: "afile.go" } 644 // 645 // will only return goroutines whose UserLoc contains "afile.go" as a substring. 646 // More specifically a goroutine matches a location filter if the specified 647 // location, formatted like this: 648 // 649 // filename:lineno in function 650 // 651 // contains Arg[0] as a substring. 652 // 653 // Filters can also be applied to goroutine labels: 654 // 655 // ListGoroutineFilter{ Kind: ListGoroutinesFilterLabel, Negated: false, Arg: "key=value" } 656 // 657 // this filter will only return goroutines that have a key=value label. 658 // 659 // If arg.GroupBy is not GoroutineFieldNone then the goroutines will 660 // be grouped with the specified criterion. 661 // If the value of arg.GroupBy is GoroutineLabel goroutines will 662 // be grouped by the value of the label with key GroupByKey. 663 // For each group a maximum of MaxGroupMembers example goroutines are 664 // returned, as well as the total number of goroutines in the group. 665 func (s *RPCServer) ListGoroutines(arg ListGoroutinesIn, out *ListGoroutinesOut) error { 666 //TODO(aarzilli): if arg contains a running goroutines filter (not negated) 667 // and start == 0 and count == 0 then we can optimize this by just looking 668 // at threads directly. 669 670 var gs []*proc.G 671 var nextg int 672 var err error 673 var gsLoaded bool 674 675 for _, filter := range arg.Filters { 676 if filter.Kind == api.GoroutineWaitingOnChannel { 677 if filter.Negated { 678 return errors.New("channel filter can not be negated") 679 } 680 if arg.Count == 0 { 681 return errors.New("count == 0 not allowed with a channel filter") 682 } 683 if arg.EvalScope == nil { 684 return errors.New("channel filter without eval scope") 685 } 686 gs, err = s.debugger.ChanGoroutines(arg.EvalScope.GoroutineID, arg.EvalScope.Frame, arg.EvalScope.DeferredCall, filter.Arg, arg.Start, arg.Count) 687 if len(gs) == arg.Count { 688 nextg = arg.Start + len(gs) 689 } else { 690 nextg = -1 691 } 692 gsLoaded = true 693 break 694 } 695 } 696 697 if !gsLoaded { 698 gs, nextg, err = s.debugger.Goroutines(arg.Start, arg.Count) 699 } 700 if err != nil { 701 return err 702 } 703 gs = s.debugger.FilterGoroutines(gs, arg.Filters) 704 gs, out.Groups, out.TooManyGroups = s.debugger.GroupGoroutines(gs, &arg.GoroutineGroupingOptions) 705 s.debugger.LockTarget() 706 defer s.debugger.UnlockTarget() 707 out.Goroutines = api.ConvertGoroutines(s.debugger.Target(), gs) 708 out.Nextg = nextg 709 return nil 710 } 711 712 type AttachedToExistingProcessIn struct { 713 } 714 715 type AttachedToExistingProcessOut struct { 716 Answer bool 717 } 718 719 // AttachedToExistingProcess returns whether we attached to a running process or not 720 func (s *RPCServer) AttachedToExistingProcess(arg AttachedToExistingProcessIn, out *AttachedToExistingProcessOut) error { 721 if s.config.Debugger.AttachPid != 0 { 722 out.Answer = true 723 } 724 return nil 725 } 726 727 type FindLocationIn struct { 728 Scope api.EvalScope 729 Loc string 730 IncludeNonExecutableLines bool 731 732 // SubstitutePathRules is a slice of source code path substitution rules, 733 // the first entry of each pair is the path of a directory as it appears in 734 // the executable file (i.e. the location of a source file when the program 735 // was compiled), the second entry of each pair is the location of the same 736 // directory on the client system. 737 SubstitutePathRules [][2]string 738 } 739 740 type FindLocationOut struct { 741 Locations []api.Location 742 SubstituteLocExpr string // if this isn't an empty string it should be passed as the location expression for CreateBreakpoint instead of the original location expression 743 } 744 745 // FindLocation returns concrete location information described by a location expression. 746 // 747 // loc ::= <filename>:<line> | <function>[:<line>] | /<regex>/ | (+|-)<offset> | <line> | *<address> 748 // * <filename> can be the full path of a file or just a suffix 749 // * <function> ::= <package>.<receiver type>.<name> | <package>.(*<receiver type>).<name> | <receiver type>.<name> | <package>.<name> | (*<receiver type>).<name> | <name> 750 // <function> must be unambiguous 751 // * /<regex>/ will return a location for each function matched by regex 752 // * +<offset> returns a location for the line that is <offset> lines after the current line 753 // * -<offset> returns a location for the line that is <offset> lines before the current line 754 // * <line> returns a location for a line in the current file 755 // * *<address> returns the location corresponding to the specified address 756 // 757 // NOTE: this function does not actually set breakpoints. 758 func (s *RPCServer) FindLocation(arg FindLocationIn, out *FindLocationOut) error { 759 var err error 760 out.Locations, out.SubstituteLocExpr, err = s.debugger.FindLocation(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Loc, arg.IncludeNonExecutableLines, arg.SubstitutePathRules) 761 return err 762 } 763 764 type DisassembleIn struct { 765 Scope api.EvalScope 766 StartPC, EndPC uint64 767 Flavour api.AssemblyFlavour 768 } 769 770 type DisassembleOut struct { 771 Disassemble api.AsmInstructions 772 } 773 774 // Disassemble code. 775 // 776 // If both StartPC and EndPC are non-zero the specified range will be disassembled, otherwise the function containing StartPC will be disassembled. 777 // 778 // Scope is used to mark the instruction the specified goroutine is stopped at. 779 // 780 // Disassemble will also try to calculate the destination address of an absolute indirect CALL if it happens to be the instruction the selected goroutine is stopped at. 781 func (s *RPCServer) Disassemble(arg DisassembleIn, out *DisassembleOut) error { 782 var err error 783 insts, err := s.debugger.Disassemble(arg.Scope.GoroutineID, arg.StartPC, arg.EndPC) 784 if err != nil { 785 return err 786 } 787 out.Disassemble = make(api.AsmInstructions, len(insts)) 788 for i := range insts { 789 out.Disassemble[i] = api.ConvertAsmInstruction(insts[i], s.debugger.AsmInstructionText(&insts[i], proc.AssemblyFlavour(arg.Flavour))) 790 } 791 return nil 792 } 793 794 type RecordedIn struct { 795 } 796 797 type RecordedOut struct { 798 Recorded bool 799 TraceDirectory string 800 } 801 802 func (s *RPCServer) Recorded(arg RecordedIn, out *RecordedOut) error { 803 out.Recorded, out.TraceDirectory = s.debugger.Recorded() 804 return nil 805 } 806 807 type CheckpointIn struct { 808 Where string 809 } 810 811 type CheckpointOut struct { 812 ID int 813 } 814 815 func (s *RPCServer) Checkpoint(arg CheckpointIn, out *CheckpointOut) error { 816 var err error 817 out.ID, err = s.debugger.Checkpoint(arg.Where) 818 return err 819 } 820 821 type ListCheckpointsIn struct { 822 } 823 824 type ListCheckpointsOut struct { 825 Checkpoints []api.Checkpoint 826 } 827 828 func (s *RPCServer) ListCheckpoints(arg ListCheckpointsIn, out *ListCheckpointsOut) error { 829 var err error 830 cps, err := s.debugger.Checkpoints() 831 if err != nil { 832 return err 833 } 834 out.Checkpoints = make([]api.Checkpoint, len(cps)) 835 for i := range cps { 836 out.Checkpoints[i] = api.Checkpoint(cps[i]) 837 } 838 return nil 839 } 840 841 type ClearCheckpointIn struct { 842 ID int 843 } 844 845 type ClearCheckpointOut struct { 846 } 847 848 func (s *RPCServer) ClearCheckpoint(arg ClearCheckpointIn, out *ClearCheckpointOut) error { 849 return s.debugger.ClearCheckpoint(arg.ID) 850 } 851 852 type IsMulticlientIn struct { 853 } 854 855 type IsMulticlientOut struct { 856 // IsMulticlient returns true if the headless instance was started with --accept-multiclient 857 IsMulticlient bool 858 } 859 860 func (s *RPCServer) IsMulticlient(arg IsMulticlientIn, out *IsMulticlientOut) error { 861 *out = IsMulticlientOut{ 862 IsMulticlient: s.config.AcceptMulti, 863 } 864 return nil 865 } 866 867 // FunctionReturnLocationsIn holds arguments for the 868 // FunctionReturnLocationsRPC call. It holds the name of 869 // the function for which all return locations should be 870 // given. 871 type FunctionReturnLocationsIn struct { 872 // FnName is the name of the function for which all 873 // return locations should be given. 874 FnName string 875 } 876 877 // FunctionReturnLocationsOut holds the result of the FunctionReturnLocations 878 // RPC call. It provides the list of addresses that the given function returns, 879 // for example with a `RET` instruction or `CALL runtime.deferreturn`. 880 type FunctionReturnLocationsOut struct { 881 // Addrs is the list of all locations where the given function returns. 882 Addrs []uint64 883 } 884 885 // FunctionReturnLocations is the implements the client call of the same name. Look at client documentation for more information. 886 func (s *RPCServer) FunctionReturnLocations(in FunctionReturnLocationsIn, out *FunctionReturnLocationsOut) error { 887 addrs, err := s.debugger.FunctionReturnLocations(in.FnName) 888 if err != nil { 889 return err 890 } 891 *out = FunctionReturnLocationsOut{ 892 Addrs: addrs, 893 } 894 return nil 895 } 896 897 // ListDynamicLibrariesIn holds the arguments of ListDynamicLibraries 898 type ListDynamicLibrariesIn struct { 899 } 900 901 // ListDynamicLibrariesOut holds the return values of ListDynamicLibraries 902 type ListDynamicLibrariesOut struct { 903 List []api.Image 904 } 905 906 func (s *RPCServer) ListDynamicLibraries(in ListDynamicLibrariesIn, out *ListDynamicLibrariesOut) error { 907 imgs := s.debugger.ListDynamicLibraries() 908 out.List = make([]api.Image, 0, len(imgs)) 909 for i := range imgs { 910 out.List = append(out.List, api.ConvertImage(imgs[i])) 911 } 912 return nil 913 } 914 915 // ListPackagesBuildInfoIn holds the arguments of ListPackages. 916 type ListPackagesBuildInfoIn struct { 917 IncludeFiles bool 918 } 919 920 // ListPackagesBuildInfoOut holds the return values of ListPackages. 921 type ListPackagesBuildInfoOut struct { 922 List []api.PackageBuildInfo 923 } 924 925 // ListPackagesBuildInfo returns the list of packages used by the program along with 926 // the directory where each package was compiled and optionally the list of 927 // files constituting the package. 928 // Note that the directory path is a best guess and may be wrong is a tool 929 // other than cmd/go is used to perform the build. 930 func (s *RPCServer) ListPackagesBuildInfo(in ListPackagesBuildInfoIn, out *ListPackagesBuildInfoOut) error { 931 pkgs := s.debugger.ListPackagesBuildInfo(in.IncludeFiles) 932 out.List = make([]api.PackageBuildInfo, 0, len(pkgs)) 933 for _, pkg := range pkgs { 934 var files []string 935 936 if len(pkg.Files) > 0 { 937 files = make([]string, 0, len(pkg.Files)) 938 for file := range pkg.Files { 939 files = append(files, file) 940 } 941 } 942 943 sort.Strings(files) 944 945 out.List = append(out.List, api.PackageBuildInfo{ 946 ImportPath: pkg.ImportPath, 947 DirectoryPath: pkg.DirectoryPath, 948 Files: files, 949 }) 950 } 951 return nil 952 } 953 954 // ExamineMemoryIn holds the arguments of ExamineMemory 955 type ExamineMemoryIn struct { 956 Address uint64 957 Length int 958 } 959 960 // ExaminedMemoryOut holds the return values of ExamineMemory 961 type ExaminedMemoryOut struct { 962 Mem []byte 963 IsLittleEndian bool 964 } 965 966 func (s *RPCServer) ExamineMemory(arg ExamineMemoryIn, out *ExaminedMemoryOut) error { 967 if arg.Length > 1000 { 968 return fmt.Errorf("len must be less than or equal to 1000") 969 } 970 Mem, err := s.debugger.ExamineMemory(arg.Address, arg.Length) 971 if err != nil { 972 return err 973 } 974 975 out.Mem = Mem 976 out.IsLittleEndian = true //TODO: get byte order from debugger.target.BinInfo().Arch 977 978 return nil 979 } 980 981 type StopRecordingIn struct { 982 } 983 984 type StopRecordingOut struct { 985 } 986 987 func (s *RPCServer) StopRecording(arg StopRecordingIn, cb service.RPCCallback) { 988 close(cb.SetupDoneChan()) 989 var out StopRecordingOut 990 err := s.debugger.StopRecording() 991 if err != nil { 992 cb.Return(nil, err) 993 return 994 } 995 cb.Return(out, nil) 996 } 997 998 type DumpStartIn struct { 999 Destination string 1000 } 1001 1002 type DumpStartOut struct { 1003 State api.DumpState 1004 } 1005 1006 // DumpStart starts a core dump to arg.Destination. 1007 func (s *RPCServer) DumpStart(arg DumpStartIn, out *DumpStartOut) error { 1008 err := s.debugger.DumpStart(arg.Destination) 1009 if err != nil { 1010 return err 1011 } 1012 out.State = *api.ConvertDumpState(s.debugger.DumpWait(0)) 1013 return nil 1014 } 1015 1016 type DumpWaitIn struct { 1017 Wait int 1018 } 1019 1020 type DumpWaitOut struct { 1021 State api.DumpState 1022 } 1023 1024 // DumpWait waits for the core dump to finish or for arg.Wait milliseconds. 1025 // Wait == 0 means return immediately. 1026 // Returns the core dump status 1027 func (s *RPCServer) DumpWait(arg DumpWaitIn, out *DumpWaitOut) error { 1028 out.State = *api.ConvertDumpState(s.debugger.DumpWait(time.Duration(arg.Wait) * time.Millisecond)) 1029 return nil 1030 } 1031 1032 type DumpCancelIn struct { 1033 } 1034 1035 type DumpCancelOut struct { 1036 } 1037 1038 // DumpCancel cancels the core dump. 1039 func (s *RPCServer) DumpCancel(arg DumpCancelIn, out *DumpCancelOut) error { 1040 return s.debugger.DumpCancel() 1041 } 1042 1043 type CreateWatchpointIn struct { 1044 Scope api.EvalScope 1045 Expr string 1046 Type api.WatchType 1047 } 1048 1049 type CreateWatchpointOut struct { 1050 *api.Breakpoint 1051 } 1052 1053 func (s *RPCServer) CreateWatchpoint(arg CreateWatchpointIn, out *CreateWatchpointOut) error { 1054 var err error 1055 out.Breakpoint, err = s.debugger.CreateWatchpoint(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Expr, arg.Type) 1056 return err 1057 } 1058 1059 type BuildIDIn struct { 1060 } 1061 1062 type BuildIDOut struct { 1063 BuildID string 1064 } 1065 1066 func (s *RPCServer) BuildID(arg BuildIDIn, out *BuildIDOut) error { 1067 out.BuildID = s.debugger.BuildID() 1068 return nil 1069 } 1070 1071 type ListTargetsIn struct { 1072 } 1073 1074 type ListTargetsOut struct { 1075 Targets []api.Target 1076 } 1077 1078 // ListTargets returns the list of targets we are currently attached to. 1079 func (s *RPCServer) ListTargets(arg ListTargetsIn, out *ListTargetsOut) error { 1080 s.debugger.LockTarget() 1081 defer s.debugger.UnlockTarget() 1082 out.Targets = []api.Target{} 1083 for _, tgt := range s.debugger.TargetGroup().Targets() { 1084 if _, err := tgt.Valid(); err == nil { 1085 out.Targets = append(out.Targets, *api.ConvertTarget(tgt, s.debugger.ConvertThreadBreakpoint)) 1086 } 1087 } 1088 return nil 1089 } 1090 1091 type FollowExecIn struct { 1092 Enable bool 1093 Regex string 1094 } 1095 1096 type FollowExecOut struct { 1097 } 1098 1099 // FollowExec enables or disables follow exec mode. 1100 func (s *RPCServer) FollowExec(arg FollowExecIn, out *FollowExecOut) error { 1101 return s.debugger.FollowExec(arg.Enable, arg.Regex) 1102 } 1103 1104 type FollowExecEnabledIn struct { 1105 } 1106 1107 type FollowExecEnabledOut struct { 1108 Enabled bool 1109 } 1110 1111 // FollowExecEnabled returns true if follow exec mode is enabled. 1112 func (s *RPCServer) FollowExecEnabled(arg FollowExecEnabledIn, out *FollowExecEnabledOut) error { 1113 out.Enabled = s.debugger.FollowExecEnabled() 1114 return nil 1115 } 1116 1117 type DebugInfoDirectoriesIn struct { 1118 Set bool 1119 List []string 1120 } 1121 1122 type DebugInfoDirectoriesOut struct { 1123 List []string 1124 } 1125 1126 func (s *RPCServer) DebugInfoDirectories(arg DebugInfoDirectoriesIn, out *DebugInfoDirectoriesOut) error { 1127 if arg.Set { 1128 s.debugger.SetDebugInfoDirectories(arg.List) 1129 } 1130 out.List = s.debugger.DebugInfoDirectories() 1131 return nil 1132 }