commit 0ac79702203fef35f9b7f91eec72d3e418570a7e
parent 06c1084371355b28feae8bc7c766578d98e406de
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 9 Jul 2015 18:27:00 -0700
gdb-bridge/lkdebug: move lk debugging stuff into its own file
Diffstat:
5 files changed, 277 insertions(+), 215 deletions(-)
diff --git a/tools/debugger-commands.c b/tools/debugger-commands.c
@@ -31,6 +31,7 @@
#include "arm-v7m.h"
#include "debugger.h"
+#include "lkdebug.h"
#define _AGENT_HOST_ 1
#include <agent/flash.h>
@@ -760,13 +761,10 @@ int do_maskints(int argc, param *argv) {
return 0;
}
-typedef struct lkthread lkthread_t;
-lkthread_t *find_lk_threads(int verbose);
-void dump_lk_threads(lkthread_t *t);
-void free_lk_threads(lkthread_t *t);
-
int do_threads(int argc, param *argv) {
- lkthread_t *t = find_lk_threads(1);
+ lkthread_t *t;
+ swdp_core_halt();
+ t = find_lk_threads(1);
dump_lk_threads(t);
free_lk_threads(t);
return 0;
diff --git a/tools/gdb-bridge.c b/tools/gdb-bridge.c
@@ -29,6 +29,7 @@
#include <protocol/rswdp.h>
#include "debugger.h"
#include "linenoise.h"
+#include "lkdebug.h"
// useful gdb stuff
// set debug remote 1 protocol tracing
@@ -47,50 +48,6 @@
#define F_CONSOLE 0x08
#define F_LK_THREADS 0x10
-#define DI_MAGIC 0x52474244
-#define DI_OFF_MAGIC 32
-#define DI_OFF_PTR 36
-
-#define LK_THREAD_MAGIC 0x74687264
-#define LIST_OFF_PREV 0
-#define LIST_OFF_NEXT 4
-
-#define LK_MAX_STATE 5
-static char *lkstate[] = {
- "SUSP ",
- "READY",
- "RUN ",
- "BLOCK",
- "SLEEP",
- "DEAD ",
- "?????",
-};
-
-typedef struct lkdebuginfo {
- u32 version;
- u32 thread_list_ptr;
- u32 current_thread_ptr;
- u8 off_list_node;
- u8 off_state;
- u8 off_saved_sp;
- u8 off_was_preempted;
- u8 off_name;
- u8 off_waitq;
-} lkdebuginfo_t;
-
-typedef struct lkthread {
- struct lkthread *next;
- int active;
- u32 threadptr;
- u32 nextptr;
- u32 state;
- u32 saved_sp;
- u32 preempted;
- u32 waitq;
- char name[32];
- u32 regs[17];
-} lkthread_t;
-
struct gdbcnxn {
int fd;
unsigned state;
@@ -331,18 +288,16 @@ static void handle_query(struct gdbcnxn *gc, char *cmd, char *args) {
gdb_puts(gc, "l");
} else if(!strcmp(cmd, "ThreadExtraInfo")) {
u32 n = strtoul(args, NULL, 16);
- lkthread_t *t;
+ lkthread_t *t = find_lk_thread(gc->threadlist, n);
/* gdb manual suggest 'Runnable', 'Blocked on Mutex', etc */
/* informational text shown in gdb's "info threads" listing */
- for (t = gc->threadlist; t != NULL; t = t->next) {
- if (t->threadptr == n) {
- char tmp[128];
- sprintf(tmp, "%s - %s", lkstate[t->state], t->name);
- gdb_puthex(gc, tmp, strlen(tmp));
- return;
- }
+ if (t) {
+ char tmp[128];
+ get_lk_thread_name(t, tmp, sizeof(tmp));
+ gdb_puthex(gc, tmp, strlen(tmp));
+ } else {
+ gdb_puthex(gc, "Native", 6);
}
- gdb_puthex(gc, "Native", 6);
} else if(!strcmp(cmd, "C")) {
/* current thread ID */
if (gc->cselected) {
@@ -585,138 +540,6 @@ int handle_breakpoint(int add, u32 addr, u32 kind) {
}
}
-void dump_lk_thread(lkthread_t *t) {
- xprintf("thread: @%08x sp=%08x wq=%08x st=%d name='%s'\n",
- t->threadptr, t->saved_sp, t->waitq, t->state, t->name);
- xprintf(" r0 %08x r4 %08x r8 %08x ip %08x\n",
- t->regs[0], t->regs[4], t->regs[8], t->regs[12]);
- xprintf(" r1 %08x r5 %08x r9 %08x sp %08x\n",
- t->regs[1], t->regs[5], t->regs[9], t->regs[13]);
- xprintf(" r2 %08x r6 %08x 10 %08x lr %08x\n",
- t->regs[2], t->regs[6], t->regs[10], t->regs[14]);
- xprintf(" r3 %08x r7 %08x 11 %08x pc %08x\n",
- t->regs[3], t->regs[7], t->regs[11], t->regs[15]);
-}
-
-void dump_lk_threads(lkthread_t *t) {
- while (t != NULL) {
- dump_lk_thread(t);
- t = t->next;
- }
-}
-
-#define LT_NEXT_PTR(di,tp) ((tp) + di->off_list_node + LIST_OFF_NEXT)
-#define LT_STATE(di,tp) ((tp) + di->off_state)
-#define LT_SAVED_SP(di,tp) ((tp) + di->off_saved_sp)
-#define LT_NAME(di,tp) ((tp) + di->off_name)
-#define LT_WAITQ(di,tp) ((tp) + di->off_waitq)
-
-#define LIST_TO_THREAD(di,lp) ((lp) - (di)->off_list_node)
-
-lkthread_t *read_lk_thread(lkdebuginfo_t *di, u32 ptr, int active) {
- lkthread_t *t = calloc(1, sizeof(lkthread_t));
- u32 x;
- int n;
- if (t == NULL) goto fail;
- t->threadptr = ptr;
- if (swdp_ahb_read(ptr, &x)) goto fail;
- if (x != LK_THREAD_MAGIC) goto fail;
- if (swdp_ahb_read(LT_NEXT_PTR(di,ptr), &t->nextptr)) goto fail;
- if (swdp_ahb_read(LT_STATE(di,ptr), &t->state)) goto fail;
- if (swdp_ahb_read(LT_SAVED_SP(di,ptr), &t->saved_sp)) goto fail;
- if (swdp_ahb_read(LT_WAITQ(di,ptr), &t->waitq)) goto fail;
- if (swdp_ahb_read32(LT_NAME(di,ptr), (void*) t->name, 32 / 4)) goto fail;
- t->name[31] = 0;
- for (n = 0; n < 31; n++) {
- if ((t->name[n] < ' ') || (t->name[n] > 127)) {
- if (t->name[n] == 0) break;
- t->name[n] = '.';
- }
- }
- if (t->state > LK_MAX_STATE) t->state = LK_MAX_STATE + 1;
- memset(t->regs, 0xee, sizeof(t->regs));
- // lk arm-m context frame: R4 R5 R6 R7 R8 R9 R10 R11 LR
- // if LR is FFFFFFxx then: R0 R1 R2 R3 R12 LR PC PSR
- t->active = active;
- if (!active) {
- u32 fr[9];
- if (swdp_ahb_read32(t->saved_sp, (void*) fr, 9)) goto fail;
- memcpy(t->regs + 4, fr, 8 * sizeof(u32));
- if ((fr[8] & 0xFFFFFF00) == 0xFFFFFF00) {
- if (swdp_ahb_read32(t->saved_sp + 9 * sizeof(u32), (void*) fr, 8)) goto fail;
- memcpy(t->regs + 0, fr, 4 * sizeof(u32));
- t->regs[12] = fr[4];
- t->regs[13] = t->saved_sp + 17 * sizeof(u32);
- t->regs[14] = fr[5];
- t->regs[15] = fr[6];
- t->regs[16] = fr[7];
- } else {
- t->regs[13] = t->saved_sp + 9 * sizeof(u32);
- t->regs[15] = fr[8];
- t->regs[16] = 0x10000000;
- }
- }
- return t;
-fail:
- free(t);
- return NULL;
-}
-
-void free_lk_threads(lkthread_t *list) {
- lkthread_t *t, *next;
- for (t = list; t != NULL; t = next) {
- next = t->next;
- free(t);
- }
-}
-
-lkthread_t *find_lk_threads(int verbose) {
- lkdebuginfo_t di;
- lkthread_t *list = NULL;
- lkthread_t *current = NULL;
- lkthread_t *t;
- u32 x;
- u32 rtp;
- if (swdp_ahb_read(DI_OFF_MAGIC, &x)) goto fail;
- if (x != DI_MAGIC) {
- if (verbose) xprintf("debuginfo: bad magic\n");
- goto fail;
- }
- if (swdp_ahb_read(DI_OFF_PTR, &x)) goto fail;
- if (x & 3) goto fail;
- if (verbose) xprintf("debuginfo @ %08x\n", x);
- if (swdp_ahb_read32(x, (void*) &di, sizeof(di) / 4)) goto fail;
- if (verbose) {
- xprintf("di %08x %08x %08x %d %d %d %d %d %d\n",
- di.version, di.thread_list_ptr, di.current_thread_ptr,
- di.off_list_node, di.off_state, di.off_saved_sp,
- di.off_was_preempted, di.off_name, di.off_waitq);
- }
- if (di.version != 0x0100) {
- if (verbose) xprintf("debuginfo: unsupported version\n");
- goto fail;
- }
- if (swdp_ahb_read(di.current_thread_ptr, &x)) goto fail;
- current = read_lk_thread(&di, x, 1);
- rtp = di.thread_list_ptr;
- for (;;) {
- if (swdp_ahb_read(rtp + LIST_OFF_NEXT, &rtp)) goto fail;
- if (rtp == di.thread_list_ptr) break;
- x = LIST_TO_THREAD(&di, rtp);
- if (current->threadptr == x) continue;
- t = read_lk_thread(&di, x, 0);
- if (t == NULL) goto fail;
- t->next = list;
- list = t;
- }
- current->next = list;
- return current;
-fail:
- if (current) free(current);
- free_lk_threads(list);
- return NULL;
-}
-
void gdb_update_threads(struct gdbcnxn *gc) {
zprintf("GDB: sync threadlist\n");
free_lk_threads(gc->threadlist);
@@ -770,42 +593,36 @@ void handle_command(struct gdbcnxn *gc, unsigned char *cmd) {
swdp_core_halt();
gdb_update_threads(gc);
break;
- case 'H':
+ case 'H': {
+ // select thread
+ lkthread_t *t = NULL;
if ((cmd[2] == '-') && (cmd[3] == '1')) {
- zprintf("GDB: selected -1??\n");
+ t = gc->threadlist;
} else {
- lkthread_t *t;
- u32 n = strtoul((char*) cmd + 2, NULL, 16);
- for (t = gc->threadlist; t != NULL; t = t->next) {
- if (t->threadptr == n) {
- zprintf("GDB: selected %c tptr=%x\n", cmd[1], n);
- if (cmd[1] == 'g') gc->gselected = t;
- if (cmd[1] == 'c') gc->cselected = t;
- goto hdone;
- }
+ n = strtoul((char*) cmd + 2, NULL, 16);
+ if ((t = find_lk_thread(gc->threadlist, n)) == NULL) {
+ t = gc->threadlist;
}
}
- /* select thread - we've only got one */
- if (cmd[1] == 'g') gc->gselected = gc->threadlist;
- if (cmd[1] == 'c') gc->cselected = gc->threadlist;
- hdone:
+ if (cmd[1] == 'g') {
+ gc->gselected = t;
+ } else if (cmd[1] == 'c') {
+ gc->cselected = t;
+ } else {
+ zprintf("GDB: selecting '%c' thread?!\n", cmd[1]);
+ }
gdb_puts(gc, "OK");
break;
+ }
// is thread alive?
- case 'T': {
- lkthread_t *t;
+ case 'T':
n = strtoul((char*) cmd + 1, NULL, 16);
- for (t = gc->threadlist; t != NULL; t = t->next) {
- if (t->threadptr == n) {
- break;
- }
- }
- if (t) {
+ if (find_lk_thread(gc->threadlist, n)) {
gdb_puts(gc, "OK");
} else {
gdb_puts(gc, "E00");
}
- }
+ break;
// m hexaddr , hexcount
// read from memory
case 'm':
diff --git a/tools/lkdebug.c b/tools/lkdebug.c
@@ -0,0 +1,203 @@
+/* lkdebug.c
+ *
+ * Copyright 2015 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fw/types.h>
+
+#include "rswdp.h"
+#include "debugger.h"
+#include "lkdebug.h"
+
+#define DI_MAGIC 0x52474244
+#define DI_OFF_MAGIC 32
+#define DI_OFF_PTR 36
+
+#define LK_THREAD_MAGIC 0x74687264
+#define LIST_OFF_PREV 0
+#define LIST_OFF_NEXT 4
+
+typedef struct lkdebuginfo {
+ u32 version;
+ u32 thread_list_ptr;
+ u32 current_thread_ptr;
+ u8 off_list_node;
+ u8 off_state;
+ u8 off_saved_sp;
+ u8 off_was_preempted;
+ u8 off_name;
+ u8 off_waitq;
+} lkdebuginfo_t;
+
+#define LK_MAX_STATE 5
+static char *lkstate[] = {
+ "SUSP ",
+ "READY",
+ "RUN ",
+ "BLOCK",
+ "SLEEP",
+ "DEAD ",
+ "?????",
+};
+
+void dump_lk_thread(lkthread_t *t) {
+ xprintf("thread: @%08x sp=%08x wq=%08x st=%d name='%s'\n",
+ t->threadptr, t->saved_sp, t->waitq, t->state, t->name);
+ xprintf(" r0 %08x r4 %08x r8 %08x ip %08x\n",
+ t->regs[0], t->regs[4], t->regs[8], t->regs[12]);
+ xprintf(" r1 %08x r5 %08x r9 %08x sp %08x\n",
+ t->regs[1], t->regs[5], t->regs[9], t->regs[13]);
+ xprintf(" r2 %08x r6 %08x 10 %08x lr %08x\n",
+ t->regs[2], t->regs[6], t->regs[10], t->regs[14]);
+ xprintf(" r3 %08x r7 %08x 11 %08x pc %08x\n",
+ t->regs[3], t->regs[7], t->regs[11], t->regs[15]);
+}
+
+void dump_lk_threads(lkthread_t *t) {
+ while (t != NULL) {
+ dump_lk_thread(t);
+ t = t->next;
+ }
+}
+
+#define LT_NEXT_PTR(di,tp) ((tp) + di->off_list_node + LIST_OFF_NEXT)
+#define LT_STATE(di,tp) ((tp) + di->off_state)
+#define LT_SAVED_SP(di,tp) ((tp) + di->off_saved_sp)
+#define LT_NAME(di,tp) ((tp) + di->off_name)
+#define LT_WAITQ(di,tp) ((tp) + di->off_waitq)
+
+#define LIST_TO_THREAD(di,lp) ((lp) - (di)->off_list_node)
+
+static lkthread_t *read_lk_thread(lkdebuginfo_t *di, u32 ptr, int active) {
+ lkthread_t *t = calloc(1, sizeof(lkthread_t));
+ u32 x;
+ int n;
+ if (t == NULL) goto fail;
+ t->threadptr = ptr;
+ if (swdp_ahb_read(ptr, &x)) goto fail;
+ if (x != LK_THREAD_MAGIC) goto fail;
+ if (swdp_ahb_read(LT_NEXT_PTR(di,ptr), &t->nextptr)) goto fail;
+ if (swdp_ahb_read(LT_STATE(di,ptr), &t->state)) goto fail;
+ if (swdp_ahb_read(LT_SAVED_SP(di,ptr), &t->saved_sp)) goto fail;
+ if (swdp_ahb_read(LT_WAITQ(di,ptr), &t->waitq)) goto fail;
+ if (swdp_ahb_read32(LT_NAME(di,ptr), (void*) t->name, 32 / 4)) goto fail;
+ t->name[31] = 0;
+ for (n = 0; n < 31; n++) {
+ if ((t->name[n] < ' ') || (t->name[n] > 127)) {
+ if (t->name[n] == 0) break;
+ t->name[n] = '.';
+ }
+ }
+ if (t->state > LK_MAX_STATE) t->state = LK_MAX_STATE + 1;
+ memset(t->regs, 0xee, sizeof(t->regs));
+ // lk arm-m context frame: R4 R5 R6 R7 R8 R9 R10 R11 LR
+ // if LR is FFFFFFxx then: R0 R1 R2 R3 R12 LR PC PSR
+ t->active = active;
+ if (!active) {
+ u32 fr[9];
+ if (swdp_ahb_read32(t->saved_sp, (void*) fr, 9)) goto fail;
+ memcpy(t->regs + 4, fr, 8 * sizeof(u32));
+ if ((fr[8] & 0xFFFFFF00) == 0xFFFFFF00) {
+ if (swdp_ahb_read32(t->saved_sp + 9 * sizeof(u32), (void*) fr, 8)) goto fail;
+ memcpy(t->regs + 0, fr, 4 * sizeof(u32));
+ t->regs[12] = fr[4];
+ t->regs[13] = t->saved_sp + 17 * sizeof(u32);
+ t->regs[14] = fr[5];
+ t->regs[15] = fr[6];
+ t->regs[16] = fr[7];
+ } else {
+ t->regs[13] = t->saved_sp + 9 * sizeof(u32);
+ t->regs[15] = fr[8];
+ t->regs[16] = 0x10000000;
+ }
+ }
+ return t;
+fail:
+ free(t);
+ return NULL;
+}
+
+void free_lk_threads(lkthread_t *list) {
+ lkthread_t *t, *next;
+ for (t = list; t != NULL; t = next) {
+ next = t->next;
+ free(t);
+ }
+}
+
+lkthread_t *find_lk_threads(int verbose) {
+ lkdebuginfo_t di;
+ lkthread_t *list = NULL;
+ lkthread_t *current = NULL;
+ lkthread_t *t;
+ u32 x;
+ u32 rtp;
+ if (swdp_ahb_read(DI_OFF_MAGIC, &x)) goto fail;
+ if (x != DI_MAGIC) {
+ if (verbose) xprintf("debuginfo: bad magic\n");
+ goto fail;
+ }
+ if (swdp_ahb_read(DI_OFF_PTR, &x)) goto fail;
+ if (x & 3) goto fail;
+ if (verbose) xprintf("debuginfo @ %08x\n", x);
+ if (swdp_ahb_read32(x, (void*) &di, sizeof(di) / 4)) goto fail;
+ if (verbose) {
+ xprintf("di %08x %08x %08x %d %d %d %d %d %d\n",
+ di.version, di.thread_list_ptr, di.current_thread_ptr,
+ di.off_list_node, di.off_state, di.off_saved_sp,
+ di.off_was_preempted, di.off_name, di.off_waitq);
+ }
+ if (di.version != 0x0100) {
+ if (verbose) xprintf("debuginfo: unsupported version\n");
+ goto fail;
+ }
+ if (swdp_ahb_read(di.current_thread_ptr, &x)) goto fail;
+ current = read_lk_thread(&di, x, 1);
+ rtp = di.thread_list_ptr;
+ for (;;) {
+ if (swdp_ahb_read(rtp + LIST_OFF_NEXT, &rtp)) goto fail;
+ if (rtp == di.thread_list_ptr) break;
+ x = LIST_TO_THREAD(&di, rtp);
+ if (current->threadptr == x) continue;
+ t = read_lk_thread(&di, x, 0);
+ if (t == NULL) goto fail;
+ t->next = list;
+ list = t;
+ }
+ current->next = list;
+ return current;
+fail:
+ if (current) free(current);
+ free_lk_threads(list);
+ return NULL;
+}
+
+lkthread_t *find_lk_thread(lkthread_t *list, u32 tptr) {
+ lkthread_t *t;
+ for (t = list; t != NULL; t = t->next) {
+ if (t->threadptr == tptr) {
+ return t;
+ }
+ }
+ return NULL;
+}
+
+void get_lk_thread_name(lkthread_t *t, char *out, size_t max) {
+ snprintf(out, max, "%s - %s", lkstate[t->state], t->name);
+}
diff --git a/tools/lkdebug.h b/tools/lkdebug.h
@@ -0,0 +1,43 @@
+/* lkdebug.h
+ *
+ * Copyright 2015 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LKDEBUG_H_
+#define _LKDEBUG_H_
+
+typedef struct lkthread {
+ struct lkthread *next;
+ int active;
+ u32 threadptr;
+ u32 nextptr;
+ u32 state;
+ u32 saved_sp;
+ u32 preempted;
+ u32 waitq;
+ char name[32];
+ u32 regs[17];
+} lkthread_t;
+
+// probe target for lk thread info
+lkthread_t *find_lk_threads(int verbose);
+
+void dump_lk_thread(lkthread_t *t);
+void dump_lk_threads(lkthread_t *t);
+void free_lk_threads(lkthread_t *list);
+lkthread_t *find_lk_thread(lkthread_t *list, u32 tptr);
+void get_lk_thread_name(lkthread_t *t, char *out, size_t max);
+
+#endif
diff --git a/tools/module.mk b/tools/module.mk
@@ -9,6 +9,7 @@ M_OBJS += tools/linenoise.o
M_OBJS += tools/usb.o
M_OBJS += tools/socket.o
M_OBJS += tools/gdb-bridge.o
+M_OBJS += tools/lkdebug.o
M_OBJS += out/debugger-builtins.o
$(call build-host-executable)