github.com/neilgarb/delve@v1.9.2-nobreaks/pkg/proc/gdbserial/gdbserver_conn.go (about) 1 package gdbserial 2 3 import ( 4 "bufio" 5 "bytes" 6 "debug/macho" 7 "encoding/json" 8 "encoding/xml" 9 "errors" 10 "fmt" 11 "io" 12 "net" 13 "os" 14 "strconv" 15 "strings" 16 "time" 17 18 "github.com/go-delve/delve/pkg/logflags" 19 "github.com/go-delve/delve/pkg/proc" 20 "github.com/sirupsen/logrus" 21 ) 22 23 type gdbConn struct { 24 conn net.Conn 25 rdr *bufio.Reader 26 27 inbuf []byte 28 outbuf bytes.Buffer 29 30 running bool 31 32 direction proc.Direction // direction of execution 33 34 packetSize int // maximum packet size supported by stub 35 regsInfo []gdbRegisterInfo // list of registers 36 37 workaroundReg *gdbRegisterInfo // used to work-around a register setting bug in debugserver, see use in gdbserver.go 38 39 pid int // cache process id 40 41 ack bool // when ack is true acknowledgment packets are enabled 42 multiprocess bool // multiprocess extensions are active 43 maxTransmitAttempts int // maximum number of transmit or receive attempts when bad checksums are read 44 threadSuffixSupported bool // thread suffix supported by stub 45 isDebugserver bool // true if the stub is debugserver 46 xcmdok bool // x command can be used to transfer memory 47 goarch string 48 goos string 49 50 useXcmd bool // forces writeMemory to use the 'X' command 51 52 log *logrus.Entry 53 } 54 55 var ErrTooManyAttempts = errors.New("too many transmit attempts") 56 57 // GdbProtocolError is an error response (Exx) of Gdb Remote Serial Protocol 58 // or an "unsupported command" response (empty packet). 59 type GdbProtocolError struct { 60 context string 61 cmd string 62 code string 63 } 64 65 func (err *GdbProtocolError) Error() string { 66 cmd := err.cmd 67 if len(cmd) > 20 { 68 cmd = cmd[:20] + "..." 69 } 70 if err.code == "" { 71 return fmt.Sprintf("unsupported packet %s during %s", cmd, err.context) 72 } 73 return fmt.Sprintf("protocol error %s during %s for packet %s", err.code, err.context, cmd) 74 } 75 76 func isProtocolErrorUnsupported(err error) bool { 77 gdberr, ok := err.(*GdbProtocolError) 78 if !ok { 79 return false 80 } 81 return gdberr.code == "" 82 } 83 84 // GdbMalformedThreadIDError is returned when a the stub responds with a 85 // thread ID that does not conform with the Gdb Remote Serial Protocol 86 // specification. 87 type GdbMalformedThreadIDError struct { 88 tid string 89 } 90 91 func (err *GdbMalformedThreadIDError) Error() string { 92 return fmt.Sprintf("malformed thread ID %q", err.tid) 93 } 94 95 const ( 96 qSupportedSimple = "$qSupported:swbreak+;hwbreak+;no-resumed+;xmlRegisters=i386" 97 qSupportedMultiprocess = "$qSupported:multiprocess+;swbreak+;hwbreak+;no-resumed+;xmlRegisters=i386" 98 ) 99 100 func (conn *gdbConn) handshake(regnames *gdbRegnames) error { 101 conn.ack = true 102 conn.packetSize = 256 103 conn.rdr = bufio.NewReader(conn.conn) 104 105 // This first ack packet is needed to start up the connection 106 conn.sendack('+') 107 108 conn.disableAck() 109 110 // Try to enable thread suffixes for the command 'g' and 'p' 111 if _, err := conn.exec([]byte("$QThreadSuffixSupported"), "init"); err != nil { 112 if isProtocolErrorUnsupported(err) { 113 conn.threadSuffixSupported = false 114 } else { 115 return err 116 } 117 } else { 118 conn.threadSuffixSupported = true 119 } 120 121 if !conn.threadSuffixSupported { 122 features, err := conn.qSupported(true) 123 if err != nil { 124 return err 125 } 126 conn.multiprocess = features["multiprocess"] 127 128 // for some reason gdbserver won't let us read target.xml unless first we 129 // select a thread. 130 if conn.multiprocess { 131 conn.exec([]byte("$Hgp0.0"), "init") 132 } else { 133 conn.exec([]byte("$Hgp0"), "init") 134 } 135 } else { 136 // execute qSupported with the multiprocess feature disabled (the 137 // interaction of thread suffixes and multiprocess is not documented), we 138 // only need this call to configure conn.packetSize. 139 if _, err := conn.qSupported(false); err != nil { 140 return err 141 } 142 } 143 144 // Attempt to figure out the name of the processor register. 145 // We either need qXfer:features:read (gdbserver/rr) or qRegisterInfo (lldb) 146 regFound := map[string]bool{ 147 regnames.PC: false, 148 regnames.SP: false, 149 regnames.BP: false, 150 regnames.CX: false, 151 } 152 if err := conn.readRegisterInfo(regFound); err != nil { 153 if isProtocolErrorUnsupported(err) { 154 if err := conn.readTargetXml(regFound); err != nil { 155 return err 156 } 157 } else { 158 return err 159 } 160 } 161 for n := range regFound { 162 if n == "" { 163 continue 164 } 165 if !regFound[n] { 166 return fmt.Errorf("could not find %s register", n) 167 } 168 } 169 170 // We either need: 171 // * QListThreadsInStopReply + qThreadStopInfo (i.e. lldb-server/debugserver), 172 // * or a stub that runs the inferior in single threaded mode (i.e. rr). 173 // Otherwise we'll have problems handling breakpoints in multithreaded programs. 174 if _, err := conn.exec([]byte("$QListThreadsInStopReply"), "init"); err != nil { 175 gdberr, ok := err.(*GdbProtocolError) 176 if !ok { 177 return err 178 } 179 if gdberr.code != "" { 180 return err 181 } 182 } 183 184 if resp, err := conn.exec([]byte("$x0,0"), "init"); err == nil && string(resp) == "OK" { 185 conn.xcmdok = true 186 } 187 188 return nil 189 } 190 191 // qSupported interprets qSupported responses. 192 func (conn *gdbConn) qSupported(multiprocess bool) (features map[string]bool, err error) { 193 q := qSupportedSimple 194 if multiprocess { 195 q = qSupportedMultiprocess 196 } 197 respBuf, err := conn.exec([]byte(q), "init/qSupported") 198 if err != nil { 199 return nil, err 200 } 201 resp := strings.Split(string(respBuf), ";") 202 features = make(map[string]bool) 203 for _, stubfeature := range resp { 204 if len(stubfeature) <= 0 { 205 continue 206 } else if equal := strings.Index(stubfeature, "="); equal >= 0 { 207 if stubfeature[:equal] == "PacketSize" { 208 if n, err := strconv.ParseInt(stubfeature[equal+1:], 16, 64); err == nil { 209 conn.packetSize = int(n) 210 } 211 } 212 } else if stubfeature[len(stubfeature)-1] == '+' { 213 features[stubfeature[:len(stubfeature)-1]] = true 214 } 215 } 216 return features, nil 217 } 218 219 // disableAck disables protocol acks. 220 func (conn *gdbConn) disableAck() error { 221 _, err := conn.exec([]byte("$QStartNoAckMode"), "init/disableAck") 222 if err == nil { 223 conn.ack = false 224 } 225 return err 226 } 227 228 // gdbTarget is a struct type used to parse target.xml 229 type gdbTarget struct { 230 Includes []gdbTargetInclude `xml:"xi include"` 231 Registers []gdbRegisterInfo `xml:"reg"` 232 } 233 234 type gdbTargetInclude struct { 235 Href string `xml:"href,attr"` 236 } 237 238 type gdbRegisterInfo struct { 239 Name string `xml:"name,attr"` 240 Bitsize int `xml:"bitsize,attr"` 241 Offset int 242 Regnum int `xml:"regnum,attr"` 243 Group string `xml:"group,attr"` 244 245 ignoreOnWrite bool 246 } 247 248 func setRegFound(regFound map[string]bool, name string) { 249 for n := range regFound { 250 if name == n { 251 regFound[n] = true 252 } 253 } 254 } 255 256 // readTargetXml reads target.xml file from stub using qXfer:features:read, 257 // then parses it requesting any additional files. 258 // The schema of target.xml is described by: 259 // 260 // https://github.com/bminor/binutils-gdb/blob/61baf725eca99af2569262d10aca03dcde2698f6/gdb/features/gdb-target.dtd 261 func (conn *gdbConn) readTargetXml(regFound map[string]bool) (err error) { 262 conn.regsInfo, err = conn.readAnnex("target.xml") 263 if err != nil { 264 return err 265 } 266 var offset int 267 regnum := 0 268 for i := range conn.regsInfo { 269 if conn.regsInfo[i].Regnum == 0 { 270 conn.regsInfo[i].Regnum = regnum 271 } else { 272 regnum = conn.regsInfo[i].Regnum 273 } 274 conn.regsInfo[i].Offset = offset 275 offset += conn.regsInfo[i].Bitsize / 8 276 277 setRegFound(regFound, conn.regsInfo[i].Name) 278 regnum++ 279 } 280 281 return nil 282 } 283 284 // readRegisterInfo uses qRegisterInfo to read register information (used 285 // when qXfer:feature:read is not supported). 286 func (conn *gdbConn) readRegisterInfo(regFound map[string]bool) (err error) { 287 regnum := 0 288 for { 289 conn.outbuf.Reset() 290 fmt.Fprintf(&conn.outbuf, "$qRegisterInfo%x", regnum) 291 respbytes, err := conn.exec(conn.outbuf.Bytes(), "register info") 292 if err != nil { 293 if regnum == 0 { 294 return err 295 } 296 break 297 } 298 299 var regname string 300 var offset int 301 var bitsize int 302 var contained bool 303 var ignoreOnWrite bool 304 305 resp := string(respbytes) 306 for { 307 semicolon := strings.Index(resp, ";") 308 keyval := resp 309 if semicolon >= 0 { 310 keyval = resp[:semicolon] 311 } 312 313 colon := strings.Index(keyval, ":") 314 if colon >= 0 { 315 name := keyval[:colon] 316 value := keyval[colon+1:] 317 318 switch name { 319 case "name": 320 regname = value 321 case "offset": 322 offset, _ = strconv.Atoi(value) 323 case "bitsize": 324 bitsize, _ = strconv.Atoi(value) 325 case "container-regs": 326 contained = true 327 case "set": 328 if value == "Exception State Registers" || value == "AMX Registers" { 329 // debugserver doesn't like it if we try to write these 330 ignoreOnWrite = true 331 } 332 } 333 } 334 335 if semicolon < 0 { 336 break 337 } 338 resp = resp[semicolon+1:] 339 } 340 341 if contained { 342 if regname == "xmm0" { 343 conn.workaroundReg = &gdbRegisterInfo{Regnum: regnum, Name: regname, Bitsize: bitsize, Offset: offset, ignoreOnWrite: ignoreOnWrite} 344 } 345 regnum++ 346 continue 347 } 348 349 setRegFound(regFound, regname) 350 351 conn.regsInfo = append(conn.regsInfo, gdbRegisterInfo{Regnum: regnum, Name: regname, Bitsize: bitsize, Offset: offset, ignoreOnWrite: ignoreOnWrite}) 352 353 regnum++ 354 } 355 356 return nil 357 } 358 359 func (conn *gdbConn) readAnnex(annex string) ([]gdbRegisterInfo, error) { 360 tgtbuf, err := conn.qXfer("features", annex, false) 361 if err != nil { 362 return nil, err 363 } 364 var tgt gdbTarget 365 if err := xml.Unmarshal(tgtbuf, &tgt); err != nil { 366 return nil, err 367 } 368 369 for _, incl := range tgt.Includes { 370 regs, err := conn.readAnnex(incl.Href) 371 if err != nil { 372 return nil, err 373 } 374 tgt.Registers = append(tgt.Registers, regs...) 375 } 376 return tgt.Registers, nil 377 } 378 379 func (conn *gdbConn) readExecFile() (string, error) { 380 outbuf, err := conn.qXfer("exec-file", "", true) 381 if err != nil { 382 return "", err 383 } 384 return string(outbuf), nil 385 } 386 387 func (conn *gdbConn) readAuxv() ([]byte, error) { 388 return conn.qXfer("auxv", "", true) 389 } 390 391 // qXfer executes a 'qXfer' read with the specified kind (i.e. feature, 392 // exec-file, etc...) and annex. 393 func (conn *gdbConn) qXfer(kind, annex string, binary bool) ([]byte, error) { 394 out := []byte{} 395 for { 396 cmd := []byte(fmt.Sprintf("$qXfer:%s:read:%s:%x,fff", kind, annex, len(out))) 397 err := conn.send(cmd) 398 if err != nil { 399 return nil, err 400 } 401 buf, err := conn.recv(cmd, "target features transfer", binary) 402 if err != nil { 403 return nil, err 404 } 405 406 out = append(out, buf[1:]...) 407 if buf[0] == 'l' { 408 break 409 } 410 } 411 return out, nil 412 } 413 414 // qXferWrite executes a 'qXfer' write with the specified kind and annex. 415 func (conn *gdbConn) qXferWrite(kind, annex string) error { 416 conn.outbuf.Reset() 417 fmt.Fprintf(&conn.outbuf, "$qXfer:%s:write:%s:0:", kind, annex) 418 //TODO(aarzilli): if we ever actually need to write something with qXfer, 419 //this will need to be implemented properly. At the moment it is only used 420 //for a fake write to the siginfo kind, to end a diversion in 'rr'. 421 _, err := conn.exec(conn.outbuf.Bytes(), "qXfer") 422 return err 423 } 424 425 type breakpointType uint8 426 427 const ( 428 swBreakpoint breakpointType = 0 429 hwBreakpoint breakpointType = 1 430 writeWatchpoint breakpointType = 2 431 readWatchpoint breakpointType = 3 432 accessWatchpoint breakpointType = 4 433 ) 434 435 // setBreakpoint executes a 'Z' (insert breakpoint) command of type '0' and kind '1' or '4' 436 func (conn *gdbConn) setBreakpoint(addr uint64, typ breakpointType, kind int) error { 437 conn.outbuf.Reset() 438 fmt.Fprintf(&conn.outbuf, "$Z%d,%x,%d", typ, addr, kind) 439 _, err := conn.exec(conn.outbuf.Bytes(), "set breakpoint") 440 return err 441 } 442 443 // clearBreakpoint executes a 'z' (remove breakpoint) command of type '0' and kind '1' or '4' 444 func (conn *gdbConn) clearBreakpoint(addr uint64, typ breakpointType, kind int) error { 445 conn.outbuf.Reset() 446 fmt.Fprintf(&conn.outbuf, "$z%d,%x,%d", typ, addr, kind) 447 _, err := conn.exec(conn.outbuf.Bytes(), "clear breakpoint") 448 return err 449 } 450 451 // kill executes a 'k' (kill) command. 452 func (conn *gdbConn) kill() error { 453 resp, err := conn.exec([]byte{'$', 'k'}, "kill") 454 if err == io.EOF { 455 // The stub is allowed to shut the connection on us immediately after a 456 // kill. This is not an error. 457 conn.conn.Close() 458 conn.conn = nil 459 return proc.ErrProcessExited{Pid: conn.pid} 460 } 461 if err != nil { 462 return err 463 } 464 _, _, err = conn.parseStopPacket(resp, "", nil) 465 return err 466 } 467 468 // detach executes a 'D' (detach) command. 469 func (conn *gdbConn) detach() error { 470 if conn.conn == nil { 471 // Already detached 472 return nil 473 } 474 _, err := conn.exec([]byte{'$', 'D'}, "detach") 475 conn.conn.Close() 476 conn.conn = nil 477 return err 478 } 479 480 // readRegisters executes a 'g' (read registers) command. 481 func (conn *gdbConn) readRegisters(threadID string, data []byte) error { 482 if !conn.threadSuffixSupported { 483 if err := conn.selectThread('g', threadID, "registers read"); err != nil { 484 return err 485 } 486 } 487 conn.outbuf.Reset() 488 conn.outbuf.WriteString("$g") 489 conn.appendThreadSelector(threadID) 490 resp, err := conn.exec(conn.outbuf.Bytes(), "registers read") 491 if err != nil { 492 return err 493 } 494 495 for i := 0; i < len(resp); i += 2 { 496 n, _ := strconv.ParseUint(string(resp[i:i+2]), 16, 8) 497 data[i/2] = uint8(n) 498 } 499 500 return nil 501 } 502 503 // writeRegisters executes a 'G' (write registers) command. 504 func (conn *gdbConn) writeRegisters(threadID string, data []byte) error { 505 if !conn.threadSuffixSupported { 506 if err := conn.selectThread('g', threadID, "registers write"); err != nil { 507 return err 508 } 509 } 510 conn.outbuf.Reset() 511 conn.outbuf.WriteString("$G") 512 513 for _, b := range data { 514 fmt.Fprintf(&conn.outbuf, "%02x", b) 515 } 516 conn.appendThreadSelector(threadID) 517 _, err := conn.exec(conn.outbuf.Bytes(), "registers write") 518 return err 519 } 520 521 // readRegister executes 'p' (read register) command. 522 func (conn *gdbConn) readRegister(threadID string, regnum int, data []byte) error { 523 if !conn.threadSuffixSupported { 524 if err := conn.selectThread('g', threadID, "registers write"); err != nil { 525 return err 526 } 527 } 528 conn.outbuf.Reset() 529 fmt.Fprintf(&conn.outbuf, "$p%x", regnum) 530 conn.appendThreadSelector(threadID) 531 resp, err := conn.exec(conn.outbuf.Bytes(), "register read") 532 if err != nil { 533 return err 534 } 535 536 for i := 0; i < len(resp); i += 2 { 537 n, _ := strconv.ParseUint(string(resp[i:i+2]), 16, 8) 538 data[i/2] = uint8(n) 539 } 540 541 return nil 542 } 543 544 // writeRegister executes 'P' (write register) command. 545 func (conn *gdbConn) writeRegister(threadID string, regnum int, data []byte) error { 546 if !conn.threadSuffixSupported { 547 if err := conn.selectThread('g', threadID, "registers write"); err != nil { 548 return err 549 } 550 } 551 conn.outbuf.Reset() 552 fmt.Fprintf(&conn.outbuf, "$P%x=", regnum) 553 for _, b := range data { 554 fmt.Fprintf(&conn.outbuf, "%02x", b) 555 } 556 conn.appendThreadSelector(threadID) 557 _, err := conn.exec(conn.outbuf.Bytes(), "register write") 558 return err 559 } 560 561 // resume execution of the target process. 562 // If the current direction is proc.Backward this is done with the 'bc' command. 563 // If the current direction is proc.Forward this is done with the vCont command. 564 // The threads argument will be used to determine which signal to use to 565 // resume each thread. If a thread has sig == 0 the 'c' action will be used, 566 // otherwise the 'C' action will be used and the value of sig will be passed 567 // to it. 568 func (conn *gdbConn) resume(cctx *proc.ContinueOnceContext, threads map[int]*gdbThread, tu *threadUpdater) (stopPacket, error) { 569 if conn.direction == proc.Forward { 570 conn.outbuf.Reset() 571 fmt.Fprintf(&conn.outbuf, "$vCont") 572 for _, th := range threads { 573 if th.sig != 0 { 574 fmt.Fprintf(&conn.outbuf, ";C%02x:%s", th.sig, th.strID) 575 } 576 } 577 fmt.Fprintf(&conn.outbuf, ";c") 578 } else { 579 if err := conn.selectThread('c', "p-1.-1", "resume"); err != nil { 580 return stopPacket{}, err 581 } 582 conn.outbuf.Reset() 583 fmt.Fprint(&conn.outbuf, "$bc") 584 } 585 cctx.StopMu.Lock() 586 if err := conn.send(conn.outbuf.Bytes()); err != nil { 587 cctx.StopMu.Unlock() 588 return stopPacket{}, err 589 } 590 conn.running = true 591 cctx.StopMu.Unlock() 592 defer func() { 593 cctx.StopMu.Lock() 594 conn.running = false 595 cctx.StopMu.Unlock() 596 }() 597 if cctx.ResumeChan != nil { 598 close(cctx.ResumeChan) 599 cctx.ResumeChan = nil 600 } 601 return conn.waitForvContStop("resume", "-1", tu) 602 } 603 604 // step executes a 'vCont' command on the specified thread with 's' action. 605 func (conn *gdbConn) step(th *gdbThread, tu *threadUpdater, ignoreFaultSignal bool) error { 606 threadID := th.strID 607 if conn.direction != proc.Forward { 608 if err := conn.selectThread('c', threadID, "step"); err != nil { 609 return err 610 } 611 conn.outbuf.Reset() 612 fmt.Fprint(&conn.outbuf, "$bs") 613 if err := conn.send(conn.outbuf.Bytes()); err != nil { 614 return err 615 } 616 _, err := conn.waitForvContStop("singlestep", threadID, tu) 617 return err 618 } 619 620 var _SIGBUS uint8 621 switch conn.goos { 622 case "linux": 623 _SIGBUS = 0x7 624 case "darwin": 625 _SIGBUS = 0xa 626 default: 627 panic(fmt.Errorf("unknown GOOS %s", conn.goos)) 628 } 629 630 var sig uint8 = 0 631 for { 632 conn.outbuf.Reset() 633 if sig == 0 { 634 fmt.Fprintf(&conn.outbuf, "$vCont;s:%s", threadID) 635 } else { 636 fmt.Fprintf(&conn.outbuf, "$vCont;S%02x:%s", sig, threadID) 637 } 638 if err := conn.send(conn.outbuf.Bytes()); err != nil { 639 return err 640 } 641 if tu != nil { 642 tu.Reset() 643 } 644 sp, err := conn.waitForvContStop("singlestep", threadID, tu) 645 sig = sp.sig 646 if err != nil { 647 return err 648 } 649 switch sig { 650 case faultSignal: 651 if ignoreFaultSignal { // we attempting to read the TLS, a fault here should be ignored 652 return nil 653 } 654 case _SIGILL, _SIGBUS, _SIGFPE: 655 // propagate these signals to inferior immediately 656 case interruptSignal, breakpointSignal, stopSignal: 657 return nil 658 case childSignal: // stop on debugserver but SIGCHLD on lldb-server/linux 659 if conn.isDebugserver { 660 return nil 661 } 662 case debugServerTargetExcBadAccess, debugServerTargetExcBadInstruction, debugServerTargetExcArithmetic, debugServerTargetExcEmulation, debugServerTargetExcSoftware, debugServerTargetExcBreakpoint: 663 if ignoreFaultSignal { 664 return nil 665 } 666 return machTargetExcToError(sig) 667 default: 668 // delay propagation of any other signal to until after the stepping is done 669 th.sig = sig 670 sig = 0 671 } 672 } 673 } 674 675 var errThreadBlocked = errors.New("thread blocked") 676 677 func (conn *gdbConn) waitForvContStop(context, threadID string, tu *threadUpdater) (stopPacket, error) { 678 count := 0 679 failed := false 680 for { 681 conn.conn.SetReadDeadline(time.Now().Add(heartbeatInterval)) 682 resp, err := conn.recv(nil, context, false) 683 conn.conn.SetReadDeadline(time.Time{}) 684 if neterr, isneterr := err.(net.Error); isneterr && neterr.Timeout() { 685 // Debugserver sometimes forgets to inform us that inferior stopped, 686 // sending this status request after a timeout helps us get unstuck. 687 // Debugserver will not respond to this request unless inferior is 688 // already stopped. 689 if conn.isDebugserver { 690 conn.send([]byte("$?")) 691 } 692 if count > 1 && context == "singlestep" { 693 failed = true 694 conn.sendCtrlC() 695 } 696 count++ 697 } else if failed { 698 return stopPacket{}, errThreadBlocked 699 } else if err != nil { 700 return stopPacket{}, err 701 } else { 702 repeat, sp, err := conn.parseStopPacket(resp, threadID, tu) 703 if !repeat { 704 return sp, err 705 } 706 } 707 } 708 } 709 710 type stopPacket struct { 711 threadID string 712 sig uint8 713 reason string 714 watchAddr uint64 715 } 716 717 // Mach exception codes used to decode metype/medata keys in stop packets (necessary to support watchpoints with debugserver). 718 // See: 719 // 720 // https://opensource.apple.com/source/xnu/xnu-4570.1.46/osfmk/mach/exception_types.h.auto.html 721 // https://opensource.apple.com/source/xnu/xnu-4570.1.46/osfmk/mach/i386/exception.h.auto.html 722 // https://opensource.apple.com/source/xnu/xnu-4570.1.46/osfmk/mach/arm/exception.h.auto.html 723 const ( 724 _EXC_BREAKPOINT = 6 // mach exception type for hardware breakpoints 725 _EXC_I386_SGL = 1 // mach exception code for single step on x86, for some reason this is also used for watchpoints 726 _EXC_ARM_DA_DEBUG = 0x102 // mach exception code for debug fault on arm/arm64 727 ) 728 729 // executes 'vCont' (continue/step) command 730 func (conn *gdbConn) parseStopPacket(resp []byte, threadID string, tu *threadUpdater) (repeat bool, sp stopPacket, err error) { 731 switch resp[0] { 732 case 'T': 733 if len(resp) < 3 { 734 return false, stopPacket{}, fmt.Errorf("malformed response for vCont %s", string(resp)) 735 } 736 737 sig, err := strconv.ParseUint(string(resp[1:3]), 16, 8) 738 if err != nil { 739 return false, stopPacket{}, fmt.Errorf("malformed stop packet: %s", string(resp)) 740 } 741 sp.sig = uint8(sig) 742 743 if logflags.GdbWire() && gdbWireFullStopPacket { 744 conn.log.Debugf("full stop packet: %s", string(resp)) 745 } 746 747 var metype int 748 var medata = make([]uint64, 0, 10) 749 750 buf := resp[3:] 751 for buf != nil { 752 colon := bytes.Index(buf, []byte{':'}) 753 if colon < 0 { 754 break 755 } 756 key := buf[:colon] 757 buf = buf[colon+1:] 758 759 semicolon := bytes.Index(buf, []byte{';'}) 760 var value []byte 761 if semicolon < 0 { 762 value = buf 763 buf = nil 764 } else { 765 value = buf[:semicolon] 766 buf = buf[semicolon+1:] 767 } 768 769 switch string(key) { 770 case "thread": 771 sp.threadID = string(value) 772 case "threads": 773 if tu != nil { 774 tu.Add(strings.Split(string(value), ",")) 775 tu.Finish() 776 } 777 case "reason": 778 sp.reason = string(value) 779 case "watch", "awatch", "rwatch": 780 sp.watchAddr, err = strconv.ParseUint(string(value), 16, 64) 781 if err != nil { 782 return false, stopPacket{}, fmt.Errorf("malformed stop packet: %s (wrong watch address)", string(resp)) 783 } 784 case "metype": 785 // mach exception type (debugserver extension) 786 metype, _ = strconv.Atoi(string(value)) 787 case "medata": 788 // mach exception data (debugserver extension) 789 d, _ := strconv.ParseUint(string(value), 16, 64) 790 medata = append(medata, d) 791 } 792 } 793 794 // Debugserver does not report watchpoint stops in the standard way preferring 795 // instead the semi-undocumented metype/medata keys. 796 // These values also have different meanings depending on the CPU architecture. 797 switch conn.goarch { 798 case "amd64": 799 if metype == _EXC_BREAKPOINT && len(medata) >= 2 && medata[0] == _EXC_I386_SGL { 800 sp.watchAddr = medata[1] // this should be zero if this is really a single step stop and non-zero for watchpoints 801 } 802 case "arm64": 803 if metype == _EXC_BREAKPOINT && len(medata) >= 2 && medata[0] == _EXC_ARM_DA_DEBUG { 804 sp.watchAddr = medata[1] 805 } 806 } 807 808 return false, sp, nil 809 810 case 'W', 'X': 811 // process exited, next two character are exit code 812 813 semicolon := bytes.Index(resp, []byte{';'}) 814 815 if semicolon < 0 { 816 semicolon = len(resp) 817 } 818 status, _ := strconv.ParseUint(string(resp[1:semicolon]), 16, 8) 819 return false, stopPacket{}, proc.ErrProcessExited{Pid: conn.pid, Status: int(status)} 820 821 case 'N': 822 // we were singlestepping the thread and the thread exited 823 sp.threadID = threadID 824 return false, sp, nil 825 826 case 'O': 827 data := make([]byte, 0, len(resp[1:])/2) 828 for i := 1; i < len(resp); i += 2 { 829 n, _ := strconv.ParseUint(string(resp[i:i+2]), 16, 8) 830 data = append(data, uint8(n)) 831 } 832 os.Stdout.Write(data) 833 return true, sp, nil 834 835 default: 836 return false, sp, fmt.Errorf("unexpected response for vCont %c", resp[0]) 837 } 838 } 839 840 const ctrlC = 0x03 // the ASCII character for ^C 841 842 // executes a ctrl-C on the line 843 func (conn *gdbConn) sendCtrlC() error { 844 conn.log.Debug("<- interrupt") 845 _, err := conn.conn.Write([]byte{ctrlC}) 846 return err 847 } 848 849 // queryProcessInfo executes a qProcessInfoPID (if pid != 0) or a qProcessInfo (if pid == 0) 850 func (conn *gdbConn) queryProcessInfo(pid int) (map[string]string, error) { 851 conn.outbuf.Reset() 852 if pid != 0 { 853 fmt.Fprintf(&conn.outbuf, "$qProcessInfoPID:%d", pid) 854 } else { 855 fmt.Fprint(&conn.outbuf, "$qProcessInfo") 856 } 857 resp, err := conn.exec(conn.outbuf.Bytes(), "process info for pid") 858 if err != nil { 859 return nil, err 860 } 861 862 pi := make(map[string]string) 863 864 for len(resp) > 0 { 865 semicolon := bytes.Index(resp, []byte{';'}) 866 keyval := resp 867 if semicolon >= 0 { 868 keyval = resp[:semicolon] 869 resp = resp[semicolon+1:] 870 } 871 872 colon := bytes.Index(keyval, []byte{':'}) 873 if colon < 0 { 874 continue 875 } 876 877 key := string(keyval[:colon]) 878 value := string(keyval[colon+1:]) 879 880 switch key { 881 case "name": 882 name := make([]byte, len(value)/2) 883 for i := 0; i < len(value); i += 2 { 884 n, _ := strconv.ParseUint(string(value[i:i+2]), 16, 8) 885 name[i/2] = byte(n) 886 } 887 pi[key] = string(name) 888 889 default: 890 pi[key] = value 891 } 892 } 893 return pi, nil 894 } 895 896 // executes qfThreadInfo/qsThreadInfo commands 897 func (conn *gdbConn) queryThreads(first bool) (threads []string, err error) { 898 // https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html 899 conn.outbuf.Reset() 900 if first { 901 conn.outbuf.WriteString("$qfThreadInfo") 902 } else { 903 conn.outbuf.WriteString("$qsThreadInfo") 904 } 905 906 resp, err := conn.exec(conn.outbuf.Bytes(), "thread info") 907 if err != nil { 908 return nil, err 909 } 910 911 switch resp[0] { 912 case 'l': 913 return nil, nil 914 case 'm': 915 // parse list... 916 default: 917 return nil, errors.New("malformed qfThreadInfo response") 918 } 919 920 var pid int 921 resp = resp[1:] 922 for { 923 tidbuf := resp 924 comma := bytes.Index(tidbuf, []byte{','}) 925 if comma >= 0 { 926 tidbuf = tidbuf[:comma] 927 } 928 if conn.multiprocess && pid == 0 { 929 dot := bytes.Index(tidbuf, []byte{'.'}) 930 if dot >= 0 { 931 pid, _ = strconv.Atoi(string(tidbuf[1:dot])) 932 } 933 } 934 threads = append(threads, string(tidbuf)) 935 if comma < 0 { 936 break 937 } 938 resp = resp[comma+1:] 939 } 940 941 if conn.multiprocess && pid > 0 { 942 conn.pid = pid 943 } 944 return threads, nil 945 } 946 947 func (conn *gdbConn) selectThread(kind byte, threadID string, context string) error { 948 if conn.threadSuffixSupported { 949 panic("selectThread when thread suffix is supported") 950 } 951 conn.outbuf.Reset() 952 fmt.Fprintf(&conn.outbuf, "$H%c%s", kind, threadID) 953 _, err := conn.exec(conn.outbuf.Bytes(), context) 954 return err 955 } 956 957 func (conn *gdbConn) appendThreadSelector(threadID string) { 958 if !conn.threadSuffixSupported { 959 return 960 } 961 fmt.Fprintf(&conn.outbuf, ";thread:%s;", threadID) 962 } 963 964 func (conn *gdbConn) readMemory(data []byte, addr uint64) error { 965 if conn.xcmdok && len(data) > conn.packetSize { 966 return conn.readMemoryBinary(data, addr) 967 } 968 return conn.readMemoryHex(data, addr) 969 } 970 971 // executes 'm' (read memory) command 972 func (conn *gdbConn) readMemoryHex(data []byte, addr uint64) error { 973 size := len(data) 974 data = data[:0] 975 976 for size > 0 { 977 conn.outbuf.Reset() 978 979 // gdbserver will crash if we ask too many bytes... not return an error, actually crash 980 sz := size 981 if dataSize := (conn.packetSize - 4) / 2; sz > dataSize { 982 sz = dataSize 983 } 984 size = size - sz 985 986 fmt.Fprintf(&conn.outbuf, "$m%x,%x", addr+uint64(len(data)), sz) 987 resp, err := conn.exec(conn.outbuf.Bytes(), "memory read") 988 if err != nil { 989 return err 990 } 991 992 for i := 0; i < len(resp); i += 2 { 993 n, _ := strconv.ParseUint(string(resp[i:i+2]), 16, 8) 994 data = append(data, uint8(n)) 995 } 996 } 997 return nil 998 } 999 1000 // executes 'x' (binary read memory) command 1001 func (conn *gdbConn) readMemoryBinary(data []byte, addr uint64) error { 1002 size := len(data) 1003 data = data[:0] 1004 1005 for len(data) < size { 1006 conn.outbuf.Reset() 1007 1008 sz := size - len(data) 1009 1010 fmt.Fprintf(&conn.outbuf, "$x%x,%x", addr+uint64(len(data)), sz) 1011 if err := conn.send(conn.outbuf.Bytes()); err != nil { 1012 return err 1013 } 1014 resp, err := conn.recv(conn.outbuf.Bytes(), "binary memory read", true) 1015 if err != nil { 1016 return err 1017 } 1018 data = append(data, resp...) 1019 } 1020 return nil 1021 } 1022 1023 func writeAsciiBytes(w io.Writer, data []byte) { 1024 for _, b := range data { 1025 fmt.Fprintf(w, "%02x", b) 1026 } 1027 } 1028 1029 // writeMemory writes memory using either 'M' or 'X' 1030 func (conn *gdbConn) writeMemory(addr uint64, data []byte) (written int, err error) { 1031 if conn.useXcmd { 1032 return conn.writeMemoryBinary(addr, data) 1033 } 1034 return conn.writeMemoryHex(addr, data) 1035 } 1036 1037 // executes 'M' (write memory) command 1038 func (conn *gdbConn) writeMemoryHex(addr uint64, data []byte) (written int, err error) { 1039 if len(data) == 0 { 1040 // LLDB can't parse requests for 0-length writes and hangs if we emit them 1041 return 0, nil 1042 } 1043 conn.outbuf.Reset() 1044 //TODO(aarzilli): do not send packets larger than conn.PacketSize 1045 fmt.Fprintf(&conn.outbuf, "$M%x,%x:", addr, len(data)) 1046 1047 writeAsciiBytes(&conn.outbuf, data) 1048 1049 _, err = conn.exec(conn.outbuf.Bytes(), "memory write") 1050 if err != nil { 1051 return 0, err 1052 } 1053 return len(data), nil 1054 } 1055 1056 func (conn *gdbConn) writeMemoryBinary(addr uint64, data []byte) (written int, err error) { 1057 conn.outbuf.Reset() 1058 fmt.Fprintf(&conn.outbuf, "$X%x,%x:", addr, len(data)) 1059 1060 for _, b := range data { 1061 switch b { 1062 case '#', '$', '}': 1063 conn.outbuf.WriteByte('}') 1064 conn.outbuf.WriteByte(b ^ escapeXor) 1065 default: 1066 conn.outbuf.WriteByte(b) 1067 } 1068 } 1069 1070 _, err = conn.exec(conn.outbuf.Bytes(), "memory write") 1071 if err != nil { 1072 return 0, err 1073 } 1074 return len(data), nil 1075 } 1076 1077 func (conn *gdbConn) allocMemory(sz uint64) (uint64, error) { 1078 conn.outbuf.Reset() 1079 fmt.Fprintf(&conn.outbuf, "$_M%x,rwx", sz) 1080 resp, err := conn.exec(conn.outbuf.Bytes(), "memory allocation") 1081 if err != nil { 1082 return 0, err 1083 } 1084 return strconv.ParseUint(string(resp), 16, 64) 1085 } 1086 1087 // threadStopInfo executes a 'qThreadStopInfo' and returns the reason the 1088 // thread stopped. 1089 func (conn *gdbConn) threadStopInfo(threadID string) (sp stopPacket, err error) { 1090 conn.outbuf.Reset() 1091 fmt.Fprintf(&conn.outbuf, "$qThreadStopInfo%s", threadID) 1092 resp, err := conn.exec(conn.outbuf.Bytes(), "thread stop info") 1093 if err != nil { 1094 return stopPacket{}, err 1095 } 1096 _, sp, err = conn.parseStopPacket(resp, "", nil) 1097 if err != nil { 1098 return stopPacket{}, err 1099 } 1100 if sp.threadID != threadID { 1101 // When we send a ^C (manual stop request) and the process is close to 1102 // stopping anyway, sometimes, debugserver will send back two stop 1103 // packets. We need to ignore this spurious stop packet. Because the first 1104 // thing we do after the stop is updateThreadList, which calls this 1105 // function, this is relatively painless. We simply need to check that the 1106 // stop packet we receive is for the thread we requested, if it isn't we 1107 // can assume it is the spurious extra stop packet and simply ignore it. 1108 // An example of a problematic interaction is in the commit message for 1109 // this change. 1110 // See https://github.com/go-delve/delve/issues/3013. 1111 1112 conn.conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond)) 1113 resp, err = conn.recv(conn.outbuf.Bytes(), "thread stop info", false) 1114 conn.conn.SetReadDeadline(time.Time{}) 1115 if err != nil { 1116 if neterr, isneterr := err.(net.Error); isneterr && neterr.Timeout() { 1117 return stopPacket{}, fmt.Errorf("qThreadStopInfo mismatch, requested %s got %s", sp.threadID, threadID) 1118 } 1119 return stopPacket{}, err 1120 } 1121 _, sp, err = conn.parseStopPacket(resp, "", nil) 1122 if err != nil { 1123 return stopPacket{}, err 1124 } 1125 if sp.threadID != threadID { 1126 return stopPacket{}, fmt.Errorf("qThreadStopInfo mismatch, requested %s got %s", sp.threadID, threadID) 1127 } 1128 } 1129 1130 return sp, nil 1131 } 1132 1133 // restart executes a 'vRun' command. 1134 func (conn *gdbConn) restart(pos string) error { 1135 conn.outbuf.Reset() 1136 fmt.Fprint(&conn.outbuf, "$vRun;") 1137 if pos != "" { 1138 fmt.Fprint(&conn.outbuf, ";") 1139 writeAsciiBytes(&conn.outbuf, []byte(pos)) 1140 } 1141 _, err := conn.exec(conn.outbuf.Bytes(), "restart") 1142 return err 1143 } 1144 1145 // qRRCmd executes a qRRCmd command 1146 func (conn *gdbConn) qRRCmd(args ...string) (string, error) { 1147 if len(args) == 0 { 1148 panic("must specify at least one argument for qRRCmd") 1149 } 1150 conn.outbuf.Reset() 1151 fmt.Fprint(&conn.outbuf, "$qRRCmd") 1152 for _, arg := range args { 1153 fmt.Fprint(&conn.outbuf, ":") 1154 writeAsciiBytes(&conn.outbuf, []byte(arg)) 1155 } 1156 resp, err := conn.exec(conn.outbuf.Bytes(), "qRRCmd") 1157 if err != nil { 1158 return "", err 1159 } 1160 data := make([]byte, 0, len(resp)/2) 1161 for i := 0; i < len(resp); i += 2 { 1162 n, _ := strconv.ParseUint(string(resp[i:i+2]), 16, 8) 1163 data = append(data, uint8(n)) 1164 } 1165 return string(data), nil 1166 } 1167 1168 type imageList struct { 1169 Images []imageDescription `json:"images"` 1170 } 1171 1172 type imageDescription struct { 1173 LoadAddress uint64 `json:"load_address"` 1174 Pathname string `json:"pathname"` 1175 MachHeader machHeader `json:"mach_header"` 1176 } 1177 1178 type machHeader struct { 1179 FileType macho.Type `json:"filetype"` 1180 } 1181 1182 // getLoadedDynamicLibraries executes jGetLoadedDynamicLibrariesInfos which 1183 // returns the list of loaded dynamic libraries 1184 func (conn *gdbConn) getLoadedDynamicLibraries() ([]imageDescription, error) { 1185 cmd := []byte("$jGetLoadedDynamicLibrariesInfos:{\"fetch_all_solibs\":true}") 1186 if err := conn.send(cmd); err != nil { 1187 return nil, err 1188 } 1189 resp, err := conn.recv(cmd, "get dynamic libraries", true) 1190 if err != nil { 1191 return nil, err 1192 } 1193 var images imageList 1194 err = json.Unmarshal(resp, &images) 1195 return images.Images, err 1196 } 1197 1198 type memoryRegionInfo struct { 1199 start uint64 1200 size uint64 1201 permissions string 1202 name string 1203 } 1204 1205 func decodeHexString(in []byte) (string, bool) { 1206 out := make([]byte, 0, len(in)/2) 1207 for i := 0; i < len(in); i += 2 { 1208 v, err := strconv.ParseUint(string(in[i:i+2]), 16, 8) 1209 if err != nil { 1210 return "", false 1211 } 1212 out = append(out, byte(v)) 1213 } 1214 return string(out), true 1215 } 1216 1217 func (conn *gdbConn) memoryRegionInfo(addr uint64) (*memoryRegionInfo, error) { 1218 conn.outbuf.Reset() 1219 fmt.Fprintf(&conn.outbuf, "$qMemoryRegionInfo:%x", addr) 1220 resp, err := conn.exec(conn.outbuf.Bytes(), "qMemoryRegionInfo") 1221 if err != nil { 1222 return nil, err 1223 } 1224 1225 mri := &memoryRegionInfo{} 1226 1227 buf := resp 1228 for len(buf) > 0 { 1229 colon := bytes.Index(buf, []byte{':'}) 1230 if colon < 0 { 1231 break 1232 } 1233 key := buf[:colon] 1234 buf = buf[colon+1:] 1235 1236 semicolon := bytes.Index(buf, []byte{';'}) 1237 var value []byte 1238 if semicolon < 0 { 1239 value = buf 1240 buf = nil 1241 } else { 1242 value = buf[:semicolon] 1243 buf = buf[semicolon+1:] 1244 } 1245 1246 switch string(key) { 1247 case "start": 1248 start, err := strconv.ParseUint(string(value), 16, 64) 1249 if err != nil { 1250 return nil, fmt.Errorf("malformed qMemoryRegionInfo response packet (start): %v in %s", err, string(resp)) 1251 } 1252 mri.start = start 1253 case "size": 1254 size, err := strconv.ParseUint(string(value), 16, 64) 1255 if err != nil { 1256 return nil, fmt.Errorf("malformed qMemoryRegionInfo response packet (size): %v in %s", err, string(resp)) 1257 } 1258 mri.size = size 1259 case "permissions": 1260 mri.permissions = string(value) 1261 case "name": 1262 namestr, ok := decodeHexString(value) 1263 if !ok { 1264 return nil, fmt.Errorf("malformed qMemoryRegionInfo response packet (name): %s", string(resp)) 1265 } 1266 mri.name = namestr 1267 case "error": 1268 errstr, ok := decodeHexString(value) 1269 if !ok { 1270 return nil, fmt.Errorf("malformed qMemoryRegionInfo response packet (error): %s", string(resp)) 1271 } 1272 return nil, fmt.Errorf("qMemoryRegionInfo error: %s", errstr) 1273 } 1274 } 1275 1276 return mri, nil 1277 } 1278 1279 // exec executes a message to the stub and reads a response. 1280 // The details of the wire protocol are described here: 1281 // 1282 // https://sourceware.org/gdb/onlinedocs/gdb/Overview.html#Overview 1283 func (conn *gdbConn) exec(cmd []byte, context string) ([]byte, error) { 1284 if err := conn.send(cmd); err != nil { 1285 return nil, err 1286 } 1287 return conn.recv(cmd, context, false) 1288 } 1289 1290 var hexdigit = []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} 1291 1292 func (conn *gdbConn) send(cmd []byte) error { 1293 if len(cmd) == 0 || cmd[0] != '$' { 1294 panic("gdb protocol error: command doesn't start with '$'") 1295 } 1296 1297 // append checksum to packet 1298 cmd = append(cmd, '#') 1299 sum := checksum(cmd) 1300 cmd = append(cmd, hexdigit[sum>>4], hexdigit[sum&0xf]) 1301 1302 attempt := 0 1303 for { 1304 if logflags.GdbWire() { 1305 if len(cmd) > gdbWireMaxLen { 1306 conn.log.Debugf("<- %s...", string(cmd[:gdbWireMaxLen])) 1307 } else { 1308 conn.log.Debugf("<- %s", string(cmd)) 1309 } 1310 } 1311 _, err := conn.conn.Write(cmd) 1312 if err != nil { 1313 return err 1314 } 1315 1316 if !conn.ack { 1317 break 1318 } 1319 1320 if conn.readack() { 1321 break 1322 } 1323 if attempt > conn.maxTransmitAttempts { 1324 return ErrTooManyAttempts 1325 } 1326 attempt++ 1327 } 1328 return nil 1329 } 1330 1331 func (conn *gdbConn) recv(cmd []byte, context string, binary bool) (resp []byte, err error) { 1332 attempt := 0 1333 for { 1334 var err error 1335 resp, err = conn.rdr.ReadBytes('#') 1336 if err != nil { 1337 return nil, err 1338 } 1339 1340 // read checksum 1341 _, err = io.ReadFull(conn.rdr, conn.inbuf[:2]) 1342 if err != nil { 1343 return nil, err 1344 } 1345 if logflags.GdbWire() { 1346 out := resp 1347 partial := false 1348 if idx := bytes.Index(out, []byte{'\n'}); idx >= 0 && !binary { 1349 out = resp[:idx] 1350 partial = true 1351 } 1352 if len(out) > gdbWireMaxLen { 1353 out = out[:gdbWireMaxLen] 1354 partial = true 1355 } 1356 if !partial { 1357 if binary { 1358 conn.log.Debugf("-> %q%s", string(resp), string(conn.inbuf[:2])) 1359 } else { 1360 conn.log.Debugf("-> %s%s", string(resp), string(conn.inbuf[:2])) 1361 } 1362 } else { 1363 if binary { 1364 conn.log.Debugf("-> %q...", string(out)) 1365 } else { 1366 conn.log.Debugf("-> %s...", string(out)) 1367 } 1368 } 1369 } 1370 1371 if !conn.ack { 1372 break 1373 } 1374 1375 if resp[0] == '%' { 1376 // If the first character is a % (instead of $) the stub sent us a 1377 // notification packet, this is weird since we specifically claimed that 1378 // we don't support notifications of any kind, but it should be safe to 1379 // ignore regardless. 1380 continue 1381 } 1382 1383 if checksumok(resp, conn.inbuf[:2]) { 1384 conn.sendack('+') 1385 break 1386 } 1387 if attempt > conn.maxTransmitAttempts { 1388 conn.sendack('+') 1389 return nil, ErrTooManyAttempts 1390 } 1391 attempt++ 1392 conn.sendack('-') 1393 } 1394 1395 if binary { 1396 conn.inbuf, resp = binarywiredecode(resp, conn.inbuf) 1397 } else { 1398 conn.inbuf, resp = wiredecode(resp, conn.inbuf) 1399 } 1400 1401 if len(resp) == 0 || (resp[0] == 'E' && !binary) || (resp[0] == 'E' && len(resp) == 3) { 1402 cmdstr := "" 1403 if cmd != nil { 1404 cmdstr = string(cmd) 1405 } 1406 return nil, &GdbProtocolError{context, cmdstr, string(resp)} 1407 } 1408 1409 return resp, nil 1410 } 1411 1412 // Readack reads one byte from stub, returns true if the byte is '+' 1413 func (conn *gdbConn) readack() bool { 1414 b, err := conn.rdr.ReadByte() 1415 if err != nil { 1416 return false 1417 } 1418 conn.log.Debugf("-> %s", string(b)) 1419 return b == '+' 1420 } 1421 1422 // Sendack executes an ack character, c must be either '+' or '-' 1423 func (conn *gdbConn) sendack(c byte) { 1424 if c != '+' && c != '-' { 1425 panic(fmt.Errorf("sendack(%c)", c)) 1426 } 1427 conn.conn.Write([]byte{c}) 1428 conn.log.Debugf("<- %s", string(c)) 1429 } 1430 1431 // escapeXor is the value mandated by the specification to escape characters 1432 const escapeXor byte = 0x20 1433 1434 // wiredecode decodes the contents of in into buf. 1435 // If buf is nil it will be allocated ex-novo, if the size of buf is not 1436 // enough to hold the decoded contents it will be grown. 1437 // Returns the newly allocated buffer as newbuf and the message contents as 1438 // msg. 1439 func wiredecode(in, buf []byte) (newbuf, msg []byte) { 1440 if buf != nil { 1441 buf = buf[:0] 1442 } else { 1443 buf = make([]byte, 0, 256) 1444 } 1445 1446 start := 1 1447 1448 for i := 0; i < len(in); i++ { 1449 switch ch := in[i]; ch { 1450 case '{': // escape 1451 if i+1 >= len(in) { 1452 buf = append(buf, ch) 1453 } else { 1454 buf = append(buf, in[i+1]^escapeXor) 1455 i++ 1456 } 1457 case ':': 1458 buf = append(buf, ch) 1459 if i == 3 { 1460 // we just read the sequence identifier 1461 start = i + 1 1462 } 1463 case '#': // end of packet 1464 return buf, buf[start:] 1465 case '*': // runlength encoding marker 1466 if i+1 >= len(in) || i == 0 { 1467 buf = append(buf, ch) 1468 } else { 1469 n := in[i+1] - 29 1470 r := buf[len(buf)-1] 1471 for j := uint8(0); j < n; j++ { 1472 buf = append(buf, r) 1473 } 1474 i++ 1475 } 1476 default: 1477 buf = append(buf, ch) 1478 } 1479 } 1480 return buf, buf[start:] 1481 } 1482 1483 // binarywiredecode is like wiredecode but decodes the wire encoding for 1484 // binary packets, such as the 'x' and 'X' packets as well as all the json 1485 // packets used by lldb/debugserver. 1486 func binarywiredecode(in, buf []byte) (newbuf, msg []byte) { 1487 if buf != nil { 1488 buf = buf[:0] 1489 } else { 1490 buf = make([]byte, 0, 256) 1491 } 1492 1493 start := 1 1494 1495 for i := 0; i < len(in); i++ { 1496 switch ch := in[i]; ch { 1497 case '}': // escape 1498 if i+1 >= len(in) { 1499 buf = append(buf, ch) 1500 } else { 1501 buf = append(buf, in[i+1]^escapeXor) 1502 i++ 1503 } 1504 case '#': // end of packet 1505 return buf, buf[start:] 1506 default: 1507 buf = append(buf, ch) 1508 } 1509 } 1510 return buf, buf[start:] 1511 } 1512 1513 // Checksumok checks that checksum is a valid checksum for packet. 1514 func checksumok(packet, checksumBuf []byte) bool { 1515 if packet[0] != '$' { 1516 return false 1517 } 1518 1519 sum := checksum(packet) 1520 tgt, err := strconv.ParseUint(string(checksumBuf), 16, 8) 1521 if err != nil { 1522 return false 1523 } 1524 1525 tgt8 := uint8(tgt) 1526 1527 return sum == tgt8 1528 } 1529 1530 func checksum(packet []byte) (sum uint8) { 1531 for i := 1; i < len(packet); i++ { 1532 if packet[i] == '#' { 1533 return sum 1534 } 1535 sum += packet[i] 1536 } 1537 return sum 1538 }