| // 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); | |
| } |