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