commit 483e0ff30303655eb57c3fad6732cc4b5ea0584e
parent 9c73597781b798b1f50f36a575ffb21509e3715d
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 22 Jun 2015 19:00:56 -0700
gdb-bridge: handle set/clear hw breakpoint
Diffstat:
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/tools/gdb-bridge.c b/tools/gdb-bridge.c
@@ -160,7 +160,7 @@ int gdb_recv(struct gdbcnxn *gc, unsigned char *ptr, int len) {
switch (gc->state) {
case S_IDLE:
if (c == 3) {
- gc->rxbuf[0] = 's';
+ gc->rxbuf[0] = '$';
gc->rxbuf[1] = 0;
gdb_recv_cmd(gc);
} else if (c == '$') {
@@ -351,6 +351,46 @@ void write_memory(u32 addr, unsigned char *data, int len) {
}
}
+#define MAXBP 4
+static u32 bp_addr[MAXBP];
+static u32 bp_state[MAXBP];
+
+int handle_breakpoint(int add, u32 addr, u32 kind) {
+ int n;
+ if (add) {
+ for (n = 0; n < MAXBP; n++) {
+ if (bp_state[n] && (bp_addr[n] == addr)) {
+ // already setup
+ return 0;
+ }
+ }
+ for (n = 0; n < MAXBP; n++) {
+ if (bp_state[n] == 0) {
+ bp_addr[n] = addr;
+ bp_state[n] = 1;
+ swdp_watchpoint_pc(n, addr);
+ zprintf("GDB: + HW BP @ %08x\n", addr);
+ return 0;
+ }
+ }
+ if (n == MAXBP) {
+ zprintf("GDB: Out of hardware breakpoints.\n");
+ return 1;
+ }
+ return 0;
+ } else {
+ for (n = 0; n < MAXBP; n++) {
+ if (bp_state[n] && (bp_addr[n] == addr)) {
+ bp_state[n] = 0;
+ swdp_watchpoint_disable(n);
+ break;
+ }
+ }
+ zprintf("GDB: - HW BP @ %08x\n", addr);
+ return 0;
+ }
+}
+
void handle_command(struct gdbcnxn *gc, unsigned char *cmd) {
union {
u32 w[256+2];
@@ -448,6 +488,11 @@ void handle_command(struct gdbcnxn *gc, unsigned char *cmd) {
}
break;
}
+ // halt (^c)
+ case '$':
+ swdp_core_halt();
+ gdb_puts(gc, "S00");
+ break;
// single step
case 's':
swdp_core_step();
@@ -472,6 +517,22 @@ void handle_command(struct gdbcnxn *gc, unsigned char *cmd) {
break;
}
+ case 'z':
+ case 'Z': {
+ u32 type, addr, kind;
+ if (sscanf((char*) cmd + 1, "%x,%x,%x", &type, &addr, &kind) != 3) {
+ break;
+ }
+ if (type != 1) {
+ // only support hw breakpoints
+ }
+ if (handle_breakpoint(cmd[0] == 'Z', addr, kind)) {
+ gdb_puts(gc, "OK");
+ } else {
+ gdb_puts(gc, "E1");
+ }
+ break;
+ }
default:
zprintf("GDB: unknown command: %c\n", cmd[0]);
}