github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/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 "github.com/go-delve/delve/pkg/dwarf/op" 83 "github.com/go-delve/delve/pkg/elfwriter" 84 "github.com/go-delve/delve/pkg/logflags" 85 "github.com/go-delve/delve/pkg/proc" 86 "github.com/go-delve/delve/pkg/proc/internal/ebpf" 87 "github.com/go-delve/delve/pkg/proc/linutil" 88 "github.com/go-delve/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://github.com/go-delve/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 int(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 if p.onDetach != nil { 1086 p.onDetach() 1087 } 1088 return p.bi.Close() 1089 } 1090 1091 // Restart will restart the process from the given position. 1092 func (p *gdbProcess) Restart(cctx *proc.ContinueOnceContext, pos string) (proc.Thread, error) { 1093 if p.tracedir == "" { 1094 return nil, proc.ErrNotRecorded 1095 } 1096 1097 p.exited = false 1098 p.almostExited = false 1099 1100 for _, th := range p.threads { 1101 th.clearBreakpointState() 1102 } 1103 1104 p.ctrlC = false 1105 1106 err := p.conn.restart(pos) 1107 if err != nil { 1108 return nil, err 1109 } 1110 1111 // for some reason we have to send a vCont;c after a vRun to make rr behave 1112 // properly, because that's what gdb does. 1113 _, err = p.conn.resume(cctx, nil, nil) 1114 if err != nil { 1115 return nil, err 1116 } 1117 1118 err = p.updateThreadList(&threadUpdater{p: p}) 1119 if err != nil { 1120 return nil, err 1121 } 1122 p.clearThreadSignals() 1123 p.clearThreadRegisters() 1124 1125 for _, bp := range p.breakpoints.M { 1126 p.WriteBreakpoint(bp) 1127 } 1128 1129 return p.currentThread, p.setCurrentBreakpoints() 1130 } 1131 1132 // When executes the 'when' command for the Mozilla RR backend. 1133 // This command will return rr's internal event number. 1134 func (p *gdbProcess) When() (string, error) { 1135 if p.tracedir == "" { 1136 return "", proc.ErrNotRecorded 1137 } 1138 event, err := p.conn.qRRCmd("when") 1139 if err != nil { 1140 return "", err 1141 } 1142 return strings.TrimSpace(event), nil 1143 } 1144 1145 const ( 1146 checkpointPrefix = "Checkpoint " 1147 ) 1148 1149 // Checkpoint creates a checkpoint from which you can restart the program. 1150 func (p *gdbProcess) Checkpoint(where string) (int, error) { 1151 if p.tracedir == "" { 1152 return -1, proc.ErrNotRecorded 1153 } 1154 resp, err := p.conn.qRRCmd("checkpoint", where) 1155 if err != nil { 1156 return -1, err 1157 } 1158 1159 if !strings.HasPrefix(resp, checkpointPrefix) { 1160 return -1, fmt.Errorf("can not parse checkpoint response %q", resp) 1161 } 1162 1163 idstr := resp[len(checkpointPrefix):] 1164 space := strings.Index(idstr, " ") 1165 if space < 0 { 1166 return -1, fmt.Errorf("can not parse checkpoint response %q", resp) 1167 } 1168 idstr = idstr[:space] 1169 1170 cpid, err := strconv.Atoi(idstr) 1171 if err != nil { 1172 return -1, err 1173 } 1174 return cpid, nil 1175 } 1176 1177 // Checkpoints returns a list of all checkpoints set. 1178 func (p *gdbProcess) Checkpoints() ([]proc.Checkpoint, error) { 1179 if p.tracedir == "" { 1180 return nil, proc.ErrNotRecorded 1181 } 1182 resp, err := p.conn.qRRCmd("info checkpoints") 1183 if err != nil { 1184 return nil, err 1185 } 1186 lines := strings.Split(resp, "\n") 1187 r := make([]proc.Checkpoint, 0, len(lines)-1) 1188 for _, line := range lines[1:] { 1189 if line == "" { 1190 continue 1191 } 1192 fields := strings.Split(line, "\t") 1193 if len(fields) != 3 { 1194 return nil, fmt.Errorf("can not parse \"info checkpoints\" output line %q", line) 1195 } 1196 cpid, err := strconv.Atoi(fields[0]) 1197 if err != nil { 1198 return nil, fmt.Errorf("can not parse \"info checkpoints\" output line %q: %v", line, err) 1199 } 1200 r = append(r, proc.Checkpoint{ID: cpid, When: fields[1], Where: fields[2]}) 1201 } 1202 return r, nil 1203 } 1204 1205 const deleteCheckpointPrefix = "Deleted checkpoint " 1206 1207 // ClearCheckpoint clears the checkpoint for the given ID. 1208 func (p *gdbProcess) ClearCheckpoint(id int) error { 1209 if p.tracedir == "" { 1210 return proc.ErrNotRecorded 1211 } 1212 resp, err := p.conn.qRRCmd("delete checkpoint", strconv.Itoa(id)) 1213 if err != nil { 1214 return err 1215 } 1216 if !strings.HasPrefix(resp, deleteCheckpointPrefix) { 1217 return errors.New(resp) 1218 } 1219 return nil 1220 } 1221 1222 // ChangeDirection sets whether to run the program forwards or in reverse execution. 1223 func (p *gdbProcess) ChangeDirection(dir proc.Direction) error { 1224 if p.tracedir == "" { 1225 if dir != proc.Forward { 1226 return proc.ErrNotRecorded 1227 } 1228 return nil 1229 } 1230 if p.conn.conn == nil { 1231 return proc.ErrProcessExited{Pid: p.conn.pid} 1232 } 1233 if p.conn.direction == dir { 1234 return nil 1235 } 1236 if p.Breakpoints().HasSteppingBreakpoints() { 1237 return ErrDirChange 1238 } 1239 p.conn.direction = dir 1240 return nil 1241 } 1242 1243 // StartCallInjection notifies the backend that we are about to inject a function call. 1244 func (p *gdbProcess) StartCallInjection() (func(), error) { 1245 if p.tracedir == "" { 1246 return func() {}, nil 1247 } 1248 if p.conn.conn == nil { 1249 return nil, proc.ErrProcessExited{Pid: p.conn.pid} 1250 } 1251 if p.conn.direction != proc.Forward { 1252 return nil, ErrStartCallInjectionBackwards 1253 } 1254 1255 // Normally it's impossible to inject function calls in a recorded target 1256 // because the sequence of instructions that the target will execute is 1257 // predetermined. 1258 // RR however allows this in a "diversion". When a diversion is started rr 1259 // takes the current state of the process and runs it forward as a normal 1260 // process, not following the recording. 1261 // The gdb serial protocol does not have a way to start a diversion and gdb 1262 // (the main frontend of rr) does not know how to do it. Instead a 1263 // diversion is started by reading siginfo, because that's the first 1264 // request gdb does when starting a function call injection. 1265 1266 _, err := p.conn.qXfer("siginfo", "", true) 1267 if err != nil { 1268 return nil, err 1269 } 1270 1271 return func() { 1272 _ = p.conn.qXferWrite("siginfo", "") // rr always returns an error for qXfer:siginfo:write... even though it works 1273 }, nil 1274 } 1275 1276 // GetDirection returns the current direction of execution. 1277 func (p *gdbProcess) GetDirection() proc.Direction { 1278 return p.conn.direction 1279 } 1280 1281 // Breakpoints returns the list of breakpoints currently set. 1282 func (p *gdbProcess) Breakpoints() *proc.BreakpointMap { 1283 return &p.breakpoints 1284 } 1285 1286 // FindBreakpoint returns the breakpoint at the given address. 1287 func (p *gdbProcess) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) { 1288 // Directly use addr to lookup breakpoint. 1289 if bp, ok := p.breakpoints.M[pc]; ok { 1290 return bp, true 1291 } 1292 return nil, false 1293 } 1294 1295 func watchTypeToBreakpointType(wtype proc.WatchType) breakpointType { 1296 switch { 1297 case wtype.Read() && wtype.Write(): 1298 return accessWatchpoint 1299 case wtype.Write(): 1300 return writeWatchpoint 1301 case wtype.Read(): 1302 return readWatchpoint 1303 default: 1304 return swBreakpoint 1305 } 1306 } 1307 1308 func (p *gdbProcess) WriteBreakpoint(bp *proc.Breakpoint) error { 1309 kind := p.breakpointKind 1310 if bp.WatchType != 0 { 1311 kind = bp.WatchType.Size() 1312 } 1313 return p.conn.setBreakpoint(bp.Addr, watchTypeToBreakpointType(bp.WatchType), kind) 1314 } 1315 1316 func (p *gdbProcess) EraseBreakpoint(bp *proc.Breakpoint) error { 1317 kind := p.breakpointKind 1318 if bp.WatchType != 0 { 1319 kind = bp.WatchType.Size() 1320 } 1321 return p.conn.clearBreakpoint(bp.Addr, watchTypeToBreakpointType(bp.WatchType), kind) 1322 } 1323 1324 // FollowExec enables (or disables) follow exec mode 1325 func (p *gdbProcess) FollowExec(bool) error { 1326 return errors.New("follow exec not supported") 1327 } 1328 1329 type threadUpdater struct { 1330 p *gdbProcess 1331 seen map[int]bool 1332 done bool 1333 } 1334 1335 func (tu *threadUpdater) Reset() { 1336 tu.done = false 1337 tu.seen = nil 1338 } 1339 1340 func (tu *threadUpdater) Add(threads []string) error { 1341 if tu.done { 1342 panic("threadUpdater: Add after Finish") 1343 } 1344 if tu.seen == nil { 1345 tu.seen = map[int]bool{} 1346 } 1347 for _, threadID := range threads { 1348 b := threadID 1349 if period := strings.Index(b, "."); period >= 0 { 1350 b = b[period+1:] 1351 } 1352 n, err := strconv.ParseUint(b, 16, 32) 1353 if err != nil { 1354 return &GdbMalformedThreadIDError{threadID} 1355 } 1356 tid := int(n) 1357 tu.seen[tid] = true 1358 if _, found := tu.p.threads[tid]; !found { 1359 tu.p.threads[tid] = &gdbThread{ID: tid, strID: threadID, p: tu.p} 1360 } 1361 } 1362 return nil 1363 } 1364 1365 func (tu *threadUpdater) Finish() { 1366 tu.done = true 1367 for threadID := range tu.p.threads { 1368 _, threadSeen := tu.seen[threadID] 1369 if threadSeen { 1370 continue 1371 } 1372 delete(tu.p.threads, threadID) 1373 if tu.p.currentThread != nil && tu.p.currentThread.ID == threadID { 1374 tu.p.currentThread = nil 1375 } 1376 } 1377 if tu.p.currentThread != nil { 1378 if _, exists := tu.p.threads[tu.p.currentThread.ID]; !exists { 1379 // current thread was removed 1380 tu.p.currentThread = nil 1381 } 1382 } 1383 if tu.p.currentThread == nil { 1384 for _, thread := range tu.p.threads { 1385 tu.p.currentThread = thread 1386 break 1387 } 1388 } 1389 } 1390 1391 // updateThreadList retrieves the list of inferior threads from 1392 // the stub and passes it to threadUpdater. 1393 // Some stubs will return the list of running threads in the stop packet, if 1394 // this happens the threadUpdater will know that we have already updated the 1395 // thread list and the first step of updateThreadList will be skipped. 1396 func (p *gdbProcess) updateThreadList(tu *threadUpdater) error { 1397 if !tu.done { 1398 first := true 1399 for { 1400 threads, err := p.conn.queryThreads(first) 1401 if err != nil { 1402 return err 1403 } 1404 if len(threads) == 0 { 1405 break 1406 } 1407 first = false 1408 if err := tu.Add(threads); err != nil { 1409 return err 1410 } 1411 } 1412 1413 tu.Finish() 1414 } 1415 1416 for _, th := range p.threads { 1417 if p.threadStopInfo { 1418 sp, err := p.conn.threadStopInfo(th.strID) 1419 if err != nil { 1420 if isProtocolErrorUnsupported(err) { 1421 p.threadStopInfo = false 1422 break 1423 } 1424 return err 1425 } 1426 th.setbp = (sp.reason == "breakpoint" || (sp.reason == "" && sp.sig == breakpointSignal) || (sp.watchAddr > 0)) 1427 th.sig = sp.sig 1428 th.watchAddr = sp.watchAddr 1429 } else { 1430 th.sig = 0 1431 th.watchAddr = 0 1432 } 1433 } 1434 1435 return nil 1436 } 1437 1438 // clearThreadRegisters clears the memoized thread register state. 1439 func (p *gdbProcess) clearThreadRegisters() { 1440 for _, thread := range p.threads { 1441 thread.regs.regs = nil 1442 } 1443 } 1444 1445 func (p *gdbProcess) clearThreadSignals() { 1446 for _, th := range p.threads { 1447 th.sig = 0 1448 } 1449 } 1450 1451 func (p *gdbProcess) setCurrentBreakpoints() error { 1452 if p.threadStopInfo { 1453 for _, th := range p.threads { 1454 if th.setbp { 1455 err := th.SetCurrentBreakpoint(true) 1456 if err != nil { 1457 return err 1458 } 1459 } 1460 } 1461 } 1462 if !p.threadStopInfo { 1463 for _, th := range p.threads { 1464 if th.CurrentBreakpoint.Breakpoint == nil { 1465 err := th.SetCurrentBreakpoint(true) 1466 if err != nil { 1467 return err 1468 } 1469 } 1470 } 1471 } 1472 return nil 1473 } 1474 1475 // ReadMemory will read into 'data' memory at the address provided. 1476 func (p *gdbProcess) ReadMemory(data []byte, addr uint64) (n int, err error) { 1477 err = p.conn.readMemory(data, addr) 1478 if err != nil { 1479 return 0, err 1480 } 1481 return len(data), nil 1482 } 1483 1484 // WriteMemory will write into the memory at 'addr' the data provided. 1485 func (p *gdbProcess) WriteMemory(addr uint64, data []byte) (written int, err error) { 1486 return p.conn.writeMemory(addr, data) 1487 } 1488 1489 func (t *gdbThread) ProcessMemory() proc.MemoryReadWriter { 1490 return t.p 1491 } 1492 1493 // Location returns the current location of this thread. 1494 func (t *gdbThread) Location() (*proc.Location, error) { 1495 regs, err := t.Registers() 1496 if err != nil { 1497 return nil, err 1498 } 1499 if pcreg, ok := regs.(*gdbRegisters).regs[regs.(*gdbRegisters).regnames.PC]; !ok { 1500 t.p.conn.log.Errorf("thread %d could not find RIP register", t.ID) 1501 } else if len(pcreg.value) < t.p.bi.Arch.PtrSize() { 1502 t.p.conn.log.Errorf("thread %d bad length for RIP register: %d", t.ID, len(pcreg.value)) 1503 } 1504 pc := regs.PC() 1505 f, l, fn := t.p.bi.PCToLine(pc) 1506 return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil 1507 } 1508 1509 // Breakpoint returns the current active breakpoint for this thread. 1510 func (t *gdbThread) Breakpoint() *proc.BreakpointState { 1511 return &t.CurrentBreakpoint 1512 } 1513 1514 // ThreadID returns this threads ID. 1515 func (t *gdbThread) ThreadID() int { 1516 return t.ID 1517 } 1518 1519 // Registers returns the CPU registers for this thread. 1520 func (t *gdbThread) Registers() (proc.Registers, error) { 1521 if t.regs.regs == nil { 1522 if err := t.reloadRegisters(); err != nil { 1523 return nil, err 1524 } 1525 } 1526 return &t.regs, nil 1527 } 1528 1529 // RestoreRegisters will set the CPU registers the value of those provided. 1530 func (t *gdbThread) RestoreRegisters(savedRegs proc.Registers) error { 1531 copy(t.regs.buf, savedRegs.(*gdbRegisters).buf) 1532 return t.writeRegisters() 1533 } 1534 1535 // BinInfo will return information on the binary being debugged. 1536 func (t *gdbThread) BinInfo() *proc.BinaryInfo { 1537 return t.p.bi 1538 } 1539 1540 // Common returns common information across Process implementations. 1541 func (t *gdbThread) Common() *proc.CommonThread { 1542 return &t.common 1543 } 1544 1545 // StepInstruction will step exactly 1 CPU instruction. 1546 func (t *gdbThread) StepInstruction() error { 1547 pc := t.regs.PC() 1548 if bp, atbp := t.p.breakpoints.M[pc]; atbp && bp.WatchType == 0 { 1549 err := t.p.conn.clearBreakpoint(pc, swBreakpoint, t.p.breakpointKind) 1550 if err != nil { 1551 return err 1552 } 1553 defer t.p.conn.setBreakpoint(pc, swBreakpoint, t.p.breakpointKind) 1554 } 1555 // Reset thread registers so the next call to 1556 // Thread.Registers will not be cached. 1557 t.regs.regs = nil 1558 return t.p.conn.step(t, &threadUpdater{p: t.p}, false) 1559 } 1560 1561 // SoftExc returns true if this thread received a software exception during the last resume. 1562 func (t *gdbThread) SoftExc() bool { 1563 return t.setbp 1564 } 1565 1566 // Blocked returns true if the thread is blocked in runtime or kernel code. 1567 func (t *gdbThread) Blocked() bool { 1568 regs, err := t.Registers() 1569 if err != nil { 1570 return false 1571 } 1572 pc := regs.PC() 1573 f, ln, fn := t.BinInfo().PCToLine(pc) 1574 if fn == nil { 1575 if f == "" && ln == 0 { 1576 return true 1577 } 1578 return false 1579 } 1580 switch fn.Name { 1581 case "runtime.futex", "runtime.usleep", "runtime.clone": 1582 return true 1583 case "runtime.kevent": 1584 return true 1585 case "runtime.mach_semaphore_wait", "runtime.mach_semaphore_timedwait": 1586 return true 1587 default: 1588 return strings.HasPrefix(fn.Name, "syscall.Syscall") || strings.HasPrefix(fn.Name, "syscall.RawSyscall") 1589 } 1590 } 1591 1592 // loadGInstr returns the correct MOV instruction for the current 1593 // OS/architecture that can be executed to load the address of G from an 1594 // inferior's thread. 1595 func (p *gdbProcess) loadGInstr() ([]byte, error) { 1596 var op []byte 1597 switch p.bi.GOOS { 1598 case "windows", "darwin", "freebsd": 1599 // mov rcx, QWORD PTR gs:{uint32(off)} 1600 op = []byte{0x65, 0x48, 0x8b, 0x0c, 0x25} 1601 case "linux": 1602 // mov rcx,QWORD PTR fs:{uint32(off)} 1603 op = []byte{0x64, 0x48, 0x8B, 0x0C, 0x25} 1604 default: 1605 panic("unsupported operating system attempting to find Goroutine on Thread") 1606 } 1607 offset, err := p.bi.GStructOffset(p.Memory()) 1608 if err != nil { 1609 return nil, err 1610 } 1611 buf := &bytes.Buffer{} 1612 buf.Write(op) 1613 binary.Write(buf, binary.LittleEndian, uint32(offset)) 1614 return buf.Bytes(), nil 1615 } 1616 1617 func (p *gdbProcess) MemoryMap() ([]proc.MemoryMapEntry, error) { 1618 r := []proc.MemoryMapEntry{} 1619 addr := uint64(0) 1620 for addr != ^uint64(0) { 1621 mri, err := p.conn.memoryRegionInfo(addr) 1622 if err != nil { 1623 return nil, err 1624 } 1625 if addr+mri.size <= addr { 1626 return nil, errors.New("qMemoryRegionInfo response wrapped around the address space or stuck") 1627 } 1628 if mri.permissions != "" { 1629 var mme proc.MemoryMapEntry 1630 1631 mme.Addr = addr 1632 mme.Size = mri.size 1633 mme.Read = strings.Contains(mri.permissions, "r") 1634 mme.Write = strings.Contains(mri.permissions, "w") 1635 mme.Exec = strings.Contains(mri.permissions, "x") 1636 1637 r = append(r, mme) 1638 } 1639 addr += mri.size 1640 } 1641 return r, nil 1642 } 1643 1644 func (p *gdbProcess) DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (threadsDone bool, out []elfwriter.Note, err error) { 1645 return false, notes, nil 1646 } 1647 1648 func (regs *gdbRegisters) init(regsInfo []gdbRegisterInfo, arch *proc.Arch, regnames *gdbRegnames) { 1649 regs.arch = arch 1650 regs.regnames = regnames 1651 regs.regs = make(map[string]gdbRegister) 1652 regs.regsInfo = regsInfo 1653 1654 regsz := 0 1655 for _, reginfo := range regsInfo { 1656 if endoff := reginfo.Offset + (reginfo.Bitsize / 8); endoff > regsz { 1657 regsz = endoff 1658 } 1659 } 1660 regs.buf = make([]byte, regsz) 1661 for _, reginfo := range regsInfo { 1662 regs.regs[reginfo.Name] = regs.gdbRegisterNew(®info) 1663 } 1664 } 1665 1666 func (regs *gdbRegisters) gdbRegisterNew(reginfo *gdbRegisterInfo) gdbRegister { 1667 return gdbRegister{regnum: reginfo.Regnum, value: regs.buf[reginfo.Offset : reginfo.Offset+reginfo.Bitsize/8], ignoreOnWrite: reginfo.ignoreOnWrite} 1668 } 1669 1670 // reloadRegisters loads the current value of the thread's registers. 1671 // It will also load the address of the thread's G. 1672 // Loading the address of G can be done in one of two ways reloadGAlloc, if 1673 // the stub can allocate memory, or reloadGAtPC, if the stub can't. 1674 func (t *gdbThread) reloadRegisters() error { 1675 if t.regs.regs == nil { 1676 t.regs.init(t.p.conn.regsInfo, t.p.bi.Arch, t.p.regnames) 1677 } 1678 1679 if t.p.gcmdok { 1680 if err := t.p.conn.readRegisters(t.strID, t.regs.buf); err != nil { 1681 gdberr, isProt := err.(*GdbProtocolError) 1682 if isProtocolErrorUnsupported(err) || (t.p.conn.isDebugserver && isProt && gdberr.code == "E74") { 1683 t.p.gcmdok = false 1684 } else { 1685 return err 1686 } 1687 } 1688 } 1689 if !t.p.gcmdok { 1690 for _, reginfo := range t.p.conn.regsInfo { 1691 if err := t.p.conn.readRegister(t.strID, reginfo.Regnum, t.regs.regs[reginfo.Name].value); err != nil { 1692 return err 1693 } 1694 } 1695 } 1696 1697 if t.p.bi.GOOS == "linux" { 1698 if reg, hasFsBase := t.regs.regs[t.p.regnames.FsBase]; hasFsBase { 1699 t.regs.gaddr = 0 1700 t.regs.tls = binary.LittleEndian.Uint64(reg.value) 1701 t.regs.hasgaddr = false 1702 return nil 1703 } 1704 } 1705 1706 if t.p.bi.Arch.Name == "arm64" { 1707 // no need to play around with the GInstr on ARM64 because 1708 // the G addr is stored in a register 1709 1710 t.regs.gaddr = t.regs.byName("x28") 1711 t.regs.hasgaddr = true 1712 t.regs.tls = 0 1713 } else { 1714 if t.p.loadGInstrAddr > 0 { 1715 return t.reloadGAlloc() 1716 } 1717 return t.reloadGAtPC() 1718 } 1719 1720 return nil 1721 } 1722 1723 func (t *gdbThread) writeSomeRegisters(regNames ...string) error { 1724 if t.p.gcmdok { 1725 return t.p.conn.writeRegisters(t.strID, t.regs.buf) 1726 } 1727 for _, regName := range regNames { 1728 if err := t.p.conn.writeRegister(t.strID, t.regs.regs[regName].regnum, t.regs.regs[regName].value); err != nil { 1729 return err 1730 } 1731 } 1732 return nil 1733 } 1734 1735 func (t *gdbThread) writeRegisters() error { 1736 if t.p.gcmdok && t.p._Gcmdok { 1737 err := t.p.conn.writeRegisters(t.strID, t.regs.buf) 1738 if isProtocolErrorUnsupported(err) { 1739 t.p._Gcmdok = false 1740 } else { 1741 return err 1742 } 1743 1744 } 1745 for _, r := range t.regs.regs { 1746 if r.ignoreOnWrite { 1747 continue 1748 } 1749 if err := t.p.conn.writeRegister(t.strID, r.regnum, r.value); err != nil { 1750 return err 1751 } 1752 } 1753 return nil 1754 } 1755 1756 func (t *gdbThread) readSomeRegisters(regNames ...string) error { 1757 if t.p.gcmdok { 1758 return t.p.conn.readRegisters(t.strID, t.regs.buf) 1759 } 1760 for _, regName := range regNames { 1761 err := t.p.conn.readRegister(t.strID, t.regs.regs[regName].regnum, t.regs.regs[regName].value) 1762 if err != nil { 1763 return err 1764 } 1765 } 1766 return nil 1767 } 1768 1769 // reloadGAtPC overwrites the instruction that the thread is stopped at with 1770 // the MOV instruction used to load current G, executes this single 1771 // instruction and then puts everything back the way it was. 1772 func (t *gdbThread) reloadGAtPC() error { 1773 movinstr, err := t.p.loadGInstr() 1774 if err != nil { 1775 return err 1776 } 1777 1778 if t.Blocked() { 1779 t.regs.tls = 0 1780 t.regs.gaddr = 0 1781 t.regs.hasgaddr = true 1782 return nil 1783 } 1784 1785 cx := t.regs.CX() 1786 pc := t.regs.PC() 1787 1788 // We are partially replicating the code of GdbserverThread.stepInstruction 1789 // here. 1790 // The reason is that lldb-server has a bug with writing to memory and 1791 // setting/clearing breakpoints to that same memory which we must work 1792 // around by clearing and re-setting the breakpoint in a specific sequence 1793 // with the memory writes. 1794 // Additionally all breakpoints in [pc, pc+len(movinstr)] need to be removed 1795 for addr, bp := range t.p.breakpoints.M { 1796 if bp.WatchType != 0 { 1797 continue 1798 } 1799 if addr >= pc && addr <= pc+uint64(len(movinstr)) { 1800 err := t.p.conn.clearBreakpoint(addr, swBreakpoint, t.p.breakpointKind) 1801 if err != nil { 1802 return err 1803 } 1804 defer t.p.conn.setBreakpoint(addr, swBreakpoint, t.p.breakpointKind) 1805 } 1806 } 1807 1808 savedcode := make([]byte, len(movinstr)) 1809 _, err = t.p.ReadMemory(savedcode, pc) 1810 if err != nil { 1811 return err 1812 } 1813 1814 _, err = t.p.WriteMemory(pc, movinstr) 1815 if err != nil { 1816 return err 1817 } 1818 1819 defer func() { 1820 _, err0 := t.p.WriteMemory(pc, savedcode) 1821 if err == nil { 1822 err = err0 1823 } 1824 t.regs.setPC(pc) 1825 t.regs.setCX(cx) 1826 err1 := t.writeSomeRegisters(t.p.regnames.PC, t.p.regnames.CX) 1827 if err == nil { 1828 err = err1 1829 } 1830 }() 1831 1832 err = t.p.conn.step(t, nil, true) 1833 if err != nil { 1834 if err == errThreadBlocked { 1835 t.regs.tls = 0 1836 t.regs.gaddr = 0 1837 t.regs.hasgaddr = true 1838 return nil 1839 } 1840 return err 1841 } 1842 1843 if err := t.readSomeRegisters(t.p.regnames.PC, t.p.regnames.CX); err != nil { 1844 return err 1845 } 1846 1847 t.regs.gaddr = t.regs.CX() 1848 t.regs.hasgaddr = true 1849 1850 return err 1851 } 1852 1853 // reloadGAlloc makes the specified thread execute one instruction stored at 1854 // t.p.loadGInstrAddr then restores the value of the thread's registers. 1855 // t.p.loadGInstrAddr must point to valid memory on the inferior, containing 1856 // a MOV instruction that loads the address of the current G in the RCX 1857 // register. 1858 func (t *gdbThread) reloadGAlloc() error { 1859 if t.Blocked() { 1860 t.regs.tls = 0 1861 t.regs.gaddr = 0 1862 t.regs.hasgaddr = true 1863 return nil 1864 } 1865 1866 cx := t.regs.CX() 1867 pc := t.regs.PC() 1868 1869 t.regs.setPC(t.p.loadGInstrAddr) 1870 if err := t.writeSomeRegisters(t.p.regnames.PC); err != nil { 1871 return err 1872 } 1873 1874 var err error 1875 1876 defer func() { 1877 t.regs.setPC(pc) 1878 t.regs.setCX(cx) 1879 err1 := t.writeSomeRegisters(t.p.regnames.PC, t.p.regnames.CX) 1880 if err == nil { 1881 err = err1 1882 } 1883 }() 1884 1885 err = t.p.conn.step(t, nil, true) 1886 if err != nil { 1887 if err == errThreadBlocked { 1888 t.regs.tls = 0 1889 t.regs.gaddr = 0 1890 t.regs.hasgaddr = true 1891 return nil 1892 } 1893 return err 1894 } 1895 1896 if err := t.readSomeRegisters(t.p.regnames.CX); err != nil { 1897 return err 1898 } 1899 1900 t.regs.gaddr = t.regs.CX() 1901 t.regs.hasgaddr = true 1902 1903 return err 1904 } 1905 1906 func (t *gdbThread) clearBreakpointState() { 1907 t.setbp = false 1908 t.CurrentBreakpoint.Clear() 1909 } 1910 1911 // SetCurrentBreakpoint will find and set the threads current breakpoint. 1912 func (t *gdbThread) SetCurrentBreakpoint(adjustPC bool) error { 1913 // adjustPC is ignored, it is the stub's responsibility to set the PC 1914 // address correctly after hitting a breakpoint. 1915 t.CurrentBreakpoint.Clear() 1916 if t.watchAddr > 0 { 1917 t.CurrentBreakpoint.Breakpoint = t.p.Breakpoints().M[t.watchAddr] 1918 if t.CurrentBreakpoint.Breakpoint == nil { 1919 return fmt.Errorf("could not find watchpoint at address %#x", t.watchAddr) 1920 } 1921 return nil 1922 } 1923 regs, err := t.Registers() 1924 if err != nil { 1925 return err 1926 } 1927 pc := regs.PC() 1928 if bp, ok := t.p.FindBreakpoint(pc); ok { 1929 if t.regs.PC() != bp.Addr { 1930 if err := t.setPC(bp.Addr); err != nil { 1931 return err 1932 } 1933 } 1934 t.CurrentBreakpoint.Breakpoint = bp 1935 } 1936 return nil 1937 } 1938 1939 func (regs *gdbRegisters) PC() uint64 { 1940 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.PC].value) 1941 } 1942 1943 func (regs *gdbRegisters) setPC(value uint64) { 1944 binary.LittleEndian.PutUint64(regs.regs[regs.regnames.PC].value, value) 1945 } 1946 1947 func (regs *gdbRegisters) SP() uint64 { 1948 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.SP].value) 1949 } 1950 1951 func (regs *gdbRegisters) BP() uint64 { 1952 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.BP].value) 1953 } 1954 1955 func (regs *gdbRegisters) CX() uint64 { 1956 return binary.LittleEndian.Uint64(regs.regs[regs.regnames.CX].value) 1957 } 1958 1959 func (regs *gdbRegisters) setCX(value uint64) { 1960 binary.LittleEndian.PutUint64(regs.regs[regs.regnames.CX].value, value) 1961 } 1962 1963 func (regs *gdbRegisters) TLS() uint64 { 1964 return regs.tls 1965 } 1966 1967 func (regs *gdbRegisters) GAddr() (uint64, bool) { 1968 return regs.gaddr, regs.hasgaddr 1969 } 1970 1971 func (regs *gdbRegisters) LR() uint64 { 1972 return binary.LittleEndian.Uint64(regs.regs["lr"].value) 1973 } 1974 1975 func (regs *gdbRegisters) byName(name string) uint64 { 1976 reg, ok := regs.regs[name] 1977 if !ok { 1978 return 0 1979 } 1980 return binary.LittleEndian.Uint64(reg.value) 1981 } 1982 1983 func (regs *gdbRegisters) FloatLoadError() error { 1984 return nil 1985 } 1986 1987 // SetPC will set the value of the PC register to the given value. 1988 func (t *gdbThread) setPC(pc uint64) error { 1989 _, _ = t.Registers() // Registers must be loaded first 1990 t.regs.setPC(pc) 1991 if t.p.gcmdok { 1992 return t.p.conn.writeRegisters(t.strID, t.regs.buf) 1993 } 1994 reg := t.regs.regs[t.regs.regnames.PC] 1995 return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value) 1996 } 1997 1998 // SetReg will change the value of a list of registers 1999 func (t *gdbThread) SetReg(regNum uint64, reg *op.DwarfRegister) error { 2000 regName := registerName(t.p.bi.Arch, regNum) 2001 _, _ = t.Registers() // Registers must be loaded first 2002 gdbreg, ok := t.regs.regs[regName] 2003 if !ok && strings.HasPrefix(regName, "xmm") { 2004 // XMMn and YMMn are the same amd64 register (in different sizes), if we 2005 // don't find XMMn try YMMn or ZMMn instead. 2006 gdbreg, ok = t.regs.regs["y"+regName[1:]] 2007 if !ok { 2008 gdbreg, ok = t.regs.regs["z"+regName[1:]] 2009 } 2010 } 2011 if !ok && t.p.bi.Arch.Name == "arm64" && regName == "x30" { 2012 gdbreg, ok = t.regs.regs["lr"] 2013 } 2014 if !ok && regName == "rflags" { 2015 // rr has eflags instead of rflags 2016 regName = "eflags" 2017 gdbreg, ok = t.regs.regs[regName] 2018 if ok { 2019 reg.FillBytes() 2020 reg.Bytes = reg.Bytes[:4] 2021 } 2022 } 2023 if !ok { 2024 return fmt.Errorf("could not set register %s: not found", regName) 2025 } 2026 reg.FillBytes() 2027 2028 wrongSizeErr := func(n int) error { 2029 return fmt.Errorf("could not set register %s: wrong size, expected %d got %d", regName, n, len(reg.Bytes)) 2030 } 2031 2032 if len(reg.Bytes) == len(gdbreg.value) { 2033 copy(gdbreg.value, reg.Bytes) 2034 err := t.p.conn.writeRegister(t.strID, gdbreg.regnum, gdbreg.value) 2035 if err != nil { 2036 return err 2037 } 2038 if t.p.conn.workaroundReg != nil && len(gdbreg.value) > 16 { 2039 // This is a workaround for a bug in debugserver where register writes (P 2040 // packet) on AVX-2 and AVX-512 registers are ignored unless they are 2041 // followed by a write to an AVX register. 2042 // See: 2043 // Issue #2767 2044 // https://bugs.llvm.org/show_bug.cgi?id=52362 2045 reg := t.regs.gdbRegisterNew(t.p.conn.workaroundReg) 2046 return t.p.conn.writeRegister(t.strID, reg.regnum, reg.value) 2047 } 2048 } else if len(reg.Bytes) == 2*len(gdbreg.value) && strings.HasPrefix(regName, "xmm") { 2049 // rr uses xmmN for the low part of the register and ymmNh for the high part 2050 gdbregh, ok := t.regs.regs["y"+regName[1:]+"h"] 2051 if !ok { 2052 return wrongSizeErr(len(gdbreg.value)) 2053 } 2054 if len(reg.Bytes) != len(gdbreg.value)+len(gdbregh.value) { 2055 return wrongSizeErr(len(gdbreg.value) + len(gdbregh.value)) 2056 } 2057 copy(gdbreg.value, reg.Bytes[:len(gdbreg.value)]) 2058 copy(gdbregh.value, reg.Bytes[len(gdbreg.value):]) 2059 err := t.p.conn.writeRegister(t.strID, gdbreg.regnum, gdbreg.value) 2060 if err != nil { 2061 return err 2062 } 2063 err = t.p.conn.writeRegister(t.strID, gdbregh.regnum, gdbregh.value) 2064 if err != nil { 2065 return err 2066 } 2067 } else { 2068 return wrongSizeErr(len(gdbreg.value)) 2069 } 2070 return nil 2071 } 2072 2073 func (regs *gdbRegisters) Slice(floatingPoint bool) ([]proc.Register, error) { 2074 r := make([]proc.Register, 0, len(regs.regsInfo)) 2075 for _, reginfo := range regs.regsInfo { 2076 if reginfo.Group == "float" && !floatingPoint { 2077 continue 2078 } 2079 switch { 2080 case reginfo.Name == "eflags": 2081 r = proc.AppendBytesRegister(r, "Rflags", regs.regs[reginfo.Name].value) 2082 case reginfo.Name == "mxcsr": 2083 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2084 case reginfo.Bitsize == 16: 2085 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2086 case reginfo.Bitsize == 32: 2087 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2088 case reginfo.Bitsize == 64: 2089 r = proc.AppendBytesRegister(r, reginfo.Name, regs.regs[reginfo.Name].value) 2090 case reginfo.Bitsize == 80: 2091 if !floatingPoint { 2092 continue 2093 } 2094 idx := 0 2095 for _, stprefix := range []string{"stmm", "st"} { 2096 if strings.HasPrefix(reginfo.Name, stprefix) { 2097 idx, _ = strconv.Atoi(reginfo.Name[len(stprefix):]) 2098 break 2099 } 2100 } 2101 r = proc.AppendBytesRegister(r, fmt.Sprintf("ST(%d)", idx), regs.regs[reginfo.Name].value) 2102 2103 case reginfo.Bitsize == 128: 2104 if floatingPoint { 2105 name := reginfo.Name 2106 if last := name[len(name)-1]; last == 'h' || last == 'H' { 2107 name = name[:len(name)-1] 2108 } 2109 r = proc.AppendBytesRegister(r, strings.ToUpper(name), regs.regs[reginfo.Name].value) 2110 } 2111 2112 case reginfo.Bitsize == 256: 2113 if !strings.HasPrefix(strings.ToLower(reginfo.Name), "ymm") || !floatingPoint { 2114 continue 2115 } 2116 2117 value := regs.regs[reginfo.Name].value 2118 xmmName := "x" + reginfo.Name[1:] 2119 r = proc.AppendBytesRegister(r, strings.ToUpper(xmmName), value) 2120 2121 case reginfo.Bitsize == 512: 2122 if !strings.HasPrefix(strings.ToLower(reginfo.Name), "zmm") || !floatingPoint { 2123 continue 2124 } 2125 2126 value := regs.regs[reginfo.Name].value 2127 xmmName := "x" + reginfo.Name[1:] 2128 r = proc.AppendBytesRegister(r, strings.ToUpper(xmmName), value) 2129 } 2130 } 2131 return r, nil 2132 } 2133 2134 func (regs *gdbRegisters) Copy() (proc.Registers, error) { 2135 savedRegs := &gdbRegisters{} 2136 savedRegs.init(regs.regsInfo, regs.arch, regs.regnames) 2137 copy(savedRegs.buf, regs.buf) 2138 return savedRegs, nil 2139 } 2140 2141 func registerName(arch *proc.Arch, regNum uint64) string { 2142 regName, _, _ := arch.DwarfRegisterToString(int(regNum), nil) 2143 return strings.ToLower(regName) 2144 } 2145 2146 func machTargetExcToError(sig uint8) error { 2147 switch sig { 2148 case 0x91: 2149 return errors.New("bad access") 2150 case 0x92: 2151 return errors.New("bad instruction") 2152 case 0x93: 2153 return errors.New("arithmetic exception") 2154 case 0x94: 2155 return errors.New("emulation exception") 2156 case 0x95: 2157 return errors.New("software exception") 2158 case 0x96: 2159 return errors.New("breakpoint exception") 2160 } 2161 return nil 2162 }