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 */ 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(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 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 int32 cpu = smp_get_current_cpu(); 128 framePointer = debug_get_debug_registers(cpu)->r1; 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] - 8) & ~0xf)) { 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(" r0 0x%08lx r1 0x%08lx r2 0x%08lx r3 0x%08lx\n", 198 frame->r0, frame->r1, frame->r2, frame->r3); 199 kprintf(" r4 0x%08lx r5 0x%08lx r6 0x%08lx r7 0x%08lx\n", 200 frame->r4, frame->r5, frame->r6, frame->r7); 201 kprintf(" r8 0x%08lx r9 0x%08lx r10 0x%08lx r11 0x%08lx\n", 202 frame->r8, frame->r9, frame->r10, frame->r11); 203 kprintf(" r12 0x%08lx r13 0x%08lx r14 0x%08lx r15 0x%08lx\n", 204 frame->r12, frame->r13, frame->r14, frame->r15); 205 kprintf(" r16 0x%08lx r17 0x%08lx r18 0x%08lx r19 0x%08lx\n", 206 frame->r16, frame->r17, frame->r18, frame->r19); 207 kprintf(" r20 0x%08lx r21 0x%08lx r22 0x%08lx r23 0x%08lx\n", 208 frame->r20, frame->r21, frame->r22, frame->r23); 209 kprintf(" r24 0x%08lx r25 0x%08lx r26 0x%08lx r27 0x%08lx\n", 210 frame->r24, frame->r25, frame->r26, frame->r27); 211 kprintf(" r28 0x%08lx r29 0x%08lx r30 0x%08lx r31 0x%08lx\n", 212 frame->r28, frame->r29, frame->r30, frame->r31); 213 kprintf(" lr 0x%08lx cr 0x%08lx xer 0x%08lx ctr 0x%08lx\n", 214 frame->lr, frame->cr, frame->xer, frame->ctr); 215 kprintf("fpscr 0x%08lx\n", frame->fpscr); 216 kprintf(" srr0 0x%08lx srr1 0x%08lx dar 0x%08lx dsisr 0x%08lx\n", 217 frame->srr0, frame->srr1, frame->dar, frame->dsisr); 218 kprintf(" vector: 0x%lx\n", frame->vector); 219 220 print_stack_frame(thread, frame->srr0, framePointer, frame->r1); 221 framePointer = frame->r1; 222 } else { 223 addr_t ip, nextFramePointer; 224 225 if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { 226 kprintf("%08lx -- read fault\n", framePointer); 227 break; 228 } 229 230 if (ip == 0 || framePointer == 0) 231 break; 232 233 print_stack_frame(thread, ip, framePointer, nextFramePointer); 234 framePointer = nextFramePointer; 235 } 236 237 if (already_visited(previousLocations, &last, &num, framePointer)) { 238 kprintf("circular stack frame: %p!\n", (void *)framePointer); 239 break; 240 } 241 if (framePointer == 0) 242 break; 243 } 244 245 /* if (oldPageDirectory != 0) { 246 // switch back to the previous page directory to no cause any troubles 247 write_cr3(oldPageDirectory); 248 } 249 */ 250 251 return 0; 252 } 253 254 255 256 // #pragma mark - 257 258 259 void 260 arch_debug_save_registers(struct arch_debug_registers* registers) 261 { 262 // get the caller's frame pointer 263 stack_frame* frame = (stack_frame*)get_current_stack_frame(); 264 registers->r1 = (addr_t)frame->previous; 265 } 266 267 268 void 269 arch_debug_stack_trace(void) 270 { 271 stack_trace(0, NULL); 272 } 273 274 275 bool 276 arch_debug_contains_call(Thread *thread, const char *symbol, 277 addr_t start, addr_t end) 278 { 279 return false; 280 } 281 282 283 int32 284 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 285 int32 skipIframes, int32 skipFrames, uint32 flags) 286 { 287 // TODO: Implement! 288 return 0; 289 } 290 291 292 void* 293 arch_debug_get_interrupt_pc(bool* _isSyscall) 294 { 295 // TODO: Implement! 296 return NULL; 297 } 298 299 300 void 301 arch_debug_unset_current_thread(void) 302 { 303 // TODO: Implement! 304 } 305 306 307 bool 308 arch_is_debug_variable_defined(const char* variableName) 309 { 310 // TODO: Implement! 311 return false; 312 } 313 314 315 status_t 316 arch_set_debug_variable(const char* variableName, uint64 value) 317 { 318 // TODO: Implement! 319 return B_ENTRY_NOT_FOUND; 320 } 321 322 323 status_t 324 arch_get_debug_variable(const char* variableName, uint64* value) 325 { 326 // TODO: Implement! 327 return B_ENTRY_NOT_FOUND; 328 } 329 330 331 ssize_t 332 arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) 333 { 334 // TODO: Implement! 335 return B_NOT_SUPPORTED; 336 } 337 338 339 status_t 340 arch_debug_init(kernel_args *args) 341 { 342 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 343 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 344 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 345 346 return B_NO_ERROR; 347 } 348 349