github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/service/debugger/debugger.go (about) 1 package debugger 2 3 import ( 4 "debug/dwarf" 5 "debug/elf" 6 "debug/macho" 7 "debug/pe" 8 "errors" 9 "fmt" 10 "go/parser" 11 "go/token" 12 "io" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "regexp" 17 "runtime" 18 "sort" 19 "strconv" 20 "strings" 21 "sync" 22 "time" 23 24 "github.com/go-delve/delve/pkg/dwarf/op" 25 "github.com/go-delve/delve/pkg/gobuild" 26 "github.com/go-delve/delve/pkg/goversion" 27 "github.com/go-delve/delve/pkg/locspec" 28 "github.com/go-delve/delve/pkg/logflags" 29 "github.com/go-delve/delve/pkg/proc" 30 "github.com/go-delve/delve/pkg/proc/core" 31 "github.com/go-delve/delve/pkg/proc/gdbserial" 32 "github.com/go-delve/delve/pkg/proc/native" 33 "github.com/go-delve/delve/service/api" 34 ) 35 36 var ( 37 // ErrCanNotRestart is returned when the target cannot be restarted. 38 // This is returned for targets that have been attached to, or when 39 // debugging core files. 40 ErrCanNotRestart = errors.New("can not restart this target") 41 42 // ErrNotRecording is returned when StopRecording is called while the 43 // debugger is not recording the target. 44 ErrNotRecording = errors.New("debugger is not recording") 45 46 // ErrCoreDumpInProgress is returned when a core dump is already in progress. 47 ErrCoreDumpInProgress = errors.New("core dump in progress") 48 49 // ErrCoreDumpNotSupported is returned when core dumping is not supported 50 ErrCoreDumpNotSupported = errors.New("core dumping not supported") 51 52 // ErrNotImplementedWithMultitarget is returned for operations that are not implemented with multiple targets 53 ErrNotImplementedWithMultitarget = errors.New("not implemented for multiple targets") 54 ) 55 56 // Debugger service. 57 // 58 // Debugger provides a higher level of 59 // abstraction over proc.Process. 60 // It handles converting from internal types to 61 // the types expected by clients. It also handles 62 // functionality needed by clients, but not needed in 63 // lower lever packages such as proc. 64 type Debugger struct { 65 config *Config 66 // arguments to launch a new process. 67 processArgs []string 68 69 targetMutex sync.Mutex 70 target *proc.TargetGroup 71 72 log logflags.Logger 73 74 running bool 75 runningMutex sync.Mutex 76 77 stopRecording func() error 78 recordMutex sync.Mutex 79 80 dumpState proc.DumpState 81 82 breakpointIDCounter int 83 } 84 85 type ExecuteKind int 86 87 const ( 88 ExecutingExistingFile = ExecuteKind(iota) 89 ExecutingGeneratedFile 90 ExecutingGeneratedTest 91 ExecutingOther 92 ) 93 94 // Config provides the configuration to start a Debugger. 95 // 96 // Only one of ProcessArgs or AttachPid should be specified. If ProcessArgs is 97 // provided, a new process will be launched. Otherwise, the debugger will try 98 // to attach to an existing process with AttachPid. 99 type Config struct { 100 // WorkingDir is working directory of the new process. This field is used 101 // only when launching a new process. 102 WorkingDir string 103 104 // AttachPid is the PID of an existing process to which the debugger should 105 // attach. 106 AttachPid int 107 // If AttachWaitFor is set the debugger will wait for a process with a name 108 // starting with WaitFor and attach to it. 109 AttachWaitFor string 110 // AttachWaitForInterval is the time (in milliseconds) that the debugger 111 // waits between checks for WaitFor. 112 AttachWaitForInterval float64 113 // AttachWaitForDuration is the time (in milliseconds) that the debugger 114 // waits for WaitFor. 115 AttachWaitForDuration float64 116 117 // CoreFile specifies the path to the core dump to open. 118 CoreFile string 119 120 // Backend specifies the debugger backend. 121 Backend string 122 123 // Foreground lets target process access stdin. 124 Foreground bool 125 126 // DebugInfoDirectories is the list of directories to look for 127 // when resolving external debug info files. 128 DebugInfoDirectories []string 129 130 // CheckGoVersion is true if the debugger should check the version of Go 131 // used to compile the executable and refuse to work on incompatible 132 // versions. 133 CheckGoVersion bool 134 135 // TTY is passed along to the target process on creation. Used to specify a 136 // TTY for that process. 137 TTY string 138 139 // Packages contains the packages that we are debugging. 140 Packages []string 141 142 // BuildFlags contains the flags passed to the compiler. 143 BuildFlags string 144 145 // ExecuteKind contains the kind of the executed program. 146 ExecuteKind ExecuteKind 147 148 // Stdin Redirect file path for stdin 149 Stdin string 150 151 // Redirects specifies redirect rules for stdout 152 Stdout proc.OutputRedirect 153 154 // Redirects specifies redirect rules for stderr 155 Stderr proc.OutputRedirect 156 157 // DisableASLR disables ASLR 158 DisableASLR bool 159 160 RrOnProcessPid int 161 } 162 163 // New creates a new Debugger. ProcessArgs specify the commandline arguments for the 164 // new process. 165 func New(config *Config, processArgs []string) (*Debugger, error) { 166 logger := logflags.DebuggerLogger() 167 d := &Debugger{ 168 config: config, 169 processArgs: processArgs, 170 log: logger, 171 } 172 173 // Create the process by either attaching or launching. 174 switch { 175 case d.config.AttachPid > 0 || d.config.AttachWaitFor != "": 176 d.log.Infof("attaching to pid %d", d.config.AttachPid) 177 path := "" 178 if len(d.processArgs) > 0 { 179 path = d.processArgs[0] 180 } 181 var waitFor *proc.WaitFor 182 if d.config.AttachWaitFor != "" { 183 waitFor = &proc.WaitFor{ 184 Name: d.config.AttachWaitFor, 185 Interval: time.Duration(d.config.AttachWaitForInterval * float64(time.Millisecond)), 186 Duration: time.Duration(d.config.AttachWaitForDuration * float64(time.Millisecond)), 187 } 188 } 189 var err error 190 d.target, err = d.Attach(d.config.AttachPid, path, waitFor) 191 if err != nil { 192 err = go11DecodeErrorCheck(err) 193 err = noDebugErrorWarning(err) 194 return nil, attachErrorMessage(d.config.AttachPid, err) 195 } 196 197 case d.config.CoreFile != "": 198 var err error 199 switch d.config.Backend { 200 case "rr": 201 d.log.Infof("opening trace %s", d.config.CoreFile) 202 d.target, err = gdbserial.Replay(d.config.CoreFile, false, false, d.config.DebugInfoDirectories, d.config.RrOnProcessPid, "") 203 default: 204 d.log.Infof("opening core file %s (executable %s)", d.config.CoreFile, d.processArgs[0]) 205 d.target, err = core.OpenCore(d.config.CoreFile, d.processArgs[0], d.config.DebugInfoDirectories) 206 } 207 if err != nil { 208 err = go11DecodeErrorCheck(err) 209 return nil, err 210 } 211 if err := d.checkGoVersion(); err != nil { 212 d.target.Detach(true) 213 return nil, err 214 } 215 216 default: 217 d.log.Infof("launching process with args: %v", d.processArgs) 218 var err error 219 d.target, err = d.Launch(d.processArgs, d.config.WorkingDir) 220 if err != nil { 221 if _, ok := err.(*proc.ErrUnsupportedArch); !ok { 222 err = go11DecodeErrorCheck(err) 223 err = noDebugErrorWarning(err) 224 err = fmt.Errorf("could not launch process: %s", err) 225 } 226 return nil, err 227 } 228 if err := d.checkGoVersion(); err != nil { 229 d.target.Detach(true) 230 return nil, err 231 } 232 } 233 234 return d, nil 235 } 236 237 // canRestart returns true if the target was started with Launch and can be restarted 238 func (d *Debugger) canRestart() bool { 239 switch { 240 case d.config.AttachPid > 0: 241 return false 242 case d.config.CoreFile != "": 243 return false 244 default: 245 return true 246 } 247 } 248 249 func (d *Debugger) checkGoVersion() error { 250 if d.isRecording() { 251 // do not do anything if we are still recording 252 return nil 253 } 254 producer := d.target.Selected.BinInfo().Producer() 255 if producer == "" { 256 return nil 257 } 258 return goversion.Compatible(producer, !d.config.CheckGoVersion) 259 } 260 261 func (d *Debugger) TargetGoVersion() string { 262 d.targetMutex.Lock() 263 defer d.targetMutex.Unlock() 264 return d.target.Selected.BinInfo().Producer() 265 } 266 267 // Launch will start a process with the given args and working directory. 268 func (d *Debugger) Launch(processArgs []string, wd string) (*proc.TargetGroup, error) { 269 fullpath, err := verifyBinaryFormat(processArgs[0]) 270 if err != nil { 271 return nil, err 272 } 273 processArgs[0] = fullpath 274 275 launchFlags := proc.LaunchFlags(0) 276 if d.config.Foreground { 277 launchFlags |= proc.LaunchForeground 278 } 279 if d.config.DisableASLR { 280 launchFlags |= proc.LaunchDisableASLR 281 } 282 283 switch d.config.Backend { 284 case "native": 285 return native.Launch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, d.config.Stdin, d.config.Stdout, d.config.Stderr) 286 case "lldb": 287 return betterGdbserialLaunchError(gdbserial.LLDBLaunch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, [3]string{d.config.Stdin, d.config.Stdout.Path, d.config.Stderr.Path})) 288 case "rr": 289 if d.target != nil { 290 // restart should not call us if the backend is 'rr' 291 panic("internal error: call to Launch with rr backend and target already exists") 292 } 293 294 run, stop, err := gdbserial.RecordAsync(processArgs, wd, false, d.config.Stdin, d.config.Stdout, d.config.Stderr) 295 if err != nil { 296 return nil, err 297 } 298 299 // let the initialization proceed but hold the targetMutex lock so that 300 // any other request to debugger will block except State(nowait=true) and 301 // Command(halt). 302 d.targetMutex.Lock() 303 d.recordingStart(stop) 304 305 go func() { 306 defer d.targetMutex.Unlock() 307 308 grp, err := d.recordingRun(run) 309 if err != nil { 310 d.log.Errorf("could not record target: %v", err) 311 // this is ugly but we can't respond to any client requests at this 312 // point so it's better if we die. 313 os.Exit(1) 314 } 315 d.recordingDone() 316 d.target = grp 317 if err := d.checkGoVersion(); err != nil { 318 d.log.Error(err) 319 err := d.target.Detach(true) 320 if err != nil { 321 d.log.Errorf("Error detaching from target: %v", err) 322 } 323 } 324 }() 325 return nil, nil 326 327 case "default": 328 if runtime.GOOS == "darwin" { 329 return betterGdbserialLaunchError(gdbserial.LLDBLaunch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, [3]string{d.config.Stdin, d.config.Stdout.Path, d.config.Stderr.Path})) 330 } 331 return native.Launch(processArgs, wd, launchFlags, d.config.DebugInfoDirectories, d.config.TTY, d.config.Stdin, d.config.Stdout, d.config.Stderr) 332 default: 333 return nil, fmt.Errorf("unknown backend %q", d.config.Backend) 334 } 335 } 336 337 func (d *Debugger) recordingStart(stop func() error) { 338 d.recordMutex.Lock() 339 d.stopRecording = stop 340 d.recordMutex.Unlock() 341 } 342 343 func (d *Debugger) recordingDone() { 344 d.recordMutex.Lock() 345 d.stopRecording = nil 346 d.recordMutex.Unlock() 347 } 348 349 func (d *Debugger) isRecording() bool { 350 d.recordMutex.Lock() 351 defer d.recordMutex.Unlock() 352 return d.stopRecording != nil 353 } 354 355 func (d *Debugger) recordingRun(run func() (string, error)) (*proc.TargetGroup, error) { 356 tracedir, err := run() 357 if err != nil && tracedir == "" { 358 return nil, err 359 } 360 361 return gdbserial.Replay(tracedir, false, true, d.config.DebugInfoDirectories, 0, strings.Join(d.processArgs, " ")) 362 } 363 364 // Attach will attach to the process specified by 'pid'. 365 func (d *Debugger) Attach(pid int, path string, waitFor *proc.WaitFor) (*proc.TargetGroup, error) { 366 switch d.config.Backend { 367 case "native": 368 return native.Attach(pid, waitFor, d.config.DebugInfoDirectories) 369 case "lldb": 370 return betterGdbserialLaunchError(gdbserial.LLDBAttach(pid, path, waitFor, d.config.DebugInfoDirectories)) 371 case "default": 372 if runtime.GOOS == "darwin" { 373 return betterGdbserialLaunchError(gdbserial.LLDBAttach(pid, path, waitFor, d.config.DebugInfoDirectories)) 374 } 375 return native.Attach(pid, waitFor, d.config.DebugInfoDirectories) 376 default: 377 return nil, fmt.Errorf("unknown backend %q", d.config.Backend) 378 } 379 } 380 381 var errMacOSBackendUnavailable = errors.New("debugserver or lldb-server not found: install Xcode's command line tools or lldb-server") 382 383 func betterGdbserialLaunchError(p *proc.TargetGroup, err error) (*proc.TargetGroup, error) { 384 if runtime.GOOS != "darwin" { 385 return p, err 386 } 387 if _, isUnavailable := err.(*gdbserial.ErrBackendUnavailable); !isUnavailable { 388 return p, err 389 } 390 391 return p, errMacOSBackendUnavailable 392 } 393 394 // ProcessPid returns the PID of the process 395 // the debugger is debugging. 396 func (d *Debugger) ProcessPid() int { 397 d.targetMutex.Lock() 398 defer d.targetMutex.Unlock() 399 return d.target.Selected.Pid() 400 } 401 402 // LastModified returns the time that the process' executable was last 403 // modified. 404 func (d *Debugger) LastModified() time.Time { 405 d.targetMutex.Lock() 406 defer d.targetMutex.Unlock() 407 return d.target.Selected.BinInfo().LastModified() 408 } 409 410 // FunctionReturnLocations returns all return locations 411 // for the given function, a list of addresses corresponding 412 // to 'ret' or 'call runtime.deferreturn'. 413 func (d *Debugger) FunctionReturnLocations(fnName string) ([]uint64, error) { 414 d.targetMutex.Lock() 415 defer d.targetMutex.Unlock() 416 417 if len(d.target.Targets()) > 1 { 418 return nil, ErrNotImplementedWithMultitarget 419 } 420 421 var ( 422 p = d.target.Selected 423 g = p.SelectedGoroutine() 424 ) 425 426 fns, err := p.BinInfo().FindFunction(fnName) 427 if err != nil { 428 return nil, err 429 } 430 431 var addrs []uint64 432 433 for _, fn := range fns { 434 var regs proc.Registers 435 mem := p.Memory() 436 if g != nil && g.Thread != nil { 437 regs, _ = g.Thread.Registers() 438 } 439 instructions, err := proc.Disassemble(mem, regs, p.Breakpoints(), p.BinInfo(), fn.Entry, fn.End) 440 if err != nil { 441 return nil, err 442 } 443 444 for _, instruction := range instructions { 445 if instruction.IsRet() { 446 addrs = append(addrs, instruction.Loc.PC) 447 } 448 } 449 addrs = append(addrs, proc.FindDeferReturnCalls(instructions)...) 450 } 451 452 return addrs, nil 453 } 454 455 // Detach detaches from the target process. 456 // If `kill` is true we will kill the process after 457 // detaching. 458 func (d *Debugger) Detach(kill bool) error { 459 d.log.Debug("detaching") 460 d.targetMutex.Lock() 461 defer d.targetMutex.Unlock() 462 if ok, _ := d.target.Valid(); !ok { 463 return nil 464 } 465 return d.detach(kill) 466 } 467 468 func (d *Debugger) detach(kill bool) error { 469 if d.config.AttachPid == 0 { 470 kill = true 471 } 472 return d.target.Detach(kill) 473 } 474 475 // Restart will restart the target process, first killing 476 // and then exec'ing it again. 477 // If the target process is a recording it will restart it from the given 478 // position. If pos starts with 'c' it's a checkpoint ID, otherwise it's an 479 // event number. If resetArgs is true, newArgs will replace the process args. 480 func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs []string, newRedirects [3]string, rebuild bool) ([]api.DiscardedBreakpoint, error) { 481 d.targetMutex.Lock() 482 defer d.targetMutex.Unlock() 483 484 recorded, _ := d.target.Recorded() 485 if recorded && !rerecord { 486 d.target.ResumeNotify(nil) 487 return nil, d.target.Restart(pos) 488 } 489 490 if pos != "" { 491 return nil, proc.ErrNotRecorded 492 } 493 494 if !d.canRestart() { 495 return nil, ErrCanNotRestart 496 } 497 498 if !resetArgs && (d.config.Stdout.File != nil || d.config.Stderr.File != nil) { 499 return nil, ErrCanNotRestart 500 501 } 502 503 if err := d.detach(true); err != nil { 504 return nil, err 505 } 506 if resetArgs { 507 d.processArgs = append([]string{d.processArgs[0]}, newArgs...) 508 d.config.Stdin = newRedirects[0] 509 d.config.Stdout = proc.OutputRedirect{Path: newRedirects[1]} 510 d.config.Stderr = proc.OutputRedirect{Path: newRedirects[2]} 511 } 512 var grp *proc.TargetGroup 513 var err error 514 515 if rebuild { 516 switch d.config.ExecuteKind { 517 case ExecutingGeneratedFile: 518 err = gobuild.GoBuild(d.processArgs[0], d.config.Packages, d.config.BuildFlags) 519 if err != nil { 520 return nil, fmt.Errorf("could not rebuild process: %s", err) 521 } 522 case ExecutingGeneratedTest: 523 err = gobuild.GoTestBuild(d.processArgs[0], d.config.Packages, d.config.BuildFlags) 524 if err != nil { 525 return nil, fmt.Errorf("could not rebuild process: %s", err) 526 } 527 default: 528 // We cannot build a process that we didn't start, because we don't know how it was built. 529 return nil, fmt.Errorf("cannot rebuild a binary") 530 } 531 } 532 533 if recorded { 534 run, stop, err2 := gdbserial.RecordAsync(d.processArgs, d.config.WorkingDir, false, d.config.Stdin, d.config.Stdout, d.config.Stderr) 535 if err2 != nil { 536 return nil, err2 537 } 538 539 d.recordingStart(stop) 540 grp, err = d.recordingRun(run) 541 d.recordingDone() 542 } else { 543 grp, err = d.Launch(d.processArgs, d.config.WorkingDir) 544 } 545 if err != nil { 546 return nil, fmt.Errorf("could not launch process: %s", err) 547 } 548 549 discarded := []api.DiscardedBreakpoint{} 550 proc.Restart(grp, d.target, func(oldBp *proc.LogicalBreakpoint, err error) { 551 discarded = append(discarded, api.DiscardedBreakpoint{Breakpoint: api.ConvertLogicalBreakpoint(oldBp), Reason: err.Error()}) 552 }) 553 d.target = grp 554 return discarded, nil 555 } 556 557 // State returns the current state of the debugger. 558 func (d *Debugger) State(nowait bool) (*api.DebuggerState, error) { 559 if d.IsRunning() && nowait { 560 return &api.DebuggerState{Running: true}, nil 561 } 562 563 if d.isRecording() && nowait { 564 return &api.DebuggerState{Recording: true}, nil 565 } 566 567 d.dumpState.Mutex.Lock() 568 if d.dumpState.Dumping && nowait { 569 return &api.DebuggerState{CoreDumping: true}, nil 570 } 571 d.dumpState.Mutex.Unlock() 572 573 d.targetMutex.Lock() 574 defer d.targetMutex.Unlock() 575 return d.state(nil, false) 576 } 577 578 func (d *Debugger) state(retLoadCfg *proc.LoadConfig, withBreakpointInfo bool) (*api.DebuggerState, error) { 579 if _, err := d.target.Valid(); err != nil { 580 return nil, err 581 } 582 583 var ( 584 state *api.DebuggerState 585 goroutine *api.Goroutine 586 ) 587 588 tgt := d.target.Selected 589 590 if tgt.SelectedGoroutine() != nil { 591 goroutine = api.ConvertGoroutine(tgt, tgt.SelectedGoroutine()) 592 } 593 594 exited := false 595 if _, err := tgt.Valid(); err != nil { 596 _, exited = err.(proc.ErrProcessExited) 597 } 598 599 state = &api.DebuggerState{ 600 Pid: tgt.Pid(), 601 TargetCommandLine: tgt.CmdLine, 602 SelectedGoroutine: goroutine, 603 Exited: exited, 604 } 605 606 for _, thread := range d.target.ThreadList() { 607 th := api.ConvertThread(thread, d.ConvertThreadBreakpoint(thread)) 608 609 th.CallReturn = thread.Common().CallReturn 610 if retLoadCfg != nil { 611 th.ReturnValues = api.ConvertVars(thread.Common().ReturnValues(*retLoadCfg)) 612 } 613 614 if withBreakpointInfo { 615 err := d.collectBreakpointInformation(th, thread) 616 if err != nil { 617 return nil, err 618 } 619 } 620 621 state.Threads = append(state.Threads, th) 622 if thread.ThreadID() == tgt.CurrentThread().ThreadID() { 623 state.CurrentThread = th 624 } 625 } 626 627 state.NextInProgress = d.target.HasSteppingBreakpoints() 628 629 if recorded, _ := d.target.Recorded(); recorded { 630 state.When, _ = d.target.When() 631 } 632 633 t := proc.ValidTargets{Group: d.target} 634 for t.Next() { 635 for _, bp := range t.Breakpoints().WatchOutOfScope { 636 abp := api.ConvertLogicalBreakpoint(bp.Logical) 637 api.ConvertPhysicalBreakpoints(abp, bp.Logical, []int{t.Pid()}, []*proc.Breakpoint{bp}) 638 state.WatchOutOfScope = append(state.WatchOutOfScope, abp) 639 } 640 } 641 642 return state, nil 643 } 644 645 // CreateBreakpoint creates a breakpoint using information from the provided `requestedBp`. 646 // This function accepts several different ways of specifying where and how to create the 647 // breakpoint that has been requested. Any error encountered during the attempt to set the 648 // breakpoint will be returned to the caller. 649 // 650 // The ways of specifying a breakpoint are listed below in the order they are considered by 651 // this function: 652 // 653 // - If requestedBp.TraceReturn is true then it is expected that 654 // requestedBp.Addrs will contain the list of return addresses 655 // supplied by the caller. 656 // 657 // - If requestedBp.File is not an empty string the breakpoint 658 // will be created on the specified file:line location 659 // 660 // - If requestedBp.FunctionName is not an empty string 661 // the breakpoint will be created on the specified function:line 662 // location. 663 // 664 // - If requestedBp.Addrs is filled it will create a logical breakpoint 665 // corresponding to all specified addresses. 666 // 667 // - Otherwise the value specified by arg.Breakpoint.Addr will be used. 668 // 669 // Note that this method will use the first successful method in order to 670 // create a breakpoint, so mixing different fields will not result is multiple 671 // breakpoints being set. 672 // 673 // If LocExpr is specified it will be used, along with substitutePathRules, 674 // to re-enable the breakpoint after it is disabled. 675 // 676 // If suspended is true a logical breakpoint will be created even if the 677 // location can not be found, the backend will attempt to enable the 678 // breakpoint every time a new plugin is loaded. 679 func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint, locExpr string, substitutePathRules [][2]string, suspended bool) (*api.Breakpoint, error) { 680 d.targetMutex.Lock() 681 defer d.targetMutex.Unlock() 682 683 var ( 684 setbp proc.SetBreakpoint 685 err error 686 ) 687 688 if requestedBp.Name != "" { 689 if d.findBreakpointByName(requestedBp.Name) != nil { 690 return nil, errors.New("breakpoint name already exists") 691 } 692 } 693 694 if lbp := d.target.LogicalBreakpoints[requestedBp.ID]; lbp != nil { 695 abp := d.convertBreakpoint(lbp) 696 return abp, proc.BreakpointExistsError{File: lbp.File, Line: lbp.Line} 697 } 698 699 switch { 700 case requestedBp.TraceReturn: 701 if len(d.target.Targets()) != 1 { 702 return nil, ErrNotImplementedWithMultitarget 703 } 704 setbp.PidAddrs = []proc.PidAddr{{Pid: d.target.Selected.Pid(), Addr: requestedBp.Addr}} 705 case len(requestedBp.File) > 0: 706 fileName := requestedBp.File 707 if runtime.GOOS == "windows" { 708 // Accept fileName which is case-insensitive and slash-insensitive match 709 fileNameNormalized := strings.ToLower(filepath.ToSlash(fileName)) 710 t := proc.ValidTargets{Group: d.target} 711 caseInsensitiveSearch: 712 for t.Next() { 713 for _, symFile := range t.BinInfo().Sources { 714 if fileNameNormalized == strings.ToLower(filepath.ToSlash(symFile)) { 715 fileName = symFile 716 break caseInsensitiveSearch 717 } 718 } 719 } 720 } 721 setbp.File = fileName 722 setbp.Line = requestedBp.Line 723 case len(requestedBp.FunctionName) > 0: 724 setbp.FunctionName = requestedBp.FunctionName 725 setbp.Line = requestedBp.Line 726 case len(requestedBp.Addrs) > 0: 727 setbp.PidAddrs = make([]proc.PidAddr, len(requestedBp.Addrs)) 728 if len(d.target.Targets()) == 1 { 729 pid := d.target.Selected.Pid() 730 for i, addr := range requestedBp.Addrs { 731 setbp.PidAddrs[i] = proc.PidAddr{Pid: pid, Addr: addr} 732 } 733 } else { 734 if len(requestedBp.Addrs) != len(requestedBp.AddrPid) { 735 return nil, errors.New("mismatched length in addrs and addrpid") 736 } 737 for i, addr := range requestedBp.Addrs { 738 setbp.PidAddrs[i] = proc.PidAddr{Pid: requestedBp.AddrPid[i], Addr: addr} 739 } 740 } 741 default: 742 if requestedBp.Addr != 0 { 743 setbp.PidAddrs = []proc.PidAddr{{Pid: d.target.Selected.Pid(), Addr: requestedBp.Addr}} 744 } 745 } 746 747 if err != nil { 748 return nil, err 749 } 750 751 if locExpr != "" { 752 loc, err := locspec.Parse(locExpr) 753 if err != nil { 754 return nil, err 755 } 756 setbp.Expr = func(t *proc.Target) []uint64 { 757 locs, _, err := loc.Find(t, d.processArgs, nil, locExpr, false, substitutePathRules) 758 if err != nil || len(locs) != 1 { 759 logflags.DebuggerLogger().Debugf("could not evaluate breakpoint expression %q: %v (number of results %d)", locExpr, err, len(locs)) 760 return nil 761 } 762 return locs[0].PCs 763 } 764 setbp.ExprString = locExpr 765 } 766 767 id := requestedBp.ID 768 769 if id <= 0 { 770 d.breakpointIDCounter++ 771 id = d.breakpointIDCounter 772 } else { 773 d.breakpointIDCounter = id 774 } 775 776 lbp := &proc.LogicalBreakpoint{LogicalID: id, HitCount: make(map[int64]uint64), Enabled: true} 777 d.target.LogicalBreakpoints[id] = lbp 778 779 err = copyLogicalBreakpointInfo(lbp, requestedBp) 780 if err != nil { 781 return nil, err 782 } 783 784 lbp.Set = setbp 785 786 if lbp.Set.Expr != nil { 787 addrs := lbp.Set.Expr(d.Target()) 788 if len(addrs) > 0 { 789 f, l, fn := d.Target().BinInfo().PCToLine(addrs[0]) 790 lbp.File = f 791 lbp.Line = l 792 if fn != nil { 793 lbp.FunctionName = fn.Name 794 } 795 } 796 } 797 798 err = d.target.EnableBreakpoint(lbp) 799 if err != nil { 800 if suspended { 801 logflags.DebuggerLogger().Debugf("could not enable new breakpoint: %v (breakpoint will be suspended)", err) 802 } else { 803 delete(d.target.LogicalBreakpoints, lbp.LogicalID) 804 return nil, err 805 } 806 } 807 808 createdBp := d.convertBreakpoint(lbp) 809 d.log.Infof("created breakpoint: %#v", createdBp) 810 return createdBp, nil 811 } 812 813 func (d *Debugger) convertBreakpoint(lbp *proc.LogicalBreakpoint) *api.Breakpoint { 814 abp := api.ConvertLogicalBreakpoint(lbp) 815 bps := []*proc.Breakpoint{} 816 pids := []int{} 817 t := proc.ValidTargets{Group: d.target} 818 for t.Next() { 819 for _, bp := range t.Breakpoints().M { 820 if bp.LogicalID() == lbp.LogicalID { 821 bps = append(bps, bp) 822 pids = append(pids, t.Pid()) 823 } 824 } 825 } 826 api.ConvertPhysicalBreakpoints(abp, lbp, pids, bps) 827 return abp 828 } 829 830 func (d *Debugger) ConvertThreadBreakpoint(thread proc.Thread) *api.Breakpoint { 831 if b := thread.Breakpoint(); b.Active && b.Breakpoint.Logical != nil { 832 return d.convertBreakpoint(b.Breakpoint.Logical) 833 } 834 return nil 835 } 836 837 func (d *Debugger) CreateEBPFTracepoint(fnName string) error { 838 d.targetMutex.Lock() 839 defer d.targetMutex.Unlock() 840 if len(d.target.Targets()) != 1 { 841 return ErrNotImplementedWithMultitarget 842 } 843 p := d.target.Selected 844 return p.SetEBPFTracepoint(fnName) 845 } 846 847 // amendBreakpoint will update the breakpoint with the matching ID. 848 // It also enables or disables the breakpoint. 849 // We can consume this function to avoid locking a goroutine. 850 func (d *Debugger) amendBreakpoint(amend *api.Breakpoint) error { 851 original := d.target.LogicalBreakpoints[amend.ID] 852 if original == nil { 853 return fmt.Errorf("no breakpoint with ID %d", amend.ID) 854 } 855 enabledBefore := original.Enabled 856 err := copyLogicalBreakpointInfo(original, amend) 857 if err != nil { 858 return err 859 } 860 original.Enabled = !amend.Disabled 861 862 switch { 863 case enabledBefore && !original.Enabled: 864 if d.isWatchpoint(original) { 865 return errors.New("can not disable watchpoints") 866 } 867 err = d.target.DisableBreakpoint(original) 868 case !enabledBefore && original.Enabled: 869 err = d.target.EnableBreakpoint(original) 870 } 871 if err != nil { 872 return err 873 } 874 875 t := proc.ValidTargets{Group: d.target} 876 for t.Next() { 877 for _, bp := range t.Breakpoints().M { 878 if bp.LogicalID() == amend.ID { 879 bp.UserBreaklet().Cond = original.Cond 880 } 881 } 882 } 883 return nil 884 } 885 886 func (d *Debugger) isWatchpoint(lbp *proc.LogicalBreakpoint) bool { 887 t := proc.ValidTargets{Group: d.target} 888 for t.Next() { 889 for _, bp := range t.Breakpoints().M { 890 if bp.LogicalID() == lbp.LogicalID { 891 return bp.WatchType != 0 892 } 893 } 894 } 895 return false 896 } 897 898 // AmendBreakpoint will update the breakpoint with the matching ID. 899 // It also enables or disables the breakpoint. 900 func (d *Debugger) AmendBreakpoint(amend *api.Breakpoint) error { 901 d.targetMutex.Lock() 902 defer d.targetMutex.Unlock() 903 904 return d.amendBreakpoint(amend) 905 } 906 907 // CancelNext will clear internal breakpoints, thus cancelling the 'next', 908 // 'step' or 'stepout' operation. 909 func (d *Debugger) CancelNext() error { 910 d.targetMutex.Lock() 911 defer d.targetMutex.Unlock() 912 return d.target.ClearSteppingBreakpoints() 913 } 914 915 func copyLogicalBreakpointInfo(lbp *proc.LogicalBreakpoint, requested *api.Breakpoint) error { 916 lbp.Name = requested.Name 917 lbp.Tracepoint = requested.Tracepoint 918 lbp.TraceReturn = requested.TraceReturn 919 lbp.Goroutine = requested.Goroutine 920 lbp.Stacktrace = requested.Stacktrace 921 lbp.Variables = requested.Variables 922 lbp.LoadArgs = api.LoadConfigToProc(requested.LoadArgs) 923 lbp.LoadLocals = api.LoadConfigToProc(requested.LoadLocals) 924 lbp.UserData = requested.UserData 925 lbp.Cond = nil 926 if requested.Cond != "" { 927 var err error 928 lbp.Cond, err = parser.ParseExpr(requested.Cond) 929 if err != nil { 930 return err 931 } 932 } 933 934 lbp.HitCond = nil 935 if requested.HitCond != "" { 936 opTok, val, err := parseHitCondition(requested.HitCond) 937 if err != nil { 938 return err 939 } 940 lbp.HitCond = &struct { 941 Op token.Token 942 Val int 943 }{opTok, val} 944 lbp.HitCondPerG = requested.HitCondPerG 945 } 946 947 return nil 948 } 949 950 func parseHitCondition(hitCond string) (token.Token, int, error) { 951 // A hit condition can be in the following formats: 952 // - "number" 953 // - "OP number" 954 hitConditionRegex := regexp.MustCompile(`((=|>|<|%|!)+|)( |)((\d|_)+)`) 955 956 match := hitConditionRegex.FindStringSubmatch(strings.TrimSpace(hitCond)) 957 if match == nil || len(match) != 6 { 958 return 0, 0, fmt.Errorf("unable to parse breakpoint hit condition: %q\nhit conditions should be of the form \"number\" or \"OP number\"", hitCond) 959 } 960 961 opStr := match[1] 962 var opTok token.Token 963 switch opStr { 964 case "==", "": 965 opTok = token.EQL 966 case ">=": 967 opTok = token.GEQ 968 case "<=": 969 opTok = token.LEQ 970 case ">": 971 opTok = token.GTR 972 case "<": 973 opTok = token.LSS 974 case "%": 975 opTok = token.REM 976 case "!=": 977 opTok = token.NEQ 978 default: 979 return 0, 0, fmt.Errorf("unable to parse breakpoint hit condition: %q\ninvalid operator: %q", hitCond, opStr) 980 } 981 982 numStr := match[4] 983 val, parseErr := strconv.Atoi(numStr) 984 if parseErr != nil { 985 return 0, 0, fmt.Errorf("unable to parse breakpoint hit condition: %q\ninvalid number: %q", hitCond, numStr) 986 } 987 988 return opTok, val, nil 989 } 990 991 // ClearBreakpoint clears a breakpoint. 992 func (d *Debugger) ClearBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) { 993 d.targetMutex.Lock() 994 defer d.targetMutex.Unlock() 995 if requestedBp.ID <= 0 { 996 if len(d.target.Targets()) != 1 { 997 return nil, ErrNotImplementedWithMultitarget 998 } 999 bp := d.target.Selected.Breakpoints().M[requestedBp.Addr] 1000 requestedBp.ID = bp.LogicalID() 1001 } 1002 1003 lbp := d.target.LogicalBreakpoints[requestedBp.ID] 1004 clearedBp := d.convertBreakpoint(lbp) 1005 1006 err := d.target.DisableBreakpoint(lbp) 1007 if err != nil { 1008 return nil, err 1009 } 1010 1011 delete(d.target.LogicalBreakpoints, requestedBp.ID) 1012 1013 d.log.Infof("cleared breakpoint: %#v", clearedBp) 1014 return clearedBp, nil 1015 } 1016 1017 // isBpHitCondNotSatisfiable returns true if the breakpoint bp has a hit 1018 // condition that is no more satisfiable. 1019 // The hit condition is considered no more satisfiable if it can no longer be 1020 // hit again, for example with {Op: "==", Val: 1} and TotalHitCount == 1. 1021 func isBpHitCondNotSatisfiable(bp *api.Breakpoint) bool { 1022 if bp.HitCond == "" { 1023 return false 1024 } 1025 1026 tok, val, err := parseHitCondition(bp.HitCond) 1027 if err != nil { 1028 return false 1029 } 1030 switch tok { 1031 case token.EQL, token.LEQ: 1032 if int(bp.TotalHitCount) >= val { 1033 return true 1034 } 1035 case token.LSS: 1036 if int(bp.TotalHitCount) >= val-1 { 1037 return true 1038 } 1039 } 1040 1041 return false 1042 } 1043 1044 // Breakpoints returns the list of current breakpoints. 1045 func (d *Debugger) Breakpoints(all bool) []*api.Breakpoint { 1046 d.targetMutex.Lock() 1047 defer d.targetMutex.Unlock() 1048 1049 abps := []*api.Breakpoint{} 1050 if all { 1051 t := proc.ValidTargets{Group: d.target} 1052 for t.Next() { 1053 for _, bp := range t.Breakpoints().M { 1054 var abp *api.Breakpoint 1055 if bp.Logical != nil { 1056 abp = api.ConvertLogicalBreakpoint(bp.Logical) 1057 } else { 1058 abp = &api.Breakpoint{} 1059 } 1060 api.ConvertPhysicalBreakpoints(abp, bp.Logical, []int{t.Pid()}, []*proc.Breakpoint{bp}) 1061 abp.VerboseDescr = bp.VerboseDescr() 1062 abps = append(abps, abp) 1063 } 1064 } 1065 } else { 1066 for _, lbp := range d.target.LogicalBreakpoints { 1067 abps = append(abps, d.convertBreakpoint(lbp)) 1068 } 1069 } 1070 return abps 1071 } 1072 1073 // FindBreakpoint returns the breakpoint specified by 'id'. 1074 func (d *Debugger) FindBreakpoint(id int) *api.Breakpoint { 1075 d.targetMutex.Lock() 1076 defer d.targetMutex.Unlock() 1077 lbp := d.target.LogicalBreakpoints[id] 1078 if lbp == nil { 1079 return nil 1080 } 1081 return d.convertBreakpoint(lbp) 1082 } 1083 1084 // FindBreakpointByName returns the breakpoint specified by 'name' 1085 func (d *Debugger) FindBreakpointByName(name string) *api.Breakpoint { 1086 d.targetMutex.Lock() 1087 defer d.targetMutex.Unlock() 1088 return d.findBreakpointByName(name) 1089 } 1090 1091 func (d *Debugger) findBreakpointByName(name string) *api.Breakpoint { 1092 for _, lbp := range d.target.LogicalBreakpoints { 1093 if lbp.Name == name { 1094 return d.convertBreakpoint(lbp) 1095 } 1096 } 1097 return nil 1098 } 1099 1100 // CreateWatchpoint creates a watchpoint on the specified expression. 1101 func (d *Debugger) CreateWatchpoint(goid int64, frame, deferredCall int, expr string, wtype api.WatchType) (*api.Breakpoint, error) { 1102 p := d.target.Selected 1103 1104 s, err := proc.ConvertEvalScope(p, goid, frame, deferredCall) 1105 if err != nil { 1106 return nil, err 1107 } 1108 d.breakpointIDCounter++ 1109 bp, err := p.SetWatchpoint(d.breakpointIDCounter, s, expr, proc.WatchType(wtype), nil) 1110 if err != nil { 1111 return nil, err 1112 } 1113 if d.findBreakpointByName(expr) == nil { 1114 bp.Logical.Name = expr 1115 } 1116 return d.convertBreakpoint(bp.Logical), nil 1117 } 1118 1119 // Threads returns the threads of the target process. 1120 func (d *Debugger) Threads() ([]proc.Thread, error) { 1121 d.targetMutex.Lock() 1122 defer d.targetMutex.Unlock() 1123 1124 if _, err := d.target.Valid(); err != nil { 1125 return nil, err 1126 } 1127 1128 return d.target.ThreadList(), nil 1129 } 1130 1131 // FindThread returns the thread for the given 'id'. 1132 func (d *Debugger) FindThread(id int) (proc.Thread, error) { 1133 d.targetMutex.Lock() 1134 defer d.targetMutex.Unlock() 1135 1136 if _, err := d.target.Valid(); err != nil { 1137 return nil, err 1138 } 1139 1140 for _, th := range d.target.ThreadList() { 1141 if th.ThreadID() == id { 1142 return th, nil 1143 } 1144 } 1145 return nil, nil 1146 } 1147 1148 // FindGoroutine returns the goroutine for the given 'id'. 1149 func (d *Debugger) FindGoroutine(id int64) (*proc.G, error) { 1150 d.targetMutex.Lock() 1151 defer d.targetMutex.Unlock() 1152 1153 return proc.FindGoroutine(d.target.Selected, id) 1154 } 1155 1156 func (d *Debugger) setRunning(running bool) { 1157 d.runningMutex.Lock() 1158 d.running = running 1159 d.runningMutex.Unlock() 1160 } 1161 1162 func (d *Debugger) IsRunning() bool { 1163 d.runningMutex.Lock() 1164 defer d.runningMutex.Unlock() 1165 return d.running 1166 } 1167 1168 // Command handles commands which control the debugger lifecycle 1169 func (d *Debugger) Command(command *api.DebuggerCommand, resumeNotify chan struct{}) (*api.DebuggerState, error) { 1170 var err error 1171 1172 if command.Name == api.Halt { 1173 // RequestManualStop does not invoke any ptrace syscalls, so it's safe to 1174 // access the process directly. 1175 d.log.Debug("halting") 1176 1177 d.recordMutex.Lock() 1178 if d.stopRecording == nil { 1179 err = d.target.RequestManualStop() 1180 // The error returned from d.target.Valid will have more context 1181 // about the exited process. 1182 if _, valErr := d.target.Valid(); valErr != nil { 1183 err = valErr 1184 } 1185 } 1186 d.recordMutex.Unlock() 1187 } 1188 1189 withBreakpointInfo := true 1190 1191 d.targetMutex.Lock() 1192 defer d.targetMutex.Unlock() 1193 1194 d.setRunning(true) 1195 defer d.setRunning(false) 1196 1197 if command.Name != api.SwitchGoroutine && command.Name != api.SwitchThread && command.Name != api.Halt { 1198 d.target.ResumeNotify(resumeNotify) 1199 } else if resumeNotify != nil { 1200 close(resumeNotify) 1201 } 1202 1203 switch command.Name { 1204 case api.Continue: 1205 d.log.Debug("continuing") 1206 if err := d.target.ChangeDirection(proc.Forward); err != nil { 1207 return nil, err 1208 } 1209 err = d.target.Continue() 1210 case api.DirectionCongruentContinue: 1211 d.log.Debug("continuing (direction congruent)") 1212 err = d.target.Continue() 1213 case api.Call: 1214 d.log.Debugf("function call %s", command.Expr) 1215 if err := d.target.ChangeDirection(proc.Forward); err != nil { 1216 return nil, err 1217 } 1218 if command.ReturnInfoLoadConfig == nil { 1219 return nil, errors.New("can not call function with nil ReturnInfoLoadConfig") 1220 } 1221 g := d.target.Selected.SelectedGoroutine() 1222 if command.GoroutineID > 0 { 1223 g, err = proc.FindGoroutine(d.target.Selected, command.GoroutineID) 1224 if err != nil { 1225 return nil, err 1226 } 1227 } 1228 err = proc.EvalExpressionWithCalls(d.target, g, command.Expr, *api.LoadConfigToProc(command.ReturnInfoLoadConfig), !command.UnsafeCall) 1229 case api.Rewind: 1230 d.log.Debug("rewinding") 1231 if err := d.target.ChangeDirection(proc.Backward); err != nil { 1232 return nil, err 1233 } 1234 err = d.target.Continue() 1235 case api.Next: 1236 d.log.Debug("nexting") 1237 if err := d.target.ChangeDirection(proc.Forward); err != nil { 1238 return nil, err 1239 } 1240 err = d.target.Next() 1241 case api.ReverseNext: 1242 d.log.Debug("reverse nexting") 1243 if err := d.target.ChangeDirection(proc.Backward); err != nil { 1244 return nil, err 1245 } 1246 err = d.target.Next() 1247 case api.Step: 1248 d.log.Debug("stepping") 1249 if err := d.target.ChangeDirection(proc.Forward); err != nil { 1250 return nil, err 1251 } 1252 err = d.target.Step() 1253 case api.ReverseStep: 1254 d.log.Debug("reverse stepping") 1255 if err := d.target.ChangeDirection(proc.Backward); err != nil { 1256 return nil, err 1257 } 1258 err = d.target.Step() 1259 case api.StepInstruction: 1260 d.log.Debug("single stepping") 1261 if err := d.target.ChangeDirection(proc.Forward); err != nil { 1262 return nil, err 1263 } 1264 err = d.target.StepInstruction() 1265 case api.ReverseStepInstruction: 1266 d.log.Debug("reverse single stepping") 1267 if err := d.target.ChangeDirection(proc.Backward); err != nil { 1268 return nil, err 1269 } 1270 err = d.target.StepInstruction() 1271 case api.StepOut: 1272 d.log.Debug("step out") 1273 if err := d.target.ChangeDirection(proc.Forward); err != nil { 1274 return nil, err 1275 } 1276 err = d.target.StepOut() 1277 case api.ReverseStepOut: 1278 d.log.Debug("reverse step out") 1279 if err := d.target.ChangeDirection(proc.Backward); err != nil { 1280 return nil, err 1281 } 1282 err = d.target.StepOut() 1283 case api.SwitchThread: 1284 d.log.Debugf("switching to thread %d", command.ThreadID) 1285 t := proc.ValidTargets{Group: d.target} 1286 for t.Next() { 1287 if _, ok := t.FindThread(command.ThreadID); ok { 1288 d.target.Selected = t.Target 1289 break 1290 } 1291 } 1292 err = d.target.Selected.SwitchThread(command.ThreadID) 1293 withBreakpointInfo = false 1294 case api.SwitchGoroutine: 1295 d.log.Debugf("switching to goroutine %d", command.GoroutineID) 1296 var g *proc.G 1297 g, err = proc.FindGoroutine(d.target.Selected, command.GoroutineID) 1298 if err == nil { 1299 err = d.target.Selected.SwitchGoroutine(g) 1300 } 1301 withBreakpointInfo = false 1302 case api.Halt: 1303 // RequestManualStop already called 1304 withBreakpointInfo = false 1305 } 1306 1307 if err != nil { 1308 if pe, ok := err.(proc.ErrProcessExited); ok && command.Name != api.SwitchGoroutine && command.Name != api.SwitchThread { 1309 state := &api.DebuggerState{} 1310 state.Pid = d.target.Selected.Pid() 1311 state.Exited = true 1312 state.ExitStatus = pe.Status 1313 state.Err = pe 1314 return state, nil 1315 } 1316 return nil, err 1317 } 1318 state, stateErr := d.state(api.LoadConfigToProc(command.ReturnInfoLoadConfig), withBreakpointInfo) 1319 if stateErr != nil { 1320 return state, stateErr 1321 } 1322 for _, th := range state.Threads { 1323 if th.Breakpoint != nil && th.Breakpoint.TraceReturn { 1324 for _, v := range th.BreakpointInfo.Arguments { 1325 if (v.Flags & api.VariableReturnArgument) != 0 { 1326 th.ReturnValues = append(th.ReturnValues, v) 1327 } 1328 } 1329 } 1330 } 1331 if bp := state.CurrentThread.Breakpoint; bp != nil && isBpHitCondNotSatisfiable(bp) { 1332 bp.Disabled = true 1333 d.amendBreakpoint(bp) 1334 } 1335 return state, err 1336 } 1337 1338 func (d *Debugger) collectBreakpointInformation(apiThread *api.Thread, thread proc.Thread) error { 1339 if apiThread.Breakpoint == nil || apiThread.BreakpointInfo != nil { 1340 return nil 1341 } 1342 1343 bp := apiThread.Breakpoint 1344 bpi := &api.BreakpointInfo{} 1345 apiThread.BreakpointInfo = bpi 1346 1347 tgt := d.target.TargetForThread(thread.ThreadID()) 1348 1349 // If we're dealing with a stripped binary don't attempt to load more 1350 // information, we won't be able to. 1351 img := tgt.BinInfo().PCToImage(bp.Addr) 1352 if img != nil && img.Stripped() { 1353 return nil 1354 } 1355 1356 if bp.Goroutine { 1357 g, err := proc.GetG(thread) 1358 if err != nil { 1359 return err 1360 } 1361 bpi.Goroutine = api.ConvertGoroutine(tgt, g) 1362 } 1363 1364 if bp.Stacktrace > 0 { 1365 rawlocs, err := proc.ThreadStacktrace(tgt, thread, bp.Stacktrace) 1366 if err != nil { 1367 return err 1368 } 1369 bpi.Stacktrace, err = d.convertStacktrace(rawlocs, nil) 1370 if err != nil { 1371 return err 1372 } 1373 } 1374 1375 if len(bp.Variables) == 0 && bp.LoadArgs == nil && bp.LoadLocals == nil { 1376 // don't try to create goroutine scope if there is nothing to load 1377 return nil 1378 } 1379 1380 s, err := proc.GoroutineScope(tgt, thread) 1381 if err != nil { 1382 return err 1383 } 1384 1385 if len(bp.Variables) > 0 { 1386 bpi.Variables = make([]api.Variable, len(bp.Variables)) 1387 } 1388 for i := range bp.Variables { 1389 v, err := s.EvalExpression(bp.Variables[i], proc.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1}) 1390 if err != nil { 1391 bpi.Variables[i] = api.Variable{Name: bp.Variables[i], Unreadable: fmt.Sprintf("eval error: %v", err)} 1392 } else { 1393 bpi.Variables[i] = *api.ConvertVar(v) 1394 } 1395 } 1396 if bp.LoadArgs != nil { 1397 if vars, err := s.FunctionArguments(*api.LoadConfigToProc(bp.LoadArgs)); err == nil { 1398 bpi.Arguments = api.ConvertVars(vars) 1399 } 1400 } 1401 if bp.LoadLocals != nil { 1402 if locals, err := s.LocalVariables(*api.LoadConfigToProc(bp.LoadLocals)); err == nil { 1403 bpi.Locals = api.ConvertVars(locals) 1404 } 1405 } 1406 return nil 1407 } 1408 1409 // Sources returns a list of the source files for target binary. 1410 func (d *Debugger) Sources(filter string) ([]string, error) { 1411 d.targetMutex.Lock() 1412 defer d.targetMutex.Unlock() 1413 1414 regex, err := regexp.Compile(filter) 1415 if err != nil { 1416 return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) 1417 } 1418 1419 files := []string{} 1420 t := proc.ValidTargets{Group: d.target} 1421 for t.Next() { 1422 for _, f := range t.BinInfo().Sources { 1423 if regex.MatchString(f) { 1424 files = append(files, f) 1425 } 1426 } 1427 } 1428 sort.Strings(files) 1429 files = uniq(files) 1430 return files, nil 1431 } 1432 1433 func uniq(s []string) []string { 1434 if len(s) == 0 { 1435 return s 1436 } 1437 src, dst := 1, 1 1438 for src < len(s) { 1439 if s[src] != s[dst-1] { 1440 s[dst] = s[src] 1441 dst++ 1442 } 1443 src++ 1444 } 1445 return s[:dst] 1446 } 1447 1448 // Functions returns a list of functions in the target process. 1449 func (d *Debugger) Functions(filter string) ([]string, error) { 1450 d.targetMutex.Lock() 1451 defer d.targetMutex.Unlock() 1452 1453 regex, err := regexp.Compile(filter) 1454 if err != nil { 1455 return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) 1456 } 1457 1458 funcs := []string{} 1459 t := proc.ValidTargets{Group: d.target} 1460 for t.Next() { 1461 for _, f := range t.BinInfo().Functions { 1462 if regex.MatchString(f.Name) { 1463 funcs = append(funcs, f.Name) 1464 } 1465 } 1466 } 1467 sort.Strings(funcs) 1468 funcs = uniq(funcs) 1469 return funcs, nil 1470 } 1471 1472 // Types returns all type information in the binary. 1473 func (d *Debugger) Types(filter string) ([]string, error) { 1474 d.targetMutex.Lock() 1475 defer d.targetMutex.Unlock() 1476 1477 regex, err := regexp.Compile(filter) 1478 if err != nil { 1479 return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) 1480 } 1481 1482 r := []string{} 1483 1484 t := proc.ValidTargets{Group: d.target} 1485 for t.Next() { 1486 types, err := t.BinInfo().Types() 1487 if err != nil { 1488 return nil, err 1489 } 1490 1491 for _, typ := range types { 1492 if regex.MatchString(typ) { 1493 r = append(r, typ) 1494 } 1495 } 1496 } 1497 sort.Strings(r) 1498 r = uniq(r) 1499 1500 return r, nil 1501 } 1502 1503 // PackageVariables returns a list of package variables for the thread, 1504 // optionally regexp filtered using regexp described in 'filter'. 1505 func (d *Debugger) PackageVariables(filter string, cfg proc.LoadConfig) ([]*proc.Variable, error) { 1506 d.targetMutex.Lock() 1507 defer d.targetMutex.Unlock() 1508 p := d.target.Selected 1509 1510 regex, err := regexp.Compile(filter) 1511 if err != nil { 1512 return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) 1513 } 1514 1515 scope, err := proc.ThreadScope(p, p.CurrentThread()) 1516 if err != nil { 1517 return nil, err 1518 } 1519 pv, err := scope.PackageVariables(cfg) 1520 if err != nil { 1521 return nil, err 1522 } 1523 pvr := pv[:0] 1524 for i := range pv { 1525 if regex.MatchString(pv[i].Name) { 1526 pvr = append(pvr, pv[i]) 1527 } 1528 } 1529 return pvr, nil 1530 } 1531 1532 // ThreadRegisters returns registers of the specified thread. 1533 func (d *Debugger) ThreadRegisters(threadID int, floatingPoint bool) (*op.DwarfRegisters, error) { 1534 d.targetMutex.Lock() 1535 defer d.targetMutex.Unlock() 1536 1537 thread, found := d.target.Selected.FindThread(threadID) 1538 if !found { 1539 return nil, fmt.Errorf("couldn't find thread %d", threadID) 1540 } 1541 regs, err := thread.Registers() 1542 if err != nil { 1543 return nil, err 1544 } 1545 return d.target.Selected.BinInfo().Arch.RegistersToDwarfRegisters(0, regs), nil 1546 } 1547 1548 // ScopeRegisters returns registers for the specified scope. 1549 func (d *Debugger) ScopeRegisters(goid int64, frame, deferredCall int, floatingPoint bool) (*op.DwarfRegisters, error) { 1550 d.targetMutex.Lock() 1551 defer d.targetMutex.Unlock() 1552 1553 s, err := proc.ConvertEvalScope(d.target.Selected, goid, frame, deferredCall) 1554 if err != nil { 1555 return nil, err 1556 } 1557 return &s.Regs, nil 1558 } 1559 1560 // DwarfRegisterToString returns the name and value representation of the given register. 1561 func (d *Debugger) DwarfRegisterToString(i int, reg *op.DwarfRegister) (string, bool, string) { 1562 return d.target.Selected.BinInfo().Arch.DwarfRegisterToString(i, reg) 1563 } 1564 1565 // LocalVariables returns a list of the local variables. 1566 func (d *Debugger) LocalVariables(goid int64, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) { 1567 d.targetMutex.Lock() 1568 defer d.targetMutex.Unlock() 1569 1570 s, err := proc.ConvertEvalScope(d.target.Selected, goid, frame, deferredCall) 1571 if err != nil { 1572 return nil, err 1573 } 1574 return s.LocalVariables(cfg) 1575 } 1576 1577 // FunctionArguments returns the arguments to the current function. 1578 func (d *Debugger) FunctionArguments(goid int64, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) { 1579 d.targetMutex.Lock() 1580 defer d.targetMutex.Unlock() 1581 1582 s, err := proc.ConvertEvalScope(d.target.Selected, goid, frame, deferredCall) 1583 if err != nil { 1584 return nil, err 1585 } 1586 return s.FunctionArguments(cfg) 1587 } 1588 1589 // Function returns the current function. 1590 func (d *Debugger) Function(goid int64, frame, deferredCall int, cfg proc.LoadConfig) (*proc.Function, error) { 1591 d.targetMutex.Lock() 1592 defer d.targetMutex.Unlock() 1593 1594 s, err := proc.ConvertEvalScope(d.target.Selected, goid, frame, deferredCall) 1595 if err != nil { 1596 return nil, err 1597 } 1598 return s.Fn, nil 1599 } 1600 1601 // EvalVariableInScope will attempt to evaluate the 'expr' in the scope 1602 // corresponding to the given 'frame' on the goroutine identified by 'goid'. 1603 func (d *Debugger) EvalVariableInScope(goid int64, frame, deferredCall int, expr string, cfg proc.LoadConfig) (*proc.Variable, error) { 1604 d.targetMutex.Lock() 1605 defer d.targetMutex.Unlock() 1606 1607 s, err := proc.ConvertEvalScope(d.target.Selected, goid, frame, deferredCall) 1608 if err != nil { 1609 return nil, err 1610 } 1611 return s.EvalExpression(expr, cfg) 1612 } 1613 1614 // LoadResliced will attempt to 'reslice' a map, array or slice so that the values 1615 // up to cfg.MaxArrayValues children are loaded starting from index start. 1616 func (d *Debugger) LoadResliced(v *proc.Variable, start int, cfg proc.LoadConfig) (*proc.Variable, error) { 1617 d.targetMutex.Lock() 1618 defer d.targetMutex.Unlock() 1619 return v.LoadResliced(start, cfg) 1620 } 1621 1622 // SetVariableInScope will set the value of the variable represented by 1623 // 'symbol' to the value given, in the given scope. 1624 func (d *Debugger) SetVariableInScope(goid int64, frame, deferredCall int, symbol, value string) error { 1625 d.targetMutex.Lock() 1626 defer d.targetMutex.Unlock() 1627 1628 s, err := proc.ConvertEvalScope(d.target.Selected, goid, frame, deferredCall) 1629 if err != nil { 1630 return err 1631 } 1632 return s.SetVariable(symbol, value) 1633 } 1634 1635 // Goroutines will return a list of goroutines in the target process. 1636 func (d *Debugger) Goroutines(start, count int) ([]*proc.G, int, error) { 1637 d.targetMutex.Lock() 1638 defer d.targetMutex.Unlock() 1639 return proc.GoroutinesInfo(d.target.Selected, start, count) 1640 } 1641 1642 // FilterGoroutines returns the goroutines in gs that satisfy the specified filters. 1643 func (d *Debugger) FilterGoroutines(gs []*proc.G, filters []api.ListGoroutinesFilter) []*proc.G { 1644 if len(filters) == 0 { 1645 return gs 1646 } 1647 d.targetMutex.Lock() 1648 defer d.targetMutex.Unlock() 1649 r := []*proc.G{} 1650 for _, g := range gs { 1651 ok := true 1652 for i := range filters { 1653 if !matchGoroutineFilter(d.target.Selected, g, &filters[i]) { 1654 ok = false 1655 break 1656 } 1657 } 1658 if ok { 1659 r = append(r, g) 1660 } 1661 } 1662 return r 1663 } 1664 1665 func matchGoroutineFilter(tgt *proc.Target, g *proc.G, filter *api.ListGoroutinesFilter) bool { 1666 var val bool 1667 switch filter.Kind { 1668 default: 1669 fallthrough 1670 case api.GoroutineFieldNone: 1671 val = true 1672 case api.GoroutineCurrentLoc: 1673 val = matchGoroutineLocFilter(g.CurrentLoc, filter.Arg) 1674 case api.GoroutineUserLoc: 1675 val = matchGoroutineLocFilter(g.UserCurrent(), filter.Arg) 1676 case api.GoroutineGoLoc: 1677 val = matchGoroutineLocFilter(g.Go(), filter.Arg) 1678 case api.GoroutineStartLoc: 1679 val = matchGoroutineLocFilter(g.StartLoc(tgt), filter.Arg) 1680 case api.GoroutineLabel: 1681 idx := strings.Index(filter.Arg, "=") 1682 if idx >= 0 { 1683 val = g.Labels()[filter.Arg[:idx]] == filter.Arg[idx+1:] 1684 } else { 1685 _, val = g.Labels()[filter.Arg] 1686 } 1687 case api.GoroutineRunning: 1688 val = g.Thread != nil 1689 case api.GoroutineUser: 1690 val = !g.System(tgt) 1691 case api.GoroutineWaitingOnChannel: 1692 val = true // handled elsewhere 1693 } 1694 if filter.Negated { 1695 val = !val 1696 } 1697 return val 1698 } 1699 1700 func matchGoroutineLocFilter(loc proc.Location, arg string) bool { 1701 return strings.Contains(formatLoc(loc), arg) 1702 } 1703 1704 func formatLoc(loc proc.Location) string { 1705 fnname := "?" 1706 if loc.Fn != nil { 1707 fnname = loc.Fn.Name 1708 } 1709 return fmt.Sprintf("%s:%d in %s", loc.File, loc.Line, fnname) 1710 } 1711 1712 // GroupGoroutines divides goroutines in gs into groups as specified by 1713 // group.{GroupBy,GroupByKey}. A maximum of group.MaxGroupMembers are saved in 1714 // each group, but the total number of goroutines in each group is recorded. If 1715 // group.MaxGroups is set, then at most that many groups are returned. If some 1716 // groups end up being dropped because of this limit, the tooManyGroups return 1717 // value is set. 1718 // 1719 // The first return value represents the goroutines that have been included in 1720 // one of the returned groups (subject to the MaxGroupMembers and MaxGroups 1721 // limits). The second return value represents the groups. 1722 func (d *Debugger) GroupGoroutines(gs []*proc.G, group *api.GoroutineGroupingOptions) ([]*proc.G, []api.GoroutineGroup, bool) { 1723 if group.GroupBy == api.GoroutineFieldNone { 1724 return gs, nil, false 1725 } 1726 d.targetMutex.Lock() 1727 defer d.targetMutex.Unlock() 1728 1729 groupMembers := map[string][]*proc.G{} 1730 totals := map[string]int{} 1731 1732 for _, g := range gs { 1733 var key string 1734 switch group.GroupBy { 1735 case api.GoroutineCurrentLoc: 1736 key = formatLoc(g.CurrentLoc) 1737 case api.GoroutineUserLoc: 1738 key = formatLoc(g.UserCurrent()) 1739 case api.GoroutineGoLoc: 1740 key = formatLoc(g.Go()) 1741 case api.GoroutineStartLoc: 1742 key = formatLoc(g.StartLoc(d.target.Selected)) 1743 case api.GoroutineLabel: 1744 key = fmt.Sprintf("%s=%s", group.GroupByKey, g.Labels()[group.GroupByKey]) 1745 case api.GoroutineRunning: 1746 key = fmt.Sprintf("running=%v", g.Thread != nil) 1747 case api.GoroutineUser: 1748 key = fmt.Sprintf("user=%v", !g.System(d.target.Selected)) 1749 } 1750 if len(groupMembers[key]) < group.MaxGroupMembers { 1751 groupMembers[key] = append(groupMembers[key], g) 1752 } 1753 totals[key]++ 1754 } 1755 1756 keys := make([]string, 0, len(groupMembers)) 1757 for key := range groupMembers { 1758 keys = append(keys, key) 1759 } 1760 sort.Strings(keys) 1761 1762 tooManyGroups := false 1763 gsout := []*proc.G{} 1764 groups := []api.GoroutineGroup{} 1765 for _, key := range keys { 1766 if group.MaxGroups > 0 && len(groups) >= group.MaxGroups { 1767 tooManyGroups = true 1768 break 1769 } 1770 groups = append(groups, api.GoroutineGroup{Name: key, Offset: len(gsout), Count: len(groupMembers[key]), Total: totals[key]}) 1771 gsout = append(gsout, groupMembers[key]...) 1772 } 1773 return gsout, groups, tooManyGroups 1774 } 1775 1776 // Stacktrace returns a list of Stackframes for the given goroutine. The 1777 // length of the returned list will be min(stack_len, depth). 1778 // If 'full' is true, then local vars, function args, etc will be returned as well. 1779 func (d *Debugger) Stacktrace(goroutineID int64, depth int, opts api.StacktraceOptions) ([]proc.Stackframe, error) { 1780 d.targetMutex.Lock() 1781 defer d.targetMutex.Unlock() 1782 1783 if _, err := d.target.Valid(); err != nil { 1784 return nil, err 1785 } 1786 1787 g, err := proc.FindGoroutine(d.target.Selected, goroutineID) 1788 if err != nil { 1789 return nil, err 1790 } 1791 1792 if g == nil { 1793 return proc.ThreadStacktrace(d.target.Selected, d.target.Selected.CurrentThread(), depth) 1794 } else { 1795 return proc.GoroutineStacktrace(d.target.Selected, g, depth, proc.StacktraceOptions(opts)) 1796 } 1797 } 1798 1799 // Ancestors returns the stacktraces for the ancestors of a goroutine. 1800 func (d *Debugger) Ancestors(goroutineID int64, numAncestors, depth int) ([]api.Ancestor, error) { 1801 d.targetMutex.Lock() 1802 defer d.targetMutex.Unlock() 1803 1804 if _, err := d.target.Valid(); err != nil { 1805 return nil, err 1806 } 1807 1808 g, err := proc.FindGoroutine(d.target.Selected, goroutineID) 1809 if err != nil { 1810 return nil, err 1811 } 1812 if g == nil { 1813 return nil, errors.New("no selected goroutine") 1814 } 1815 1816 ancestors, err := proc.Ancestors(d.target.Selected, g, numAncestors) 1817 if err != nil { 1818 return nil, err 1819 } 1820 1821 r := make([]api.Ancestor, len(ancestors)) 1822 for i := range ancestors { 1823 r[i].ID = ancestors[i].ID 1824 if ancestors[i].Unreadable != nil { 1825 r[i].Unreadable = ancestors[i].Unreadable.Error() 1826 continue 1827 } 1828 frames, err := ancestors[i].Stack(depth) 1829 if err != nil { 1830 r[i].Unreadable = fmt.Sprintf("could not read ancestor stacktrace: %v", err) 1831 continue 1832 } 1833 r[i].Stack, err = d.convertStacktrace(frames, nil) 1834 if err != nil { 1835 r[i].Unreadable = fmt.Sprintf("could not read ancestor stacktrace: %v", err) 1836 } 1837 } 1838 return r, nil 1839 } 1840 1841 // ConvertStacktrace converts a slice of proc.Stackframe into a slice of 1842 // api.Stackframe, loading local variables and arguments of each frame if 1843 // cfg is not nil. 1844 func (d *Debugger) ConvertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadConfig) ([]api.Stackframe, error) { 1845 d.targetMutex.Lock() 1846 defer d.targetMutex.Unlock() 1847 return d.convertStacktrace(rawlocs, cfg) 1848 } 1849 1850 func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadConfig) ([]api.Stackframe, error) { 1851 locations := make([]api.Stackframe, 0, len(rawlocs)) 1852 for i := range rawlocs { 1853 frame := api.Stackframe{ 1854 Location: api.ConvertLocation(rawlocs[i].Call), 1855 1856 FrameOffset: rawlocs[i].FrameOffset(), 1857 FramePointerOffset: rawlocs[i].FramePointerOffset(), 1858 1859 Defers: d.convertDefers(rawlocs[i].Defers), 1860 1861 Bottom: rawlocs[i].Bottom, 1862 } 1863 if rawlocs[i].Err != nil { 1864 frame.Err = rawlocs[i].Err.Error() 1865 } 1866 if cfg != nil && rawlocs[i].Current.Fn != nil { 1867 var err error 1868 scope := proc.FrameToScope(d.target.Selected, d.target.Selected.Memory(), nil, 0, rawlocs[i:]...) 1869 locals, err := scope.LocalVariables(*cfg) 1870 if err != nil { 1871 return nil, err 1872 } 1873 arguments, err := scope.FunctionArguments(*cfg) 1874 if err != nil { 1875 return nil, err 1876 } 1877 1878 frame.Locals = api.ConvertVars(locals) 1879 frame.Arguments = api.ConvertVars(arguments) 1880 } 1881 locations = append(locations, frame) 1882 } 1883 1884 return locations, nil 1885 } 1886 1887 func (d *Debugger) convertDefers(defers []*proc.Defer) []api.Defer { 1888 r := make([]api.Defer, len(defers)) 1889 for i := range defers { 1890 ddf, ddl, ddfn := defers[i].DeferredFunc(d.target.Selected) 1891 drf, drl, drfn := d.target.Selected.BinInfo().PCToLine(defers[i].DeferPC) 1892 1893 if defers[i].Unreadable != nil { 1894 r[i].Unreadable = defers[i].Unreadable.Error() 1895 } else { 1896 var entry uint64 = defers[i].DeferPC 1897 if ddfn != nil { 1898 entry = ddfn.Entry 1899 } 1900 r[i] = api.Defer{ 1901 DeferredLoc: api.ConvertLocation(proc.Location{ 1902 PC: entry, 1903 File: ddf, 1904 Line: ddl, 1905 Fn: ddfn, 1906 }), 1907 DeferLoc: api.ConvertLocation(proc.Location{ 1908 PC: defers[i].DeferPC, 1909 File: drf, 1910 Line: drl, 1911 Fn: drfn, 1912 }), 1913 SP: defers[i].SP, 1914 } 1915 } 1916 1917 } 1918 1919 return r 1920 } 1921 1922 // CurrentPackage returns the fully qualified name of the 1923 // package corresponding to the function location of the 1924 // current thread. 1925 func (d *Debugger) CurrentPackage() (string, error) { 1926 d.targetMutex.Lock() 1927 defer d.targetMutex.Unlock() 1928 1929 if _, err := d.target.Valid(); err != nil { 1930 return "", err 1931 } 1932 loc, err := d.target.Selected.CurrentThread().Location() 1933 if err != nil { 1934 return "", err 1935 } 1936 if loc.Fn == nil { 1937 return "", fmt.Errorf("unable to determine current package due to unspecified function location") 1938 } 1939 return loc.Fn.PackageName(), nil 1940 } 1941 1942 // FindLocation will find the location specified by 'locStr'. 1943 func (d *Debugger) FindLocation(goid int64, frame, deferredCall int, locStr string, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, string, error) { 1944 d.targetMutex.Lock() 1945 defer d.targetMutex.Unlock() 1946 1947 if _, err := d.target.Valid(); err != nil { 1948 return nil, "", err 1949 } 1950 1951 loc, err := locspec.Parse(locStr) 1952 if err != nil { 1953 return nil, "", err 1954 } 1955 1956 return d.findLocation(goid, frame, deferredCall, locStr, loc, includeNonExecutableLines, substitutePathRules) 1957 } 1958 1959 // FindLocationSpec will find the location specified by 'locStr' and 'locSpec'. 1960 // 'locSpec' should be the result of calling 'locspec.Parse(locStr)'. 'locStr' 1961 // is also passed, because it made be used to broaden the search criteria, if 1962 // the parsed result did not find anything. 1963 func (d *Debugger) FindLocationSpec(goid int64, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { 1964 d.targetMutex.Lock() 1965 defer d.targetMutex.Unlock() 1966 1967 if _, err := d.target.Valid(); err != nil { 1968 return nil, err 1969 } 1970 1971 locs, _, err := d.findLocation(goid, frame, deferredCall, locStr, locSpec, includeNonExecutableLines, substitutePathRules) 1972 return locs, err 1973 } 1974 1975 func (d *Debugger) findLocation(goid int64, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, string, error) { 1976 locations := []api.Location{} 1977 t := proc.ValidTargets{Group: d.target} 1978 subst := "" 1979 for t.Next() { 1980 pid := t.Pid() 1981 s, _ := proc.ConvertEvalScope(t.Target, goid, frame, deferredCall) 1982 locs, s1, err := locSpec.Find(t.Target, d.processArgs, s, locStr, includeNonExecutableLines, substitutePathRules) 1983 if s1 != "" { 1984 subst = s1 1985 } 1986 if err != nil { 1987 return nil, "", err 1988 } 1989 for i := range locs { 1990 if locs[i].PC == 0 { 1991 continue 1992 } 1993 file, line, fn := t.BinInfo().PCToLine(locs[i].PC) 1994 locs[i].File = file 1995 locs[i].Line = line 1996 locs[i].Function = api.ConvertFunction(fn) 1997 locs[i].PCPids = make([]int, len(locs[i].PCs)) 1998 for j := range locs[i].PCs { 1999 locs[i].PCPids[j] = pid 2000 } 2001 } 2002 locations = append(locations, locs...) 2003 } 2004 return locations, subst, nil 2005 } 2006 2007 // Disassemble code between startPC and endPC. 2008 // if endPC == 0 it will find the function containing startPC and disassemble the whole function. 2009 func (d *Debugger) Disassemble(goroutineID int64, addr1, addr2 uint64) ([]proc.AsmInstruction, error) { 2010 d.targetMutex.Lock() 2011 defer d.targetMutex.Unlock() 2012 2013 if _, err := d.target.Valid(); err != nil { 2014 return nil, err 2015 } 2016 2017 if addr2 == 0 { 2018 fn := d.target.Selected.BinInfo().PCToFunc(addr1) 2019 if fn == nil { 2020 return nil, fmt.Errorf("address %#x does not belong to any function", addr1) 2021 } 2022 addr1 = fn.Entry 2023 addr2 = fn.End 2024 } 2025 2026 g, err := proc.FindGoroutine(d.target.Selected, goroutineID) 2027 if err != nil { 2028 return nil, err 2029 } 2030 2031 curthread := d.target.Selected.CurrentThread() 2032 if g != nil && g.Thread != nil { 2033 curthread = g.Thread 2034 } 2035 regs, _ := curthread.Registers() 2036 2037 return proc.Disassemble(d.target.Selected.Memory(), regs, d.target.Selected.Breakpoints(), d.target.Selected.BinInfo(), addr1, addr2) 2038 } 2039 2040 func (d *Debugger) AsmInstructionText(inst *proc.AsmInstruction, flavour proc.AssemblyFlavour) string { 2041 d.targetMutex.Lock() 2042 defer d.targetMutex.Unlock() 2043 return inst.Text(flavour, d.target.Selected.BinInfo()) 2044 } 2045 2046 // Recorded returns true if the target is a recording. 2047 func (d *Debugger) Recorded() (recorded bool, tracedir string) { 2048 d.targetMutex.Lock() 2049 defer d.targetMutex.Unlock() 2050 return d.target.Recorded() 2051 } 2052 2053 // FindThreadReturnValues returns the return values of the function that 2054 // the thread of the given 'id' just stepped out of. 2055 func (d *Debugger) FindThreadReturnValues(id int, cfg proc.LoadConfig) ([]*proc.Variable, error) { 2056 d.targetMutex.Lock() 2057 defer d.targetMutex.Unlock() 2058 2059 if _, err := d.target.Valid(); err != nil { 2060 return nil, err 2061 } 2062 2063 thread, found := d.target.Selected.FindThread(id) 2064 if !found { 2065 return nil, fmt.Errorf("could not find thread %d", id) 2066 } 2067 2068 return thread.Common().ReturnValues(cfg), nil 2069 } 2070 2071 // Checkpoint will set a checkpoint specified by the locspec. 2072 func (d *Debugger) Checkpoint(where string) (int, error) { 2073 d.targetMutex.Lock() 2074 defer d.targetMutex.Unlock() 2075 return d.target.Checkpoint(where) 2076 } 2077 2078 // Checkpoints will return a list of checkpoints. 2079 func (d *Debugger) Checkpoints() ([]proc.Checkpoint, error) { 2080 d.targetMutex.Lock() 2081 defer d.targetMutex.Unlock() 2082 return d.target.Checkpoints() 2083 } 2084 2085 // ClearCheckpoint will clear the checkpoint of the given ID. 2086 func (d *Debugger) ClearCheckpoint(id int) error { 2087 d.targetMutex.Lock() 2088 defer d.targetMutex.Unlock() 2089 return d.target.ClearCheckpoint(id) 2090 } 2091 2092 // ListDynamicLibraries returns a list of loaded dynamic libraries. 2093 func (d *Debugger) ListDynamicLibraries() []*proc.Image { 2094 d.targetMutex.Lock() 2095 defer d.targetMutex.Unlock() 2096 return d.target.Selected.BinInfo().Images[1:] // skips the first image because it's the executable file 2097 2098 } 2099 2100 // ExamineMemory returns the raw memory stored at the given address. 2101 // The amount of data to be read is specified by length. 2102 // This function will return an error if it reads less than `length` bytes. 2103 func (d *Debugger) ExamineMemory(address uint64, length int) ([]byte, error) { 2104 d.targetMutex.Lock() 2105 defer d.targetMutex.Unlock() 2106 2107 mem := d.target.Selected.Memory() 2108 data := make([]byte, length) 2109 n, err := mem.ReadMemory(data, address) 2110 if err != nil { 2111 return nil, err 2112 } 2113 if length != n { 2114 return nil, errors.New("the specific range has exceeded readable area") 2115 } 2116 return data, nil 2117 } 2118 2119 func (d *Debugger) GetVersion(out *api.GetVersionOut) error { 2120 if d.config.CoreFile != "" { 2121 if d.config.Backend == "rr" { 2122 out.Backend = "rr" 2123 } else { 2124 out.Backend = "core" 2125 } 2126 } else { 2127 if d.config.Backend == "default" { 2128 if runtime.GOOS == "darwin" { 2129 out.Backend = "lldb" 2130 } else { 2131 out.Backend = "native" 2132 } 2133 } else { 2134 out.Backend = d.config.Backend 2135 } 2136 } 2137 2138 if !d.isRecording() && !d.IsRunning() { 2139 out.TargetGoVersion = d.target.Selected.BinInfo().Producer() 2140 } 2141 2142 out.MinSupportedVersionOfGo = fmt.Sprintf("%d.%d.0", goversion.MinSupportedVersionOfGoMajor, goversion.MinSupportedVersionOfGoMinor) 2143 out.MaxSupportedVersionOfGo = fmt.Sprintf("%d.%d.0", goversion.MaxSupportedVersionOfGoMajor, goversion.MaxSupportedVersionOfGoMinor) 2144 2145 return nil 2146 } 2147 2148 // ListPackagesBuildInfo returns the list of packages used by the program along with 2149 // the directory where each package was compiled and optionally the list of 2150 // files constituting the package. 2151 func (d *Debugger) ListPackagesBuildInfo(includeFiles bool) []*proc.PackageBuildInfo { 2152 d.targetMutex.Lock() 2153 defer d.targetMutex.Unlock() 2154 return d.target.Selected.BinInfo().ListPackagesBuildInfo(includeFiles) 2155 } 2156 2157 // StopRecording stops a recording (if one is in progress) 2158 func (d *Debugger) StopRecording() error { 2159 d.recordMutex.Lock() 2160 defer d.recordMutex.Unlock() 2161 if d.stopRecording == nil { 2162 return ErrNotRecording 2163 } 2164 return d.stopRecording() 2165 } 2166 2167 // StopReason returns the reason the reason why the target process is stopped. 2168 // A process could be stopped for multiple simultaneous reasons, in which 2169 // case only one will be reported. 2170 func (d *Debugger) StopReason() proc.StopReason { 2171 d.targetMutex.Lock() 2172 defer d.targetMutex.Unlock() 2173 return d.target.Selected.StopReason 2174 } 2175 2176 // LockTarget acquires the target mutex. 2177 func (d *Debugger) LockTarget() { 2178 d.targetMutex.Lock() 2179 } 2180 2181 // UnlockTarget releases the target mutex. 2182 func (d *Debugger) UnlockTarget() { 2183 d.targetMutex.Unlock() 2184 } 2185 2186 // DumpStart starts a core dump to dest. 2187 func (d *Debugger) DumpStart(dest string) error { 2188 d.targetMutex.Lock() 2189 // targetMutex will only be unlocked when the dump is done 2190 2191 //TODO(aarzilli): what do we do if the user switches to a different target after starting a dump but before it's finished? 2192 2193 if !d.target.CanDump { 2194 d.targetMutex.Unlock() 2195 return ErrCoreDumpNotSupported 2196 } 2197 2198 d.dumpState.Mutex.Lock() 2199 defer d.dumpState.Mutex.Unlock() 2200 2201 if d.dumpState.Dumping { 2202 d.targetMutex.Unlock() 2203 return ErrCoreDumpInProgress 2204 } 2205 2206 fh, err := os.Create(dest) 2207 if err != nil { 2208 d.targetMutex.Unlock() 2209 return err 2210 } 2211 2212 d.dumpState.Dumping = true 2213 d.dumpState.AllDone = false 2214 d.dumpState.Canceled = false 2215 d.dumpState.DoneChan = make(chan struct{}) 2216 d.dumpState.ThreadsDone = 0 2217 d.dumpState.ThreadsTotal = 0 2218 d.dumpState.MemDone = 0 2219 d.dumpState.MemTotal = 0 2220 d.dumpState.Err = nil 2221 go func() { 2222 defer d.targetMutex.Unlock() 2223 d.target.Selected.Dump(fh, 0, &d.dumpState) 2224 }() 2225 2226 return nil 2227 } 2228 2229 // DumpWait waits for the dump to finish, or for the duration of wait. 2230 // Returns the state of the dump. 2231 // If wait == 0 returns immediately. 2232 func (d *Debugger) DumpWait(wait time.Duration) *proc.DumpState { 2233 d.dumpState.Mutex.Lock() 2234 if !d.dumpState.Dumping { 2235 d.dumpState.Mutex.Unlock() 2236 return &d.dumpState 2237 } 2238 d.dumpState.Mutex.Unlock() 2239 2240 if wait > 0 { 2241 alarm := time.After(wait) 2242 select { 2243 case <-alarm: 2244 case <-d.dumpState.DoneChan: 2245 } 2246 } 2247 2248 return &d.dumpState 2249 } 2250 2251 // DumpCancel cancels a dump in progress 2252 func (d *Debugger) DumpCancel() error { 2253 d.dumpState.Mutex.Lock() 2254 d.dumpState.Canceled = true 2255 d.dumpState.Mutex.Unlock() 2256 return nil 2257 } 2258 2259 func (d *Debugger) Target() *proc.Target { 2260 return d.target.Selected 2261 } 2262 2263 func (d *Debugger) TargetGroup() *proc.TargetGroup { 2264 return d.target 2265 } 2266 2267 func (d *Debugger) BuildID() string { 2268 return d.target.Selected.BinInfo().BuildID 2269 } 2270 2271 func (d *Debugger) AttachPid() int { 2272 return d.config.AttachPid 2273 } 2274 2275 func (d *Debugger) GetBufferedTracepoints() []api.TracepointResult { 2276 traces := d.target.Selected.GetBufferedTracepoints() 2277 if traces == nil { 2278 return nil 2279 } 2280 results := make([]api.TracepointResult, len(traces)) 2281 for i, trace := range traces { 2282 results[i].IsRet = trace.IsRet 2283 2284 f, l, fn := d.target.Selected.BinInfo().PCToLine(uint64(trace.FnAddr)) 2285 2286 results[i].FunctionName = fn.Name 2287 results[i].Line = l 2288 results[i].File = f 2289 results[i].GoroutineID = trace.GoroutineID 2290 2291 for _, p := range trace.InputParams { 2292 results[i].InputParams = append(results[i].InputParams, *api.ConvertVar(p)) 2293 } 2294 for _, p := range trace.ReturnParams { 2295 results[i].ReturnParams = append(results[i].ReturnParams, *api.ConvertVar(p)) 2296 } 2297 } 2298 return results 2299 } 2300 2301 // FollowExec enabled or disables follow exec mode. 2302 func (d *Debugger) FollowExec(enabled bool, regex string) error { 2303 d.targetMutex.Lock() 2304 defer d.targetMutex.Unlock() 2305 return d.target.FollowExec(enabled, regex) 2306 } 2307 2308 // FollowExecEnabled returns true if follow exec mode is enabled. 2309 func (d *Debugger) FollowExecEnabled() bool { 2310 d.targetMutex.Lock() 2311 defer d.targetMutex.Unlock() 2312 return d.target.FollowExecEnabled() 2313 } 2314 2315 func (d *Debugger) SetDebugInfoDirectories(v []string) { 2316 d.recordMutex.Lock() 2317 defer d.recordMutex.Unlock() 2318 it := proc.ValidTargets{Group: d.target} 2319 for it.Next() { 2320 it.BinInfo().DebugInfoDirectories = v 2321 } 2322 } 2323 2324 func (d *Debugger) DebugInfoDirectories() []string { 2325 d.recordMutex.Lock() 2326 defer d.recordMutex.Unlock() 2327 return d.target.Selected.BinInfo().DebugInfoDirectories 2328 } 2329 2330 // ChanGoroutines returns the list of goroutines waiting on the channel specified by expr. 2331 func (d *Debugger) ChanGoroutines(goid int64, frame, deferredCall int, expr string, start, count int) ([]*proc.G, error) { 2332 d.targetMutex.Lock() 2333 defer d.targetMutex.Unlock() 2334 s, err := proc.ConvertEvalScope(d.target.Selected, goid, frame, deferredCall) 2335 if err != nil { 2336 return nil, err 2337 } 2338 2339 goids, err := s.ChanGoroutines(expr, start, count) 2340 if err != nil { 2341 return nil, err 2342 } 2343 2344 gs := make([]*proc.G, len(goids)) 2345 for i := range goids { 2346 g, err := proc.FindGoroutine(d.target.Selected, goids[i]) 2347 if g == nil { 2348 g = &proc.G{Unreadable: err} 2349 } 2350 gs[i] = g 2351 } 2352 return gs, nil 2353 } 2354 2355 func go11DecodeErrorCheck(err error) error { 2356 if _, isdecodeerr := err.(dwarf.DecodeError); !isdecodeerr { 2357 return err 2358 } 2359 2360 gover, ok := goversion.Installed() 2361 if !ok || !gover.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 11, Rev: -1}) || goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 2362 return err 2363 } 2364 2365 return fmt.Errorf("executables built by Go 1.11 or later need Delve built by Go 1.11 or later") 2366 } 2367 2368 const NoDebugWarning string = "debuggee must not be built with 'go run' or -ldflags='-s -w', which strip debug info" 2369 2370 func noDebugErrorWarning(err error) error { 2371 if _, isdecodeerr := err.(dwarf.DecodeError); isdecodeerr || strings.Contains(err.Error(), "could not open debug info") { 2372 return fmt.Errorf("%s - %s", err.Error(), NoDebugWarning) 2373 } 2374 return err 2375 } 2376 2377 func verifyBinaryFormat(exePath string) (string, error) { 2378 fullpath, err := filepath.Abs(exePath) 2379 if err != nil { 2380 return "", err 2381 } 2382 2383 f, err := os.Open(fullpath) 2384 if err != nil { 2385 return "", err 2386 } 2387 defer f.Close() 2388 2389 // Skip this check on Windows. 2390 // TODO(derekparker) exec.LookPath looks for valid Windows extensions. 2391 // We don't create our binaries with valid extensions, even though we should. 2392 // Skip this check for now. 2393 if runtime.GOOS != "windows" { 2394 _, err = exec.LookPath(fullpath) 2395 if err != nil { 2396 return "", api.ErrNotExecutable 2397 } 2398 } 2399 2400 // check that the binary format is what we expect for the host system 2401 var exe io.Closer 2402 switch runtime.GOOS { 2403 case "darwin": 2404 exe, err = macho.NewFile(f) 2405 case "linux", "freebsd": 2406 exe, err = elf.NewFile(f) 2407 case "windows": 2408 exe, err = pe.NewFile(f) 2409 default: 2410 panic("attempting to open file Delve cannot parse") 2411 } 2412 2413 if err != nil { 2414 return "", api.ErrNotExecutable 2415 } 2416 exe.Close() 2417 return fullpath, nil 2418 } 2419 2420 var attachErrorMessage = attachErrorMessageDefault 2421 2422 func attachErrorMessageDefault(pid int, err error) error { 2423 return fmt.Errorf("could not attach to pid %d: %s", pid, err) 2424 }