| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * taken from gdb/remote.c |
| * |
| * I am only interested in the write to memory stuff - everything else |
| * has been ripped out |
| * |
| * all the copyright notices etc have been left in |
| */ |
| |
| /* enough so that it will compile */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| /*nicked from gcc..*/ |
| |
| #ifndef alloca |
| #ifdef __GNUC__ |
| #define alloca __builtin_alloca |
| #else /* not GNU C. */ |
| #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) |
| #include <alloca.h> |
| #else /* not sparc */ |
| #if defined (MSDOS) && !defined (__TURBOC__) |
| #include <malloc.h> |
| #else /* not MSDOS, or __TURBOC__ */ |
| #if defined(_AIX) |
| #include <malloc.h> |
| #pragma alloca |
| #else /* not MSDOS, __TURBOC__, or _AIX */ |
| #ifdef __hpux |
| #endif /* __hpux */ |
| #endif /* not _AIX */ |
| #endif /* not MSDOS, or __TURBOC__ */ |
| #endif /* not sparc. */ |
| #endif /* not GNU C. */ |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| void* alloca(size_t); |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif /* alloca not defined. */ |
| |
| #include "serial.h" |
| #include "error.h" |
| #include "remote.h" |
| #define REGISTER_BYTES 0 |
| #define fprintf_unfiltered fprintf |
| #define fprintf_filtered fprintf |
| #define fputs_unfiltered fputs |
| #define fputs_filtered fputs |
| #define fputc_unfiltered fputc |
| #define fputc_filtered fputc |
| #define printf_unfiltered printf |
| #define printf_filtered printf |
| #define puts_unfiltered puts |
| #define puts_filtered puts |
| #define putchar_unfiltered putchar |
| #define putchar_filtered putchar |
| #define fputstr_unfiltered(a,b,c) fputs((a), (c)) |
| #define gdb_stdlog stderr |
| #define SERIAL_READCHAR(fd,timo) serialreadchar((fd), (timo)) |
| #define SERIAL_WRITE(fd, addr, len) serialwrite((fd), (addr), (len)) |
| #define error Error |
| #define perror_with_name Perror |
| #define gdb_flush fflush |
| #define max(a,b) (((a)>(b))?(a):(b)) |
| #define min(a,b) (((a)<(b))?(a):(b)) |
| #define target_mourn_inferior() {} |
| #define ULONGEST unsigned long |
| #define CORE_ADDR unsigned long |
| |
| static int putpkt (char *); |
| static int putpkt_binary(char *, int); |
| static void getpkt (char *, int); |
| |
| static int remote_debug = 0, remote_register_buf_size = 0, watchdog = 0; |
| |
| int remote_desc = -1, remote_timeout = 10; |
| |
| static void |
| fputstrn_unfiltered(char *s, int n, int x, FILE *fp) |
| { |
| while (n-- > 0) |
| fputc(*s++, fp); |
| } |
| |
| void |
| remote_reset(void) |
| { |
| SERIAL_WRITE(remote_desc, "+", 1); |
| } |
| |
| void |
| remote_continue(void) |
| { |
| putpkt("c"); |
| } |
| |
| /* Remote target communications for serial-line targets in custom GDB protocol |
| Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 98, 1999 |
| Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| */ |
| /* *INDENT-OFF* */ |
| /* Remote communication protocol. |
| |
| A debug packet whose contents are <data> |
| is encapsulated for transmission in the form: |
| |
| $ <data> # CSUM1 CSUM2 |
| |
| <data> must be ASCII alphanumeric and cannot include characters |
| '$' or '#'. If <data> starts with two characters followed by |
| ':', then the existing stubs interpret this as a sequence number. |
| |
| CSUM1 and CSUM2 are ascii hex representation of an 8-bit |
| checksum of <data>, the most significant nibble is sent first. |
| the hex digits 0-9,a-f are used. |
| |
| Receiver responds with: |
| |
| + - if CSUM is correct and ready for next packet |
| - - if CSUM is incorrect |
| |
| <data> is as follows: |
| Most values are encoded in ascii hex digits. Signal numbers are according |
| to the numbering in target.h. |
| |
| Request Packet |
| |
| set thread Hct... Set thread for subsequent operations. |
| c = 'c' for thread used in step and |
| continue; t... can be -1 for all |
| threads. |
| c = 'g' for thread used in other |
| operations. If zero, pick a thread, |
| any thread. |
| reply OK for success |
| ENN for an error. |
| |
| read registers g |
| reply XX....X Each byte of register data |
| is described by two hex digits. |
| Registers are in the internal order |
| for GDB, and the bytes in a register |
| are in the same order the machine uses. |
| or ENN for an error. |
| |
| write regs GXX..XX Each byte of register data |
| is described by two hex digits. |
| reply OK for success |
| ENN for an error |
| |
| write reg Pn...=r... Write register n... with value r..., |
| which contains two hex digits for each |
| byte in the register (target byte |
| order). |
| reply OK for success |
| ENN for an error |
| (not supported by all stubs). |
| |
| read mem mAA..AA,LLLL AA..AA is address, LLLL is length. |
| reply XX..XX XX..XX is mem contents |
| Can be fewer bytes than requested |
| if able to read only part of the data. |
| or ENN NN is errno |
| |
| write mem MAA..AA,LLLL:XX..XX |
| AA..AA is address, |
| LLLL is number of bytes, |
| XX..XX is data |
| reply OK for success |
| ENN for an error (this includes the case |
| where only part of the data was |
| written). |
| |
| write mem XAA..AA,LLLL:XX..XX |
| (binary) AA..AA is address, |
| LLLL is number of bytes, |
| XX..XX is binary data |
| reply OK for success |
| ENN for an error |
| |
| continue cAA..AA AA..AA is address to resume |
| If AA..AA is omitted, |
| resume at same address. |
| |
| step sAA..AA AA..AA is address to resume |
| If AA..AA is omitted, |
| resume at same address. |
| |
| continue with Csig;AA..AA Continue with signal sig (hex signal |
| signal number). If ;AA..AA is omitted, |
| resume at same address. |
| |
| step with Ssig;AA..AA Like 'C' but step not continue. |
| signal |
| |
| last signal ? Reply the current reason for stopping. |
| This is the same reply as is generated |
| for step or cont : SAA where AA is the |
| signal number. |
| |
| detach D Reply OK. |
| |
| There is no immediate reply to step or cont. |
| The reply comes when the machine stops. |
| It is SAA AA is the signal number. |
| |
| or... TAAn...:r...;n...:r...;n...:r...; |
| AA = signal number |
| n... = register number (hex) |
| r... = register contents |
| n... = `thread' |
| r... = thread process ID. This is |
| a hex integer. |
| n... = other string not starting |
| with valid hex digit. |
| gdb should ignore this n,r pair |
| and go on to the next. This way |
| we can extend the protocol. |
| or... WAA The process exited, and AA is |
| the exit status. This is only |
| applicable for certains sorts of |
| targets. |
| or... XAA The process terminated with signal |
| AA. |
| or (obsolete) NAA;tttttttt;dddddddd;bbbbbbbb |
| AA = signal number |
| tttttttt = address of symbol "_start" |
| dddddddd = base of data section |
| bbbbbbbb = base of bss section. |
| Note: only used by Cisco Systems |
| targets. The difference between this |
| reply and the "qOffsets" query is that |
| the 'N' packet may arrive spontaneously |
| whereas the 'qOffsets' is a query |
| initiated by the host debugger. |
| or... OXX..XX XX..XX is hex encoding of ASCII data. This |
| can happen at any time while the |
| program is running and the debugger |
| should continue to wait for |
| 'W', 'T', etc. |
| |
| thread alive TXX Find out if the thread XX is alive. |
| reply OK thread is still alive |
| ENN thread is dead |
| |
| remote restart RXX Restart the remote server |
| |
| extended ops ! Use the extended remote protocol. |
| Sticky -- only needs to be set once. |
| |
| kill request k |
| |
| toggle debug d toggle debug flag (see 386 & 68k stubs) |
| reset r reset -- see sparc stub. |
| reserved <other> On other requests, the stub should |
| ignore the request and send an empty |
| response ($#<checksum>). This way |
| we can extend the protocol and GDB |
| can tell whether the stub it is |
| talking to uses the old or the new. |
| search tAA:PP,MM Search backwards starting at address |
| AA for a match with pattern PP and |
| mask MM. PP and MM are 4 bytes. |
| Not supported by all stubs. |
| |
| general query qXXXX Request info about XXXX. |
| general set QXXXX=yyyy Set value of XXXX to yyyy. |
| query sect offs qOffsets Get section offsets. Reply is |
| Text=xxx;Data=yyy;Bss=zzz |
| |
| Responses can be run-length encoded to save space. A '*' means that |
| the next character is an ASCII encoding giving a repeat count which |
| stands for that many repititions of the character preceding the '*'. |
| The encoding is n+29, yielding a printable character where n >=3 |
| (which is where rle starts to win). Don't use an n > 126. |
| |
| So |
| "0* " means the same as "0000". */ |
| /* *INDENT-ON* */ |
| |
| /* This variable (available to the user via "set remotebinarydownload") |
| dictates whether downloads are sent in binary (via the 'X' packet). |
| We assume that the stub can, and attempt to do it. This will be cleared if |
| the stub does not understand it. This switch is still needed, though |
| in cases when the packet is supported in the stub, but the connection |
| does not allow it (i.e., 7-bit serial connection only). */ |
| static int remote_binary_download = 1; |
| |
| /* Have we already checked whether binary downloads work? */ |
| static int remote_binary_checked; |
| |
| /* Maximum number of bytes to read/write at once. The value here |
| is chosen to fill up a packet (the headers account for the 32). */ |
| #define MAXBUFBYTES(N) (((N)-32)/2) |
| |
| /* Having this larger than 400 causes us to be incompatible with m68k-stub.c |
| and i386-stub.c. Normally, no one would notice because it only matters |
| for writing large chunks of memory (e.g. in downloads). Also, this needs |
| to be more than 400 if required to hold the registers (see below, where |
| we round it up based on REGISTER_BYTES). */ |
| /* Round up PBUFSIZ to hold all the registers, at least. */ |
| #define PBUFSIZ ((REGISTER_BYTES > MAXBUFBYTES (400)) \ |
| ? (REGISTER_BYTES * 2 + 32) \ |
| : 400) |
| |
| /* This variable sets the number of bytes to be written to the target |
| in a single packet. Normally PBUFSIZ is satisfactory, but some |
| targets need smaller values (perhaps because the receiving end |
| is slow). */ |
| |
| static int remote_write_size = 0x7fffffff; |
| |
| /* This variable sets the number of bits in an address that are to be |
| sent in a memory ("M" or "m") packet. Normally, after stripping |
| leading zeros, the entire address would be sent. This variable |
| restricts the address to REMOTE_ADDRESS_SIZE bits. HISTORY: The |
| initial implementation of remote.c restricted the address sent in |
| memory packets to ``host::sizeof long'' bytes - (typically 32 |
| bits). Consequently, for 64 bit targets, the upper 32 bits of an |
| address was never sent. Since fixing this bug may cause a break in |
| some remote targets this variable is principly provided to |
| facilitate backward compatibility. */ |
| |
| static int remote_address_size; |
| |
| /* Convert hex digit A to a number. */ |
| |
| static int |
| fromhex (int a) |
| { |
| if (a >= '0' && a <= '9') |
| return a - '0'; |
| else if (a >= 'a' && a <= 'f') |
| return a - 'a' + 10; |
| else if (a >= 'A' && a <= 'F') |
| return a - 'A' + 10; |
| else { |
| error ("Reply contains invalid hex digit %d", a); |
| return -1; |
| } |
| } |
| |
| /* Convert number NIB to a hex digit. */ |
| |
| static int |
| tohex (int nib) |
| { |
| if (nib < 10) |
| return '0' + nib; |
| else |
| return 'a' + nib - 10; |
| } |
| |
| /* Return the number of hex digits in num. */ |
| |
| static int |
| hexnumlen (ULONGEST num) |
| { |
| int i; |
| |
| for (i = 0; num != 0; i++) |
| num >>= 4; |
| |
| return max (i, 1); |
| } |
| |
| /* Set BUF to the hex digits representing NUM. */ |
| |
| static int |
| hexnumstr (char *buf, ULONGEST num) |
| { |
| int i; |
| int len = hexnumlen (num); |
| |
| buf[len] = '\0'; |
| |
| for (i = len - 1; i >= 0; i--) |
| { |
| buf[i] = "0123456789abcdef"[(num & 0xf)]; |
| num >>= 4; |
| } |
| |
| return len; |
| } |
| |
| /* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */ |
| |
| static CORE_ADDR |
| remote_address_masked (CORE_ADDR addr) |
| { |
| if (remote_address_size > 0 |
| && remote_address_size < (sizeof (ULONGEST) * 8)) |
| { |
| /* Only create a mask when that mask can safely be constructed |
| in a ULONGEST variable. */ |
| ULONGEST mask = 1; |
| mask = (mask << remote_address_size) - 1; |
| addr &= mask; |
| } |
| return addr; |
| } |
| |
| /* Determine whether the remote target supports binary downloading. |
| This is accomplished by sending a no-op memory write of zero length |
| to the target at the specified address. It does not suffice to send |
| the whole packet, since many stubs strip the eighth bit and subsequently |
| compute a wrong checksum, which causes real havoc with remote_write_bytes. |
| |
| NOTE: This can still lose if the serial line is not eight-bit clean. In |
| cases like this, the user should clear "remotebinarydownload". */ |
| static void |
| check_binary_download (CORE_ADDR addr) |
| { |
| if (remote_binary_download && !remote_binary_checked) |
| { |
| char *buf = alloca (PBUFSIZ); |
| char *p; |
| remote_binary_checked = 1; |
| |
| p = buf; |
| *p++ = 'X'; |
| p += hexnumstr (p, (ULONGEST) addr); |
| *p++ = ','; |
| p += hexnumstr (p, (ULONGEST) 0); |
| *p++ = ':'; |
| *p = '\0'; |
| |
| putpkt_binary (buf, (int) (p - buf)); |
| getpkt (buf, 0); |
| |
| if (buf[0] == '\0') |
| remote_binary_download = 0; |
| } |
| |
| if (remote_debug) |
| { |
| if (remote_binary_download) |
| fprintf_unfiltered (gdb_stdlog, |
| "binary downloading suppported by target\n"); |
| else |
| fprintf_unfiltered (gdb_stdlog, |
| "binary downloading NOT suppported by target\n"); |
| } |
| } |
| |
| /* Write memory data directly to the remote machine. |
| This does not inform the data cache; the data cache uses this. |
| MEMADDR is the address in the remote memory space. |
| MYADDR is the address of the buffer in our space. |
| LEN is the number of bytes. |
| |
| Returns number of bytes transferred, or 0 for error. */ |
| |
| int |
| remote_write_bytes (memaddr, myaddr, len) |
| CORE_ADDR memaddr; |
| char *myaddr; |
| int len; |
| { |
| unsigned char *buf = alloca (PBUFSIZ); |
| int max_buf_size; /* Max size of packet output buffer */ |
| int origlen; |
| extern int verbose; |
| |
| /* Verify that the target can support a binary download */ |
| check_binary_download (memaddr); |
| |
| /* Chop the transfer down if necessary */ |
| |
| max_buf_size = min (remote_write_size, PBUFSIZ); |
| if (remote_register_buf_size != 0) |
| max_buf_size = min (max_buf_size, remote_register_buf_size); |
| |
| /* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */ |
| max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4; |
| |
| origlen = len; |
| while (len > 0) |
| { |
| unsigned char *p, *plen; |
| int todo; |
| int i; |
| |
| /* construct "M"<memaddr>","<len>":" */ |
| /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */ |
| memaddr = remote_address_masked (memaddr); |
| p = buf; |
| if (remote_binary_download) |
| { |
| *p++ = 'X'; |
| todo = min (len, max_buf_size); |
| } |
| else |
| { |
| *p++ = 'M'; |
| todo = min (len, max_buf_size / 2); /* num bytes that will fit */ |
| } |
| |
| p += hexnumstr ((char *)p, (ULONGEST) memaddr); |
| *p++ = ','; |
| |
| plen = p; /* remember where len field goes */ |
| p += hexnumstr ((char *)p, (ULONGEST) todo); |
| *p++ = ':'; |
| *p = '\0'; |
| |
| /* We send target system values byte by byte, in increasing byte |
| addresses, each byte encoded as two hex characters (or one |
| binary character). */ |
| if (remote_binary_download) |
| { |
| int escaped = 0; |
| for (i = 0; |
| (i < todo) && (i + escaped) < (max_buf_size - 2); |
| i++) |
| { |
| switch (myaddr[i] & 0xff) |
| { |
| case '$': |
| case '#': |
| case 0x7d: |
| /* These must be escaped */ |
| escaped++; |
| *p++ = 0x7d; |
| *p++ = (myaddr[i] & 0xff) ^ 0x20; |
| break; |
| default: |
| *p++ = myaddr[i] & 0xff; |
| break; |
| } |
| } |
| |
| if (i < todo) |
| { |
| /* Escape chars have filled up the buffer prematurely, |
| and we have actually sent fewer bytes than planned. |
| Fix-up the length field of the packet. */ |
| |
| /* FIXME: will fail if new len is a shorter string than |
| old len. */ |
| |
| plen += hexnumstr ((char *)plen, (ULONGEST) i); |
| *plen++ = ':'; |
| } |
| } |
| else |
| { |
| for (i = 0; i < todo; i++) |
| { |
| *p++ = tohex ((myaddr[i] >> 4) & 0xf); |
| *p++ = tohex (myaddr[i] & 0xf); |
| } |
| *p = '\0'; |
| } |
| |
| putpkt_binary ((char *)buf, (int) (p - buf)); |
| getpkt ((char *)buf, 0); |
| |
| if (buf[0] == 'E') |
| { |
| /* There is no correspondance between what the remote protocol uses |
| for errors and errno codes. We would like a cleaner way of |
| representing errors (big enough to include errno codes, bfd_error |
| codes, and others). But for now just return EIO. */ |
| errno = EIO; |
| return 0; |
| } |
| |
| /* Increment by i, not by todo, in case escape chars |
| caused us to send fewer bytes than we'd planned. */ |
| myaddr += i; |
| memaddr += i; |
| len -= i; |
| |
| if (verbose) |
| putc('.', stderr); |
| } |
| return origlen; |
| } |
| |
| /* Stuff for dealing with the packets which are part of this protocol. |
| See comment at top of file for details. */ |
| |
| /* Read a single character from the remote end, masking it down to 7 bits. */ |
| |
| static int |
| readchar (int timeout) |
| { |
| int ch; |
| |
| ch = SERIAL_READCHAR (remote_desc, timeout); |
| |
| switch (ch) |
| { |
| case SERIAL_EOF: |
| error ("Remote connection closed"); |
| case SERIAL_ERROR: |
| perror_with_name ("Remote communication error"); |
| case SERIAL_TIMEOUT: |
| return ch; |
| default: |
| return ch & 0x7f; |
| } |
| } |
| |
| static int |
| putpkt (buf) |
| char *buf; |
| { |
| return putpkt_binary (buf, strlen (buf)); |
| } |
| |
| /* Send a packet to the remote machine, with error checking. The data |
| of the packet is in BUF. The string in BUF can be at most PBUFSIZ - 5 |
| to account for the $, # and checksum, and for a possible /0 if we are |
| debugging (remote_debug) and want to print the sent packet as a string */ |
| |
| static int |
| putpkt_binary (buf, cnt) |
| char *buf; |
| int cnt; |
| { |
| int i; |
| unsigned char csum = 0; |
| char *buf2 = alloca (PBUFSIZ); |
| char *junkbuf = alloca (PBUFSIZ); |
| |
| int ch; |
| int tcount = 0; |
| char *p; |
| |
| /* Copy the packet into buffer BUF2, encapsulating it |
| and giving it a checksum. */ |
| |
| if (cnt > BUFSIZ - 5) /* Prosanity check */ |
| abort (); |
| |
| p = buf2; |
| *p++ = '$'; |
| |
| for (i = 0; i < cnt; i++) |
| { |
| csum += buf[i]; |
| *p++ = buf[i]; |
| } |
| *p++ = '#'; |
| *p++ = tohex ((csum >> 4) & 0xf); |
| *p++ = tohex (csum & 0xf); |
| |
| /* Send it over and over until we get a positive ack. */ |
| |
| while (1) |
| { |
| int started_error_output = 0; |
| |
| if (remote_debug) |
| { |
| *p = '\0'; |
| fprintf_unfiltered (gdb_stdlog, "Sending packet: "); |
| fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog); |
| fprintf_unfiltered (gdb_stdlog, "..."); |
| gdb_flush (gdb_stdlog); |
| } |
| if (SERIAL_WRITE (remote_desc, buf2, p - buf2)) |
| perror_with_name ("putpkt: write failed"); |
| |
| /* read until either a timeout occurs (-2) or '+' is read */ |
| while (1) |
| { |
| ch = readchar (remote_timeout); |
| |
| if (remote_debug) |
| { |
| switch (ch) |
| { |
| case '+': |
| case SERIAL_TIMEOUT: |
| case '$': |
| if (started_error_output) |
| { |
| putchar_unfiltered ('\n'); |
| started_error_output = 0; |
| } |
| } |
| } |
| |
| switch (ch) |
| { |
| case '+': |
| if (remote_debug) |
| fprintf_unfiltered (gdb_stdlog, "Ack\n"); |
| return 1; |
| case SERIAL_TIMEOUT: |
| tcount++; |
| if (tcount > 3) |
| return 0; |
| break; /* Retransmit buffer */ |
| case '$': |
| { |
| /* It's probably an old response, and we're out of sync. |
| Just gobble up the packet and ignore it. */ |
| getpkt (junkbuf, 0); |
| continue; /* Now, go look for + */ |
| } |
| default: |
| if (remote_debug) |
| { |
| if (!started_error_output) |
| { |
| started_error_output = 1; |
| fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: "); |
| } |
| fputc_unfiltered (ch & 0177, gdb_stdlog); |
| } |
| continue; |
| } |
| break; /* Here to retransmit */ |
| } |
| |
| #if 0 |
| /* This is wrong. If doing a long backtrace, the user should be |
| able to get out next time we call QUIT, without anything as |
| violent as interrupt_query. If we want to provide a way out of |
| here without getting to the next QUIT, it should be based on |
| hitting ^C twice as in remote_wait. */ |
| if (quit_flag) |
| { |
| quit_flag = 0; |
| interrupt_query (); |
| } |
| #endif |
| } |
| } |
| |
| /* Come here after finding the start of the frame. Collect the rest |
| into BUF, verifying the checksum, length, and handling run-length |
| compression. Returns 0 on any error, 1 on success. */ |
| |
| static int |
| read_frame (char *buf) |
| { |
| unsigned char csum; |
| char *bp; |
| int c; |
| |
| csum = 0; |
| bp = buf; |
| |
| while (1) |
| { |
| c = readchar (remote_timeout); |
| |
| switch (c) |
| { |
| case SERIAL_TIMEOUT: |
| if (remote_debug) |
| fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog); |
| return 0; |
| case '$': |
| if (remote_debug) |
| fputs_filtered ("Saw new packet start in middle of old one\n", |
| gdb_stdlog); |
| return 0; /* Start a new packet, count retries */ |
| case '#': |
| { |
| unsigned char pktcsum; |
| |
| *bp = '\000'; |
| |
| pktcsum = fromhex (readchar (remote_timeout)) << 4; |
| pktcsum |= fromhex (readchar (remote_timeout)); |
| |
| if (csum == pktcsum) |
| { |
| return 1; |
| } |
| |
| if (remote_debug) |
| { |
| fprintf_filtered (gdb_stdlog, |
| "Bad checksum, sentsum=0x%x, csum=0x%x, buf=", |
| pktcsum, csum); |
| fputs_filtered (buf, gdb_stdlog); |
| fputs_filtered ("\n", gdb_stdlog); |
| } |
| return 0; |
| } |
| case '*': /* Run length encoding */ |
| csum += c; |
| c = readchar (remote_timeout); |
| csum += c; |
| c = c - ' ' + 3; /* Compute repeat count */ |
| |
| if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1) |
| { |
| memset (bp, *(bp - 1), c); |
| bp += c; |
| continue; |
| } |
| |
| *bp = '\0'; |
| printf_filtered ("Repeat count %d too large for buffer: ", c); |
| puts_filtered (buf); |
| puts_filtered ("\n"); |
| return 0; |
| default: |
| if (bp < buf + PBUFSIZ - 1) |
| { |
| *bp++ = c; |
| csum += c; |
| continue; |
| } |
| |
| *bp = '\0'; |
| puts_filtered ("Remote packet too long: "); |
| puts_filtered (buf); |
| puts_filtered ("\n"); |
| |
| return 0; |
| } |
| } |
| } |
| |
| /* Read a packet from the remote machine, with error checking, and |
| store it in BUF. BUF is expected to be of size PBUFSIZ. If |
| FOREVER, wait forever rather than timing out; this is used while |
| the target is executing user code. */ |
| |
| static void |
| getpkt (buf, forever) |
| char *buf; |
| int forever; |
| { |
| int c; |
| int tries; |
| int timeout; |
| int val; |
| |
| strcpy (buf, "timeout"); |
| |
| if (forever) |
| { |
| timeout = watchdog > 0 ? watchdog : -1; |
| } |
| |
| else |
| timeout = remote_timeout; |
| |
| #define MAX_TRIES 3 |
| |
| for (tries = 1; tries <= MAX_TRIES; tries++) |
| { |
| /* This can loop forever if the remote side sends us characters |
| continuously, but if it pauses, we'll get a zero from readchar |
| because of timeout. Then we'll count that as a retry. */ |
| |
| /* Note that we will only wait forever prior to the start of a packet. |
| After that, we expect characters to arrive at a brisk pace. They |
| should show up within remote_timeout intervals. */ |
| |
| do |
| { |
| c = readchar (timeout); |
| |
| if (c == SERIAL_TIMEOUT) |
| { |
| if (forever) /* Watchdog went off. Kill the target. */ |
| { |
| target_mourn_inferior (); |
| error ("Watchdog has expired. Target detached.\n"); |
| } |
| if (remote_debug) |
| fputs_filtered ("Timed out.\n", gdb_stdlog); |
| goto retry; |
| } |
| } |
| while (c != '$'); |
| |
| /* We've found the start of a packet, now collect the data. */ |
| |
| val = read_frame (buf); |
| |
| if (val == 1) |
| { |
| if (remote_debug) |
| { |
| fprintf_unfiltered (gdb_stdlog, "Packet received: "); |
| fputstr_unfiltered (buf, 0, gdb_stdlog); |
| fprintf_unfiltered (gdb_stdlog, "\n"); |
| } |
| SERIAL_WRITE (remote_desc, "+", 1); |
| return; |
| } |
| |
| /* Try the whole thing again. */ |
| retry: |
| SERIAL_WRITE (remote_desc, "-", 1); |
| } |
| |
| /* We have tried hard enough, and just can't receive the packet. Give up. */ |
| |
| printf_unfiltered ("Ignoring packet error, continuing...\n"); |
| SERIAL_WRITE (remote_desc, "+", 1); |
| } |