github.com/neilgarb/delve@v1.9.2-nobreaks/pkg/proc/gdbserial/gdbserver.go (about) 1 // This file and its companion gdbserver_conn implement a target.Interface 2 // backed by a connection to a debugger speaking the "Gdb Remote Serial 3 // Protocol". 4 // 5 // The "Gdb Remote Serial Protocol" is a low level debugging protocol 6 // originally designed so that gdb could be used to debug programs running 7 // in embedded environments but it was later extended to support programs 8 // running on any environment and a variety of debuggers support it: 9 // gdbserver, lldb-server, macOS's debugserver and rr. 10 // 11 // The protocol is specified at: 12 // https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html 13 // with additional documentation for lldb specific extensions described at: 14 // https://github.com/llvm/llvm-project/blob/main/lldb/docs/lldb-gdb-remote.txt 15 // 16 // Terminology: 17 // * inferior: the program we are trying to debug 18 // * stub: the debugger on the other side of the protocol's connection (for 19 // example lldb-server) 20 // * gdbserver: stub version of gdb 21 // * lldb-server: stub version of lldb 22 // * debugserver: a different stub version of lldb, installed with lldb on 23 // macOS. 24 // * mozilla rr: a stub that records the full execution of a program 25 // and can then play it back. 26 // 27 // Implementations of the protocol vary wildly between stubs, while there is 28 // a command to query the stub about supported features (qSupported) this 29 // only covers *some* of the more recent additions to the protocol and most 30 // of the older packets are optional and *not* implemented by all stubs. 31 // For example gdbserver implements 'g' (read all registers) but not 'p' 32 // (read single register) while lldb-server implements 'p' but not 'g'. 33 // 34 // The protocol is also underspecified with regards to how the stub should 35 // handle a multithreaded inferior. Its default mode of operation is 36 // "all-stop mode", when a thread hits a breakpoint all other threads are 37 // also stopped. But the protocol doesn't say what happens if a second 38 // thread hits a breakpoint while the stub is in the process of stopping all 39 // other threads. 40 // 41 // In practice the stub is allowed to swallow the second breakpoint hit or 42 // to return it at a later time. If the stub chooses the latter behavior 43 // (like gdbserver does) it is allowed to return delayed events on *any* 44 // vCont packet. This is incredibly inconvenient since if we get notified 45 // about a delayed breakpoint while we are trying to singlestep another 46 // thread it's impossible to know when the singlestep we requested ended. 47 // 48 // What this means is that gdbserver can only be supported for multithreaded 49 // inferiors by selecting non-stop mode, which behaves in a markedly 50 // different way from all-stop mode and isn't supported by anything except 51 // gdbserver. 52 // 53 // lldb-server/debugserver takes a different approach, only the first stop 54 // event is reported, if any other event happens "simultaneously" they are 55 // suppressed by the stub and the debugger can query for them using 56 // qThreadStopInfo. This is much easier for us to implement and the 57 // implementation gracefully degrades to the case where qThreadStopInfo is 58 // unavailable but the inferior is run in single threaded mode. 59 // 60 // Therefore the following code will assume lldb-server-like behavior. 61 62 package gdbserial 63 64 import ( 65 "bytes" 66 "debug/macho" 67 "encoding/binary" 68 "errors" 69 "fmt" 70 "net" 71 "os" 72 "os/exec" 73 "path/filepath" 74 "runtime" 75 "strconv" 76 "strings" 77 "sync" 78 "time" 79 80 "github.com/go-delve/delve/pkg/dwarf/op" 81 "github.com/go-delve/delve/pkg/elfwriter" 82 "github.com/go-delve/delve/pkg/logflags" 83 "github.com/go-delve/delve/pkg/proc" 84 "github.com/go-delve/delve/pkg/proc/internal/ebpf" 85 "github.com/go-delve/delve/pkg/proc/linutil" 86 "github.com/go-delve/delve/pkg/proc/macutil" 87 isatty "github.com/mattn/go-isatty" 88 ) 89 90 const ( 91 gdbWireFullStopPacket = false 92 gdbWireMaxLen = 120 93 94 maxTransmitAttempts = 3 // number of retransmission attempts on failed checksum 95 initialInputBufferSize = 2048 // size of the input buffer for gdbConn 96 97 debugServerEnvVar = "DELVE_DEBUGSERVER_PATH" // use this environment variable to override the path to debugserver used by Launch/Attach 98 ) 99 100 const heartbeatInterval = 10 * time.Second 101 102 // Relative to $(xcode-select --print-path)/../ 103 // xcode-select typically returns the path to the Developer directory, which is a sibling to SharedFrameworks. 104 var debugserverXcodeRelativeExecutablePath = "SharedFrameworks/LLDB.framework/Versions/A/Resources/debugserver" 105 106 var debugserverExecutablePaths = []string{ 107 "debugserver", 108 "/Library/Developer/CommandLineTools/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/debugserver", 109 // Function returns the active developer directory provided by xcode-select to compute a debugserver path. 110 func() string { 111 if _, err := exec.LookPath("xcode-select"); err != nil { 112 return "" 113 } 114 115 stdout, err := exec.Command("xcode-select", "--print-path").Output() 116 if err != nil { 117 return "" 118 } 119 120 xcodePath := strings.TrimSpace(string(stdout)) 121 if xcodePath == "" { 122 return "" 123 } 124 125 // xcode-select prints the path to the active Developer directory, which is typically a sibling to SharedFrameworks. 126 return filepath.Join(xcodePath, "..", debugserverXcodeRelativeExecutablePath) 127 }(), 128 } 129 130 // ErrDirChange is returned when trying to change execution direction 131 // while there are still internal breakpoints set. 132 var ErrDirChange = errors.New("direction change with internal breakpoints") 133 134 // ErrStartCallInjectionBackwards is returned when trying to start a call 135 // injection while the recording is being run backwards. 136 var ErrStartCallInjectionBackwards = errors.New("can not start a call injection while running backwards") 137 138 var checkCanUnmaskSignalsOnce sync.Once 139 var canUnmaskSignalsCached bool 140 141 // gdbProcess implements proc.Process using a connection to a debugger stub 142 // that understands Gdb Remote Serial Protocol. 143 type gdbProcess struct { 144 bi *proc.BinaryInfo 145 regnames *gdbRegnames 146 conn gdbConn 147 148 threads map[int]*gdbThread 149 currentThread *gdbThread 150 151 exited, detached bool 152 almostExited bool // true if 'rr' has sent its synthetic SIGKILL 153 ctrlC bool // ctrl-c was sent to stop inferior 154 155 breakpoints proc.BreakpointMap 156 157 gcmdok bool // true if the stub supports g and (maybe) G commands 158 _Gcmdok bool // true if the stub supports G command 159 threadStopInfo bool // true if the stub supports qThreadStopInfo 160 tracedir string // if attached to rr the path to the trace directory 161 162 loadGInstrAddr uint64 // address of the g loading instruction, zero if we couldn't allocate it 163 164 breakpointKind int // breakpoint kind to pass to 'z' and 'Z' when creating software breakpoints 165 166 process *os.Process 167 waitChan chan *os.ProcessState 168 169 onDetach func() // called after a successful detach 170 } 171 172 var _ proc.RecordingManipulationInternal = &gdbProcess{} 173 174 // gdbThread represents an operating system thread. 175 type gdbThread struct { 176 ID int 177 strID string 178 regs gdbRegisters 179 CurrentBreakpoint proc.BreakpointState 180 p *gdbProcess 181 sig uint8 // signal received by thread after last stop 182 setbp bool // thread was stopped because of a breakpoint 183 watchAddr uint64 // if > 0 this is the watchpoint address 184 common proc.CommonThread 185 } 186 187 // ErrBackendUnavailable is returned when the stub program can not be found. 188 type ErrBackendUnavailable struct{} 189 190 func (err *ErrBackendUnavailable) Error() string { 191 return "backend unavailable" 192 } 193 194 // gdbRegisters represents the current value of the registers of a thread. 195 // The storage space for all the registers is allocated as a single memory 196 // block in buf, the value field inside an individual gdbRegister will be a 197 // slice of the global buf field. 198 type gdbRegisters struct { 199 regs map[string]gdbRegister 200 regsInfo []gdbRegisterInfo 201 tls uint64 202 gaddr uint64 203 hasgaddr bool 204 buf []byte 205 arch *proc.Arch 206 regnames *gdbRegnames 207 } 208 209 type gdbRegister struct { 210 value []byte 211 regnum int 212 213 ignoreOnWrite bool 214 } 215 216 // gdbRegname records names of important CPU registers 217 type gdbRegnames struct { 218 PC, SP, BP, CX, FsBase string 219 } 220 221 // newProcess creates a new Process instance. 222 // If process is not nil it is the stub's process and will be killed after 223 // Detach. 224 // Use Listen, Dial or Connect to complete connection. 225 func newProcess(process *os.Process) *gdbProcess { 226 logger := logflags.GdbWireLogger() 227 p := &gdbProcess{ 228 conn: gdbConn{ 229 maxTransmitAttempts: maxTransmitAttempts, 230 inbuf: make([]byte, 0, initialInputBufferSize), 231 direction: proc.Forward, 232 log: logger, 233 goarch: runtime.GOARCH, 234 goos: runtime.GOOS, 235 }, 236 threads: make(map[int]*gdbThread), 237 bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH), 238 regnames: new(gdbRegnames), 239 breakpoints: proc.NewBreakpointMap(), 240 gcmdok: true, 241 threadStopInfo: true, 242 process: process, 243 } 244 245 switch p.bi.Arch.Name { 246 default: 247 fallthrough 248 case "amd64": 249 p.breakpointKind = 1 250 case "arm64": 251 p.breakpointKind = 4 252 } 253 254 p.regnames.PC = registerName(p.bi.Arch, p.bi.Arch.PCRegNum) 255 p.regnames.SP = registerName(p.bi.Arch, p.bi.Arch.SPRegNum) 256 p.regnames.BP = registerName(p.bi.Arch, p.bi.Arch.BPRegNum) 257 258 switch p.bi.Arch.Name { 259 case "arm64": 260 p.regnames.BP = "fp" 261 p.regnames.CX = "x0" 262 case "amd64": 263 p.regnames.CX = "rcx" 264 p.regnames.FsBase = "fs_base" 265 default: 266 panic("not implemented") 267 } 268 269 if process != nil { 270 p.waitChan = make(chan *os.ProcessState) 271 go func() { 272 state, _ := process.Wait() 273 p.waitChan <- state 274 }() 275 } 276 277 return p 278 } 279 280 // Listen waits for a connection from the stub. 281 func (p *gdbProcess) Listen(listener net.Listener, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { 282 acceptChan := make(chan net.Conn) 283 284 go func() { 285 conn, _ := listener.Accept() 286 acceptChan <- conn 287 }() 288 289 select { 290 case conn := <-acceptChan: 291 listener.Close() 292 if conn == nil { 293 return nil, errors.New("could not connect") 294 } 295 return p.Connect(conn, path, pid, debugInfoDirs, stopReason) 296 case status := <-p.waitChan: 297 listener.Close() 298 return nil, fmt.Errorf("stub exited while waiting for connection: %v", status) 299 } 300 } 301 302 // Dial attempts to connect to the stub. 303 func (p *gdbProcess) Dial(addr string, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { 304 for { 305 conn, err := net.Dial("tcp", addr) 306 if err == nil { 307 return p.Connect(conn, path, pid, debugInfoDirs, stopReason) 308 } 309 select { 310 case status := <-p.waitChan: 311 return nil, fmt.Errorf("stub exited while attempting to connect: %v", status) 312 default: 313 } 314 time.Sleep(time.Second) 315 } 316 } 317 318 // Connect connects to a stub and performs a handshake. 319 // 320 // Path and pid are, respectively, the path to the executable of the target 321 // program and the PID of the target process, both are optional, however 322 // some stubs do not provide ways to determine path and pid automatically 323 // and Connect will be unable to function without knowing them. 324 func (p *gdbProcess) Connect(conn net.Conn, path string, pid int, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { 325 p.conn.conn = conn 326 p.conn.pid = pid 327 err := p.conn.handshake(p.regnames) 328 if err != nil { 329 conn.Close() 330 return nil, err 331 } 332 333 if p.conn.isDebugserver { 334 // There are multiple problems with the 'g'/'G' commands on debugserver. 335 // On version 902 it used to crash the server completely (https://bugs.llvm.org/show_bug.cgi?id=36968), 336 // on arm64 it results in E74 being returned (https://bugs.llvm.org/show_bug.cgi?id=50169) 337 // and on systems where AVX-512 is used it returns the floating point 338 // registers scrambled and sometimes causes the mask registers to be 339 // zeroed out (https://github.com/go-delve/delve/pull/2498). 340 // All of these bugs stem from the fact that the main consumer of 341 // debugserver, lldb, never uses 'g' or 'G' which would make Delve the 342 // sole tester of those codepaths. 343 // Therefore we disable it here. The associated code is kept around to be 344 // used with Mozilla RR. 345 p.gcmdok = false 346 } 347 348 tgt, err := p.initialize(path, debugInfoDirs, stopReason) 349 if err != nil { 350 return nil, err 351 } 352 353 if p.bi.Arch.Name != "arm64" { 354 // None of the stubs we support returns the value of fs_base or gs_base 355 // along with the registers, therefore we have to resort to executing a MOV 356 // instruction on the inferior to find out where the G struct of a given 357 // thread is located. 358 // Here we try to allocate some memory on the inferior which we will use to 359 // store the MOV instruction. 360 // If the stub doesn't support memory allocation reloadRegisters will 361 // overwrite some existing memory to store the MOV. 362 if addr, err := p.conn.allocMemory(256); err == nil { 363 if _, err := p.conn.writeMemory(addr, p.loadGInstr()); err == nil { 364 p.loadGInstrAddr = addr 365 } 366 } 367 } 368 369 return tgt, nil 370 } 371 372 func (p *gdbProcess) SupportsBPF() bool { 373 return false 374 } 375 376 func (dbp *gdbProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams { 377 return nil 378 } 379 380 func (dbp *gdbProcess) SetUProbe(fnName string, goidOffset int64, args []ebpf.UProbeArgMap) error { 381 panic("not implemented") 382 } 383 384 // unusedPort returns an unused tcp port 385 // This is a hack and subject to a race condition with other running 386 // programs, but most (all?) OS will cycle through all ephemeral ports 387 // before reassigning one port they just assigned, unless there's heavy 388 // churn in the ephemeral range this should work. 389 func unusedPort() string { 390 listener, err := net.Listen("tcp", "127.0.0.1:0") 391 if err != nil { 392 return ":8081" 393 } 394 port := listener.Addr().(*net.TCPAddr).Port 395 listener.Close() 396 return fmt.Sprintf(":%d", port) 397 } 398 399 // getDebugServerAbsolutePath returns a string of the absolute path to the debugserver binary IFF it is 400 // found in the system path ($PATH), the Xcode bundle or the standalone CLT location. 401 func getDebugServerAbsolutePath() string { 402 if path := os.Getenv(debugServerEnvVar); path != "" { 403 return path 404 } 405 for _, debugServerPath := range debugserverExecutablePaths { 406 if debugServerPath == "" { 407 continue 408 } 409 if _, err := exec.LookPath(debugServerPath); err == nil { 410 return debugServerPath 411 } 412 } 413 return "" 414 } 415 416 func canUnmaskSignals(debugServerExecutable string) bool { 417 checkCanUnmaskSignalsOnce.Do(func() { 418 buf, _ := exec.Command(debugServerExecutable, "--unmask-signals").CombinedOutput() 419 canUnmaskSignalsCached = !strings.Contains(string(buf), "unrecognized option") 420 }) 421 return canUnmaskSignalsCached 422 } 423 424 // commandLogger is a wrapper around the exec.Command() function to log the arguments prior to 425 // starting the process 426 func commandLogger(binary string, arguments ...string) *exec.Cmd { 427 logflags.GdbWireLogger().Debugf("executing %s %v", binary, arguments) 428 return exec.Command(binary, arguments...) 429 } 430 431 // ErrUnsupportedOS is returned when trying to use the lldb backend on Windows. 432 var ErrUnsupportedOS = errors.New("lldb backend not supported on Windows") 433 434 func getLdEnvVars() []string { 435 var result []string 436 437 environ := os.Environ() 438 for i := 0; i < len(environ); i++ { 439 if strings.HasPrefix(environ[i], "LD_") || 440 strings.HasPrefix(environ[i], "DYLD_") { 441 result = append(result, "-e", environ[i]) 442 } 443 } 444 445 return result 446 } 447 448 // LLDBLaunch starts an instance of lldb-server and connects to it, asking 449 // it to launch the specified target program with the specified arguments 450 // (cmd) on the specified directory wd. 451 func LLDBLaunch(cmd []string, wd string, flags proc.LaunchFlags, debugInfoDirs []string, tty string, redirects [3]string) (*proc.Target, error) { 452 if runtime.GOOS == "windows" { 453 return nil, ErrUnsupportedOS 454 } 455 if err := macutil.CheckRosetta(); err != nil { 456 return nil, err 457 } 458 459 foreground := flags&proc.LaunchForeground != 0 460 461 var ( 462 isDebugserver bool 463 listener net.Listener 464 port string 465 process *exec.Cmd 466 err error 467 hasRedirects bool 468 ) 469 470 if debugserverExecutable := getDebugServerAbsolutePath(); debugserverExecutable != "" { 471 listener, err = net.Listen("tcp", "127.0.0.1:0") 472 if err != nil { 473 return nil, err 474 } 475 ldEnvVars := getLdEnvVars() 476 args := make([]string, 0, len(cmd)+4+len(ldEnvVars)) 477 args = append(args, ldEnvVars...) 478 479 if tty != "" { 480 args = append(args, "--stdio-path", tty) 481 } else { 482 found := [3]bool{} 483 names := [3]string{"stdin", "stdout", "stderr"} 484 for i := range redirects { 485 if redirects[i] != "" { 486 found[i] = true 487 hasRedirects = true 488 args = append(args, fmt.Sprintf("--%s-path", names[i]), redirects[i]) 489 } 490 } 491 492 if foreground || hasRedirects { 493 for i := range found { 494 if !found[i] { 495 args = append(args, fmt.Sprintf("--%s-path", names[i]), "/dev/"+names[i]) 496 } 497 } 498 } 499 } 500 501 if logflags.LLDBServerOutput() { 502 args = append(args, "-g", "-l", "stdout") 503 } 504 if flags&proc.LaunchDisableASLR != 0 { 505 args = append(args, "-D") 506 } 507 if canUnmaskSignals(debugserverExecutable) { 508 args = append(args, "--unmask-signals") 509 } 510 args = append(args, "-F", "-R", fmt.Sprintf("127.0.0.1:%d", listener.Addr().(*net.TCPAddr).Port), "--") 511 args = append(args, cmd...) 512 513 isDebugserver = true 514 515 process = commandLogger(debugserverExecutable, args...) 516 } else { 517 if _, err = exec.LookPath("lldb-server"); err != nil { 518 return nil, &ErrBackendUnavailable{} 519 } 520 port = unusedPort() 521 args := make([]string, 0, len(cmd)+3) 522 args = append(args, "gdbserver", port, "--") 523 args = append(args, cmd...) 524 525 process = commandLogger("lldb-server", args...) 526 } 527 528 if logflags.LLDBServerOutput() || logflags.GdbWire() || foreground || hasRedirects { 529 process.Stdout = os.Stdout 530 process.Stderr = os.Stderr 531 } 532 if foreground || hasRedirects { 533 if isatty.IsTerminal(os.Stdin.Fd()) { 534 foregroundSignalsIgnore() 535 } 536 process.Stdin = os.Stdin 537 } 538 if wd != "" { 539 process.Dir = wd 540 } 541 542 if isatty.IsTerminal(os.Stdin.Fd()) { 543 process.SysProcAttr = sysProcAttr(foreground) 544 } 545 546 if runtime.GOOS == "darwin" { 547 process.Env = proc.DisableAsyncPreemptEnv() 548 } 549 550 if err = process.Start(); err != nil { 551 return nil, err 552 } 553 554 p := newProcess(process.Process) 555 p.conn.isDebugserver = isDebugserver 556 557 var tgt *proc.Target 558 if listener != nil { 559 tgt, err = p.Listen(listener, cmd[0], 0, debugInfoDirs, proc.StopLaunched) 560 } else { 561 tgt, err = p.Dial(port, cmd[0], 0, debugInfoDirs, proc.StopLaunched) 562 } 563 return tgt, err 564 } 565 566 // LLDBAttach starts an instance of lldb-server and connects to it, asking 567 // it to attach to the specified pid. 568 // Path is path to the target's executable, path only needs to be specified 569 // for some stubs that do not provide an automated way of determining it 570 // (for example debugserver). 571 func LLDBAttach(pid int, path string, debugInfoDirs []string) (*proc.Target, error) { 572 if runtime.GOOS == "windows" { 573 return nil, ErrUnsupportedOS 574 } 575 if err := macutil.CheckRosetta(); err != nil { 576 return nil, err 577 } 578 579 var ( 580 isDebugserver bool 581 process *exec.Cmd 582 listener net.Listener 583 port string 584 err error 585 ) 586 if debugserverExecutable := getDebugServerAbsolutePath(); debugserverExecutable != "" { 587 isDebugserver = true 588 listener, err = net.Listen("tcp", "127.0.0.1:0") 589 if err != nil { 590 return nil, err 591 } 592 args := []string{"-R", fmt.Sprintf("127.0.0.1:%d", listener.Addr().(*net.TCPAddr).Port), "--attach=" + strconv.Itoa(pid)} 593 if canUnmaskSignals(debugserverExecutable) { 594 args = append(args, "--unmask-signals") 595 } 596 process = commandLogger(debugserverExecutable, args...) 597 } else { 598 if _, err = exec.LookPath("lldb-server"); err != nil { 599 return nil, &ErrBackendUnavailable{} 600 } 601 port = unusedPort() 602 process = commandLogger("lldb-server", "gdbserver", "--attach", strconv.Itoa(pid), port) 603 } 604 605 process.Stdout = os.Stdout 606 process.Stderr = os.Stderr 607 process.SysProcAttr = sysProcAttr(false) 608 609 if err = process.Start(); err != nil { 610 return nil, err 611 } 612 613 p := newProcess(process.Process) 614 p.conn.isDebugserver = isDebugserver 615 616 var tgt *proc.Target 617 if listener != nil { 618 tgt, err = p.Listen(listener, path, pid, debugInfoDirs, proc.StopAttached) 619 } else { 620 tgt, err = p.Dial(port, path, pid, debugInfoDirs, proc.StopAttached) 621 } 622 return tgt, err 623 } 624 625 // EntryPoint will return the process entry point address, useful for 626 // debugging PIEs. 627 func (p *gdbProcess) EntryPoint() (uint64, error) { 628 var entryPoint uint64 629 if p.bi.GOOS == "darwin" && p.bi.Arch.Name == "arm64" { 630 // There is no auxv on darwin, however, we can get the location of the mach-o 631 // header from the debugserver by going through the loaded libraries, which includes 632 // the exe itself 633 images, _ := p.conn.getLoadedDynamicLibraries() 634 for _, image := range images { 635 if image.MachHeader.FileType == macho.TypeExec { 636 // This is a bit hacky. This is technically not the entrypoint, 637 // but rather we use the variable to points at the mach-o header, 638 // so we can get the offset in bininfo 639 entryPoint = image.LoadAddress 640 break 641 } 642 } 643 } else if auxv, err := p.conn.readAuxv(); err == nil { 644 // If we can't read the auxiliary vector it just means it's not supported 645 // by the OS or by the stub. If we are debugging a PIE and the entry point 646 // is needed proc.LoadBinaryInfo will complain about it. 647 entryPoint = linutil.EntryPointFromAuxv(auxv, p.BinInfo().Arch.PtrSize()) 648 } 649 650 return entryPoint, nil 651 } 652 653 // initialize uses qProcessInfo to load the inferior's PID and 654 // executable path. This command is not supported by all stubs and not all 655 // stubs will report both the PID and executable path. 656 func (p *gdbProcess) initialize(path string, debugInfoDirs []string, stopReason proc.StopReason) (*proc.Target, error) { 657 var err error 658 if path == "" { 659 // If we are attaching to a running process and the user didn't specify 660 // the executable file manually we must ask the stub for it. 661 // We support both qXfer:exec-file:read:: (the gdb way) and calling 662 // qProcessInfo (the lldb way). 663 // Unfortunately debugserver on macOS supports neither. 664 path, err = p.conn.readExecFile() 665 if err != nil { 666 if isProtocolErrorUnsupported(err) { 667 _, path, err = queryProcessInfo(p, p.Pid()) 668 if err != nil { 669 p.conn.conn.Close() 670 return nil, err 671 } 672 } else { 673 p.conn.conn.Close() 674 return nil, fmt.Errorf("could not determine executable path: %v", err) 675 } 676 } 677 } 678 679 if path == "" { 680 // try using jGetLoadedDynamicLibrariesInfos which is the only way to do 681 // this supported on debugserver (but only on macOS >= 12.10) 682 images, _ := p.conn.getLoadedDynamicLibraries() 683 for _, image := range images { 684 if image.MachHeader.FileType == macho.TypeExec { 685 path = image.Pathname 686 break 687 } 688 } 689 } 690 691 err = p.updateThreadList(&threadUpdater{p: p}) 692 if err != nil { 693 p.conn.conn.Close() 694 p.bi.Close() 695 return nil, err 696 } 697 p.clearThreadSignals() 698 699 if p.conn.pid <= 0 { 700 p.conn.pid, _, err = queryProcessInfo(p, 0) 701 if err != nil && !isProtocolErrorUnsupported(err) { 702 p.conn.conn.Close() 703 p.bi.Close() 704 return nil, err 705 } 706 } 707 tgt, err := proc.NewTarget(p, p.conn.pid, p.currentThread, proc.NewTargetConfig{ 708 Path: path, 709 DebugInfoDirs: debugInfoDirs, 710 DisableAsyncPreempt: runtime.GOOS == "darwin", 711 StopReason: stopReason, 712 CanDump: runtime.GOOS == "darwin"}) 713 if err != nil { 714 p.Detach(true) 715 return nil, err 716 } 717 return tgt, nil 718 } 719 720 func queryProcessInfo(p *gdbProcess, pid int) (int, string, error) { 721 pi, err := p.conn.queryProcessInfo(pid) 722 if err != nil { 723 return 0, "", err 724 } 725 if pid == 0 { 726 n, _ := strconv.ParseUint(pi["pid"], 16, 64) 727 pid = int(n) 728 } 729 return pid, pi["name"], nil 730 } 731 732 // BinInfo returns information on the binary. 733 func (p *gdbProcess) BinInfo() *proc.BinaryInfo { 734 return p.bi 735 } 736 737 // Recorded returns whether or not we are debugging 738 // a recorded "traced" program. 739 func (p *gdbProcess) Recorded() (bool, string) { 740 return p.tracedir != "", p.tracedir 741 } 742 743 // Pid returns the process ID. 744 func (p *gdbProcess) Pid() int { 745 return int(p.conn.pid) 746 } 747 748 // Valid returns true if we are not detached 749 // and the process has not exited. 750 func (p *gdbProcess) Valid() (bool, error) { 751 if p.detached { 752 return false, proc.ErrProcessDetached 753 } 754 if p.exited { 755 return false, proc.ErrProcessExited{Pid: p.Pid()} 756 } 757 if p.almostExited && p.conn.direction == proc.Forward { 758 return false, proc.ErrProcessExited{Pid: p.Pid()} 759 } 760 return true, nil 761 } 762 763 // FindThread returns the thread with the given ID. 764 func (p *gdbProcess) FindThread(threadID int) (proc.Thread, bool) { 765 thread, ok := p.threads[threadID] 766 return thread, ok 767 } 768 769 // ThreadList returns all threads in the process. 770 func (p *gdbProcess) ThreadList() []proc.Thread { 771 r := make([]proc.Thread, 0, len(p.threads)) 772 for _, thread := range p.threads { 773 r = append(r, thread) 774 } 775 return r 776 } 777 778 // Memory returns the process memory. 779 func (p *gdbProcess) Memory() proc.MemoryReadWriter { 780 return p 781 } 782 783 const ( 784 interruptSignal = 0x2 785 breakpointSignal = 0x5 786 faultSignal = 0xb 787 childSignal = 0x11 788 stopSignal = 0x13 789 790 _SIGILL = 0x4 791 _SIGFPE = 0x8 792 _SIGKILL = 0x9 793 794 debugServerTargetExcBadAccess = 0x91 795 debugServerTargetExcBadInstruction = 0x92 796 debugServerTargetExcArithmetic = 0x93 797 debugServerTargetExcEmulation = 0x94 798 debugServerTargetExcSoftware = 0x95 799 debugServerTargetExcBreakpoint = 0x96 800 ) 801 802 // ContinueOnce will continue execution of the process until 803 // a breakpoint is hit or signal is received. 804 func (p *gdbProcess) ContinueOnce(cctx *proc.ContinueOnceContext) (proc.Thread, proc.StopReason, error) { 805 if p.exited { 806 return nil, proc.StopExited, proc.ErrProcessExited{Pid: p.conn.pid} 807 } 808 if p.almostExited { 809 if p.conn.direction == proc.Forward { 810 return nil, proc.StopExited, proc.ErrProcessExited{Pid: p.conn.pid} 811 } 812 p.almostExited = false 813 } 814 815 if p.conn.direction == proc.Forward { 816 // step threads stopped at any breakpoint over their breakpoint 817 for _, thread := range p.threads { 818 if thread.CurrentBreakpoint.Breakpoint != nil { 819 if err := thread.StepInstruction(); err != nil { 820 return nil, proc.StopUnknown, err 821 } 822 } 823 } 824 } 825 826 for _, th := range p.threads { 827 th.clearBreakpointState() 828 } 829 830 p.setCtrlC(cctx, false) 831 832 // resume all threads 833 var threadID string 834 var trapthread *gdbThread 835 var tu = threadUpdater{p: p} 836 var atstart bool 837 continueLoop: 838 for { 839 tu.Reset() 840 sp, err := p.conn.resume(cctx, p.threads, &tu) 841 threadID = sp.threadID 842 if err != nil { 843 if _, exited := err.(proc.ErrProcessExited); exited { 844 p.exited = true 845 return nil, proc.StopExited, err 846 } 847 return nil, proc.StopUnknown, err 848 } 849 850 // For stubs that support qThreadStopInfo updateThreadList will 851 // find out the reason why each thread stopped. 852 // NOTE: because debugserver will sometimes send two stop packets after a 853 // continue it is important that this is the very first thing we do after 854 // resume(). See comment in threadStopInfo for an explanation. 855 p.updateThreadList(&tu) 856 857 trapthread = p.findThreadByStrID(threadID) 858 if trapthread != nil && !p.threadStopInfo { 859 // For stubs that do not support qThreadStopInfo we manually set the 860 // reason the thread returned by resume() stopped. 861 trapthread.sig = sp.sig 862 trapthread.watchAddr = sp.watchAddr 863 } 864 865 var shouldStop, shouldExitErr bool 866 trapthread, atstart, shouldStop, shouldExitErr = p.handleThreadSignals(cctx, trapthread) 867 if shouldExitErr { 868 p.almostExited = true 869 return nil, proc.StopExited, proc.ErrProcessExited{Pid: p.conn.pid} 870 } 871 if shouldStop { 872 break continueLoop 873 } 874 } 875 876 p.clearThreadRegisters() 877 878 stopReason := proc.StopUnknown 879 if atstart { 880 stopReason = proc.StopLaunched 881 } 882 883 if p.BinInfo().GOOS == "linux" { 884 if err := linutil.ElfUpdateSharedObjects(p); err != nil { 885 return nil, stopReason, err 886 } 887 } 888 889 if err := p.setCurrentBreakpoints(); err != nil { 890 return nil, stopReason, err 891 } 892 893 if trapthread == nil { 894 return nil, stopReason, fmt.Errorf("could not find thread %s", threadID) 895 } 896 897 err := machTargetExcToError(trapthread.sig) 898 if err != nil { 899 // the signals that are reported here can not be propagated back to the target process. 900 trapthread.sig = 0 901 } 902 p.currentThread = trapthread 903 return trapthread, stopReason, err 904 } 905 906 func (p *gdbProcess) findThreadByStrID(threadID string) *gdbThread { 907 for _, thread := range p.threads { 908 if thread.strID == threadID { 909 return thread 910 } 911 } 912 return nil 913 } 914 915 // handleThreadSignals looks at the signals received by each thread and 916 // decides which ones to mask and which ones to propagate back to the target 917 // and returns true if we should stop execution in response to one of the 918 // signals and return control to the user. 919 // Adjusts trapthread to a thread that we actually want to stop at. 920 func (p *gdbProcess) handleThreadSignals(cctx *proc.ContinueOnceContext, trapthread *gdbThread) (trapthreadOut *gdbThread, atstart, shouldStop, shouldExitErr bool) { 921 var trapthreadCandidate *gdbThread 922 923 for _, th := range p.threads { 924 isStopSignal := false 925 926 // 0x5 is always a breakpoint, a manual stop either manifests as 0x13 927 // (lldb), 0x11 (debugserver) or 0x2 (gdbserver). 928 // Since 0x2 could also be produced by the user 929 // pressing ^C (in which case it should be passed to the inferior) we need 930 // the ctrlC flag to know that we are the originators. 931 switch th.sig { 932 case interruptSignal: // interrupt 933 if p.getCtrlC(cctx) { 934 isStopSignal = true 935 } 936 case breakpointSignal: // breakpoint 937 isStopSignal = true 938 case childSignal: // stop on debugserver but SIGCHLD on lldb-server/linux 939 if p.conn.isDebugserver { 940 isStopSignal = true 941 } 942 case stopSignal: // stop 943 isStopSignal = true 944 945 case _SIGKILL: 946 if p.tracedir != "" { 947 // RR will send a synthetic SIGKILL packet right before the program 948 // exits, even if the program exited normally. 949 // Treat this signal as if the process had exited because right after 950 // this it is still possible to set breakpoints and rewind the process. 951 shouldExitErr = true 952 isStopSignal = true 953 } 954 955 // The following are fake BSD-style signals sent by debugserver 956 // Unfortunately debugserver can not convert them into signals for the 957 // process so we must stop here. 958 case debugServerTargetExcBadAccess, debugServerTargetExcBadInstruction, debugServerTargetExcArithmetic, debugServerTargetExcEmulation, debugServerTargetExcSoftware, debugServerTargetExcBreakpoint: 959 960 trapthreadCandidate = th 961 shouldStop = true 962 963 // Signal 0 is returned by rr when it reaches the start of the process 964 // in backward continue mode. 965 case 0: 966 if p.conn.direction == proc.Backward && th == trapthread { 967 isStopSignal = true 968 atstart = true 969 } 970 971 default: 972 // any other signal is always propagated to inferior 973 } 974 975 if isStopSignal { 976 if trapthreadCandidate == nil { 977 trapthreadCandidate = th 978 } 979 th.sig = 0 980 shouldStop = true 981 } 982 } 983 984 if (trapthread == nil || trapthread.sig != 0) && trapthreadCandidate != nil { 985 // proc.Continue wants us to return one of the threads that we should stop 986 // at, if the thread returned by vCont received a signal that we want to 987 // propagate back to the target thread but there were also other threads 988 // that we wish to stop at we should pick one of those. 989 trapthread = trapthreadCandidate 990 } 991 992 if p.getCtrlC(cctx) || cctx.GetManualStopRequested() { 993 // If we request an interrupt and a target thread simultaneously receives 994 // an unrelated singal debugserver will discard our interrupt request and 995 // report the signal but we should stop anyway. 996 shouldStop = true 997 } 998 999 return trapthread, atstart, shouldStop, shouldExitErr 1000 } 1001 1002 // RequestManualStop will attempt to stop the process 1003 // without a breakpoint or signal having been received. 1004 func (p *gdbProcess) RequestManualStop(cctx *proc.ContinueOnceContext) error { 1005 if !p.conn.running { 1006 return nil 1007 } 1008 p.ctrlC = true 1009 return p.conn.sendCtrlC() 1010 } 1011 1012 func (p *gdbProcess) setCtrlC(cctx *proc.ContinueOnceContext, v bool) { 1013 cctx.StopMu.Lock() 1014 p.ctrlC = v 1015 cctx.StopMu.Unlock() 1016 } 1017 1018 func (p *gdbProcess) getCtrlC(cctx *proc.ContinueOnceContext) bool { 1019 cctx.StopMu.Lock() 1020 defer cctx.StopMu.Unlock() 1021 return p.ctrlC 1022 } 1023 1024 // Detach will detach from the target process, 1025 // if 'kill' is true it will also kill the process. 1026 func (p *gdbProcess) Detach(kill bool) error { 1027 if kill && !p.exited { 1028 err := p.conn.kill() 1029 if err != nil { 1030 if _, exited := err.(proc.ErrProcessExited); !exited { 1031 return err 1032 } 1033 p.exited = true 1034 } 1035 } 1036 if !p.exited { 1037 if err := p.conn.detach(); err != nil { 1038 return err 1039 } 1040 } 1041 if p.process != nil { 1042 p.process.Kill() 1043 <-p.waitChan 1044 p.process = nil 1045 } 1046 p.detached = true 1047 if p.onDetach != nil { 1048 p.onDetach() 1049 } 1050 return p.bi.Close() 1051 } 1052 1053 // Restart will restart the process from the given position. 1054 func (p *gdbProcess) Restart(cctx *proc.ContinueOnceContext, pos string) (proc.Thread, error) { 1055 if p.tracedir == "" { 1056 return nil, proc.ErrNotRecorded 1057 } 1058 1059 p.exited = false 1060 p.almostExited = false 1061 1062 for _, th := range p.threads { 1063 th.clearBreakpointState() 1064 } 1065 1066 p.ctrlC = false 1067 1068 err := p.conn.restart(pos) 1069 if err != nil { 1070 return nil, err 1071 } 1072 1073 // for some reason we have to send a vCont;c after a vRun to make rr behave 1074 // properly, because that's what gdb does. 1075 _, err = p.conn.resume(cctx, nil, nil) 1076 if err != nil { 1077 return nil, err 1078 } 1079 1080 err = p.updateThreadList(&threadUpdater{p: p}) 1081 if err != nil { 1082 return nil, err 1083 } 1084 p.clearThreadSignals() 1085 p.clearThreadRegisters() 1086 1087 for _, bp := range p.breakpoints.M { 1088 p.WriteBreakpoint(bp) 1089 } 1090 1091 return p.currentThread, p.setCurrentBreakpoints() 1092 } 1093 1094 // When executes the 'when' command for the Mozilla RR backend. 1095 // This command will return rr's internal event number. 1096 func (p *gdbProcess) When() (string, error) { 1097 if p.tracedir == "" { 1098 return "", proc.ErrNotRecorded 1099 } 1100 event, err := p.conn.qRRCmd("when") 1101 if err != nil { 1102 return "", err 1103 } 1104 return strings.TrimSpace(event), nil 1105 } 1106 1107 const ( 1108 checkpointPrefix = "Checkpoint " 1109 ) 1110 1111 // Checkpoint creates a checkpoint from which you can restart the program. 1112 func (p *gdbProcess) Checkpoint(where string) (int, error) { 1113 if p.tracedir == "" { 1114 return -1, proc.ErrNotRecorded 1115 } 1116 resp, err := p.conn.qRRCmd("checkpoint", where) 1117 if err != nil { 1118 return -1, err 1119 } 1120 1121 if !strings.HasPrefix(resp, checkpointPrefix) { 1122 return -1, fmt.Errorf("can not parse checkpoint response %q", resp) 1123 } 1124 1125 idstr := resp[len(checkpointPrefix):] 1126 space := strings.Index(idstr, " ") 1127 if space < 0 { 1128 return -1, fmt.Errorf("can not parse checkpoint response %q", resp) 1129 } 1130 idstr = idstr[:space] 1131 1132 cpid, err := strconv.Atoi(idstr) 1133 if err != nil { 1134 return -1, err 1135 } 1136 return cpid, nil 1137 } 1138 1139 // Checkpoints returns a list of all checkpoints set. 1140 func (p *gdbProcess) Checkpoints() ([]proc.Checkpoint, error) { 1141 if p.tracedir == "" { 1142 return nil, proc.ErrNotRecorded 1143 } 1144 resp, err := p.conn.qRRCmd("info checkpoints") 1145 if err != nil { 1146 return nil, err 1147 } 1148 lines := strings.Split(resp, "\n") 1149 r := make([]proc.Checkpoint, 0, len(lines)-1) 1150 for _, line := range lines[1:] { 1151 if line == "" { 1152 continue 1153 } 1154 fields := strings.Split(line, "\t") 1155 if len(fields) != 3 { 1156 return nil, fmt.Errorf("can not parse \"info checkpoints\" output line %q", line) 1157 } 1158 cpid, err := strconv.Atoi(fields[0]) 1159 if err != nil { 1160 return nil, fmt.Errorf("can not parse \"info checkpoints\" output line %q: %v", line, err) 1161 } 1162 r = append(r, proc.Checkpoint{ID: cpid, When: fields[1], Where: fields[2]}) 1163 } 1164 return r, nil 1165 } 1166 1167 const deleteCheckpointPrefix = "Deleted checkpoint " 1168 1169 // ClearCheckpoint clears the checkpoint for the given ID. 1170 func (p *gdbProcess) ClearCheckpoint(id int) error { 1171 if p.tracedir == "" { 1172 return proc.ErrNotRecorded 1173 } 1174 resp, err := p.conn.qRRCmd("delete checkpoint", strconv.Itoa(id)) 1175 if err != nil { 1176 return err 1177 } 1178 if !strings.HasPrefix(resp, deleteCheckpointPrefix) { 1179 return errors.New(resp) 1180 } 1181 return nil 1182 } 1183 1184 // ChangeDirection sets whether to run the program forwards or in reverse execution. 1185 func (p *gdbProcess) ChangeDirection(dir proc.Direction) error { 1186 if p.tracedir == "" { 1187 if dir != proc.Forward { 1188 return proc.ErrNotRecorded 1189 } 1190 return nil 1191 } 1192 if p.conn.conn == nil { 1193 return proc.ErrProcessExited{Pid: p.conn.pid} 1194 } 1195 if p.conn.direction == dir { 1196 return nil 1197 } 1198 if p.Breakpoints().HasSteppingBreakpoints() { 1199 return ErrDirChange 1200 } 1201 p.conn.direction = dir 1202 return nil 1203 } 1204 1205 // StartCallInjection notifies the backend that we are about to inject a function call. 1206 func (p *gdbProcess) StartCallInjection() (func(), error) { 1207 if p.tracedir == "" { 1208 return func() {}, nil 1209 } 1210 if p.conn.conn == nil { 1211 return nil, proc.ErrProcessExited{Pid: p.conn.pid} 1212 } 1213 if p.conn.direction != proc.Forward { 1214 return nil, ErrStartCallInjectionBackwards 1215 } 1216 1217 // Normally it's impossible to inject function calls in a recorded target 1218 // because the sequence of instructions that the target will execute is 1219 // predetermined. 1220 // RR however allows this in a "diversion". When a diversion is started rr 1221 // takes the current state of the process and runs it forward as a normal 1222 // process, not following the recording. 1223 // The gdb serial protocol does not have a way to start a diversion and gdb 1224 // (the main frontend of rr) does not know how to do it. Instead a 1225 // diversion is started by reading siginfo, because that's the first 1226 // request gdb does when starting a function call injection. 1227 1228 _, err := p.conn.qXfer("siginfo", "", true) 1229 if err != nil { 1230 return nil, err 1231 } 1232 1233 return func() { 1234 _ = p.conn.qXferWrite("siginfo", "") // rr always returns an error for qXfer:siginfo:write... even though it works 1235 }, nil 1236 } 1237 1238 // GetDirection returns the current direction of execution. 1239 func (p *gdbProcess) GetDirection() proc.Direction { 1240 return p.conn.direction 1241 } 1242 1243 // Breakpoints returns the list of breakpoints currently set. 1244 func (p *gdbProcess) Breakpoints() *proc.BreakpointMap { 1245 return &p.breakpoints 1246 } 1247 1248 // FindBreakpoint returns the breakpoint at the given address. 1249 func (p *gdbProcess) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) { 1250 // Directly use addr to lookup breakpoint. 1251 if bp, ok := p.breakpoints.M[pc]; ok { 1252 return bp, true 1253 } 1254 return nil, false 1255 } 1256 1257 func watchTypeToBreakpointType(wtype proc.WatchType) breakpointType { 1258 switch { 1259 case wtype.Read() && wtype.Write(): 1260 return accessWatchpoint 1261 case wtype.Write(): 1262 return writeWatchpoint 1263 case wtype.Read(): 1264 return readWatchpoint 1265 default: 1266 return swBreakpoint 1267 } 1268 } 1269 1270 func (p *gdbProcess) WriteBreakpoint(bp *proc.Breakpoint) error { 1271 kind := p.breakpointKind 1272 if bp.WatchType != 0 { 1273 kind = bp.WatchType.Size() 1274 } 1275 return p.conn.setBreakpoint(bp.Addr, watchTypeToBreakpointType(bp.WatchType), kind) 1276 } 1277 1278 func (p *gdbProcess) EraseBreakpoint(bp *proc.Breakpoint) error { 1279 kind := p.breakpointKind 1280 if bp.WatchType != 0 { 1281 kind = bp.WatchType.Size() 1282 } 1283 return p.conn.clearBreakpoint(bp.Addr, watchTypeToBreakpointType(bp.WatchType), kind) 1284 } 1285 1286 type threadUpdater struct { 1287 p *gdbProcess 1288 seen map[int]bool 1289 done bool 1290 } 1291 1292 func (tu *threadUpdater) Reset() { 1293 tu.done = false 1294 tu.seen = nil 1295 } 1296 1297 func (tu *threadUpdater) Add(threads []string) error { 1298 if tu.done { 1299 panic("threadUpdater: Add after Finish") 1300 } 1301 if tu.seen == nil { 1302 tu.seen = map[int]bool{} 1303 } 1304 for _, threadID := range threads { 1305 b := threadID 1306 if period := strings.Index(b, "."); period >= 0 { 1307 b = b[period+1:] 1308 } 1309 n, err := strconv.ParseUint(b, 16, 32) 1310 if err != nil { 1311 return &GdbMalformedThreadIDError{threadID} 1312 } 1313 tid := int(n) 1314 tu.seen[tid] = true 1315 if _, found := tu.p.threads[tid]; !found { 1316 tu.p.threads[tid] = &gdbThread{ID: tid, strID: threadID, p: tu.p} 1317 } 1318 } 1319 return nil 1320 } 1321 1322 func (tu *threadUpdater) Finish() { 1323 tu.done = true 1324 for threadID := range tu.p.threads { 1325 _, threadSeen := tu.seen[threadID] 1326 if threadSeen { 1327 continue 1328 } 1329 delete(tu.p.threads, threadID) 1330 if tu.p.currentThread != nil && tu.p.currentThread.ID == threadID { 1331 tu.p.currentThread = nil 1332 } 1333 } 1334 if tu.p.currentThread != nil { 1335 if _, exists := tu.p.threads[tu.p.currentThread.ID]; !exists { 1336 // current thread was removed 1337 tu.p.currentThread = nil 1338 } 1339 } 1340 if tu.p.currentThread == nil { 1341 for _, thread := range tu.p.threads { 1342 tu.p.currentThread = thread 1343 break 1344 } 1345 } 1346 } 1347 1348 // updateThreadList retrieves the list of inferior threads from 1349 // the stub and passes it to threadUpdater. 1350 // Some stubs will return the list of running threads in the stop packet, if 1351 // this happens the threadUpdater will know that we have already updated the 1352 // thread list and the first step of updateThreadList will be skipped. 1353 func (p *gdbProcess) updateThreadList(tu *threadUpdater) error { 1354 if !tu.done { 1355 first := true 1356 for { 1357 threads, err := p.conn.queryThreads(first) 1358 if err != nil { 1359 return err 1360 } 1361 if len(threads) == 0 { 1362 break 1363 } 1364 first = false 1365 if err := tu.Add(threads); err != nil { 1366 return err 1367 } 1368 } 1369 1370 tu.Finish() 1371 } 1372 1373 for _, th := range p.threads { 1374 if p.threadStopInfo { 1375 sp, err := p.conn.threadStopInfo(th.strID) 1376 if err != nil { 1377 if isProtocolErrorUnsupported(err) { 1378 p.threadStopInfo = false 1379 break 1380 } 1381 return err 1382 } 1383 th.setbp = (sp.reason == "breakpoint" || (sp.reason == "" && sp.sig == breakpointSignal) || (sp.watchAddr > 0)) 1384 th.sig = sp.sig 1385 th.watchAddr = sp.watchAddr 1386 } else { 1387 th.sig = 0 1388 th.watchAddr = 0 1389 } 1390 } 1391 1392 return nil 1393 } 1394 1395 // clearThreadRegisters clears the memoized thread register state. 1396 func (p *gdbProcess) clearThreadRegisters() { 1397 for _, thread := range p.threads { 1398 thread.regs.regs = nil 1399 } 1400 } 1401 1402 func (p *gdbProcess) clearThreadSignals() { 1403 for _, th := range p.threads { 1404 th.sig = 0 1405 } 1406 } 1407 1408 func (p *gdbProcess) setCurrentBreakpoints() error { 1409 if p.threadStopInfo { 1410 for _, th := range p.threads { 1411 if th.setbp { 1412 err := th.SetCurrentBreakpoint(true) 1413 if err != nil { 1414 return err 1415 } 1416 } 1417 } 1418 } 1419 if !p.threadStopInfo { 1420 for _, th := range p.threads { 1421 if th.CurrentBreakpoint.Breakpoint == nil { 1422 err := th.SetCurrentBreakpoint(true) 1423 if err != nil { 1424 return err 1425 } 1426 } 1427 } 1428 } 1429 return nil 1430 } 1431 1432 // ReadMemory will read into 'data' memory at the address provided. 1433 func (p *gdbProcess) ReadMemory(data []byte, addr uint64) (n int, err error) { 1434 err = p.conn.readMemory(data, addr) 1435 if err != nil { 1436 return 0, err 1437 } 1438 return len(data), nil 1439 } 1440 1441 // WriteMemory will write into the memory at 'addr' the data provided. 1442 func (p *gdbProcess) WriteMemory(addr uint64, data []byte) (written int, err error) { 1443 return p.conn.writeMemory(addr, data) 1444 } 1445 1446 func (t *gdbThread) ProcessMemory() proc.MemoryReadWriter { 1447 return t.p 1448 } 1449 1450 // Location returns the current location of this thread. 1451 func (t *gdbThread) Location() (*proc.Location, error) { 1452 regs, err := t.Registers() 1453 if err != nil { 1454 return nil, err 1455 } 1456 if pcreg, ok := regs.(*gdbRegisters).regs[regs.(*gdbRegisters).regnames.PC]; !ok { 1457 t.p.conn.log.Errorf("thread %d could not find RIP register", t.ID) 1458 } else if len(pcreg.value) < t.p.bi.Arch.PtrSize() { 1459 t.p.conn.log.Errorf("thread %d bad length for RIP register: %d", t.ID, len(pcreg.value)) 1460 } 1461 pc := regs.PC() 1462 f, l, fn := t.p.bi.PCToLine(pc) 1463 return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil 1464 } 1465 1466 // Breakpoint returns the current active breakpoint for this thread. 1467 func (t *gdbThread) Breakpoint() *proc.BreakpointState { 1468 return &t.CurrentBreakpoint 1469 } 1470 1471 // ThreadID returns this threads ID. 1472 func (t *gdbThread) ThreadID() int { 1473 return t.ID 1474 } 1475 1476 // Registers returns the CPU registers for this thread. 1477 func (t *gdbThread) Registers() (proc.Registers, error) { 1478 if t.regs.regs == nil { 1479 if err := t.reloadRegisters(); err != nil { 1480 return nil, err 1481 } 1482 } 1483 return &t.regs, nil 1484 } 1485 1486 // RestoreRegisters will set the CPU registers the value of those provided. 1487 func (t *gdbThread) RestoreRegisters(savedRegs proc.Registers) error { 1488 copy(t.regs.buf, savedRegs.(*gdbRegisters).buf) 1489 return t.writeRegisters() 1490 } 1491 1492 // BinInfo will return information on the binary being debugged. 1493 func (t *gdbThread) BinInfo() *proc.BinaryInfo { 1494 return t.p.bi 1495 } 1496 1497 // Common returns common information across Process implementations. 1498 func (t *gdbThread) Common() *proc.CommonThread { 1499 return &t.common 1500 } 1501 1502 // StepInstruction will step exactly 1 CPU instruction. 1503 func (t *gdbThread) StepInstruction() error { 1504 pc := t.regs.PC() 1505 if bp, atbp := t.p.breakpoints.M[pc]; atbp && bp.WatchType == 0 { 1506 err := t.p.conn.clearBreakpoint(pc, swBreakpoint, t.p.breakpointKind) 1507 if err != nil { 1508 return err 1509 } 1510 defer t.p.conn.setBreakpoint(pc, swBreakpoint, t.p.breakpointKind) 1511 } 1512 // Reset thread registers so the next call to 1513 // Thread.Registers will not be cached. 1514 t.regs.regs = nil 1515 return t.p.conn.step(t, &threadUpdater{p: t.p}, false) 1516 } 1517 1518 // SoftExc returns true if this thread received a software exception during the last resume. 1519 func (t *gdbThread) SoftExc() bool { 1520 return t.setbp 1521 } 1522 1523 // Blocked returns true if the thread is blocked in runtime or kernel code. 1524 func (t *gdbThread) Blocked() bool { 1525 regs, err := t.Registers() 1526 if err != nil { 1527 return false 1528 } 1529 pc := regs.PC() 1530 f, ln, fn := t.BinInfo().PCToLine(pc) 1531 if fn == nil { 1532 if f == "" && ln == 0 { 1533 return true 1534 } 1535 return false 1536 } 1537 switch fn.Name { 1538 case "runtime.futex", "runtime.usleep", "runtime.clone": 1539 return true 1540 case "runtime.kevent": 1541 return true 1542 case "runtime.mach_semaphore_wait", "runtime.mach_semaphore_timedwait": 1543 return true 1544 default: 1545 return strings.HasPrefix(fn.Name, "syscall.Syscall") || strings.HasPrefix(fn.Name, "syscall.RawSyscall") 1546 } 1547 } 1548 1549 // loadGInstr returns the correct MOV instruction for the current 1550 // OS/architecture that can be executed to load the address of G from an 1551 // inferior's thread. 1552 func (p *gdbProcess) loadGInstr() []byte { 1553 var op []byte 1554 switch p.bi.GOOS { 1555 case "windows", "darwin", "freebsd": 1556 // mov rcx, QWORD PTR gs:{uint32(off)} 1557 op = []byte{0x65, 0x48, 0x8b, 0x0c, 0x25} 1558 case "linux": 1559 // mov rcx,QWORD PTR fs:{uint32(off)} 1560 op = []byte{0x64, 0x48, 0x8B, 0x0C, 0x25} 1561 default: 1562 panic("unsupported operating system attempting to find Goroutine on Thread") 1563 } 1564 buf := &bytes.Buffer{} 1565 buf.Write(op) 1566 binary.Write(buf, binary.LittleEndian, uint32(p.bi.GStructOffset())) 1567 return buf.Bytes() 1568 } 1569 1570 func (p *gdbProcess) MemoryMap() ([]proc.MemoryMapEntry, error) { 1571 r := []proc.MemoryMapEntry{} 1572 addr := uint64(0) 1573 for addr != ^uint64(0) { 1574 mri, err := p.conn.memoryRegionInfo(addr) 1575 if err != nil { 1576 return nil, err 1577 } 1578 if addr+mri.size <= addr { 1579 return nil, errors.New("qMemoryRegionInfo response wrapped around the address space or stuck") 1580 } 1581 if mri.permissions != "" { 1582 var mme proc.MemoryMapEntry 1583 1584 mme.Addr = addr 1585 mme.Size = mri.size 1586 mme.Read = strings.Contains(mri.permissions, "r") 1587 mme.Write = strings.Contains(mri.permissions, "w") 1588 mme.Exec = strings.Contains(mri.permissions, "x") 1589 1590 r = append(r, mme) 1591 } 1592 addr += mri.size 1593 } 1594 return r, nil 1595 } 1596 1597 func (p *gdbProcess) DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (threadsDone bool, out []elfwriter.Note, err error) { 1598 return false, notes, nil 1599 } 1600 1601 func (regs *gdbRegisters) init(regsInfo []gdbRegisterInfo, arch *proc.Arch, regnames *gdbRegnames) { 1602 regs.arch = arch 1603 regs.regnames = regnames 1604 regs.regs = make(map[string]gdbRegister) 1605 regs.regsInfo = regsInfo 1606 1607 regsz := 0 1608 for _, reginfo := range regsInfo { 1609 if endoff := reginfo.Offset + (reginfo.Bitsize / 8); endoff > regsz { 1610 regsz = endoff 1611 } 1612 } 1613 regs.buf = make([]byte, regsz) 1614 for _, reginfo := range regsInfo { 1615 regs.regs[reginfo.Name] = regs.gdbRegisterNew(®info) 1616 } 1617 } 1618 1619 func (regs *gdbRegisters) gdbRegisterNew(reginfo *gdbRegisterInfo) gdbRegister { 1620 return gdbRegister{regnum: reginfo.Regnum, value: regs.buf[reginfo.Offset : reginfo.Offset+reginfo.Bitsize/8], ignoreOnWrite: reginfo.ignoreOnWrite} 1621 } 1622 1623 // reloadRegisters loads the current value of the thread's registers. 1624 // It will also load the address of the thread's G. 1625 // Loading the address of G can be done in one of two ways reloadGAlloc, if 1626 // the stub can allocate memory, or reloadGAtPC, if the stub can't. 1627 func (t *gdbThread) reloadRegisters() error { 1628 if t.regs.regs == nil { 1629 t.regs.init(t.p.conn.regsInfo, t.p.bi.Arch, t.p.regnames) 1630 } 1631 1632 if t.p.gcmdok { 1633 if err := t.p.conn.readRegisters(t.strID, t.regs.buf); err != nil { 1634 gdberr, isProt := err.(*GdbProtocolError) 1635 if isProtocolErrorUnsupported(err) || (t.p.conn.isDebugserver && isProt && gdberr.code == "E74") { 1636 t.p.gcmdok = false 1637 } else { 1638 return err 1639 } 1640 } 1641 } 1642 if !t.p.gcmdok { 1643 for _, reginfo := range t.p.conn.regsInfo { 1644 if err := t.p.conn.readRegister(t.strID, reginfo.Regnum, t.regs.regs[reginfo.Name].value); err != nil { 1645 return err 1646 } 1647 } 1648 } 1649 1650 if t.p.bi.GOOS == "linux" { 1651 if reg, hasFsBase := t.regs.regs[t.p.regnames.FsBase]; hasFsBase { 1652 t.regs.gaddr = 0 1653 t.regs.tls = binary.LittleEndian.Uint64(reg.value) 1654 t.regs.hasgaddr = false 1655 return nil 1656 } 1657 } 1658 1659 if t.p.bi.Arch.Name == "arm64" { 1660 // no need to play around with the GInstr on ARM64 because 1661 // the G addr is stored in a register 1662 1663 t.regs.gaddr = t.regs.byName("x28") 1664 t.regs.hasgaddr = true 1665 t.regs.tls = 0 1666 } else { 1667 if t.p.loadGInstrAddr > 0 { 1668 return t.reloadGAlloc() 1669 } 1670 return t.reloadGAtPC() 1671 } 1672 1673 return nil 1674 } 1675 1676 func (t *gdbThread) writeSomeRegisters(regNames ...string) error { 1677 if t.p.gcmdok { 1678 return t.p.conn.writeRegisters(t.strID, t.regs.buf) 1679 } 1680 for _, regName := range regNames { 1681 if err := t.p.conn.writeRegister(t.strID, t.regs.regs[regName].regnum, t.regs.regs[regName].value); err != nil { 1682 return err 1683 } 1684 } 1685 return nil 1686 } 1687 1688 func (t *gdbThread) writeRegisters() error { 1689 if t.p.gcmdok && t.p._Gcmdok { 1690 err := t.p.conn.writeRegisters(t.strID, t.regs.buf) 1691 if isProtocolErrorUnsupported(err) { 1692 t.p._Gcmdok = false 1693 } else { 1694 return err 1695 } 1696 1697 } 1698 for _, r := range t.regs.regs { 1699 if r.ignoreOnWrite { 1700 continue 1701 } 1702 if err := t.p.conn.writeRegister(t.strID, r.regnum, r.value); err != nil { 1703 return err 1704 } 1705 } 1706 return nil 1707 } 1708 1709 func (t *gdbThread) readSomeRegisters(regNames ...string) error { 1710 if t.p.gcmdok { 1711 return t.p.conn.readRegisters(t.strID, t.regs.buf) 1712 } 1713 for _, regName := range regNames { 1714 err := t.p.conn.readRegister(t.strID, t.regs.regs[regName].regnum, t.regs.regs[regName].value) 1715 if err != nil { 1716 return err 1717 } 1718 } 1719 return nil 1720 } 1721 1722 // reloadGAtPC overwrites the instruction that the thread is stopped at with 1723 // the MOV instruction used to load current G, executes this single 1724 // instruction and then puts everything back the way it was. 1725 func (t *gdbThread) reloadGAtPC() error { 1726 movinstr := t.p.loadGInstr() 1727 1728 if t.Blocked() { 1729 t.regs.tls = 0 1730 t.regs.gaddr = 0 1731 t.regs.hasgaddr = true 1732 return nil 1733 } 1734 1735 cx := t.regs.CX() 1736 pc := t.regs.PC() 1737 1738 // We are partially replicating the code of GdbserverThread.stepInstruction 1739 // here. 1740 // The reason is that lldb-server has a bug with writing to memory and 1741 // setting/clearing breakpoints to that same memory which we must work 1742 // around by clearing and re-setting the breakpoint in a specific sequence 1743 // with the memory writes. 1744 // Additionally all breakpoints in [pc, pc+len(movinstr)] need to be removed 1745 for addr, bp := range t.p.breakpoints.M { 1746 if bp.WatchType != 0 { 1747 continue 1748 } 1749 if addr >= pc && addr <= pc+uint64(len(movinstr)) { 1750 err := t.p.conn.clearBreakpoint(addr, swBreakpoint, t.p.breakpointKind) 1751 if err != nil { 1752 return err 1753 } 1754 defer t.p.conn.setBreakpoint(addr, swBreakpoint, t.p.breakpointKind) 1755 } 1756 } 1757 1758 savedcode := make([]byte, len(movinstr)) 1759 _, err := t.p.ReadMemory(savedcode, pc) 1760 if err != nil { 1761 return err 1762 } 1763 1764 _, err = t.p.WriteMemory(pc, movinstr) 1765 if err != nil { 1766 return err 1767 } 1768 1769 defer func() { 1770 _, err0 := t.p.WriteMemory(pc, savedcode) 1771 if err == nil { 1772 err = err0 1773 } 1774 t.regs.setPC(pc) 1775 t.regs.setCX(cx) 1776 err1 := t.writeSomeRegisters(t.p.regnames.PC, t.p.regnames.CX) 1777 if err == nil { 1778 err = err1 1779 } 1780 }() 1781 1782 err = t.p.conn.step(t, nil, true) 1783 if err != nil { 1784 if err == errThreadBlocked { 1785 t.regs.tls = 0 1786 t.regs.gaddr = 0 1787 t.regs.hasgaddr = true 1788 return nil 1789 } 1790 return err 1791 } 1792 1793 if err := t.readSomeRegisters(t.p.regnames.PC, t.p.regnames.CX); err != nil { 1794 return err 1795 } 1796 1797 t.regs.gaddr = t.regs.CX() 1798 t.regs.hasgaddr = true 1799 1800 return err 1801 } 1802 1803 // reloadGAlloc makes the specified thread execute one instruction stored at 1804 // t.p.loadGInstrAddr then restores the value of the thread's registers. 1805 // t.p.loadGInstrAddr must point to valid memory on the inferior, containing 1806 // a MOV instruction that loads the address of the current G in the RCX 1807 // register. 1808 func (t *gdbThread) reloadGAlloc() error { 1809 if t.Blocked() { 1810 t.regs.tls = 0 1811 t.regs.gaddr = 0 1812 t.regs.hasgaddr = true 1813 return nil 1814 } 1815 1816 cx := t.regs.CX() 1817 pc := t.regs.PC() 1818 1819 t.regs.setPC(t.p.loadGInstrAddr) 1820 if err := t.writeSomeRegisters(t.p.regnames.PC); err != nil { 1821 return err 1822 } 1823 1824 var err error 1825 1826 defer func() { 1827 t.regs.setPC(pc) 1828 t.regs.setCX(cx) 1829 err1 := t.writeSomeRegisters(t.p.regnames.PC, t.p.regnames.CX) 1830 if err == nil { 1831 err = err1 1832 } 1833 }() 1834 1835 err = t.p.conn.step(t, nil, true) 1836 if err != nil { 1837 if err == errThreadBlocked { 1838 t.regs.tls = 0 1839 t.regs.gaddr = 0 1840 t.regs.hasgaddr = true 1841 return nil 1842 } 1843 return err 1844 } 1845 1846 if err := t.readSomeRegisters(t.p.regnames.CX); err != nil { 1847 return err 1848 } 1849 1850 t.regs.gaddr = t.regs.CX() 1851 t.regs.hasgaddr = true 1852 1853 return err 1854 } 1855 1856 func (t *gdbThread) clearBreakpointState() { 1857 t.setbp = false 1858 t.CurrentBreakpoint.Clear() 1859 } 1860 1861 // SetCurrentBreakpoint will find and set the threads current breakpoint. 1862 func (t *gdbThread) SetCurrentBreakpoint(adjustPC bool) error { 1863 // adjustPC is ignored, it is the stub's responsibiility to set the PC 1864 // address correctly after hitting a breakpoint. 1865 t.CurrentBreakpoint.Clear() 1866 if t.watchAddr > 0 { 1867 t.CurrentBreakpoint.Breakpoint = t.p.Breakpoints().M[t.watchAddr] 1868 if t.CurrentBreakpoint.Breakpoint == nil { 1869 return fmt.Errorf("could not find watchpoint at address %#x", t.watchAddr) 1870 } 1871 return nil 1872 } 1873 regs, err := t.Registers() 1874 if err != nil { 1875 return err 1876 } 1877 pc := regs.PC() 1878 if bp, ok := t.p.FindBreakpoint(pc); ok { 1879 if t.regs.PC() != bp.Addr { 1880 if err := t.setPC(bp.Addr); err != nil { 1881 return err 1882 } 1883 } 1884 t.CurrentBreakpoint.Breakpoint = bp 1885 } 1886 return nil 1887 } 1888 1889 func (regs *gdbRegisters) PC() uint64 { 1890 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.PC].value) 1891 } 1892 1893 func (regs *gdbRegisters) setPC(value uint64) { 1894 binary.LittleEndian.PutUint64(regs.regs[regs.regnames.PC].value, value) 1895 } 1896 1897 func (regs *gdbRegisters) SP() uint64 { 1898 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.SP].value) 1899 } 1900 1901 func (regs *gdbRegisters) BP() uint64 { 1902 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.BP].value) 1903 } 1904 1905 func (regs *gdbRegisters) CX() uint64 { 1906 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.CX].value) 1907 } 1908 1909 func (regs *gdbRegisters) setCX(value uint64) { 1910 binary.LittleEndian.PutUint64(regs.regs[regs.regnames.CX].value, value) 1911 } 1912 1913 func (regs *gdbRegisters) TLS() uint64 { 1914 return regs.tls 1915 } 1916 1917 func (regs *gdbRegisters) GAddr() (uint64, bool) { 1918 return regs.gaddr, regs.hasgaddr 1919 } 1920 1921 func (regs *gdbRegisters) LR() uint64 { 1922 return binary.LittleEndian.Uint64(regs.regs["lr"].value) 1923 } 1924 1925 func (regs *gdbRegisters) byName(name string) uint64 { 1926 reg, ok := regs.regs[name] 1927 if !ok { 1928 return 0 1929 } 1930 return binary.LittleEndian.Uint64(reg.value) 1931 } 1932 1933 func (r *gdbRegisters) FloatLoadError() error { 1934 return nil 1935 } 1936 1937 // SetPC will set the value of the PC register to the given value. 1938 func (t *gdbThread) setPC(pc uint64) error { 1939 _, _ = t.Registers() // Registes must be loaded first 1940 t.regs.setPC(pc) 1941 if t.p.gcmdok { 1942 return t.p.conn.writeRegisters(t.strID, t.regs.buf) 1943 } 1944 reg := t.regs.regs[t.regs.regnames.PC] 1945 return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value) 1946 } 1947 1948 // SetReg will change the value of a list of registers 1949 func (t *gdbThread) SetReg(regNum uint64, reg *op.DwarfRegister) error { 1950 regName := registerName(t.p.bi.Arch, regNum) 1951 _, _ = t.Registers() // Registers must be loaded first 1952 gdbreg, ok := t.regs.regs[regName] 1953 if !ok && strings.HasPrefix(regName, "xmm") { 1954 // XMMn and YMMn are the same amd64 register (in different sizes), if we 1955 // don't find XMMn try YMMn or ZMMn instead. 1956 gdbreg, ok = t.regs.regs["y"+regName[1:]] 1957 if !ok { 1958 gdbreg, ok = t.regs.regs["z"+regName[1:]] 1959 } 1960 } 1961 if !ok && t.p.bi.Arch.Name == "arm64" && regName == "x30" { 1962 gdbreg, ok = t.regs.regs["lr"] 1963 } 1964 if !ok && regName == "rflags" { 1965 // rr has eflags instead of rflags 1966 regName = "eflags" 1967 gdbreg, ok = t.regs.regs[regName] 1968 if ok { 1969 reg.FillBytes() 1970 reg.Bytes = reg.Bytes[:4] 1971 } 1972 } 1973 if !ok { 1974 return fmt.Errorf("could not set register %s: not found", regName) 1975 } 1976 reg.FillBytes() 1977 1978 wrongSizeErr := func(n int) error { 1979 return fmt.Errorf("could not set register %s: wrong size, expected %d got %d", regName, n, len(reg.Bytes)) 1980 } 1981 1982 if len(reg.Bytes) == len(gdbreg.value) { 1983 copy(gdbreg.value, reg.Bytes) 1984 err := t.p.conn.writeRegister(t.strID, gdbreg.regnum, gdbreg.value) 1985 if err != nil { 1986 return err 1987 } 1988 if t.p.conn.workaroundReg != nil && len(gdbreg.value) > 16 { 1989 // This is a workaround for a bug in debugserver where register writes (P 1990 // packet) on AVX-2 and AVX-512 registers are ignored unless they are 1991 // followed by a write to an AVX register. 1992 // See: 1993 // Issue #2767 1994 // https://bugs.llvm.org/show_bug.cgi?id=52362 1995 reg := t.regs.gdbRegisterNew(t.p.conn.workaroundReg) 1996 return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value) 1997 } 1998 } else if len(reg.Bytes) == 2*len(gdbreg.value) && strings.HasPrefix(regName, "xmm") { 1999 // rr uses xmmN for the low part of the register and ymmNh for the high part 2000 gdbregh, ok := t.regs.regs["y"+regName[1:]+"h"] 2001 if !ok { 2002 return wrongSizeErr(len(gdbreg.value)) 2003 } 2004 if len(reg.Bytes) != len(gdbreg.value)+len(gdbregh.value) { 2005 return wrongSizeErr(len(gdbreg.value) + len(gdbregh.value)) 2006 } 2007 copy(gdbreg.value, reg.Bytes[:len(gdbreg.value)]) 2008 copy(gdbregh.value, reg.Bytes[len(gdbreg.value):]) 2009 err := t.p.conn.writeRegister(t.strID, gdbreg.regnum, gdbreg.value) 2010 if err != nil { 2011 return err 2012 } 2013 err = t.p.conn.writeRegister(t.strID, gdbregh.regnum, gdbregh.value) 2014 if err != nil { 2015 return err 2016 } 2017 } else { 2018 return wrongSizeErr(len(gdbreg.value)) 2019 } 2020 return nil 2021 } 2022 2023 func (regs *gdbRegisters) Slice(floatingPoint bool) ([]proc.Register, error) { 2024 r := make([]proc.Register, 0, len(regs.regsInfo)) 2025 for _, reginfo := range regs.regsInfo { 2026 if reginfo.Group == "float" && !floatingPoint { 2027 continue 2028 } 2029 switch { 2030 case reginfo.Name == "eflags": 2031 r = proc.AppendBytesRegister(r, "Rflags", regs.regs[reginfo.Name].value) 2032 case reginfo.Name == "mxcsr": 2033 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2034 case reginfo.Bitsize == 16: 2035 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2036 case reginfo.Bitsize == 32: 2037 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2038 case reginfo.Bitsize == 64: 2039 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2040 case reginfo.Bitsize == 80: 2041 if !floatingPoint { 2042 continue 2043 } 2044 idx := 0 2045 for _, stprefix := range []string{"stmm", "st"} { 2046 if strings.HasPrefix(reginfo.Name, stprefix) { 2047 idx, _ = strconv.Atoi(reginfo.Name[len(stprefix):]) 2048 break 2049 } 2050 } 2051 r = proc.AppendBytesRegister(r, fmt.Sprintf("ST(%d)", idx), regs.regs[reginfo.Name].value) 2052 2053 case reginfo.Bitsize == 128: 2054 if floatingPoint { 2055 name := reginfo.Name 2056 if last := name[len(name)-1]; last == 'h' || last == 'H' { 2057 name = name[:len(name)-1] 2058 } 2059 r = proc.AppendBytesRegister(r, strings.ToUpper(name), regs.regs[reginfo.Name].value) 2060 } 2061 2062 case reginfo.Bitsize == 256: 2063 if !strings.HasPrefix(strings.ToLower(reginfo.Name), "ymm") || !floatingPoint { 2064 continue 2065 } 2066 2067 value := regs.regs[reginfo.Name].value 2068 xmmName := "x" + reginfo.Name[1:] 2069 r = proc.AppendBytesRegister(r, strings.ToUpper(xmmName), value) 2070 2071 case reginfo.Bitsize == 512: 2072 if !strings.HasPrefix(strings.ToLower(reginfo.Name), "zmm") || !floatingPoint { 2073 continue 2074 } 2075 2076 value := regs.regs[reginfo.Name].value 2077 xmmName := "x" + reginfo.Name[1:] 2078 r = proc.AppendBytesRegister(r, strings.ToUpper(xmmName), value) 2079 } 2080 } 2081 return r, nil 2082 } 2083 2084 func (regs *gdbRegisters) Copy() (proc.Registers, error) { 2085 savedRegs := &gdbRegisters{} 2086 savedRegs.init(regs.regsInfo, regs.arch, regs.regnames) 2087 copy(savedRegs.buf, regs.buf) 2088 return savedRegs, nil 2089 } 2090 2091 func registerName(arch *proc.Arch, regNum uint64) string { 2092 regName, _, _ := arch.DwarfRegisterToString(int(regNum), nil) 2093 return strings.ToLower(regName) 2094 } 2095 2096 func machTargetExcToError(sig uint8) error { 2097 switch sig { 2098 case 0x91: 2099 return errors.New("bad access") 2100 case 0x92: 2101 return errors.New("bad instruction") 2102 case 0x93: 2103 return errors.New("arithmetic exception") 2104 case 0x94: 2105 return errors.New("emulation exception") 2106 case 0x95: 2107 return errors.New("software exception") 2108 case 0x96: 2109 return errors.New("breakpoint exception") 2110 } 2111 return nil 2112 }