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 asm volatile("move.l %%fp,%0" : "=r"(frame)); 61 return frame; 62 } 63 64 65 static status_t 66 get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) 67 { 68 struct thread *thread = thread_get_current_thread(); 69 addr_t oldFaultHandler = thread->fault_handler; 70 71 // set fault handler, so that we can safely access user stacks 72 if (thread) { 73 if (m68k_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) 74 goto error; 75 } 76 77 *ip = ((struct stack_frame *)framePointer)->return_address; 78 *next = (addr_t)((struct stack_frame *)framePointer)->previous; 79 80 if (thread) 81 thread->fault_handler = oldFaultHandler; 82 return B_OK; 83 84 error: 85 thread->fault_handler = oldFaultHandler; 86 return B_BAD_ADDRESS; 87 } 88 89 90 static void 91 print_stack_frame(struct thread *thread, addr_t ip, addr_t framePointer, 92 addr_t nextFramePointer) 93 { 94 addr_t diff = nextFramePointer - framePointer; 95 96 // kernel space/user space switch 97 if (diff & 0x80000000) 98 diff = 0; 99 100 // lookup symbol 101 const char *symbol, *image; 102 addr_t baseAddress; 103 bool exactMatch; 104 status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol, 105 &image, &exactMatch); 106 if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) { 107 // try to locate the image in the images loaded into user space 108 status = image_debug_lookup_user_symbol_address(thread->team, ip, 109 &baseAddress, &symbol, &image, &exactMatch); 110 } 111 if (status == B_OK) { 112 if (symbol != NULL) { 113 kprintf("%08lx (+%4ld) %08lx <%s>:%s + 0x%04lx%s\n", framePointer, 114 diff, ip, image, symbol, ip - baseAddress, 115 (exactMatch ? "" : " (nearest)")); 116 } else { 117 kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n", 118 framePointer, diff, ip, image, (void *)baseAddress, 119 ip - baseAddress); 120 } 121 } else 122 kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip); 123 } 124 125 126 static int 127 stack_trace(int argc, char **argv) 128 { 129 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; 130 struct iframe_stack *frameStack; 131 struct thread *thread; 132 addr_t framePointer; 133 int32 i, num = 0, last = 0; 134 135 if (argc < 2) { 136 thread = thread_get_current_thread(); 137 framePointer = (addr_t)get_current_stack_frame(); 138 } else { 139 // TODO: Add support for stack traces of other threads. 140 /* thread_id id = strtoul(argv[1], NULL, 0); 141 thread = thread_get_thread_struct_locked(id); 142 if (thread == NULL) { 143 kprintf("could not find thread %ld\n", id); 144 return 0; 145 } 146 147 // read %ebp from the thread's stack stored by a pushad 148 ebp = thread->arch_info.current_stack.esp[2]; 149 150 if (id != thread_get_current_thread_id()) { 151 // switch to the page directory of the new thread to be 152 // able to follow the stack trace into userland 153 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 154 thread_get_current_thread(), thread); 155 156 if (newPageDirectory != 0) { 157 read_cr3(oldPageDirectory); 158 write_cr3(newPageDirectory); 159 } 160 } 161 */ 162 kprintf("Stack traces of other threads not supported yet!\n"); 163 return 0; 164 } 165 166 // We don't have a thread pointer early in the boot process 167 if (thread != NULL) 168 frameStack = &thread->arch_info.iframes; 169 else 170 frameStack = &gBootFrameStack; 171 172 for (i = 0; i < frameStack->index; i++) { 173 kprintf("iframe %p (end = %p)\n", 174 frameStack->frames[i], frameStack->frames[i] + 1); 175 } 176 177 if (thread != NULL) { 178 kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, 179 thread->name); 180 181 kprintf(" kernel stack: %p to %p\n", 182 (void *)thread->kernel_stack_base, 183 (void *)(thread->kernel_stack_top)); 184 if (thread->user_stack_base != 0) { 185 kprintf(" user stack: %p to %p\n", 186 (void *)thread->user_stack_base, 187 (void *)(thread->user_stack_base + thread->user_stack_size)); 188 } 189 } 190 191 kprintf("frame caller <image>:function + offset\n"); 192 193 for (;;) { 194 // see if the frame pointer matches the iframe 195 struct iframe *frame = NULL; 196 for (i = 0; i < frameStack->index; i++) { 197 if (framePointer == (((addr_t)frameStack->frames[i] - 8) & ~0xf)) { 198 // it's an iframe 199 frame = frameStack->frames[i]; 200 break; 201 } 202 } 203 204 if (frame) { 205 kprintf("iframe at %p\n", frame); 206 kprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", 207 frame->d[0], frame->d[1], frame->d[2], frame->d[3]); 208 kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", 209 frame->d[4], frame->d[5], frame->d[6], frame->d[7]); 210 kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", 211 frame->a[0], frame->a[1], frame->a[2], frame->a[3]); 212 kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx a7 0x%08lx (sp)\n", 213 #warning M68K: a7 in iframe ?? 214 frame->a[4], frame->a[5], frame->a[6], -1L/*frame->a[7]*/); 215 216 /*kprintf(" pc 0x%08lx ccr 0x%02x\n", 217 frame->pc, frame->ccr);*/ 218 kprintf(" pc 0x%08lx sr 0x%04x\n", 219 frame->cpu.pc, frame->cpu.sr); 220 #warning M68K: missing regs 221 222 print_stack_frame(thread, frame->cpu.pc, framePointer, frame->a[6]); 223 framePointer = frame->a[6]; 224 } else { 225 addr_t ip, nextFramePointer; 226 227 if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { 228 kprintf("%08lx -- read fault\n", framePointer); 229 break; 230 } 231 232 if (ip == 0 || framePointer == 0) 233 break; 234 235 print_stack_frame(thread, ip, framePointer, nextFramePointer); 236 framePointer = nextFramePointer; 237 } 238 239 if (already_visited(previousLocations, &last, &num, framePointer)) { 240 kprintf("circular stack frame: %p!\n", (void *)framePointer); 241 break; 242 } 243 if (framePointer == 0) 244 break; 245 } 246 247 /* if (oldPageDirectory != 0) { 248 // switch back to the previous page directory to no cause any troubles 249 write_cr3(oldPageDirectory); 250 } 251 */ 252 253 return 0; 254 } 255 256 257 258 // #pragma mark - 259 260 261 void 262 arch_debug_save_registers(int *regs) 263 { 264 } 265 266 267 bool 268 arch_debug_contains_call(struct thread *thread, const char *symbol, 269 addr_t start, addr_t end) 270 { 271 return false; 272 } 273 274 275 void * 276 arch_debug_get_caller(void) 277 { 278 // TODO: implement me 279 //return __builtin_frame_address(1); 280 struct stack_frame *frame; 281 //frame = __builtin_frame_address(0); 282 frame = get_current_stack_frame(); 283 return (void *)frame->previous->return_address; 284 } 285 286 287 int32 288 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 289 int32 skipFrames, bool userOnly) 290 { 291 struct iframe_stack *frameStack; 292 addr_t framePointer; 293 int32 count = 0; 294 int32 i, num = 0, last = 0; 295 296 // always skip our own frame 297 skipFrames++; 298 299 struct thread* thread = thread_get_current_thread(); 300 framePointer = (addr_t)get_current_stack_frame(); 301 302 // We don't have a thread pointer early in the boot process 303 if (thread != NULL) 304 frameStack = &thread->arch_info.iframes; 305 else 306 frameStack = &gBootFrameStack; 307 308 while (framePointer != 0 && count < maxCount) { 309 // see if the frame pointer matches the iframe 310 struct iframe *frame = NULL; 311 for (i = 0; i < frameStack->index; i++) { 312 if (framePointer == (((addr_t)frameStack->frames[i] - 8) & ~0xf)) { 313 // it's an iframe 314 frame = frameStack->frames[i]; 315 break; 316 } 317 } 318 319 addr_t ip; 320 addr_t nextFrame; 321 322 if (frame) { 323 ip = frame->cpu.pc; 324 nextFrame = frame->a[6]; 325 } else { 326 if (get_next_frame(framePointer, &nextFrame, &ip) != B_OK) 327 break; 328 } 329 330 if (skipFrames <= 0 && (!userOnly || IS_USER_ADDRESS(framePointer))) 331 returnAddresses[count++] = ip; 332 else 333 skipFrames--; 334 335 framePointer = nextFrame; 336 } 337 338 return count; 339 } 340 341 342 void* 343 arch_debug_get_interrupt_pc() 344 { 345 // TODO: Implement! 346 return NULL; 347 } 348 349 350 bool 351 arch_is_debug_variable_defined(const char* variableName) 352 { 353 // TODO: Implement! 354 return false; 355 } 356 357 358 status_t 359 arch_set_debug_variable(const char* variableName, uint64 value) 360 { 361 // TODO: Implement! 362 return B_ENTRY_NOT_FOUND; 363 } 364 365 366 status_t 367 arch_get_debug_variable(const char* variableName, uint64* value) 368 { 369 // TODO: Implement! 370 return B_ENTRY_NOT_FOUND; 371 } 372 373 374 status_t 375 arch_debug_init(kernel_args *args) 376 { 377 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 378 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 379 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 380 381 return B_NO_ERROR; 382 } 383 384