github.com/neilgarb/delve@v1.9.2-nobreaks/pkg/proc/gdbserial/gdbserver_conn.go (about)

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