1 /* 2 * Copyright 2003-2010, 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 stack_frame frame; 68 if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)framePointer, sizeof(frame)) 69 != B_OK) { 70 return B_BAD_ADDRESS; 71 } 72 73 *ip = frame.return_address; 74 *next = (addr_t)frame.previous; 75 76 return B_OK; 77 } 78 79 80 static void 81 print_stack_frame(struct thread *thread, addr_t ip, addr_t framePointer, 82 addr_t nextFramePointer) 83 { 84 addr_t diff = nextFramePointer - framePointer; 85 86 // kernel space/user space switch 87 if (diff & 0x80000000) 88 diff = 0; 89 90 // lookup symbol 91 const char *symbol, *image; 92 addr_t baseAddress; 93 bool exactMatch; 94 status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol, 95 &image, &exactMatch); 96 if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) { 97 // try to locate the image in the images loaded into user space 98 status = image_debug_lookup_user_symbol_address(thread->team, ip, 99 &baseAddress, &symbol, &image, &exactMatch); 100 } 101 if (status == B_OK) { 102 if (symbol != NULL) { 103 kprintf("%08lx (+%4ld) %08lx <%s>:%s + 0x%04lx%s\n", framePointer, 104 diff, ip, image, symbol, ip - baseAddress, 105 (exactMatch ? "" : " (nearest)")); 106 } else { 107 kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n", 108 framePointer, diff, ip, image, (void *)baseAddress, 109 ip - baseAddress); 110 } 111 } else 112 kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip); 113 } 114 115 116 static int 117 stack_trace(int argc, char **argv) 118 { 119 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; 120 struct iframe_stack *frameStack; 121 struct thread *thread; 122 addr_t framePointer; 123 int32 i, num = 0, last = 0; 124 125 if (argc < 2) { 126 thread = thread_get_current_thread(); 127 framePointer = (addr_t)get_current_stack_frame(); 128 } else { 129 // TODO: Add support for stack traces of other threads. 130 /* thread_id id = strtoul(argv[1], NULL, 0); 131 thread = thread_get_thread_struct_locked(id); 132 if (thread == NULL) { 133 kprintf("could not find thread %ld\n", id); 134 return 0; 135 } 136 137 // read %ebp from the thread's stack stored by a pushad 138 ebp = thread->arch_info.current_stack.esp[2]; 139 140 if (id != thread_get_current_thread_id()) { 141 // switch to the page directory of the new thread to be 142 // able to follow the stack trace into userland 143 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 144 thread_get_current_thread(), thread); 145 146 if (newPageDirectory != 0) { 147 read_cr3(oldPageDirectory); 148 write_cr3(newPageDirectory); 149 } 150 } 151 */ 152 kprintf("Stack traces of other threads not supported yet!\n"); 153 return 0; 154 } 155 156 // We don't have a thread pointer early in the boot process 157 if (thread != NULL) 158 frameStack = &thread->arch_info.iframes; 159 else 160 frameStack = &gBootFrameStack; 161 162 for (i = 0; i < frameStack->index; i++) { 163 kprintf("iframe %p (end = %p)\n", 164 frameStack->frames[i], frameStack->frames[i] + 1); 165 } 166 167 if (thread != NULL) { 168 kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, 169 thread->name); 170 171 kprintf(" kernel stack: %p to %p\n", 172 (void *)thread->kernel_stack_base, 173 (void *)(thread->kernel_stack_top)); 174 if (thread->user_stack_base != 0) { 175 kprintf(" user stack: %p to %p\n", 176 (void *)thread->user_stack_base, 177 (void *)(thread->user_stack_base + thread->user_stack_size)); 178 } 179 } 180 181 kprintf("frame caller <image>:function + offset\n"); 182 183 for (;;) { 184 // see if the frame pointer matches the iframe 185 struct iframe *frame = NULL; 186 for (i = 0; i < frameStack->index; i++) { 187 if (framePointer == (((addr_t)frameStack->frames[i] - 8) & ~0xf)) { 188 // it's an iframe 189 frame = frameStack->frames[i]; 190 break; 191 } 192 } 193 194 if (frame) { 195 kprintf("iframe at %p\n", frame); 196 kprintf(" r0 0x%08lx r1 0x%08lx r2 0x%08lx r3 0x%08lx\n", 197 frame->r0, frame->r1, frame->r2, frame->r3); 198 kprintf(" r4 0x%08lx r5 0x%08lx r6 0x%08lx r7 0x%08lx\n", 199 frame->r4, frame->r5, frame->r6, frame->r7); 200 kprintf(" r8 0x%08lx r9 0x%08lx r10 0x%08lx r11 0x%08lx\n", 201 frame->r8, frame->r9, frame->r10, frame->r11); 202 kprintf(" r12 0x%08lx r13 0x%08lx r14 0x%08lx r15 0x%08lx\n", 203 frame->r12, frame->r13, frame->r14, frame->r15); 204 kprintf(" r16 0x%08lx r17 0x%08lx r18 0x%08lx r19 0x%08lx\n", 205 frame->r16, frame->r17, frame->r18, frame->r19); 206 kprintf(" r20 0x%08lx r21 0x%08lx r22 0x%08lx r23 0x%08lx\n", 207 frame->r20, frame->r21, frame->r22, frame->r23); 208 kprintf(" r24 0x%08lx r25 0x%08lx r26 0x%08lx r27 0x%08lx\n", 209 frame->r24, frame->r25, frame->r26, frame->r27); 210 kprintf(" r28 0x%08lx r29 0x%08lx r30 0x%08lx r31 0x%08lx\n", 211 frame->r28, frame->r29, frame->r30, frame->r31); 212 kprintf(" lr 0x%08lx cr 0x%08lx xer 0x%08lx ctr 0x%08lx\n", 213 frame->lr, frame->cr, frame->xer, frame->ctr); 214 kprintf("fpscr 0x%08lx\n", frame->fpscr); 215 kprintf(" srr0 0x%08lx srr1 0x%08lx dar 0x%08lx dsisr 0x%08lx\n", 216 frame->srr0, frame->srr1, frame->dar, frame->dsisr); 217 kprintf(" vector: 0x%lx\n", frame->vector); 218 219 print_stack_frame(thread, frame->srr0, framePointer, frame->r1); 220 framePointer = frame->r1; 221 } else { 222 addr_t ip, nextFramePointer; 223 224 if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { 225 kprintf("%08lx -- read fault\n", framePointer); 226 break; 227 } 228 229 if (ip == 0 || framePointer == 0) 230 break; 231 232 print_stack_frame(thread, ip, framePointer, nextFramePointer); 233 framePointer = nextFramePointer; 234 } 235 236 if (already_visited(previousLocations, &last, &num, framePointer)) { 237 kprintf("circular stack frame: %p!\n", (void *)framePointer); 238 break; 239 } 240 if (framePointer == 0) 241 break; 242 } 243 244 /* if (oldPageDirectory != 0) { 245 // switch back to the previous page directory to no cause any troubles 246 write_cr3(oldPageDirectory); 247 } 248 */ 249 250 return 0; 251 } 252 253 254 255 // #pragma mark - 256 257 258 void 259 arch_debug_save_registers(struct arch_debug_registers* registers) 260 { 261 } 262 263 264 void 265 arch_debug_stack_trace(void) 266 { 267 stack_trace(0, NULL); 268 } 269 270 271 bool 272 arch_debug_contains_call(struct thread *thread, const char *symbol, 273 addr_t start, addr_t end) 274 { 275 return false; 276 } 277 278 279 void * 280 arch_debug_get_caller(void) 281 { 282 // TODO: implement me 283 return (void *)&arch_debug_get_caller; 284 } 285 286 287 int32 288 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 289 int32 skipIframes, int32 skipFrames, uint32 flags) 290 { 291 // TODO: Implement! 292 return 0; 293 } 294 295 296 void* 297 arch_debug_get_interrupt_pc(bool* _isSyscall) 298 { 299 // TODO: Implement! 300 return NULL; 301 } 302 303 304 void 305 arch_debug_unset_current_thread(void) 306 { 307 // TODO: Implement! 308 } 309 310 311 void 312 arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, 313 void (*function)(void*), void* parameter) 314 { 315 // TODO: Implement! Most likely in assembly. 316 longjmp(jumpBuffer, 1); 317 } 318 319 320 bool 321 arch_is_debug_variable_defined(const char* variableName) 322 { 323 // TODO: Implement! 324 return false; 325 } 326 327 328 status_t 329 arch_set_debug_variable(const char* variableName, uint64 value) 330 { 331 // TODO: Implement! 332 return B_ENTRY_NOT_FOUND; 333 } 334 335 336 status_t 337 arch_get_debug_variable(const char* variableName, uint64* value) 338 { 339 // TODO: Implement! 340 return B_ENTRY_NOT_FOUND; 341 } 342 343 344 status_t 345 arch_debug_init(kernel_args *args) 346 { 347 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 348 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 349 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 350 351 return B_NO_ERROR; 352 } 353 354