diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 47f346fb9a..6eb5b937aa 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -242,6 +242,8 @@ switch $(HAIKU_CPU) { case arm : { HAIKU_DEFINES += __ARM__ ; + HAIKU_CCFLAGS += -mapcs-frame ; # For stackcrawls + HAIKU_C++FLAGS += -mapcs-frame ; HAIKU_BOOT_PLATFORM ?= u-boot ; HAIKU_BOOT_BOARD ?= verdex ; HAIKU_BOOT_FLOPPY_IMAGE_SIZE = 1440 ; diff --git a/headers/private/kernel/arch/arm/arch_cpu.h b/headers/private/kernel/arch/arm/arch_cpu.h index a70398aa64..fea6c68979 100644 --- a/headers/private/kernel/arch/arm/arch_cpu.h +++ b/headers/private/kernel/arch/arm/arch_cpu.h @@ -63,6 +63,7 @@ extern "C" { extern addr_t arm_get_far(void); extern int32 arm_get_fsr(void); +extern addr_t arm_get_fp(void); extern int mmu_read_c1(void); extern int mmu_write_c1(int val); diff --git a/src/system/kernel/arch/arm/arch_asm.S b/src/system/kernel/arch/arm/arch_asm.S index 689f615646..50e9508274 100644 --- a/src/system/kernel/arch/arm/arch_asm.S +++ b/src/system/kernel/arch/arm/arch_asm.S @@ -94,6 +94,12 @@ FUNCTION(arm_get_far): bx lr FUNCTION_END(arm_get_far) +/* addr_t arm_get_fp(void); */ +FUNCTION(arm_get_fp): + mov r0, fp @ get framepointer + bx lr +FUNCTION_END(arm_get_fp); + /* status_t arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *faultHandler) */ FUNCTION(arch_cpu_user_memcpy): stmfd sp!, { r4-r6 } diff --git a/src/system/kernel/arch/arm/arch_debug.cpp b/src/system/kernel/arch/arm/arch_debug.cpp index daae859148..1832ca2962 100644 --- a/src/system/kernel/arch/arm/arch_debug.cpp +++ b/src/system/kernel/arch/arm/arch_debug.cpp @@ -6,6 +6,8 @@ * Axel Dörfler * Ingo Weinhold * François Revol + * Ithamar R. Adema + * */ @@ -13,25 +15,22 @@ #include #include +#include #include #include #include #include - - -struct stack_frame { - struct stack_frame *previous; - addr_t return_address; -}; +#include +#include +#include #define NUM_PREVIOUS_LOCATIONS 32 extern struct iframe_stack gBootFrameStack; -/* static bool -already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer) +already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 fp) { int32 last = *_last; int32 num = *_num; @@ -39,13 +38,13 @@ already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer) for (i = 0; i < num; i++) { if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) - % NUM_PREVIOUS_LOCATIONS] == framePointer) { + % NUM_PREVIOUS_LOCATIONS] == fp) { return true; } } *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; - visited[last] = framePointer; + visited[last] = fp; if (num < NUM_PREVIOUS_LOCATIONS) *_num = num + 1; @@ -54,99 +53,327 @@ already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer) } -static inline stack_frame * -get_current_stack_frame() +static status_t +get_next_frame(addr_t fp, addr_t *next, addr_t *ip) { - stack_frame *frame; - asm volatile("move.l %%fp,%0" : "=r"(frame)); - return frame; + if (fp != 0) { + addr_t _fp = *(((addr_t*)fp) -3); + addr_t _sp = *(((addr_t*)fp) -2); + addr_t _lr = *(((addr_t*)fp) -1); + addr_t _pc = *(((addr_t*)fp) -0); + + *ip = (_fp != 0) ? _lr : _pc; + *next = _fp; + + return B_OK; + } + + return B_BAD_VALUE; } static status_t -get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) +lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress, + const char** _symbolName, const char** _imageName, bool* _exactMatch) { - Thread *thread = thread_get_current_thread(); - addr_t oldFaultHandler = thread->fault_handler; + status_t status = B_ENTRY_NOT_FOUND; - // set fault handler, so that we can safely access user stacks - if (thread) { - if (m68k_set_fault_handler(&thread->fault_handler, (addr_t)&&error)) - goto error; + if (IS_KERNEL_ADDRESS(address)) { + // a kernel symbol + status = elf_debug_lookup_symbol_address(address, _baseAddress, + _symbolName, _imageName, _exactMatch); + } else if (thread != NULL && thread->team != NULL) { + // try a lookup using the userland runtime loader structures + status = elf_debug_lookup_user_symbol_address(thread->team, address, + _baseAddress, _symbolName, _imageName, _exactMatch); + + if (status != B_OK) { + // try to locate the image in the images loaded into user space + status = image_debug_lookup_user_symbol_address(thread->team, + address, _baseAddress, _symbolName, _imageName, _exactMatch); + } } - *ip = ((struct stack_frame *)framePointer)->return_address; - *next = (addr_t)((struct stack_frame *)framePointer)->previous; - - if (thread) - thread->fault_handler = oldFaultHandler; - return B_OK; - -error: - thread->fault_handler = oldFaultHandler; - return B_BAD_ADDRESS; + return status; } static void -print_stack_frame(Thread *thread, addr_t ip, addr_t framePointer, - addr_t nextFramePointer) +set_debug_argument_variable(int32 index, uint64 value) { - addr_t diff = nextFramePointer - framePointer; - - // kernel space/user space switch - if (diff & 0x80000000) - diff = 0; - - // lookup symbol - const char *symbol, *image; - addr_t baseAddress; - bool exactMatch; - status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol, - &image, &exactMatch); - if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) { - // try to locate the image in the images loaded into user space - status = image_debug_lookup_user_symbol_address(thread->team, ip, - &baseAddress, &symbol, &image, &exactMatch); - } - if (status == B_OK) { - if (symbol != NULL) { - kprintf("%08lx (+%4ld) %08lx <%s>:%s + 0x%04lx%s\n", framePointer, - diff, ip, image, symbol, ip - baseAddress, - (exactMatch ? "" : " (nearest)")); - } else { - kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n", - framePointer, diff, ip, image, (void *)baseAddress, - ip - baseAddress); - } - } else - kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip); + char name[8]; + snprintf(name, sizeof(name), "_arg%ld", index); + set_debug_variable(name, value); } +template +static Type +read_function_argument_value(void* argument, bool& _valueKnown) +{ + Type value; + if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) { + _valueKnown = true; + return value; + } + + _valueKnown = false; + return 0; +} + + +static status_t +print_demangled_call(const char* image, const char* symbol, addr_t args, + bool noObjectMethod, bool addDebugVariables) +{ + static const size_t kBufferSize = 256; + char* buffer = (char*)debug_malloc(kBufferSize); + if (buffer == NULL) + return B_NO_MEMORY; + + bool isObjectMethod; + const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize, + &isObjectMethod); + if (name == NULL) { + debug_free(buffer); + return B_ERROR; + } + + uint32* arg = (uint32*)args; + + if (noObjectMethod) + isObjectMethod = false; + if (isObjectMethod) { + const char* lastName = strrchr(name, ':') - 1; + int namespaceLength = lastName - name; + + uint32 argValue = 0; + if (debug_memcpy(B_CURRENT_TEAM, &argValue, arg, 4) == B_OK) { + kprintf("<%s> %.*s<\33[32m%#" B_PRIx32 "\33[0m>%s", image, + namespaceLength, name, argValue, lastName); + } else + kprintf("<%s> %.*s%s", image, namespaceLength, name, lastName); + + if (addDebugVariables) + set_debug_variable("_this", argValue); + arg++; + } else + kprintf("<%s> %s", image, name); + + kprintf("("); + + size_t length; + int32 type, i = 0; + uint32 cookie = 0; + while (debug_get_next_demangled_argument(&cookie, symbol, buffer, + kBufferSize, &type, &length) == B_OK) { + if (i++ > 0) + kprintf(", "); + + // retrieve value and type identifier + + uint64 value; + bool valueKnown = false; + + switch (type) { + case B_INT64_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) + kprintf("int64: \33[34m%Ld\33[0m", value); + break; + case B_INT32_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) + kprintf("int32: \33[34m%ld\33[0m", (int32)value); + break; + case B_INT16_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) + kprintf("int16: \33[34m%d\33[0m", (int16)value); + break; + case B_INT8_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) + kprintf("int8: \33[34m%d\33[0m", (int8)value); + break; + case B_UINT64_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) { + kprintf("uint64: \33[34m%#Lx\33[0m", value); + if (value < 0x100000) + kprintf(" (\33[34m%Lu\33[0m)", value); + } + break; + case B_UINT32_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) { + kprintf("uint32: \33[34m%#lx\33[0m", (uint32)value); + if (value < 0x100000) + kprintf(" (\33[34m%lu\33[0m)", (uint32)value); + } + break; + case B_UINT16_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) { + kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)", + (uint16)value, (uint16)value); + } + break; + case B_UINT8_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) { + kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)", + (uint8)value, (uint8)value); + } + break; + case B_BOOL_TYPE: + value = read_function_argument_value(arg, valueKnown); + if (valueKnown) + kprintf("\33[34m%s\33[0m", value ? "true" : "false"); + break; + default: + if (buffer[0]) + kprintf("%s: ", buffer); + + if (length == 4) { + value = read_function_argument_value(arg, + valueKnown); + if (valueKnown) { + if (value == 0 + && (type == B_POINTER_TYPE || type == B_REF_TYPE)) + kprintf("NULL"); + else + kprintf("\33[34m%#lx\33[0m", (uint32)value); + } + break; + } + + + if (length == 8) { + value = read_function_argument_value(arg, + valueKnown); + } else + value = (uint64)arg; + + if (valueKnown) + kprintf("\33[34m%#Lx\33[0m", value); + break; + } + + if (!valueKnown) + kprintf("???"); + + if (valueKnown && type == B_STRING_TYPE) { + if (value == 0) + kprintf(" \33[31m\"\"\33[0m"); + else if (debug_strlcpy(B_CURRENT_TEAM, buffer, (char*)(addr_t)value, + kBufferSize) < B_OK) { + kprintf(" \33[31m\"\"\33[0m"); + } else + kprintf(" \33[36m\"%s\"\33[0m", buffer); + } + + if (addDebugVariables) + set_debug_argument_variable(i, value); + arg = (uint32*)((uint8*)arg + length); + } + + debug_free(buffer); + + kprintf(")"); + return B_OK; +} + + + +static void +print_stack_frame(Thread *thread, addr_t ip, addr_t fp, addr_t next, + int32 callIndex, bool demangle) +{ + const char* symbol; + const char* image; + addr_t baseAddress; + bool exactMatch; + status_t status; + addr_t diff; + + diff = next - fp; + + // MSB set = kernel space/user space switch + if (diff & ~((addr_t)-1 >> 1)) + diff = 0; + + status = lookup_symbol(thread, ip, &baseAddress, &symbol, &image, + &exactMatch); + + kprintf("%2" B_PRId32 " %0*lx (+%4ld) %0*lx ", callIndex, + B_PRINTF_POINTER_WIDTH, fp, diff, B_PRINTF_POINTER_WIDTH, ip); + + if (status == B_OK) { + if (exactMatch && demangle) { + status = print_demangled_call(image, symbol, + next, false, false); + } + + if (!exactMatch || !demangle || status != B_OK) { + if (symbol != NULL) { + kprintf("<%s> %s%s", image, symbol, + exactMatch ? "" : " (nearest)"); + } else + kprintf("<%s@%p> ", image, (void*)baseAddress); + } + + kprintf(" + %#04lx\n", ip - baseAddress); + } else { + VMArea *area = NULL; + if (thread != NULL && thread->team != NULL + && thread->team->address_space != NULL) { + area = thread->team->address_space->LookupArea(ip); + } + if (area != NULL) { + kprintf("%" B_PRId32 ":%s@%p + %#lx\n", area->id, area->name, + (void*)area->Base(), ip - area->Base()); + } else + kprintf("\n"); + } +} + static int stack_trace(int argc, char **argv) { - uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; - struct iframe_stack *frameStack; - Thread *thread; - addr_t framePointer; - int32 i, num = 0, last = 0; - - if (argc < 2) { - thread = thread_get_current_thread(); - framePointer = (addr_t)get_current_stack_frame(); - } else { -kprintf("Stack traces of other threads not supported yet!\n"); -return 0; + static const char* usage = "usage: %s [-d] [ ]\n" + "Prints a stack trace for the current, respectively the specified\n" + "thread.\n" + " -d - Disables the demangling of the symbols.\n" + " - The ID of the thread for which to print the stack\n" + " trace.\n"; + bool demangle = true; + int32 threadIndex = 1; + if (argc > 1 && !strcmp(argv[1], "-d")) { + demangle = false; + threadIndex++; } + if (argc > threadIndex + 1 + || (argc == 2 && strcmp(argv[1], "--help") == 0)) { + kprintf(usage, argv[0]); + return 0; + } + + addr_t previousLocations[NUM_PREVIOUS_LOCATIONS]; + Thread* thread = NULL; + phys_addr_t oldPageDirectory = 0; + addr_t fp = arm_get_fp(); + int32 num = 0, last = 0; + struct iframe_stack *frameStack; + // We don't have a thread pointer early in the boot process if (thread != NULL) frameStack = &thread->arch_info.iframes; else frameStack = &gBootFrameStack; + int32 i; for (i = 0; i < frameStack->index; i++) { kprintf("iframe %p (end = %p)\n", frameStack->frames[i], frameStack->frames[i] + 1); @@ -168,11 +395,11 @@ return 0; kprintf("frame caller :function + offset\n"); - for (;;) { + for (int32 callIndex = 0;; callIndex++) { // see if the frame pointer matches the iframe struct iframe *frame = NULL; for (i = 0; i < frameStack->index; i++) { - if (framePointer == (addr_t)frameStack->frames[i]) { + if (fp == (addr_t)frameStack->frames[i]) { // it's an iframe frame = frameStack->frames[i]; break; @@ -181,49 +408,43 @@ return 0; if (frame) { kprintf("iframe at %p\n", frame); - kprintf(" d0 0x%08lx d1 0x%08lx d2 0x%08lx d3 0x%08lx\n", - frame->d[0], frame->d[1], frame->d[2], frame->d[3]); - kprintf(" d4 0x%08lx d5 0x%08lx d6 0x%08lx d7 0x%08lx\n", - frame->d[4], frame->d[5], frame->d[6], frame->d[7]); - kprintf(" a0 0x%08lx a1 0x%08lx a2 0x%08lx a3 0x%08lx\n", - frame->a[0], frame->a[1], frame->a[2], frame->a[3]); - kprintf(" a4 0x%08lx a5 0x%08lx a6 0x%08lx a7 0x%08lx (sp)\n", -#warning M68K: a7 in iframe ?? - frame->a[4], frame->a[5], frame->a[6], -1L); - kprintf(" pc 0x%08lx sr 0x%04x\n", - frame->cpu.pc, frame->cpu.sr); -#warning M68K: missing regs + kprintf(" r0 0x%08lx r1 0x%08lx r2 0x%08lx r3 0x%08lx\n", + frame->r0, frame->r1, frame->r2, frame->r3); + kprintf(" r4 0x%08lx r5 0x%08lx r6 0x%08lx r7 0x%08lx\n", + frame->r4, frame->r5, frame->r6, frame->r7); + kprintf(" r8 0x%08lx r9 0x%08lx r10 0x%08lx r11 0x%08lx\n", + frame->r8, frame->r9, frame->r10, frame->r11); + kprintf(" r12 0x%08lx sp 0x%08lx lr 0x%08lx pc 0x%08lx\n", + frame->r12, frame->svc_sp, frame->svc_lr, frame->pc); - print_stack_frame(thread, frame->cpu.pc, framePointer, frame->a[6]); - framePointer = frame->a[6]; + fp = frame->svc_sp; + print_stack_frame(thread, frame->pc, frame->svc_sp, frame->svc_lr, callIndex, demangle); } else { - addr_t ip, nextFramePointer; + addr_t ip, next; - if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { - kprintf("%08lx -- read fault\n", framePointer); + if (get_next_frame(fp, &next, &ip) != B_OK) { + kprintf("%08lx -- read fault\n", fp); break; } - if (ip == 0 || framePointer == 0) + if (ip == 0 || fp == 0) break; - print_stack_frame(thread, ip, framePointer, nextFramePointer); - framePointer = nextFramePointer; + print_stack_frame(thread, ip, fp, next, callIndex, demangle); + fp = next; } - if (already_visited(previousLocations, &last, &num, framePointer)) { - kprintf("circular stack frame: %p!\n", (void *)framePointer); + if (already_visited(previousLocations, &last, &num, fp)) { + kprintf("circular stack frame: %p!\n", (void *)fp); break; } - if (framePointer == 0) + if (fp == 0) break; } - return 0; } -*/ // #pragma mark - @@ -245,6 +466,7 @@ arch_debug_contains_call(Thread *thread, const char *symbol, void arch_debug_stack_trace(void) { + stack_trace(0, NULL); } @@ -261,8 +483,7 @@ int32 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, int32 skipIframes, int32 skipFrames, uint32 flags) { -#warning ARM:IMPLEMENT - + // TODO: Implement! return 0; } @@ -302,10 +523,9 @@ arch_get_debug_variable(const char* variableName, uint64* value) status_t arch_debug_init(kernel_args *args) { -// add_debugger_command("where", &stack_trace, "Same as \"sc\""); -// add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); -// add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); -#warning ARM:IMPLEMENT + add_debugger_command("where", &stack_trace, "Same as \"sc\""); + add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); + add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); return B_NO_ERROR; } diff --git a/src/system/kernel/arch/arm/arch_int.cpp b/src/system/kernel/arch/arm/arch_int.cpp index b41cc7154d..0dc4fdcd9f 100644 --- a/src/system/kernel/arch/arm/arch_int.cpp +++ b/src/system/kernel/arch/arm/arch_int.cpp @@ -188,9 +188,35 @@ arch_int_init_post_device_manager(struct kernel_args *args) } +// Little helper class for handling the +// iframe stack as used by KDL. +class IFrameScope { +public: + IFrameScope(struct iframe *iframe) { + fThread = thread_get_current_thread(); + if (fThread) + arm_push_iframe(&fThread->arch_info.iframes, iframe); + else + arm_push_iframe(&gBootFrameStack, iframe); + } + + virtual ~IFrameScope() { + // pop iframe + if (fThread) + arm_pop_iframe(&fThread->arch_info.iframes); + else + arm_pop_iframe(&gBootFrameStack); + } +private: + Thread* fThread; +}; + + extern "C" void arch_arm_undefined(struct iframe *iframe) { + IFrameScope scope(iframe); // push/pop iframe + print_iframe("Undefined Instruction", iframe); panic("not handled!"); } @@ -199,6 +225,8 @@ arch_arm_undefined(struct iframe *iframe) extern "C" void arch_arm_syscall(struct iframe *iframe) { + IFrameScope scope(iframe); // push/pop iframe + print_iframe("Software interrupt", iframe); } @@ -206,6 +234,8 @@ arch_arm_syscall(struct iframe *iframe) extern "C" void arch_arm_data_abort(struct iframe *frame) { + IFrameScope scope(iframe); + Thread *thread = thread_get_current_thread(); bool isUser = (frame->spsr & 0x1f) == 0x10; addr_t far = arm_get_far(); @@ -290,6 +320,8 @@ arch_arm_data_abort(struct iframe *frame) extern "C" void arch_arm_prefetch_abort(struct iframe *iframe) { + IFrameScope scope(iframe); + print_iframe("Prefetch Abort", iframe); panic("not handled!"); } @@ -298,6 +330,8 @@ arch_arm_prefetch_abort(struct iframe *iframe) extern "C" void arch_arm_irq(struct iframe *iframe) { + IFrameScope scope(iframe); + for (int i=0; i < 32; i++) { if (sPxaInterruptBase[PXA_ICIP] & (1 << i)) int_io_interrupt_handler(i, true); @@ -308,6 +342,8 @@ arch_arm_irq(struct iframe *iframe) extern "C" void arch_arm_fiq(struct iframe *iframe) { + IFrameScope scope(iframe); + for (int i=0; i < 32; i++) { if (sPxaInterruptBase[PXA_ICIP] & (1 << i)) { dprintf("arch_arm_fiq: help me, FIQ %d was triggered but no " diff --git a/src/system/kernel/arch/arm/arch_thread.cpp b/src/system/kernel/arch/arm/arch_thread.cpp index 3f7950e380..2de87612e8 100644 --- a/src/system/kernel/arch/arm/arch_thread.cpp +++ b/src/system/kernel/arch/arm/arch_thread.cpp @@ -42,6 +42,23 @@ static struct arch_thread sInitialState; Thread *gCurrentThread; +void +arm_push_iframe(struct iframe_stack *stack, struct iframe *frame) +{ + ASSERT(stack->index < IFRAME_TRACE_DEPTH); + stack->frames[stack->index++] = frame; +} + + +void +arm_pop_iframe(struct iframe_stack *stack) +{ + ASSERT(stack->index > 0); + stack->index--; +} + + + status_t arch_thread_init(struct kernel_args *args) {