1 /* 2 * Copyright 2003-2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler <axeld@pinc-software.de> 7 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 8 * François Revol <revol@free.fr> 9 */ 10 11 12 #include <arch/debug.h> 13 14 #include <arch_cpu.h> 15 #include <debug.h> 16 #include <elf.h> 17 #include <kernel.h> 18 #include <kimage.h> 19 #include <thread.h> 20 21 22 struct stack_frame { 23 struct stack_frame *previous; 24 addr_t return_address; 25 }; 26 27 #define NUM_PREVIOUS_LOCATIONS 32 28 29 extern struct iframe_stack gBootFrameStack; 30 31 32 static bool 33 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer) 34 { 35 int32 last = *_last; 36 int32 num = *_num; 37 int32 i; 38 39 for (i = 0; i < num; i++) { 40 if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) 41 % NUM_PREVIOUS_LOCATIONS] == framePointer) { 42 return true; 43 } 44 } 45 46 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; 47 visited[last] = framePointer; 48 49 if (num < NUM_PREVIOUS_LOCATIONS) 50 *_num = num + 1; 51 52 return false; 53 } 54 55 56 static inline stack_frame * 57 get_current_stack_frame() 58 { 59 stack_frame *frame; 60 #warning M68K: a6 or a7 ? 61 asm volatile("move.l %%a6,%0" : "=r"(frame)); 62 return frame; 63 } 64 65 66 static status_t 67 get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) 68 { 69 struct thread *thread = thread_get_current_thread(); 70 addr_t oldFaultHandler = thread->fault_handler; 71 72 // set fault handler, so that we can safely access user stacks 73 if (thread) { 74 if (m68k_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) 75 goto error; 76 } 77 78 *ip = ((struct stack_frame *)framePointer)->return_address; 79 *next = (addr_t)((struct stack_frame *)framePointer)->previous; 80 81 if (thread) 82 thread->fault_handler = oldFaultHandler; 83 return B_OK; 84 85 error: 86 thread->fault_handler = oldFaultHandler; 87 return B_BAD_ADDRESS; 88 } 89 90 91 static void 92 print_stack_frame(struct thread *thread, addr_t ip, addr_t framePointer, 93 addr_t nextFramePointer) 94 { 95 addr_t diff = nextFramePointer - framePointer; 96 97 // kernel space/user space switch 98 if (diff & 0x80000000) 99 diff = 0; 100 101 // lookup symbol 102 const char *symbol, *image; 103 addr_t baseAddress; 104 bool exactMatch; 105 status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol, 106 &image, &exactMatch); 107 if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) { 108 // try to locate the image in the images loaded into user space 109 status = image_debug_lookup_user_symbol_address(thread->team, ip, 110 &baseAddress, &symbol, &image, &exactMatch); 111 } 112 if (status == B_OK) { 113 if (symbol != NULL) { 114 kprintf("%08lx (+%4ld) %08lx <%s>:%s + 0x%04lx%s\n", framePointer, 115 diff, ip, image, symbol, ip - baseAddress, 116 (exactMatch ? "" : " (nearest)")); 117 } else { 118 kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n", 119 framePointer, diff, ip, image, (void *)baseAddress, 120 ip - baseAddress); 121 } 122 } else 123 kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip); 124 } 125 126 127 static int 128 stack_trace(int argc, char **argv) 129 { 130 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; 131 struct iframe_stack *frameStack; 132 struct thread *thread; 133 addr_t framePointer; 134 int32 i, num = 0, last = 0; 135 136 if (argc < 2) { 137 thread = thread_get_current_thread(); 138 framePointer = (addr_t)get_current_stack_frame(); 139 } else { 140 // TODO: Add support for stack traces of other threads. 141 /* thread_id id = strtoul(argv[1], NULL, 0); 142 thread = thread_get_thread_struct_locked(id); 143 if (thread == NULL) { 144 kprintf("could not find thread %ld\n", id); 145 return 0; 146 } 147 148 // read %ebp from the thread's stack stored by a pushad 149 ebp = thread->arch_info.current_stack.esp[2]; 150 151 if (id != thread_get_current_thread_id()) { 152 // switch to the page directory of the new thread to be 153 // able to follow the stack trace into userland 154 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 155 thread_get_current_thread(), thread); 156 157 if (newPageDirectory != 0) { 158 read_cr3(oldPageDirectory); 159 write_cr3(newPageDirectory); 160 } 161 } 162 */ 163 kprintf("Stack traces of other threads not supported yet!\n"); 164 return 0; 165 } 166 167 // We don't have a thread pointer early in the boot process 168 if (thread != NULL) 169 frameStack = &thread->arch_info.iframes; 170 else 171 frameStack = &gBootFrameStack; 172 173 for (i = 0; i < frameStack->index; i++) { 174 kprintf("iframe %p (end = %p)\n", 175 frameStack->frames[i], frameStack->frames[i] + 1); 176 } 177 178 if (thread != NULL) { 179 kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, 180 thread->name); 181 182 kprintf(" kernel stack: %p to %p\n", 183 (void *)thread->kernel_stack_base, 184 (void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE)); 185 if (thread->user_stack_base != 0) { 186 kprintf(" user stack: %p to %p\n", 187 (void *)thread->user_stack_base, 188 (void *)(thread->user_stack_base + thread->user_stack_size)); 189 } 190 } 191 192 kprintf("frame caller <image>:function + offset\n"); 193 194 for (;;) { 195 // see if the frame pointer matches the iframe 196 struct iframe *frame = NULL; 197 for (i = 0; i < frameStack->index; i++) { 198 if (framePointer == (((addr_t)frameStack->frames[i] - 8) & ~0xf)) { 199 // it's an iframe 200 frame = frameStack->frames[i]; 201 break; 202 } 203 } 204 205 if (frame) { 206 kprintf("iframe at %p\n", frame); 207 kprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", 208 frame->d[0], frame->d[1], frame->d[2], frame->d[3]); 209 kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", 210 frame->d[4], frame->d[5], frame->d[6], frame->d[7]); 211 kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", 212 frame->a[0], frame->a[1], frame->a[2], frame->a[3]); 213 kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx a7 0x%08lx (sp)\n", 214 #warning M68K: a7 in iframe ?? 215 frame->a[4], frame->a[5], frame->a[6], -1/*frame->a[7]*/); 216 217 /*kprintf(" pc 0x%08lx ccr 0x%02x\n", 218 frame->pc, frame->ccr);*/ 219 kprintf(" pc 0x%08lx sr 0x%04x\n", 220 frame->cpu.pc, frame->cpu.sr); 221 #warning M68K: missing regs 222 223 print_stack_frame(thread, frame->cpu.pc, framePointer, frame->a[6]); 224 framePointer = frame->a[6]; 225 } else { 226 addr_t ip, nextFramePointer; 227 228 if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { 229 kprintf("%08lx -- read fault\n", framePointer); 230 break; 231 } 232 233 if (ip == 0 || framePointer == 0) 234 break; 235 236 print_stack_frame(thread, ip, framePointer, nextFramePointer); 237 framePointer = nextFramePointer; 238 } 239 240 if (already_visited(previousLocations, &last, &num, framePointer)) { 241 kprintf("circular stack frame: %p!\n", (void *)framePointer); 242 break; 243 } 244 if (framePointer == 0) 245 break; 246 } 247 248 /* if (oldPageDirectory != 0) { 249 // switch back to the previous page directory to no cause any troubles 250 write_cr3(oldPageDirectory); 251 } 252 */ 253 254 return 0; 255 } 256 257 258 259 // #pragma mark - 260 261 262 void 263 arch_debug_save_registers(int *regs) 264 { 265 } 266 267 268 bool 269 arch_debug_contains_call(struct thread *thread, const char *symbol, 270 addr_t start, addr_t end) 271 { 272 return false; 273 } 274 275 276 void * 277 arch_debug_get_caller(void) 278 { 279 // TODO: implement me 280 return (void *)&arch_debug_get_caller; 281 } 282 283 284 status_t 285 arch_debug_init(kernel_args *args) 286 { 287 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 288 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 289 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 290 291 return B_NO_ERROR; 292 } 293 294