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 */ 9 10 11 #include <arch/debug.h> 12 13 #include <arch_cpu.h> 14 #include <debug.h> 15 #include <elf.h> 16 #include <kernel.h> 17 #include <kimage.h> 18 #include <thread.h> 19 20 21 struct stack_frame { 22 struct stack_frame *previous; 23 addr_t return_address; 24 }; 25 26 #define NUM_PREVIOUS_LOCATIONS 32 27 28 extern struct iframe_stack gBootFrameStack; 29 30 31 static bool 32 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer) 33 { 34 int32 last = *_last; 35 int32 num = *_num; 36 int32 i; 37 38 for (i = 0; i < num; i++) { 39 if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) 40 % NUM_PREVIOUS_LOCATIONS] == framePointer) { 41 return true; 42 } 43 } 44 45 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; 46 visited[last] = framePointer; 47 48 if (num < NUM_PREVIOUS_LOCATIONS) 49 *_num = num + 1; 50 51 return false; 52 } 53 54 55 static inline stack_frame * 56 get_current_stack_frame() 57 { 58 stack_frame *frame; 59 asm volatile("mr %0, %%r1" : "=r"(frame)); 60 return frame; 61 } 62 63 64 static status_t 65 get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) 66 { 67 struct thread *thread = thread_get_current_thread(); 68 addr_t oldFaultHandler = thread->fault_handler; 69 70 // set fault handler, so that we can safely access user stacks 71 if (thread) { 72 if (ppc_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) 73 goto error; 74 } 75 76 *ip = ((struct stack_frame *)framePointer)->return_address; 77 *next = (addr_t)((struct stack_frame *)framePointer)->previous; 78 79 if (thread) 80 thread->fault_handler = oldFaultHandler; 81 return B_OK; 82 83 error: 84 thread->fault_handler = oldFaultHandler; 85 return B_BAD_ADDRESS; 86 } 87 88 89 static void 90 print_stack_frame(struct thread *thread, addr_t ip, addr_t framePointer, 91 addr_t nextFramePointer) 92 { 93 addr_t diff = nextFramePointer - framePointer; 94 95 // kernel space/user space switch 96 if (diff & 0x80000000) 97 diff = 0; 98 99 // lookup symbol 100 const char *symbol, *image; 101 addr_t baseAddress; 102 bool exactMatch; 103 status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol, 104 &image, &exactMatch); 105 if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) { 106 // try to locate the image in the images loaded into user space 107 status = image_debug_lookup_user_symbol_address(thread->team, ip, 108 &baseAddress, &symbol, &image, &exactMatch); 109 } 110 if (status == B_OK) { 111 if (symbol != NULL) { 112 kprintf("%08lx (+%4ld) %08lx <%s>:%s + 0x%04lx%s\n", framePointer, 113 diff, ip, image, symbol, ip - baseAddress, 114 (exactMatch ? "" : " (nearest)")); 115 } else { 116 kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n", 117 framePointer, diff, ip, image, (void *)baseAddress, 118 ip - baseAddress); 119 } 120 } else 121 kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip); 122 } 123 124 125 static int 126 stack_trace(int argc, char **argv) 127 { 128 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; 129 struct iframe_stack *frameStack; 130 struct thread *thread; 131 addr_t framePointer; 132 int32 i, num = 0, last = 0; 133 134 if (argc < 2) { 135 thread = thread_get_current_thread(); 136 framePointer = (addr_t)get_current_stack_frame(); 137 } else { 138 // TODO: Add support for stack traces of other threads. 139 /* thread_id id = strtoul(argv[1], NULL, 0); 140 thread = thread_get_thread_struct_locked(id); 141 if (thread == NULL) { 142 kprintf("could not find thread %ld\n", id); 143 return 0; 144 } 145 146 // read %ebp from the thread's stack stored by a pushad 147 ebp = thread->arch_info.current_stack.esp[2]; 148 149 if (id != thread_get_current_thread_id()) { 150 // switch to the page directory of the new thread to be 151 // able to follow the stack trace into userland 152 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 153 thread_get_current_thread(), thread); 154 155 if (newPageDirectory != 0) { 156 read_cr3(oldPageDirectory); 157 write_cr3(newPageDirectory); 158 } 159 } 160 */ 161 kprintf("Stack traces of other threads not supported yet!\n"); 162 return 0; 163 } 164 165 // We don't have a thread pointer early in the boot process 166 if (thread != NULL) 167 frameStack = &thread->arch_info.iframes; 168 else 169 frameStack = &gBootFrameStack; 170 171 for (i = 0; i < frameStack->index; i++) { 172 kprintf("iframe %p (end = %p)\n", 173 frameStack->frames[i], frameStack->frames[i] + 1); 174 } 175 176 if (thread != NULL) { 177 kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, 178 thread->name); 179 180 kprintf(" kernel stack: %p to %p\n", 181 (void *)thread->kernel_stack_base, 182 (void *)(thread->kernel_stack_top)); 183 if (thread->user_stack_base != 0) { 184 kprintf(" user stack: %p to %p\n", 185 (void *)thread->user_stack_base, 186 (void *)(thread->user_stack_base + thread->user_stack_size)); 187 } 188 } 189 190 kprintf("frame caller <image>:function + offset\n"); 191 192 for (;;) { 193 // see if the frame pointer matches the iframe 194 struct iframe *frame = NULL; 195 for (i = 0; i < frameStack->index; i++) { 196 if (framePointer == (((addr_t)frameStack->frames[i] - 8) & ~0xf)) { 197 // it's an iframe 198 frame = frameStack->frames[i]; 199 break; 200 } 201 } 202 203 if (frame) { 204 kprintf("iframe at %p\n", frame); 205 kprintf(" r0 0x%08lx r1 0x%08lx r2 0x%08lx r3 0x%08lx\n", 206 frame->r0, frame->r1, frame->r2, frame->r3); 207 kprintf(" r4 0x%08lx r5 0x%08lx r6 0x%08lx r7 0x%08lx\n", 208 frame->r4, frame->r5, frame->r6, frame->r7); 209 kprintf(" r8 0x%08lx r9 0x%08lx r10 0x%08lx r11 0x%08lx\n", 210 frame->r8, frame->r9, frame->r10, frame->r11); 211 kprintf(" r12 0x%08lx r13 0x%08lx r14 0x%08lx r15 0x%08lx\n", 212 frame->r12, frame->r13, frame->r14, frame->r15); 213 kprintf(" r16 0x%08lx r17 0x%08lx r18 0x%08lx r19 0x%08lx\n", 214 frame->r16, frame->r17, frame->r18, frame->r19); 215 kprintf(" r20 0x%08lx r21 0x%08lx r22 0x%08lx r23 0x%08lx\n", 216 frame->r20, frame->r21, frame->r22, frame->r23); 217 kprintf(" r24 0x%08lx r25 0x%08lx r26 0x%08lx r27 0x%08lx\n", 218 frame->r24, frame->r25, frame->r26, frame->r27); 219 kprintf(" r28 0x%08lx r29 0x%08lx r30 0x%08lx r31 0x%08lx\n", 220 frame->r28, frame->r29, frame->r30, frame->r31); 221 kprintf(" lr 0x%08lx cr 0x%08lx xer 0x%08lx ctr 0x%08lx\n", 222 frame->lr, frame->cr, frame->xer, frame->ctr); 223 kprintf("fpscr 0x%08lx\n", frame->fpscr); 224 kprintf(" srr0 0x%08lx srr1 0x%08lx dar 0x%08lx dsisr 0x%08lx\n", 225 frame->srr0, frame->srr1, frame->dar, frame->dsisr); 226 kprintf(" vector: 0x%lx\n", frame->vector); 227 228 print_stack_frame(thread, frame->srr0, framePointer, frame->r1); 229 framePointer = frame->r1; 230 } else { 231 addr_t ip, nextFramePointer; 232 233 if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { 234 kprintf("%08lx -- read fault\n", framePointer); 235 break; 236 } 237 238 if (ip == 0 || framePointer == 0) 239 break; 240 241 print_stack_frame(thread, ip, framePointer, nextFramePointer); 242 framePointer = nextFramePointer; 243 } 244 245 if (already_visited(previousLocations, &last, &num, framePointer)) { 246 kprintf("circular stack frame: %p!\n", (void *)framePointer); 247 break; 248 } 249 if (framePointer == 0) 250 break; 251 } 252 253 /* if (oldPageDirectory != 0) { 254 // switch back to the previous page directory to no cause any troubles 255 write_cr3(oldPageDirectory); 256 } 257 */ 258 259 return 0; 260 } 261 262 263 264 // #pragma mark - 265 266 267 void 268 arch_debug_save_registers(int *regs) 269 { 270 } 271 272 273 bool 274 arch_debug_contains_call(struct thread *thread, const char *symbol, 275 addr_t start, addr_t end) 276 { 277 return false; 278 } 279 280 281 void * 282 arch_debug_get_caller(void) 283 { 284 // TODO: implement me 285 return (void *)&arch_debug_get_caller; 286 } 287 288 289 void* 290 arch_debug_get_interrupt_pc() 291 { 292 // TODO: Implement! 293 return NULL; 294 } 295 296 297 bool 298 arch_is_debug_variable_defined(const char* variableName) 299 { 300 // TODO: Implement! 301 return false; 302 } 303 304 305 status_t 306 arch_set_debug_variable(const char* variableName, uint64 value) 307 { 308 // TODO: Implement! 309 return B_ENTRY_NOT_FOUND; 310 } 311 312 313 status_t 314 arch_get_debug_variable(const char* variableName, uint64* value) 315 { 316 // TODO: Implement! 317 return B_ENTRY_NOT_FOUND; 318 } 319 320 321 status_t 322 arch_debug_init(kernel_args *args) 323 { 324 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 325 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 326 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 327 328 return B_NO_ERROR; 329 } 330 331