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  }