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 22struct stack_frame { 23 struct stack_frame *previous; 24 addr_t return_address; 25}; 26 27#define NUM_PREVIOUS_LOCATIONS 32 28 29extern struct iframe_stack gBootFrameStack; 30 31 32/* 33static bool 34already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer) 35{ 36 int32 last = *_last; 37 int32 num = *_num; 38 int32 i; 39 40 for (i = 0; i < num; i++) { 41 if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) 42 % NUM_PREVIOUS_LOCATIONS] == framePointer) { 43 return true; 44 } 45 } 46 47 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; 48 visited[last] = framePointer; 49 50 if (num < NUM_PREVIOUS_LOCATIONS) 51 *_num = num + 1; 52 53 return false; 54} 55 56 57static inline stack_frame * 58get_current_stack_frame() 59{ 60 stack_frame *frame; 61 asm volatile("move.l %%fp,%0" : "=r"(frame)); 62 return frame; 63} 64 65 66static status_t 67get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) 68{ 69 Thread *thread = thread_get_current_thread(); 70 addr_t oldFaultHandler = thread->fault_handler; 71 72 // set fault handler, so that we can safely access user stacks 73 if (thread) { 74 if (m68k_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) 75 goto error; 76 } 77 78 *ip = ((struct stack_frame *)framePointer)->return_address; 79 *next = (addr_t)((struct stack_frame *)framePointer)->previous; 80 81 if (thread) 82 thread->fault_handler = oldFaultHandler; 83 return B_OK; 84 85error: 86 thread->fault_handler = oldFaultHandler; 87 return B_BAD_ADDRESS; 88} 89 90 91static void 92print_stack_frame(Thread *thread, addr_t ip, addr_t framePointer, 93 addr_t nextFramePointer) 94{ 95 addr_t diff = nextFramePointer - framePointer; 96 97 // kernel space/user space switch 98 if (diff & 0x80000000) 99 diff = 0; 100 101 // lookup symbol 102 const char *symbol, *image; 103 addr_t baseAddress; 104 bool exactMatch; 105 status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol, 106 &image, &exactMatch); 107 if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) { 108 // try to locate the image in the images loaded into user space 109 status = image_debug_lookup_user_symbol_address(thread->team, ip, 110 &baseAddress, &symbol, &image, &exactMatch); 111 } 112 if (status == B_OK) { 113 if (symbol != NULL) { 114 kprintf("%08lx (+%4ld) %08lx <%s>:%s + 0x%04lx%s\n", framePointer, 115 diff, ip, image, symbol, ip - baseAddress, 116 (exactMatch ? "" : " (nearest)")); 117 } else { 118 kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n", 119 framePointer, diff, ip, image, (void *)baseAddress, 120 ip - baseAddress); 121 } 122 } else 123 kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip); 124} 125 126 127static int 128stack_trace(int argc, char **argv) 129{ 130 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; 131 struct iframe_stack *frameStack; 132 Thread *thread; 133 addr_t framePointer; 134 int32 i, num = 0, last = 0; 135 136 if (argc < 2) { 137 thread = thread_get_current_thread(); 138 framePointer = (addr_t)get_current_stack_frame(); 139 } else { 140kprintf("Stack traces of other threads not supported yet!\n"); 141return 0; 142 } 143 144 // We don't have a thread pointer early in the boot process 145 if (thread != NULL) 146 frameStack = &thread->arch_info.iframes; 147 else 148 frameStack = &gBootFrameStack; 149 150 for (i = 0; i < frameStack->index; i++) { 151 kprintf("iframe %p (end = %p)\n", 152 frameStack->frames[i], frameStack->frames[i] + 1); 153 } 154 155 if (thread != NULL) { 156 kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, 157 thread->name); 158 159 kprintf(" kernel stack: %p to %p\n", 160 (void *)thread->kernel_stack_base, 161 (void *)(thread->kernel_stack_top)); 162 if (thread->user_stack_base != 0) { 163 kprintf(" user stack: %p to %p\n", 164 (void *)thread->user_stack_base, 165 (void *)(thread->user_stack_base + thread->user_stack_size)); 166 } 167 } 168 169 kprintf("frame caller <image>:function + offset\n"); 170 171 for (;;) { 172 // see if the frame pointer matches the iframe 173 struct iframe *frame = NULL; 174 for (i = 0; i < frameStack->index; i++) { 175 if (framePointer == (addr_t)frameStack->frames[i]) { 176 // it's an iframe 177 frame = frameStack->frames[i]; 178 break; 179 } 180 } 181 182 if (frame) { 183 kprintf("iframe at %p\n", frame); 184 kprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", 185 frame->d[0], frame->d[1], frame->d[2], frame->d[3]); 186 kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", 187 frame->d[4], frame->d[5], frame->d[6], frame->d[7]); 188 kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", 189 frame->a[0], frame->a[1], frame->a[2], frame->a[3]); 190 kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx a7 0x%08lx (sp)\n", 191#warning M68K: a7 in iframe ?? 192 frame->a[4], frame->a[5], frame->a[6], -1L); 193 kprintf(" pc 0x%08lx sr 0x%04x\n", 194 frame->cpu.pc, frame->cpu.sr); 195#warning M68K: missing regs 196 197 print_stack_frame(thread, frame->cpu.pc, framePointer, frame->a[6]); 198 framePointer = frame->a[6]; 199 } else { 200 addr_t ip, nextFramePointer; 201 202 if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { 203 kprintf("%08lx -- read fault\n", framePointer); 204 break; 205 } 206 207 if (ip == 0 || framePointer == 0) 208 break; 209 210 print_stack_frame(thread, ip, framePointer, nextFramePointer); 211 framePointer = nextFramePointer; 212 } 213 214 if (already_visited(previousLocations, &last, &num, framePointer)) { 215 kprintf("circular stack frame: %p!\n", (void *)framePointer); 216 break; 217 } 218 if (framePointer == 0) 219 break; 220 } 221 222 223 return 0; 224} 225 226*/ 227 228// #pragma mark - 229 230 231void 232arch_debug_save_registers(struct arch_debug_registers* registers) 233{ 234} 235 236 237bool 238arch_debug_contains_call(Thread *thread, const char *symbol, 239 addr_t start, addr_t end) 240{ 241 return false; 242} 243 244 245void 246arch_debug_stack_trace(void) 247{ 248} 249 250 251void * 252arch_debug_get_caller(void) 253{ 254 /* Return the thread id as the kernel (for example the lock code) actually 255 gets a somewhat valid indication of the caller back. */ 256 return (void*) thread_get_current_thread_id(); 257} 258 259 260int32 261arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 262 int32 skipIframes, int32 skipFrames, uint32 flags) 263{ 264#warning ARM:IMPLEMENT 265 266 return 0; 267} 268 269 270void* 271arch_debug_get_interrupt_pc(bool* _isSyscall) 272{ 273 // TODO: Implement! 274 return NULL; 275} 276 277 278bool 279arch_is_debug_variable_defined(const char* variableName) 280{ 281 // TODO: Implement! 282 return false; 283} 284 285 286status_t 287arch_set_debug_variable(const char* variableName, uint64 value) 288{ 289 // TODO: Implement! 290 return B_ENTRY_NOT_FOUND; 291} 292 293 294status_t 295arch_get_debug_variable(const char* variableName, uint64* value) 296{ 297 // TODO: Implement! 298 return B_ENTRY_NOT_FOUND; 299} 300 301 302status_t 303arch_debug_init(kernel_args *args) 304{ 305// add_debugger_command("where", &stack_trace, "Same as \"sc\""); 306// add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 307// add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 308#warning ARM:IMPLEMENT 309 310 return B_NO_ERROR; 311} 312 313 314/* arch_debug_call_with_fault_handler is in arch_asm.S */ 315 316void 317arch_debug_unset_current_thread(void) 318{ 319 // TODO: Implement! 320} 321 322 323ssize_t 324arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) 325{ 326 // TODO: Implement! 327 return B_NOT_SUPPORTED; 328} 329