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)