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