mdebug

cortex m series debugger
git clone http://frotz.net/git/mdebug.git
Log | Files | Refs | README | LICENSE

lkdebug.c (6230B)


      1 /* lkdebug.c
      2  *
      3  * Copyright 2015 Brian Swetland <swetland@frotz.net>
      4  * 
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 
     22 #include <fw/types.h>
     23 
     24 #include "rswdp.h"
     25 #include "debugger.h"
     26 #include "lkdebug.h"
     27 
     28 #define DI_MAGIC	0x52474244
     29 #define DI_OFF_MAGIC	32
     30 #define DI_OFF_PTR	36
     31 
     32 #define LK_THREAD_MAGIC	0x74687264
     33 #define LIST_OFF_PREV	0
     34 #define LIST_OFF_NEXT	4
     35 
     36 typedef struct lkdebuginfo {
     37 	u32 version;
     38 	u32 thread_list_ptr;
     39 	u32 current_thread_ptr;
     40 	u8 off_list_node;
     41 	u8 off_state;
     42 	u8 off_saved_sp;
     43 	u8 off_was_preempted;
     44 	u8 off_name;
     45 	u8 off_waitq;
     46 } lkdebuginfo_t;
     47 
     48 #define LK_MAX_STATE	5
     49 static char *lkstate[] = {
     50 	"SUSP ",
     51 	"READY",
     52 	"RUN  ",
     53 	"BLOCK",
     54 	"SLEEP",
     55 	"DEAD ",
     56 	"?????",
     57 };
     58 
     59 void dump_lk_thread(lkthread_t *t) {
     60 	xprintf(XDATA, "thread: @%08x sp=%08x wq=%08x st=%d name='%s'\n",
     61 		t->threadptr, t->saved_sp, t->waitq, t->state, t->name);
     62 	xprintf(XDATA, "  r0 %08x r4 %08x r8 %08x ip %08x\n",
     63 		t->regs[0], t->regs[4], t->regs[8], t->regs[12]);
     64 	xprintf(XDATA, "  r1 %08x r5 %08x r9 %08x sp %08x\n",
     65 		t->regs[1], t->regs[5], t->regs[9], t->regs[13]);
     66 	xprintf(XDATA, "  r2 %08x r6 %08x 10 %08x lr %08x\n",
     67 		t->regs[2], t->regs[6], t->regs[10], t->regs[14]);
     68 	xprintf(XDATA, "  r3 %08x r7 %08x 11 %08x pc %08x\n",
     69 		t->regs[3], t->regs[7], t->regs[11], t->regs[15]);
     70 }
     71 
     72 void dump_lk_threads(lkthread_t *t) {
     73 	while (t != NULL) {
     74 		dump_lk_thread(t);
     75 		t = t->next;
     76 	}
     77 }
     78 
     79 #define LT_NEXT_PTR(di,tp) ((tp) + di->off_list_node + LIST_OFF_NEXT)
     80 #define LT_STATE(di,tp) ((tp) + di->off_state)
     81 #define LT_SAVED_SP(di,tp) ((tp) + di->off_saved_sp)
     82 #define LT_NAME(di,tp) ((tp) + di->off_name)
     83 #define LT_WAITQ(di,tp) ((tp) + di->off_waitq)
     84 
     85 #define LIST_TO_THREAD(di,lp) ((lp) - (di)->off_list_node)
     86 
     87 static lkthread_t *read_lk_thread(lkdebuginfo_t *di, u32 ptr, int active) {
     88 	lkthread_t *t = calloc(1, sizeof(lkthread_t));
     89 	u32 x;
     90 	int n;
     91 	if (t == NULL) goto fail;
     92 	t->threadptr = ptr;
     93 	if (swdp_ahb_read(ptr, &x)) goto fail;
     94 	if (x != LK_THREAD_MAGIC) goto fail;
     95 	if (swdp_ahb_read(LT_NEXT_PTR(di,ptr), &t->nextptr)) goto fail;
     96 	if (swdp_ahb_read(LT_STATE(di,ptr), &t->state)) goto fail;
     97 	if (swdp_ahb_read(LT_SAVED_SP(di,ptr), &t->saved_sp)) goto fail;
     98 	if (swdp_ahb_read(LT_WAITQ(di,ptr), &t->waitq)) goto fail;
     99 	if (swdp_ahb_read32(LT_NAME(di,ptr), (void*) t->name, 32 / 4)) goto fail;
    100 	t->name[31] = 0;
    101 	for (n = 0; n < 31; n++) {
    102 		if ((t->name[n] < ' ') || (t->name[n] > 127)) {
    103 			if (t->name[n] == 0) break;
    104 			t->name[n] = '.';
    105 		}
    106 	}
    107 	if (t->state > LK_MAX_STATE) t->state = LK_MAX_STATE + 1;
    108 	memset(t->regs, 0xee, sizeof(t->regs));
    109 	// lk arm-m context frame: R4 R5 R6 R7 R8 R9 R10 R11 LR
    110 	// if LR is FFFFFFxx then: R0 R1 R2 R3 R12 LR PC PSR
    111 	t->active = active;
    112 	if (!active) {
    113 		u32 fr[9];
    114 		if (swdp_ahb_read32(t->saved_sp, (void*) fr, 9)) goto fail;
    115 		memcpy(t->regs + 4, fr, 8 * sizeof(u32));
    116 		if ((fr[8] & 0xFFFFFF00) == 0xFFFFFF00) {
    117 			if (swdp_ahb_read32(t->saved_sp + 9 * sizeof(u32), (void*) fr, 8)) goto fail;
    118 			memcpy(t->regs + 0, fr, 4 * sizeof(u32));
    119 			t->regs[12] = fr[4];
    120 			t->regs[13] = t->saved_sp + 17 * sizeof(u32);
    121 			t->regs[14] = fr[5];
    122 			t->regs[15] = fr[6];
    123 			t->regs[16] = fr[7];
    124 		} else {
    125 			t->regs[13] = t->saved_sp + 9 * sizeof(u32);
    126 			t->regs[15] = fr[8];
    127 			t->regs[16] = 0x10000000;
    128 		}
    129 	}
    130 	return t;
    131 fail:
    132 	free(t);
    133 	return NULL;
    134 }
    135 
    136 void free_lk_threads(lkthread_t *list) {
    137 	lkthread_t *t, *next;
    138 	for (t = list; t != NULL; t = next) {
    139 		next = t->next;
    140 		free(t);
    141 	}
    142 }
    143 
    144 static int load_debuginfo(lkdebuginfo_t *di, int verbose) {
    145 	u32 x;
    146 	u32 vtbl;
    147 	//read Vector Table Offset Register
    148 	if (swdp_ahb_read(0xE000ED08, &vtbl)) vtbl = 0;
    149 	if (swdp_ahb_read((DI_OFF_MAGIC + vtbl), &x)) return -1;
    150 	if (x != DI_MAGIC) {
    151 		if (verbose) xprintf(XCORE, "debuginfo: bad magic\n");
    152 		return -1;
    153 	}
    154 	if (swdp_ahb_read((DI_OFF_PTR + vtbl), &x)) return -1;
    155 	if (x & 3) return -1;
    156 	if (verbose) xprintf(XCORE, "debuginfo @ %08x\n", x);
    157 	if (swdp_ahb_read32(x, (void*) di, sizeof(lkdebuginfo_t) / 4)) return -1;
    158 	if (verbose) {
    159 		xprintf(XDATA, "di %08x %08x %08x %d %d %d %d %d %d\n",
    160 			di->version, di->thread_list_ptr, di->current_thread_ptr,
    161 			di->off_list_node, di->off_state, di->off_saved_sp,
    162 			di->off_was_preempted, di->off_name, di->off_waitq);
    163 	}
    164 	if (di->version != 0x0100) {
    165 		if (verbose) xprintf(XCORE, "debuginfo: unsupported version\n");
    166 		return -1;
    167 	}
    168 	return 0;
    169 }
    170 
    171 void clear_lk_threads(void) {
    172 	lkdebuginfo_t di;
    173 	if (load_debuginfo(&di, 0)) return;
    174 	swdp_ahb_write(di.current_thread_ptr, 0xffffffff);
    175 	swdp_ahb_write(di.thread_list_ptr + 0, 0xffffffff);
    176 	swdp_ahb_write(di.thread_list_ptr + 4, 0xffffffff);
    177 }
    178 
    179 lkthread_t *find_lk_threads(int verbose) {
    180 	lkdebuginfo_t di;
    181 	lkthread_t *list = NULL;
    182 	lkthread_t *current = NULL;
    183 	lkthread_t *t;
    184 	u32 x;
    185 	u32 rtp;
    186 	if (load_debuginfo(&di, verbose)) goto fail;
    187 	if (swdp_ahb_read(di.current_thread_ptr, &x)) goto fail;
    188 	current = read_lk_thread(&di, x, 1);
    189 	if (current == NULL) goto fail;
    190 	rtp = di.thread_list_ptr;
    191 	for (;;) {
    192 		if (swdp_ahb_read(rtp + LIST_OFF_NEXT, &rtp)) goto fail;
    193 		if (rtp == di.thread_list_ptr) break;
    194 		x = LIST_TO_THREAD(&di, rtp);
    195 		if (current->threadptr == x) continue;
    196 		t = read_lk_thread(&di, x, 0);
    197 		if (t == NULL) goto fail;
    198 		t->next = list;
    199 		list = t;
    200 	}
    201 	current->next = list;
    202 	return current;
    203 fail:
    204 	if (current) free(current);
    205 	free_lk_threads(list);
    206 	return NULL;
    207 }
    208 
    209 lkthread_t *find_lk_thread(lkthread_t *list, u32 tptr) {
    210 	lkthread_t *t;
    211 	for (t = list; t != NULL; t = t->next) {
    212 		if (t->threadptr == tptr) {
    213 			return t;
    214 		}
    215 	}
    216 	return NULL;
    217 }
    218 
    219 void get_lk_thread_name(lkthread_t *t, char *out, size_t max) {
    220 	snprintf(out, max, "%s - %s", lkstate[t->state], t->name);
    221 }