aboutsummaryrefslogtreecommitdiff
path: root/src/gdb_packet.c
diff options
context:
space:
mode:
authorGareth McMullin2011-02-04 20:23:52 +1300
committerGareth McMullin2011-02-04 20:23:52 +1300
commit406617a2a470021d9412e9280feda0d28bdb653b (patch)
tree43b2cb9b562fde0bf5187c31dea77d72318cfc29 /src/gdb_packet.c
Import of working source tree.
Diffstat (limited to 'src/gdb_packet.c')
-rw-r--r--src/gdb_packet.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/gdb_packet.c b/src/gdb_packet.c
new file mode 100644
index 0000000..0c690f8
--- /dev/null
+++ b/src/gdb_packet.c
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Written by Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file implements the GDB Remote Serial Debugging protocol packet
+ * reception and transmission as well as some convenience functions.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdarg.h>
+
+#include <alloca.h>
+
+#include "general.h"
+#include "gdb_if.h"
+#include "gdb_packet.h"
+#include "hex_utils.h"
+
+int
+gdb_getpacket(unsigned char *packet, int size)
+{
+ unsigned char c;
+ unsigned char csum;
+ char recv_csum[3];
+ int i;
+
+ while(1) {
+ /* Wait for packet start */
+ while((packet[0] = gdb_if_getchar()) != '$')
+ if(packet[0] == 0x04) return 1;
+
+ i = 0; csum = 0;
+ /* Capture packet data into buffer */
+ while((c = gdb_if_getchar()) != '#') {
+
+ if(i == size) break; /* Oh shit */
+
+ if(c == '$') { /* Restart capture */
+ i = 0;
+ csum = 0;
+ continue;
+ }
+ if(c == '}') { /* escaped char */
+ c = gdb_if_getchar();
+ csum += c + '}';
+ packet[i++] = c ^ 0x20;
+ continue;
+ }
+ csum += c;
+ packet[i++] = c;
+ }
+ recv_csum[0] = gdb_if_getchar();
+ recv_csum[1] = gdb_if_getchar();
+ recv_csum[2] = 0;
+
+ /* return packet if checksum matches */
+ if(csum == strtol(recv_csum, NULL, 16)) break;
+
+ /* get here if checksum fails */
+ gdb_if_putchar('-', 1); /* send nack */
+ }
+ gdb_if_putchar('+', 1); /* send ack */
+ packet[i] = 0;
+ return i;
+}
+
+void gdb_putpacket(unsigned char *packet, int size)
+{
+ int i;
+ unsigned char csum;
+ unsigned char c;
+ char xmit_csum[3];
+ int tries = 0;
+
+ do {
+ csum = 0;
+ gdb_if_putchar('$', 0);
+ for(i = 0; i < size; i++) {
+ c = packet[i];
+ if((c == '$') || (c == '#') || (c == '}')) {
+ gdb_if_putchar('}', 0);
+ gdb_if_putchar(c ^ 0x20, 0);
+ csum += '}' + (c ^ 0x20);
+ } else {
+ gdb_if_putchar(c, 0);
+ csum += c;
+ }
+ }
+ gdb_if_putchar('#', 0);
+ siprintf(xmit_csum, "%02X", csum);
+ gdb_if_putchar(xmit_csum[0], 0);
+ gdb_if_putchar(xmit_csum[1], 1);
+
+ } while((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
+
+}
+
+void gdb_putpacket_f(const unsigned char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int size;
+
+ va_start(ap, fmt);
+ size = vasiprintf(&buf, fmt, ap);
+ gdb_putpacket(buf, size);
+ free(buf);
+ va_end(ap);
+}
+
+void gdb_out(const char *buf)
+{
+ char *hexdata;
+ int i;
+
+ hexdata = alloca((i = strlen(buf)*2 + 1) + 1);
+ hexdata[0] = 'O';
+ hexify(hexdata+1, buf, strlen(buf));
+ gdb_putpacket(hexdata, i);
+}
+
+void gdb_outf(const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+
+ va_start(ap, fmt);
+ vasiprintf(&buf, fmt, ap);
+ gdb_out(buf);
+ free(buf);
+ va_end(ap);
+}
+