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