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