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