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