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 }