+/*
+ * make_gdb_packet -- make a GDB packet. The data is always ASCII.
+ * 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.
+ *
+ */
+static void
+make_gdb_packet (buf, data)
+ char *buf, *data;
+{
+ int i;
+ unsigned char csum = 0;
+ int cnt;
+ char *p;
+
+ debuglogs (3, "make_gdb_packet(%s)\n", data);
+ cnt = strlen (data);
+ if (cnt > PBUFSIZ)
+ error ("make_gdb_packet(): to much data\n");
+
+ /* start with the packet header */
+ p = buf;
+ *p++ = '$';
+
+ /* calculate the checksum */
+ for (i = 0; i < cnt; i++) {
+ csum += data[i];
+ *p++ = data[i];
+ }
+
+ /* terminate the data with a '#' */
+ *p++ = '#';
+
+ /* add the checksum as two ascii digits */
+ *p++ = tohex ((csum >> 4) & 0xf);
+ *p++ = tohex (csum & 0xf);
+ *p = 0x0; /* Null terminator on string */
+}
+
+/*
+ * monitor_send_packet -- send a GDB packet to the target with error handling. We
+ * get a '+' (ACK) back if the packet is received and the checksum
+ * matches. Otherwise a '-' (NAK) is returned. It returns a 1 for a
+ * successful transmition, or a 0 for a failure.
+ */
+int
+monitor_send_packet (packet)
+ char *packet;
+{
+ int c, retries, i;
+ char junk[PBUFSIZ];
+
+ retries = 0;
+
+#if 0
+ /* scan the packet to make sure it only contains valid characters.
+ this may sound silly, but sometimes a garbled packet will hang
+ the target board. We scan the whole thing, then print the error
+ message.
+ */
+ for (i = 0; i < strlen(packet); i++) {
+ debuglogs (5, "monitor_send_packet(): Scanning \'%c\'\n", packet[i]);
+ /* legit hex numbers or command */
+ if ((isxdigit(packet[i])) || (isalpha(packet[i])))
+ continue;
+ switch (packet[i]) {
+ case '+': /* ACK */
+ case '-': /* NAK */
+ case '#': /* end of packet */
+ case '$': /* start of packet */
+ continue;
+ default: /* bogus character */
+ retries++;
+ debuglogs (4, "monitor_send_packet(): Found a non-ascii digit \'%c\' in the packet.\n", packet[i]);
+ }
+ }
+#endif
+
+ if (retries > 0)
+ error ("Can't send packet, found %d non-ascii characters", retries);
+
+ /* ok, try to send the packet */
+ retries = 0;
+ while (retries <= 10) {
+ printf_monitor ("%s", packet);
+
+ /* read until either a timeout occurs (-2) or '+' is read */
+ while (retries <= 10) {
+ c = readchar (timeout);
+ debuglogs (3, "Reading a GDB protocol packet... Got a '%c'\n", c);
+ switch (c) {
+ case '+':
+ debuglogs (3, "Got Ack\n");
+ return 1;
+ case SERIAL_TIMEOUT:
+ debuglogs (3, "Timed out reading serial port\n");
+ break; /* Retransmit buffer */
+ case '-':
+ debuglogs (3, "Got NAK\n");
+ break; /* FIXME: (maybe) was a continue */
+ case '$':
+ /* it's probably an old response, or the echo of our command.
+ * just gobble up the packet and ignore it.
+ */
+ debuglogs (3, "Got a junk packet\n");
+ do {
+ c = readchar (timeout);
+ junk[i++] = c;
+ } while (c != '#');
+ c = readchar (timeout);
+ junk[i++] = c;
+ c = readchar (timeout);
+ junk[i++] = c;
+ junk[i++] = '\0';
+ debuglogs (3, "Reading a junk packet, got a \"%s\"\n", junk);
+ continue; /* Now, go look for next packet */
+ default:
+ continue;
+ }
+ retries++;
+ debuglogs (3, "Retransmitting packet \"%s\"\n", packet);
+ break; /* Here to retransmit */
+ }
+ } /* outer while */
+ return 0;
+}
+
+/*
+ * monitor_get_packet -- get a GDB packet from the target. Basically we read till we
+ * see a '#', then check the checksum. It returns a 1 if it's gotten a
+ * packet, or a 0 it the packet wasn't transmitted correctly.
+ */
+int
+monitor_get_packet (packet)
+ char *packet;
+{
+ int c;
+ int retries;
+ unsigned char csum;
+ unsigned char pktcsum;
+ char *bp;
+
+ csum = 0;
+ bp = packet;
+
+ memset (packet, 1, PBUFSIZ);
+ retries = 0;
+ while (retries <= 10) {
+ do {
+ c = readchar (timeout);
+ if (c == SERIAL_TIMEOUT) {
+ debuglogs (3, "monitor_get_packet: got time out from serial port.\n");
+ }
+ debuglogs (3, "Waiting for a '$', got a %c\n", c);
+ } while (c != '$');
+
+ retries = 0;
+ while (retries <= 10) {
+ c = readchar (timeout);
+ debuglogs (3, "monitor_get_packet: got a '%c'\n", c);
+ switch (c) {
+ case SERIAL_TIMEOUT:
+ debuglogs (3, "Timeout in mid-packet, retrying\n");
+ return 0;
+ case '$':
+ debuglogs (3, "Saw new packet start in middle of old one\n");
+ return 0; /* Start a new packet, count retries */
+ case '#':
+ *bp = '\0';
+ pktcsum = from_hex (readchar (timeout)) << 4;
+ pktcsum |= from_hex (readchar (timeout));
+ if (csum == pktcsum) {
+ debuglogs (3, "\nGDB packet checksum correct, packet data is \"%s\",\n", packet);
+ printf_monitor ("+");
+ expect_prompt (1);
+ return 1;
+ }
+ debuglogs (3, "Bad checksum, sentsum=0x%x, csum=0x%x\n", pktcsum, csum);
+ return 0;
+ case '*': /* Run length encoding */
+ debuglogs (5, "Run length encoding in packet\n");
+ csum += c;
+ c = readchar (timeout);
+ csum += c;
+ c = c - ' ' + 3; /* Compute repeat count */
+
+ if (c > 0 && c < 255 && bp + c - 1 < packet + PBUFSIZ - 1) {
+ memset (bp, *(bp - 1), c);
+ bp += c;
+ continue;
+ }
+ *bp = '\0';
+ printf_filtered ("Repeat count %d too large for buffer.\n", c);
+ return 0;
+
+ default:
+ if ((!isxdigit(c)) && (!ispunct(c)))
+ debuglogs (4, "Got a non-ascii digit \'%c\'.\\n", c);
+ if (bp < packet + PBUFSIZ - 1) {
+ *bp++ = c;
+ csum += c;
+ continue;
+ }
+
+ *bp = '\0';
+ puts_filtered ("Remote packet too long.\n");
+ return 0;
+ }
+ }
+ }
+}
+
+/*
+ * ascii2hexword -- convert an ascii number represented by 8 digits to a hex value.
+ */
+static unsigned long
+ascii2hexword (mem)
+ unsigned char *mem;
+{
+ unsigned long val;
+ int i;
+ char buf[9];
+
+ val = 0;
+ for (i = 0; i < 8; i++) {
+ val <<= 4;
+ if (mem[i] >= 'A' && mem[i] <= 'F')
+ val = val + mem[i] - 'A' + 10;
+ if (mem[i] >= 'a' && mem[i] <= 'f')
+ val = val + mem[i] - 'a' + 10;
+ if (mem[i] >= '0' && mem[i] <= '9')
+ val = val + mem[i] - '0';
+ buf[i] = mem[i];
+ }
+ buf[8] = '\0';
+ debuglogs (4, "ascii2hexword() got a 0x%x from %s(%x).\n", val, buf, mem);
+ return val;
+}
+
+/*
+ * ascii2hexword -- convert a hex value to an ascii number represented by 8
+ * digits.
+ */
+static char*
+hexword2ascii (mem, num)
+ unsigned char *mem;
+ unsigned long num;
+{
+ int i;
+ unsigned char ch;
+
+ debuglogs (4, "hexword2ascii() converting %x ", num);
+ for (i = 7; i >= 0; i--) {
+ mem[i] = tohex ((num >> 4) & 0xf);
+ mem[i] = tohex (num & 0xf);
+ num = num >> 4;
+ }
+ mem[8] = '\0';
+ debuglogs (4, "\tto a %s", mem);
+}
+
+/* Convert hex digit A to a number. */
+static int
+from_hex (a)
+ int a;
+{
+ if (a == 0)
+ return 0;
+
+ debuglogs (4, "from_hex got a 0x%x(%c)\n",a,a);
+ if (a >= '0' && a <= '9')
+ return a - '0';
+ if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ if (a >= 'A' && a <= 'F')
+ return a - 'A' + 10;
+ else {
+ error ("Reply contains invalid hex digit 0x%x", a);
+ }
+}
+
+/* Convert number NIB to a hex digit. */
+static int
+tohex (nib)
+ int nib;
+{
+ if (nib < 10)
+ return '0'+nib;
+ else
+ return 'a'+nib-10;
+}
+