github.com/ks888/tgo@v0.0.0-20190130135156-80bf89407292/debugapi/client_darwin.go (about) 1 package debugapi 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "io" 9 "net" 10 "os" 11 "os/exec" 12 "strconv" 13 "strings" 14 "syscall" 15 "time" 16 17 "github.com/ks888/tgo/log" 18 "golang.org/x/sys/unix" 19 ) 20 21 // Assumes the packet size is not larger than this. 22 const ( 23 maxPacketSize = 4096 24 excBadAccess = syscall.Signal(0x91) // EXC_BAD_ACCESS 25 ) 26 27 // Client is the debug api client which depends on lldb's debugserver. 28 // See the gdb's doc for the reference: https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html 29 // Some commands use the lldb extension: https://github.com/llvm-mirror/lldb/blob/master/docs/lldb-gdb-remote.txt 30 type Client struct { 31 conn net.Conn 32 pid int 33 killOnDetach bool 34 noAckMode bool 35 registerMetadataList []registerMetadata 36 buffer []byte 37 // outputWriter is the writer to which the output of the debugee process will be written. 38 outputWriter io.Writer 39 40 readTLSFuncAddr uint64 41 currentTLSOffset uint32 42 pendingSignal int 43 } 44 45 // NewClient returns the new debug api client which depends on OS API. 46 func NewClient() *Client { 47 return &Client{buffer: make([]byte, maxPacketSize), outputWriter: os.Stdout} 48 } 49 50 // LaunchProcess lets the debugserver launch the new prcoess. 51 func (c *Client) LaunchProcess(name string, arg ...string) error { 52 listener, err := net.Listen("tcp", "localhost:") 53 if err != nil { 54 return err 55 } 56 57 path, err := debugServerPath() 58 if err != nil { 59 return err 60 } 61 62 debugServerArgs := []string{"-F", "-R", listener.Addr().String(), "--", name} 63 debugServerArgs = append(debugServerArgs, arg...) 64 cmd := exec.Command(path, debugServerArgs...) 65 cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} // Otherwise, the signal sent to all the group members. 66 if err := cmd.Start(); err != nil { 67 return err 68 } 69 70 c.conn, err = c.waitConnectOrExit(listener, cmd) 71 if err != nil { 72 return err 73 } 74 c.pid = cmd.Process.Pid 75 c.killOnDetach = true 76 77 return c.initialize() 78 } 79 80 func (c *Client) waitConnectOrExit(listener net.Listener, cmd *exec.Cmd) (net.Conn, error) { 81 waitCh := make(chan error) 82 go func(ch chan error) { 83 ch <- cmd.Wait() 84 }(waitCh) 85 86 connCh := make(chan net.Conn) 87 go func(ch chan net.Conn) { 88 conn, err := listener.Accept() 89 if err != nil { 90 connCh <- nil 91 } 92 connCh <- conn 93 }(connCh) 94 95 select { 96 case <-waitCh: 97 return nil, errors.New("the command exits immediately") 98 case conn := <-connCh: 99 if conn == nil { 100 return nil, errors.New("failed to accept the connection") 101 } 102 return conn, nil 103 } 104 } 105 106 func (c *Client) initialize() error { 107 if err := c.setNoAckMode(); err != nil { 108 return err 109 } 110 111 if err := c.qSupported(); err != nil { 112 return err 113 } 114 115 if err := c.qThreadSuffixSupported(); err != nil { 116 return err 117 } 118 119 var err error 120 c.registerMetadataList, err = c.collectRegisterMetadata() 121 if err != nil { 122 return err 123 } 124 125 if err := c.qListThreadsInStopReply(); err != nil { 126 return err 127 } 128 129 readTLSFunction := c.buildReadTLSFunction(0) // need the function length here. So the offset doesn't matter. 130 c.readTLSFuncAddr, err = c.allocateMemory(len(readTLSFunction)) 131 return err 132 } 133 134 func (c *Client) setNoAckMode() error { 135 const command = "QStartNoAckMode" 136 if err := c.send(command); err != nil { 137 return err 138 } 139 140 if err := c.receiveAndCheck(); err != nil { 141 return err 142 } 143 144 c.noAckMode = true 145 return nil 146 } 147 148 func (c *Client) qSupported() error { 149 var supportedFeatures = []string{"swbreak+", "hwbreak+", "no-resumed+"} 150 command := fmt.Sprintf("qSupported:%s", strings.Join(supportedFeatures, ";")) 151 if err := c.send(command); err != nil { 152 return err 153 } 154 155 // TODO: adjust the buffer size so that it doesn't exceed the PacketSize in the response. 156 _, err := c.receive() 157 return err 158 } 159 160 func (c *Client) qThreadSuffixSupported() error { 161 const command = "QThreadSuffixSupported" 162 if err := c.send(command); err != nil { 163 return err 164 } 165 return c.receiveAndCheck() 166 } 167 168 var errEndOfList = errors.New("the end of list") 169 170 type registerMetadata struct { 171 name string 172 id, offset, size int 173 } 174 175 func (c *Client) collectRegisterMetadata() ([]registerMetadata, error) { 176 var regs []registerMetadata 177 for i := 0; ; i++ { 178 reg, err := c.qRegisterInfo(i) 179 if err != nil { 180 if err == errEndOfList { 181 break 182 } 183 return nil, err 184 } 185 regs = append(regs, reg) 186 } 187 188 return regs, nil 189 } 190 191 func (c *Client) qRegisterInfo(registerID int) (registerMetadata, error) { 192 command := fmt.Sprintf("qRegisterInfo%x", registerID) 193 if err := c.send(command); err != nil { 194 return registerMetadata{}, err 195 } 196 197 data, err := c.receive() 198 if err != nil { 199 return registerMetadata{}, err 200 } 201 202 if strings.HasPrefix(data, "E") { 203 if data == "E45" { 204 return registerMetadata{}, errEndOfList 205 } 206 return registerMetadata{}, fmt.Errorf("error response: %s", data) 207 } 208 209 return c.parseRegisterMetaData(registerID, data) 210 } 211 212 func (c *Client) parseRegisterMetaData(registerID int, data string) (registerMetadata, error) { 213 reg := registerMetadata{id: registerID} 214 for _, chunk := range strings.Split(data, ";") { 215 keyValue := strings.SplitN(chunk, ":", 2) 216 if len(keyValue) < 2 { 217 continue 218 } 219 220 key, value := keyValue[0], keyValue[1] 221 if key == "name" { 222 reg.name = value 223 224 } else if key == "bitsize" { 225 num, err := strconv.Atoi(value) 226 if err != nil { 227 return registerMetadata{}, err 228 } 229 reg.size = num / 8 230 231 } else if key == "offset" { 232 num, err := strconv.Atoi(value) 233 if err != nil { 234 return registerMetadata{}, err 235 } 236 237 reg.offset = num 238 } 239 } 240 241 return reg, nil 242 } 243 244 func (c *Client) qListThreadsInStopReply() error { 245 const command = "QListThreadsInStopReply" 246 if err := c.send(command); err != nil { 247 return err 248 } 249 250 return c.receiveAndCheck() 251 } 252 253 func (c *Client) allocateMemory(size int) (uint64, error) { 254 command := fmt.Sprintf("_M%x,rwx", size) 255 if err := c.send(command); err != nil { 256 return 0, err 257 } 258 259 data, err := c.receive() 260 if err != nil { 261 return 0, err 262 } else if data == "" || strings.HasPrefix(data, "E") { 263 return 0, fmt.Errorf("error response: %s", data) 264 } 265 266 return hexToUint64(data, false) 267 } 268 269 func (c *Client) deallocateMemory(addr uint64) error { 270 command := fmt.Sprintf("_m%x", addr) 271 if err := c.send(command); err != nil { 272 return err 273 } 274 275 return c.receiveAndCheck() 276 } 277 278 // ThreadIDs returns all the thread ids. 279 func (c *Client) ThreadIDs() ([]int, error) { 280 rawThreadIDs, err := c.qfThreadInfo() 281 if err != nil { 282 return nil, err 283 } 284 // TODO: call qsThreadInfo 285 286 var threadIDs []int 287 for _, rawThreadID := range strings.Split(rawThreadIDs, ",") { 288 threadID, err := hexToUint64(rawThreadID, false) 289 if err != nil { 290 return nil, err 291 } 292 threadIDs = append(threadIDs, int(threadID)) 293 } 294 return threadIDs, nil 295 } 296 297 func (c *Client) qfThreadInfo() (string, error) { 298 const command = "qfThreadInfo" 299 if err := c.send(command); err != nil { 300 return "", err 301 } 302 303 data, err := c.receive() 304 if err != nil { 305 return "", err 306 } else if !strings.HasPrefix(data, "m") { 307 return "", fmt.Errorf("unexpected response: %s", data) 308 } 309 310 return data[1:], nil 311 } 312 313 // AttachProcess lets the debugserver attach the new prcoess. 314 func (c *Client) AttachProcess(pid int) error { 315 listener, err := net.Listen("tcp", "localhost:") 316 if err != nil { 317 return err 318 } 319 320 path, err := debugServerPath() 321 if err != nil { 322 return err 323 } 324 325 debugServerArgs := []string{"-F", "-R", listener.Addr().String(), fmt.Sprintf("--attach=%d", pid)} 326 cmd := exec.Command(path, debugServerArgs...) 327 cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} // Otherwise, the signal sent to all the group members. 328 if err := cmd.Start(); err != nil { 329 return err 330 } 331 332 c.conn, err = c.waitConnectOrExit(listener, cmd) 333 if err != nil { 334 return err 335 } 336 c.pid = cmd.Process.Pid 337 338 return c.initialize() 339 } 340 341 // DetachProcess detaches from the prcoess. 342 func (c *Client) DetachProcess() error { 343 defer c.close() 344 if c.killOnDetach { 345 return c.killProcess() 346 } 347 348 if err := c.send("D"); err != nil { 349 return err 350 } 351 352 return c.receiveAndCheck() 353 } 354 355 func (c *Client) close() error { 356 return c.conn.Close() 357 } 358 359 func (c *Client) killProcess() error { 360 if err := c.send("k"); err != nil { 361 return err 362 } 363 data, err := c.receive() 364 if err != nil { 365 return err 366 } else if !strings.HasPrefix(data, "X09") { 367 return fmt.Errorf("unexpected reply: %s", data) 368 } 369 // debugserver automatically exits. So don't explicitly detach here. 370 return nil 371 } 372 373 // ReadRegisters reads the target threadID's registers. 374 func (c *Client) ReadRegisters(threadID int) (Registers, error) { 375 data, err := c.readRegisters(threadID) 376 if err != nil { 377 return Registers{}, err 378 } 379 380 return c.parseRegisterData(data) 381 } 382 383 func (c *Client) readRegisters(threadID int) (string, error) { 384 command := fmt.Sprintf("g;thread:%x;", threadID) 385 if err := c.send(command); err != nil { 386 return "", err 387 } 388 389 data, err := c.receive() 390 if err != nil { 391 return "", err 392 } else if strings.HasPrefix(data, "E") { 393 return data, fmt.Errorf("error response: %s", data) 394 } 395 return data, nil 396 } 397 398 func (c *Client) parseRegisterData(data string) (Registers, error) { 399 var regs Registers 400 for _, metadata := range c.registerMetadataList { 401 rawValue := data[metadata.offset*2 : (metadata.offset+metadata.size)*2] 402 403 var err error 404 switch metadata.name { 405 case "rip": 406 regs.Rip, err = hexToUint64(rawValue, true) 407 case "rsp": 408 regs.Rsp, err = hexToUint64(rawValue, true) 409 case "rcx": 410 regs.Rcx, err = hexToUint64(rawValue, true) 411 } 412 if err != nil { 413 return Registers{}, err 414 } 415 } 416 417 return regs, nil 418 } 419 420 // WriteRegisters updates the registers' value. 421 func (c *Client) WriteRegisters(threadID int, regs Registers) error { 422 data, err := c.readRegisters(threadID) 423 if err != nil { 424 return err 425 } 426 427 // The 'P' command is not used due to the bug explained here: https://github.com/llvm-mirror/lldb/commit/d8d7a40ca5377aa777e3840f3e9b6a63c6b09445 428 429 for _, metadata := range c.registerMetadataList { 430 prefix := data[0 : metadata.offset*2] 431 suffix := data[(metadata.offset+metadata.size)*2:] 432 433 var err error 434 switch metadata.name { 435 case "rip": 436 data = fmt.Sprintf("%s%s%s", prefix, uint64ToHex(regs.Rip, true), suffix) 437 case "rsp": 438 data = fmt.Sprintf("%s%s%s", prefix, uint64ToHex(regs.Rsp, true), suffix) 439 case "rcx": 440 data = fmt.Sprintf("%s%s%s", prefix, uint64ToHex(regs.Rcx, true), suffix) 441 } 442 if err != nil { 443 return err 444 } 445 } 446 447 command := fmt.Sprintf("G%s;thread:%x;", data, threadID) 448 if err := c.send(command); err != nil { 449 return err 450 } 451 452 return c.receiveAndCheck() 453 } 454 455 // ReadMemory reads the specified memory region. 456 func (c *Client) ReadMemory(addr uint64, out []byte) error { 457 command := fmt.Sprintf("m%x,%x", addr, len(out)) 458 if err := c.send(command); err != nil { 459 return err 460 } 461 462 data, err := c.receive() 463 if err != nil { 464 return err 465 } else if strings.HasPrefix(data, "E") { 466 return fmt.Errorf("error response: %s", data) 467 } 468 469 byteArrary, err := hexToByteArray(data) 470 if err != nil { 471 return err 472 } 473 if len(byteArrary) != len(out) { 474 log.Debugf("The data size read from the memory is smaller than the requested size. actual: %d, expected: %d", len(byteArrary), len(out)) 475 } 476 copy(out, byteArrary) 477 return nil 478 } 479 480 // WriteMemory write the data to the specified region 481 func (c *Client) WriteMemory(addr uint64, data []byte) error { 482 dataInHex := "" 483 for _, b := range data { 484 dataInHex += fmt.Sprintf("%02x", b) 485 } 486 command := fmt.Sprintf("M%x,%x:%s", addr, len(data), dataInHex) 487 if err := c.send(command); err != nil { 488 return err 489 } 490 491 return c.receiveAndCheck() 492 } 493 494 // ReadTLS reads the offset from the beginning of the TLS block. 495 func (c *Client) ReadTLS(threadID int, offset int32) (uint64, error) { 496 if err := c.updateReadTLSFunction(uint32(offset)); err != nil { 497 return 0, err 498 } 499 500 originalRegs, err := c.ReadRegisters(threadID) 501 if err != nil { 502 return 0, err 503 } 504 defer func() { err = c.WriteRegisters(threadID, originalRegs) }() 505 506 modifiedRegs := originalRegs 507 modifiedRegs.Rip = c.readTLSFuncAddr 508 if err = c.WriteRegisters(threadID, modifiedRegs); err != nil { 509 return 0, err 510 } 511 512 if _, err := c.StepAndWait(threadID); err != nil { 513 return 0, err 514 } 515 516 modifiedRegs, err = c.ReadRegisters(threadID) 517 return modifiedRegs.Rcx, err 518 } 519 520 func (c *Client) updateReadTLSFunction(offset uint32) error { 521 if c.currentTLSOffset == offset { 522 return nil 523 } 524 525 readTLSFunction := c.buildReadTLSFunction(offset) 526 if err := c.WriteMemory(c.readTLSFuncAddr, readTLSFunction); err != nil { 527 return err 528 } 529 c.currentTLSOffset = offset 530 return nil 531 } 532 533 func (c *Client) buildReadTLSFunction(offset uint32) []byte { 534 offsetBytes := make([]byte, 4) 535 binary.LittleEndian.PutUint32(offsetBytes, offset) 536 537 readTLSFunction := []byte{0x65, 0x48, 0x8b, 0x0c, 0x25} // mac OS X uses gs_base 538 return append(readTLSFunction, offsetBytes...) 539 } 540 541 // ContinueAndWait resumes processes and waits until an event happens. 542 // The exited event is reported when the main process exits (and not when its threads exit). 543 func (c *Client) ContinueAndWait() (Event, error) { 544 return c.continueAndWait(c.pendingSignal) 545 } 546 547 // StepAndWait executes the one instruction of the specified thread and waits until an event happens. 548 // The returned event may not be the trapped event. 549 // If unspecified thread is stopped, UnspecifiedThreadError is returned. 550 func (c *Client) StepAndWait(threadID int) (Event, error) { 551 var command string 552 if c.pendingSignal == 0 { 553 command = fmt.Sprintf("vCont;s:%x", threadID) 554 } else { 555 command = fmt.Sprintf("vCont;S%02x:%x", c.pendingSignal, threadID) 556 } 557 558 if err := c.send(command); err != nil { 559 return Event{}, fmt.Errorf("send error: %v", err) 560 } 561 562 event, err := c.wait() 563 if err != nil { 564 return Event{}, err 565 } else if event.Type != EventTypeTrapped { 566 return Event{}, fmt.Errorf("unexpected event: %#v", event) 567 } else if threadIDs := event.Data.([]int); len(threadIDs) != 1 || threadIDs[0] != threadID { 568 return Event{}, UnspecifiedThreadError{ThreadIDs: threadIDs} 569 } 570 return event, err 571 } 572 573 func (c *Client) continueAndWait(signalNumber int) (Event, error) { 574 var command string 575 if signalNumber == 0 { 576 command = "vCont;c" 577 } else { 578 // Though the signal number is specified, it's like the debugserver does not pass the signals like SIGTERM and SIGINT to the debugee. 579 // QPassSignals can change this setting, but debugserver (900.0.64) doesn't support the query. 580 command = fmt.Sprintf("vCont;C%02x", signalNumber) 581 } 582 if err := c.send(command); err != nil { 583 return Event{}, fmt.Errorf("send error: %v", err) 584 } 585 586 return c.wait() 587 } 588 589 func (c *Client) wait() (Event, error) { 590 var data string 591 var err error 592 for { 593 data, err = c.receiveWithTimeout(10 * time.Second) 594 if netErr, ok := err.(net.Error); ok && netErr.Timeout() { 595 // debugserver sometimes does not send a reply packet even when a thread is stopped. 596 data, err = c.checkStopReply() 597 if err != nil { 598 return Event{}, fmt.Errorf("failed to query stop reply: %v", err) 599 } else if data != "" { 600 log.Debugf("debugserver did not reply packets though there is the stopped thread.") 601 break 602 } 603 } else if err != nil { 604 return Event{}, fmt.Errorf("receive error: %v", err) 605 } 606 if data != "" { 607 break 608 } 609 } 610 611 stopReplies := c.buildStopReplies(data) 612 // process O packet beforehand in order to simplify further processing. 613 stopReplies, err = c.processOutputPacket(stopReplies) 614 if err != nil { 615 return Event{}, fmt.Errorf("failed to process output packet: %v", err) 616 } 617 if len(stopReplies) == 0 { 618 return c.wait() 619 } 620 return c.handleStopReply(stopReplies) 621 } 622 623 func (c *Client) checkStopReply() (string, error) { 624 threadIDs, err := c.ThreadIDs() 625 if err != nil { 626 return "", err 627 } 628 629 for _, threadID := range threadIDs { 630 data, err := c.qThreadStopInfo(threadID) 631 if err != nil { 632 return "", err 633 } 634 if !strings.HasPrefix(data, "T00") { 635 return data, nil 636 } 637 } 638 return "", nil 639 } 640 641 func (c *Client) buildStopReplies(data string) []string { 642 replies := strings.Split(data, "$") 643 for i, reply := range replies { 644 if reply[len(reply)-3] == '#' { 645 replies[i] = reply[0 : len(reply)-3] 646 } 647 } 648 return replies 649 } 650 651 func (c *Client) processOutputPacket(stopReplies []string) ([]string, error) { 652 var unprocessedReplies []string 653 for _, stopReply := range stopReplies { 654 if stopReply[0] != 'O' { 655 unprocessedReplies = append(unprocessedReplies, stopReply) 656 continue 657 } 658 659 out, err := hexToByteArray(stopReply[1:]) 660 if err != nil { 661 return nil, err 662 } 663 c.outputWriter.Write(out) 664 } 665 return unprocessedReplies, nil 666 } 667 668 func (c *Client) handleStopReply(stopReplies []string) (event Event, err error) { 669 switch stopReplies[0][0] { 670 case 'T': 671 if len(stopReplies) > 1 { 672 log.Debugf("received 2 or more stop replies at once. Consider only first one. data: %v", stopReplies) 673 } 674 event, err = c.handleTPacket(stopReplies[0]) 675 case 'W': 676 // Ignore remaining packets because the process ends. 677 event, err = c.handleWPacket(stopReplies[0]) 678 case 'X': 679 // Ignore remaining packets because the process ends. 680 event, err = c.handleXPacket(stopReplies[0]) 681 default: 682 err = fmt.Errorf("unknown packet type: %s", stopReplies[0]) 683 } 684 if err != nil { 685 log.Debugf("failed to handle the packet (data: %v): %v", stopReplies[0], err) 686 return Event{}, err 687 } 688 689 if IsExitEvent(event.Type) { 690 // the connection may be closed already. 691 _ = c.close() 692 } 693 return event, nil 694 } 695 696 func (c *Client) handleTPacket(packet string) (Event, error) { 697 signalNumber, err := hexToUint64(packet[1:3], false) 698 if err != nil { 699 return Event{}, err 700 } 701 if syscall.Signal(signalNumber) == excBadAccess { 702 log.Debugf("bad memory access: %s", packet) 703 return Event{}, fmt.Errorf("bad memory access") 704 } 705 706 var threadIDs []int 707 for _, kvInStr := range strings.Split(packet[3:len(packet)-1], ";") { 708 kvArr := strings.Split(kvInStr, ":") 709 key, value := kvArr[0], kvArr[1] 710 if key == "threads" { 711 for _, threadID := range strings.Split(value, ",") { 712 threadIDInNum, err := hexToUint64(threadID, false) 713 if err != nil { 714 return Event{}, err 715 } 716 threadIDs = append(threadIDs, int(threadIDInNum)) 717 } 718 } 719 } 720 721 trappedThreadIDs, err := c.selectTrappedThreads(threadIDs) 722 if err != nil { 723 return Event{}, err 724 } else if len(trappedThreadIDs) == 0 { 725 return c.continueAndWait(int(signalNumber)) 726 } 727 if syscall.Signal(signalNumber) != unix.SIGTRAP { 728 c.pendingSignal = int(signalNumber) 729 } else { 730 c.pendingSignal = 0 731 } 732 733 return Event{Type: EventTypeTrapped, Data: trappedThreadIDs}, nil 734 } 735 736 func (c *Client) selectTrappedThreads(threadIDs []int) ([]int, error) { 737 var trappedThreads []int 738 for _, threadID := range threadIDs { 739 data, err := c.qThreadStopInfo(threadID) 740 if err != nil { 741 return nil, err 742 } 743 744 signalNumber, err := hexToUint64(data[1:3], false) 745 if err != nil { 746 return nil, err 747 } 748 749 if syscall.Signal(signalNumber) == unix.SIGTRAP { 750 trappedThreads = append(trappedThreads, threadID) 751 } 752 } 753 return trappedThreads, nil 754 } 755 756 func (c *Client) qThreadStopInfo(threadID int) (string, error) { 757 command := fmt.Sprintf("qThreadStopInfo%02x", threadID) 758 if err := c.send(command); err != nil { 759 return "", err 760 } 761 762 data, err := c.receive() 763 if err != nil { 764 return "", err 765 } else if strings.HasPrefix(data, "E") { 766 return data, fmt.Errorf("error response: %s", data) 767 } 768 return data, nil 769 } 770 771 func (c *Client) handleWPacket(packet string) (Event, error) { 772 exitStatus, err := hexToUint64(packet[1:3], false) 773 return Event{Type: EventTypeExited, Data: int(exitStatus)}, err 774 } 775 776 func (c *Client) handleXPacket(packet string) (Event, error) { 777 signalNumber, err := hexToUint64(packet[1:3], false) 778 // TODO: signalNumber here looks always 0. The number in the description looks correct, so maybe better to use it instead. 779 return Event{Type: EventTypeTerminated, Data: int(signalNumber)}, err 780 } 781 782 func (c *Client) send(command string) error { 783 packet := fmt.Sprintf("$%s#00", command) 784 if !c.noAckMode { 785 packet = fmt.Sprintf("$%s#%02x", command, calcChecksum([]byte(command))) 786 } 787 788 if n, err := c.conn.Write([]byte(packet)); err != nil { 789 return err 790 } else if n != len(packet) { 791 return fmt.Errorf("only part of the buffer is sent: %d / %d", n, len(packet)) 792 } 793 794 if !c.noAckMode { 795 return c.receiveAck() 796 } 797 return nil 798 } 799 800 func (c *Client) receiveAndCheck() error { 801 if data, err := c.receive(); err != nil { 802 return err 803 } else if data != "OK" { 804 return fmt.Errorf("the error response is returned: %s", data) 805 } 806 807 return nil 808 } 809 810 func (c *Client) receive() (string, error) { 811 var rawPacket []byte 812 for { 813 n, err := c.conn.Read(c.buffer) 814 if err != nil { 815 return "", err 816 } 817 818 rawPacket = append(rawPacket, c.buffer[0:n]...) 819 if len(rawPacket) < 4 { 820 // there should be at least 4 bytes 821 continue 822 } else if rawPacket[len(rawPacket)-3] == '#' { 823 // received at least 1 packet. 824 // TODO: handle multiple packets case 825 break 826 } 827 } 828 829 packet := string(rawPacket) 830 data := string(rawPacket[1 : len(rawPacket)-3]) 831 if !c.noAckMode { 832 if err := verifyPacket(packet); err != nil { 833 return "", err 834 } 835 return data, c.sendAck() 836 } 837 838 return data, nil 839 } 840 841 func (c *Client) receiveWithTimeout(timeout time.Duration) (string, error) { 842 c.conn.SetReadDeadline(time.Now().Add(timeout)) 843 defer c.conn.SetReadDeadline(time.Time{}) 844 845 return c.receive() 846 } 847 848 func (c *Client) sendAck() error { 849 _, err := c.conn.Write([]byte("+")) 850 return err 851 } 852 853 func (c *Client) receiveAck() error { 854 if _, err := c.conn.Read(c.buffer[0:1]); err != nil { 855 return err 856 } else if c.buffer[0] != '+' { 857 return errors.New("failed to receive ack") 858 } 859 860 return nil 861 } 862 863 func verifyPacket(packet string) error { 864 if packet[0:1] != "$" { 865 return fmt.Errorf("invalid head data: %v", packet[0]) 866 } 867 868 if packet[len(packet)-3:len(packet)-2] != "#" { 869 return fmt.Errorf("invalid tail data: %v", packet[len(packet)-3]) 870 } 871 872 body := packet[1 : len(packet)-3] 873 bodyChecksum := strconv.FormatUint(uint64(calcChecksum([]byte(body))), 16) 874 tailChecksum := packet[len(packet)-2:] 875 if tailChecksum != bodyChecksum { 876 return fmt.Errorf("invalid checksum: %s", tailChecksum) 877 } 878 879 return nil 880 } 881 882 func hexToUint64(hex string, littleEndian bool) (uint64, error) { 883 if littleEndian { 884 var reversedHex bytes.Buffer 885 for i := len(hex) - 2; i >= 0; i -= 2 { 886 reversedHex.WriteString(hex[i : i+2]) 887 } 888 hex = reversedHex.String() 889 } 890 return strconv.ParseUint(hex, 16, 64) 891 } 892 893 func hexToByteArray(hex string) ([]byte, error) { 894 out := make([]byte, len(hex)/2) 895 for i := 0; i < len(hex); i += 2 { 896 value, err := strconv.ParseUint(hex[i:i+2], 16, 8) 897 if err != nil { 898 return nil, err 899 } 900 901 out[i/2] = uint8(value) 902 } 903 return out, nil 904 } 905 906 func uint64ToHex(input uint64, littleEndian bool) string { 907 hex := fmt.Sprintf("%016x", input) 908 if littleEndian { 909 var reversedHex bytes.Buffer 910 for i := len(hex) - 2; i >= 0; i -= 2 { 911 reversedHex.WriteString(hex[i : i+2]) 912 } 913 hex = reversedHex.String() 914 } 915 return hex 916 } 917 918 func calcChecksum(buff []byte) uint8 { 919 var sum uint8 920 for _, b := range buff { 921 sum += b 922 } 923 return sum 924 } 925 926 var debugServerPathList = []string{ 927 "/Library/Developer/CommandLineTools/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/debugserver", 928 "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/debugserver", 929 } 930 931 func debugServerPath() (string, error) { 932 for _, path := range debugServerPathList { 933 if _, err := os.Stat(path); !os.IsNotExist(err) { 934 return path, nil 935 } 936 } 937 return "", fmt.Errorf("debugserver is not found in these paths: %v", debugServerPathList) 938 }