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