added 1 changeset to branch 'refs/remotes/xyzzy-github/x86_64' old head: e690e5ab3b4adc583b94a27400b7fd12da80ce51 new head: bcb07a319b647eb0af60398e972525cc0a686aa9 ---------------------------------------------------------------------------- bcb07a3: Implemented the rest of the kernel debugger functions for x86_64. Merged with the x86 implementations, mostly the same except for a few differences. GDB stub is currently broken, will investigate later. [ Alex Smith <alex@xxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: bcb07a319b647eb0af60398e972525cc0a686aa9 Author: Alex Smith <alex@xxxxxxxxxxxxxxxx> Date: Fri Jul 13 13:09:09 2012 UTC ---------------------------------------------------------------------------- 6 files changed, 335 insertions(+), 423 deletions(-) headers/private/kernel/arch/x86/64/iframe.h | 13 +- .../private/kernel/arch/x86/arch_thread_types.h | 26 +- src/system/kernel/arch/x86/64/stubs.cpp | 209 ------- src/system/kernel/arch/x86/Jamfile | 2 +- src/system/kernel/arch/x86/arch_debug.cpp | 496 +++++++++------- src/system/kernel/arch/x86/arch_thread.cpp | 12 +- ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/arch/x86/64/iframe.h b/headers/private/kernel/arch/x86/64/iframe.h index cd257ef..ff0dae7 100644 --- a/headers/private/kernel/arch/x86/64/iframe.h +++ b/headers/private/kernel/arch/x86/64/iframe.h @@ -29,9 +29,16 @@ struct iframe { uint64 cs; uint64 flags; - // Only present when the iframe is a userland iframe (IFRAME_IS_USER()). - uint64 user_sp; - uint64 user_ss; + // SP and SS are unconditionally present on x86_64, make both names + // available. + union { + uint64 sp; + uint64 user_sp; + }; + union { + uint64 ss; + uint64 user_ss; + }; } _PACKED; #define IFRAME_IS_USER(f) (((f)->cs & DPL_USER) == DPL_USER) diff --git a/headers/private/kernel/arch/x86/arch_thread_types.h b/headers/private/kernel/arch/x86/arch_thread_types.h index 209543e..85dfc6b 100644 --- a/headers/private/kernel/arch/x86/arch_thread_types.h +++ b/headers/private/kernel/arch/x86/arch_thread_types.h @@ -48,6 +48,8 @@ struct arch_thread { // 512 byte floating point save point - this must be 16 byte aligned uint8 fpu_state[512] _ALIGNED(16); + + addr_t GetFramePointer() const; } _ALIGNED(16); @@ -64,4 +66,26 @@ struct arch_fork_arg { }; -#endif /* _KERNEL_ARCH_x86_THREAD_TYPES_H */ +#ifdef __x86_64__ + + +inline addr_t +arch_thread::GetFramePointer() const +{ + return current_stack[1]; +} + + +#else + + +inline addr_t +arch_thread::GetFramePointer() const +{ + return current_stack.esp[2]; +} + + +#endif // __x86_64__ + +#endif // _KERNEL_ARCH_x86_THREAD_TYPES_H diff --git a/src/system/kernel/arch/x86/64/stubs.cpp b/src/system/kernel/arch/x86/64/stubs.cpp index 72b95c6..b8efb2f 100644 --- a/src/system/kernel/arch/x86/64/stubs.cpp +++ b/src/system/kernel/arch/x86/64/stubs.cpp @@ -52,215 +52,6 @@ arch_commpage_init_post_cpus(void) void -arch_debug_save_registers(struct arch_debug_registers* registers) -{ - -} - - -struct stack_frame { - struct stack_frame *previous; - addr_t return_address; -}; - - -static bool -is_iframe(addr_t frame) -{ - addr_t previousFrame = *(addr_t*)frame; - return ((previousFrame & ~(addr_t)IFRAME_TYPE_MASK) == 0 - && previousFrame != 0); -} - - -static void -print_iframe(struct iframe* frame) -{ - bool isUser = IFRAME_IS_USER(frame); - - kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame, - isUser ? (uint64*)(frame + 1) : &frame->user_sp); - - kprintf(" rax 0x%-16lx rbx 0x%-16lx rcx 0x%lx\n", frame->ax, - frame->bx, frame->cx); - kprintf(" rdx 0x%-16lx rsi 0x%-16lx rdi 0x%lx\n", frame->dx, - frame->si, frame->di); - kprintf(" rbp 0x%-16lx r8 0x%-16lx r9 0x%lx\n", frame->bp, - frame->r8, frame->r9); - kprintf(" r10 0x%-16lx r11 0x%-16lx r12 0x%lx\n", frame->r10, - frame->r11, frame->r12); - kprintf(" r13 0x%-16lx r14 0x%-16lx r15 0x%lx\n", frame->r13, - frame->r14, frame->r15); - kprintf(" rip 0x%-16lx rflags 0x%-16lx", frame->ip, frame->flags); - - if (isUser) { - // from user space - kprintf("user rsp 0x%lx", frame->user_sp); - } - kprintf("\n"); - kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector, - frame->error_code); -} - - -static status_t -lookup_symbol(addr_t address, addr_t* _baseAddress, const char** _symbolName, - const char** _imageName, bool* _exactMatch) -{ - status_t status = B_ENTRY_NOT_FOUND; - - if (IS_KERNEL_ADDRESS(address)) { - status = elf_debug_lookup_symbol_address(address, _baseAddress, - _symbolName, _imageName, _exactMatch); - } - - return status; -} - - -static void -print_stack_frame(addr_t rip, addr_t rbp, addr_t nextRbp, int32 callIndex) -{ - const char* symbol; - const char* image; - addr_t baseAddress; - bool exactMatch; - status_t status; - addr_t diff; - - diff = nextRbp - rbp; - - // kernel space/user space switch - if (diff & (1L << 63)) - diff = 0; - - status = lookup_symbol(rip, &baseAddress, &symbol, &image, &exactMatch); - - kprintf("%2d %016lx (+%4ld) %016lx ", callIndex, rbp, diff, rip); - - if (status == B_OK) { - if (symbol != NULL) - kprintf("<%s>:%s%s", image, symbol, exactMatch ? "" : " (nearest)"); - else - kprintf("<%s@%p>:unknown", image, (void*)baseAddress); - - kprintf(" + 0x%04lx\n", rip - baseAddress); - } else { - VMArea *area = VMAddressSpace::Kernel()->LookupArea(rip); - if (area != NULL) { - kprintf("%d:%s@%p + %#lx\n", area->id, area->name, - (void*)area->Base(), rip - area->Base()); - } else - kprintf("\n"); - } -} - - -void -arch_debug_stack_trace(void) -{ - addr_t rbp = x86_get_stack_frame(); - - kprintf("frame caller <image>:function" - " + offset\n"); - - for (int32 callIndex = 0;; callIndex++) { - if (rbp == 0) - break; - - if (is_iframe(rbp)) { - struct iframe* frame = (struct iframe*)rbp; - print_iframe(frame); - print_stack_frame(frame->ip, rbp, frame->bp, callIndex); - - rbp = frame->bp; - } else { - stack_frame* frame = (stack_frame*)rbp; - if (frame->return_address == 0) - break; - - print_stack_frame(frame->return_address, rbp, - (frame->previous != NULL) ? (addr_t)frame->previous : rbp, - callIndex); - - rbp = (addr_t)frame->previous; - } - } -} - - -bool -arch_debug_contains_call(Thread *thread, const char *symbol, - addr_t start, addr_t end) -{ - return false; -} - - -void * -arch_debug_get_caller(void) -{ - return NULL; -} - - -int32 -arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, - int32 skipIframes, int32 skipFrames, uint32 flags) -{ - return 0; -} - - -void* -arch_debug_get_interrupt_pc(bool* _isSyscall) -{ - return NULL; -} - - -void -arch_debug_unset_current_thread(void) -{ - -} - - -bool -arch_is_debug_variable_defined(const char* variableName) -{ - return false; -} - - -status_t -arch_set_debug_variable(const char* variableName, uint64 value) -{ - return B_OK; -} - - -status_t -arch_get_debug_variable(const char* variableName, uint64* value) -{ - return B_OK; -} - - -ssize_t -arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) -{ - return B_ERROR; -} - - -status_t -arch_debug_init(kernel_args *args) -{ - return B_OK; -} - -void arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, void (*function)(void*), void* parameter) { diff --git a/src/system/kernel/arch/x86/Jamfile b/src/system/kernel/arch/x86/Jamfile index 2d41509..9b1a888 100644 --- a/src/system/kernel/arch/x86/Jamfile +++ b/src/system/kernel/arch/x86/Jamfile @@ -51,7 +51,6 @@ if $(TARGET_ARCH) = x86_64 { vm86.cpp arch_commpage.cpp - arch_debug.cpp arch_user_debugger.cpp ioapic.cpp irq_routing_table.cpp @@ -78,6 +77,7 @@ if $(TARGET_ARCH) = x86_64 { local archGenericSources = arch_cpu.cpp + arch_debug.cpp arch_debug_console.cpp arch_elf.cpp arch_int.cpp diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index 9d21c7b..0f3faa8 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -1,6 +1,7 @@ /* * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@xxxxxxx * Copyright 2002-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * Copyright 2012, Alex Smith, alex@xxxxxxxxxxxxxxxxx * Distributed under the terms of the MIT License. * * Copyright 2001, Travis Geiselbrecht. All rights reserved. @@ -28,31 +29,29 @@ #include <vm/VMAddressSpace.h> #include <vm/VMArea.h> -#include <arch_cpu.h> - struct stack_frame { - struct stack_frame *previous; - addr_t return_address; + stack_frame* previous; + addr_t return_address; }; #define NUM_PREVIOUS_LOCATIONS 32 static bool -already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 ebp) +already_visited(addr_t* visited, int32* _last, int32* _num, addr_t bp) { int32 last = *_last; int32 num = *_num; int32 i; for (i = 0; i < num; i++) { - if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == ebp) + if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == bp) return true; } *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; - visited[last] = ebp; + visited[last] = bp; if (num < NUM_PREVIOUS_LOCATIONS) *_num = num + 1; @@ -64,14 +63,14 @@ already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 ebp) /*! Safe to be called only from outside the debugger. */ static status_t -get_next_frame_no_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) +get_next_frame_no_debugger(addr_t bp, addr_t* _next, addr_t* _ip) { // TODO: Do this more efficiently in assembly. stack_frame frame; - if (user_memcpy(&frame, (void*)ebp, sizeof(frame)) != B_OK) + if (user_memcpy(&frame, (void*)bp, sizeof(frame)) != B_OK) return B_BAD_ADDRESS; - *_eip = frame.return_address; + *_ip = frame.return_address; *_next = (addr_t)frame.previous; return B_OK; @@ -81,13 +80,13 @@ get_next_frame_no_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) /*! Safe to be called only from inside the debugger. */ static status_t -get_next_frame_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) +get_next_frame_debugger(addr_t bp, addr_t* _next, addr_t* _ip) { stack_frame frame; - if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)ebp, sizeof(frame)) != B_OK) + if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)bp, sizeof(frame)) != B_OK) return B_BAD_ADDRESS; - *_eip = frame.return_address; + *_ip = frame.return_address; *_next = (addr_t)frame.previous; return B_OK; @@ -95,8 +94,8 @@ get_next_frame_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) static status_t -lookup_symbol(Thread* thread, addr_t address, addr_t *_baseAddress, - const char **_symbolName, const char **_imageName, bool *_exactMatch) +lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress, + const char** _symbolName, const char** _imageName, bool* _exactMatch) { status_t status = B_ENTRY_NOT_FOUND; @@ -120,6 +119,9 @@ lookup_symbol(Thread* thread, addr_t address, addr_t *_baseAddress, } +#ifndef __x86_64__ + + static void set_debug_argument_variable(int32 index, uint64 value) { @@ -307,31 +309,53 @@ print_demangled_call(const char* image, const char* symbol, addr_t args, } +#else // __x86_64__ + + +static status_t +print_demangled_call(const char* image, const char* symbol, addr_t args, + bool noObjectMethod, bool addDebugVariables) +{ + // Since x86_64 uses registers rather than the stack for the first 6 + // arguments we cannot use the same method as x86 to read the function + // arguments. Maybe we need DWARF support in the kernel debugger. For now + // just print out the function signature without the argument values. + + // TODO x86_64. + return B_NOT_SUPPORTED; +} + + +#endif // __x86_64__ + + static void -print_stack_frame(Thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, +print_stack_frame(Thread* thread, addr_t ip, addr_t bp, addr_t nextBp, int32 callIndex, bool demangle) { - const char *symbol, *image; + const char* symbol; + const char* image; addr_t baseAddress; bool exactMatch; status_t status; addr_t diff; - diff = nextEbp - ebp; + diff = nextBp - bp; - // kernel space/user space switch - if (diff & 0x80000000) + // MSB set = kernel space/user space switch + if (diff & ~((addr_t)-1 >> 1)) diff = 0; - status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image, + status = lookup_symbol(thread, ip, &baseAddress, &symbol, &image, &exactMatch); - kprintf("%2ld %08lx (+%4ld) %08lx ", callIndex, ebp, diff, eip); + kprintf("%2" B_PRId32 " %0*lx (+%4ld) %0*lx ", callIndex, + B_PRINTF_POINTER_WIDTH, bp, diff, B_PRINTF_POINTER_WIDTH, ip); if (status == B_OK) { if (exactMatch && demangle) { - status = print_demangled_call(image, symbol, nextEbp + 8, false, - false); + status = print_demangled_call(image, symbol, + nextBp + sizeof(stack_frame), false, false); } if (!exactMatch || !demangle || status != B_OK) { @@ -339,19 +363,19 @@ print_stack_frame(Thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, kprintf("<%s>:%s%s", image, symbol, exactMatch ? "" : " (nearest)"); } else - kprintf("<%s@%p>:unknown", image, (void *)baseAddress); + kprintf("<%s@%p>:unknown", image, (void*)baseAddress); } - kprintf(" + 0x%04lx\n", eip - 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(eip); + area = thread->team->address_space->LookupArea(ip); } if (area != NULL) { - kprintf("%ld:%s@%p + %#lx\n", area->id, area->name, - (void*)area->Base(), eip - area->Base()); + kprintf("%" B_PRId32 ":%s@%p + %#lx\n", area->id, area->name, + (void*)area->Base(), ip - area->Base()); } else kprintf("\n"); } @@ -359,45 +383,65 @@ print_stack_frame(Thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, static void -print_iframe(struct iframe *frame) +print_iframe(iframe* frame) { bool isUser = IFRAME_IS_USER(frame); + +#ifdef __x86_64__ + kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame, + frame + 1); + + kprintf(" rax %#-18lx rbx %#-18lx rcx %#lx\n", frame->ax, + frame->bx, frame->cx); + kprintf(" rdx %#-18lx rsi %#-18lx rdi %#lx\n", frame->dx, + frame->si, frame->di); + kprintf(" rbp %#-18lx r8 %#-18lx r9 %#lx\n", frame->bp, + frame->r8, frame->r9); + kprintf(" r10 %#-18lx r11 %#-18lx r12 %#lx\n", frame->r10, + frame->r11, frame->r12); + kprintf(" r13 %#-18lx r14 %#-18lx r15 %#lx\n", frame->r13, + frame->r14, frame->r15); + kprintf(" rip %#-18lx rsp %#-18lx rflags %#lx\n", frame->ip, + frame->sp, frame->flags); +#else kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame, - isUser ? (uint32*)(frame + 1) : &frame->user_sp); + isUser ? (void*)(frame + 1) : (void*)&frame->user_sp); - kprintf(" eax 0x%-9lx ebx 0x%-9lx ecx 0x%-9lx edx 0x%lx\n", + kprintf(" eax %#-10lx ebx %#-10lx ecx %#-10lx edx %#lx\n", frame->ax, frame->bx, frame->cx, frame->dx); - kprintf(" esi 0x%-9lx edi 0x%-9lx ebp 0x%-9lx esp 0x%lx\n", + kprintf(" esi %#-10lx edi %#-10lx ebp %#-10lx esp %#lx\n", frame->si, frame->di, frame->bp, frame->sp); - kprintf(" eip 0x%-9lx eflags 0x%-9lx", frame->ip, frame->flags); + kprintf(" eip %#-10lx eflags %#-10lx", frame->ip, frame->flags); if (isUser) { // from user space - kprintf("user esp 0x%lx", frame->user_sp); + kprintf("user esp %#lx", frame->user_sp); } kprintf("\n"); - kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector, +#endif + + kprintf(" vector: %#lx, error code: %#lx\n", frame->vector, frame->error_code); } static bool -setup_for_thread(char *arg, Thread **_thread, uint32 *_ebp, - uint32 *_oldPageDirectory) +setup_for_thread(char* arg, Thread** _thread, addr_t* _bp, + phys_addr_t* _oldPageDirectory) { - Thread *thread = NULL; + Thread* thread = NULL; if (arg != NULL) { thread_id id = strtoul(arg, NULL, 0); thread = Thread::GetDebug(id); if (thread == NULL) { - kprintf("could not find thread %ld\n", id); + kprintf("could not find thread %" B_PRId32 "\n", id); return false; } if (id != thread_get_current_thread_id()) { // switch to the page directory of the new thread to be // able to follow the stack trace into userland - uint32 newPageDirectory = x86_next_page_directory( + phys_addr_t newPageDirectory = x86_next_page_directory( thread_get_current_thread(), thread); if (newPageDirectory != 0) { @@ -413,10 +457,10 @@ setup_for_thread(char *arg, Thread **_thread, uint32 *_ebp, thread->cpu->cpu_num); if (registers == NULL) return false; - *_ebp = registers->bp; + *_bp = registers->bp; } else { - // read %ebp from the thread's stack stored by a pushad - *_ebp = thread->arch_info.current_stack.esp[2]; + // Read frame pointer from the thread's stack. + *_bp = thread->arch_info.GetFramePointer(); } } else thread = NULL; @@ -474,13 +518,13 @@ is_iframe(Thread* thread, addr_t frame) } -static struct iframe * -find_previous_iframe(Thread *thread, addr_t frame) +static iframe* +find_previous_iframe(Thread* thread, addr_t frame) { // iterate backwards through the stack frames, until we hit an iframe while (is_kernel_stack_address(thread, frame)) { if (is_iframe(thread, frame)) - return (struct iframe*)frame; + return (iframe*)frame; frame = *(addr_t*)frame; } @@ -489,8 +533,8 @@ find_previous_iframe(Thread *thread, addr_t frame) } -static struct iframe* -get_previous_iframe(Thread* thread, struct iframe* frame) +static iframe* +get_previous_iframe(Thread* thread, iframe* frame) { if (frame == NULL) return NULL; @@ -499,90 +543,83 @@ get_previous_iframe(Thread* thread, struct iframe* frame) } -static struct iframe* +static iframe* get_current_iframe(Thread* thread) { if (thread == thread_get_current_thread()) return x86_get_current_iframe(); - addr_t ebp = thread->arch_info.current_stack.esp[2]; - // NOTE: This doesn't work, if the thread is running (on another CPU). - return find_previous_iframe(thread, ebp); + // NOTE: This doesn't work, if the thread is running (on another CPU). + return find_previous_iframe(thread, thread->arch_info.GetFramePointer()); } -uint32* +#define CHECK_DEBUG_VARIABLE(_name, _member, _settable) \ + if (strcmp(variableName, _name) == 0) { \ + settable = _settable; \ + return &_member; \ + } + + +static size_t* find_debug_variable(const char* variableName, bool& settable) { - struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); + iframe* frame = get_current_iframe(debug_get_debugged_thread()); if (frame == NULL) return NULL; - settable = false; - - if (strcmp(variableName, "gs") == 0) { - return &frame->gs; - } else if (strcmp(variableName, "fs") == 0) { - return &frame->fs; - } else if (strcmp(variableName, "es") == 0) { - return &frame->es; - } else if (strcmp(variableName, "ds") == 0) { - return &frame->ds; - } else if (strcmp(variableName, "cs") == 0) { - return &frame->cs; - } else if (strcmp(variableName, "edi") == 0) { - settable = true; - return &frame->di; - } else if (strcmp(variableName, "esi") == 0) { - settable = true; - return &frame->si; - } else if (strcmp(variableName, "ebp") == 0) { - settable = true; - return &frame->bp; - } else if (strcmp(variableName, "esp") == 0) { - settable = true; - return &frame->sp; - } else if (strcmp(variableName, "ebx") == 0) { - settable = true; - return &frame->bx; - } else if (strcmp(variableName, "edx") == 0) { - settable = true; - return &frame->dx; - } else if (strcmp(variableName, "ecx") == 0) { - settable = true; - return &frame->cx; - } else if (strcmp(variableName, "eax") == 0) { - settable = true; - return &frame->ax; - } else if (strcmp(variableName, "orig_eax") == 0) { - settable = true; - return &frame->orig_eax; - } else if (strcmp(variableName, "orig_edx") == 0) { - settable = true; - return &frame->orig_edx; - } else if (strcmp(variableName, "eip") == 0) { - settable = true; - return &frame->ip; - } else if (strcmp(variableName, "eflags") == 0) { - settable = true; - return &frame->flags; - } +#ifdef __x86_64__ + CHECK_DEBUG_VARIABLE("cs", frame->cs, false); + CHECK_DEBUG_VARIABLE("ss", frame->ss, false); + CHECK_DEBUG_VARIABLE("r15", frame->r15, true); + CHECK_DEBUG_VARIABLE("r14", frame->r14, true); + CHECK_DEBUG_VARIABLE("r13", frame->r13, true); + CHECK_DEBUG_VARIABLE("r12", frame->r12, true); + CHECK_DEBUG_VARIABLE("r11", frame->r11, true); + CHECK_DEBUG_VARIABLE("r10", frame->r10, true); + CHECK_DEBUG_VARIABLE("r9", frame->r9, true); + CHECK_DEBUG_VARIABLE("r8", frame->r8, true); + CHECK_DEBUG_VARIABLE("rbp", frame->bp, true); + CHECK_DEBUG_VARIABLE("rsi", frame->si, true); + CHECK_DEBUG_VARIABLE("rdi", frame->di, true); + CHECK_DEBUG_VARIABLE("rdx", frame->dx, true); + CHECK_DEBUG_VARIABLE("rcx", frame->cx, true); + CHECK_DEBUG_VARIABLE("rbx", frame->bx, true); + CHECK_DEBUG_VARIABLE("rax", frame->ax, true); + CHECK_DEBUG_VARIABLE("rip", frame->ip, true); + CHECK_DEBUG_VARIABLE("rflags", frame->flags, true); + CHECK_DEBUG_VARIABLE("rsp", frame->sp, true); +#else + CHECK_DEBUG_VARIABLE("gs", frame->gs, false); + CHECK_DEBUG_VARIABLE("fs", frame->fs, false); + CHECK_DEBUG_VARIABLE("es", frame->es, false); + CHECK_DEBUG_VARIABLE("ds", frame->ds, false); + CHECK_DEBUG_VARIABLE("cs", frame->cs, false); + CHECK_DEBUG_VARIABLE("edi", frame->di, true); + CHECK_DEBUG_VARIABLE("esi", frame->si, true); + CHECK_DEBUG_VARIABLE("ebp", frame->bp, true); + CHECK_DEBUG_VARIABLE("esp", frame->sp, true); + CHECK_DEBUG_VARIABLE("ebx", frame->bx, true); + CHECK_DEBUG_VARIABLE("edx", frame->dx, true); + CHECK_DEBUG_VARIABLE("ecx", frame->cx, true); + CHECK_DEBUG_VARIABLE("eax", frame->ax, true); + CHECK_DEBUG_VARIABLE("orig_eax", frame->orig_eax, true); + CHECK_DEBUG_VARIABLE("orig_edx", frame->orig_edx, true); + CHECK_DEBUG_VARIABLE("eip", frame->ip, true); + CHECK_DEBUG_VARIABLE("eflags", frame->flags, true); if (IFRAME_IS_USER(frame)) { - if (strcmp(variableName, "user_esp") == 0) { - settable = true; - return &frame->user_sp; - } else if (strcmp(variableName, "user_ss") == 0) { - return &frame->user_ss; - } + CHECK_DEBUG_VARIABLE("user_esp", frame->user_sp, true); + CHECK_DEBUG_VARIABLE("user_ss", frame->user_ss, false); } +#endif return NULL; } static int -stack_trace(int argc, char **argv) +stack_trace(int argc, char** argv) { static const char* usage = "usage: %s [-d] [ <thread id> ]\n" "Prints a stack trace for the current, respectively the specified\n" @@ -603,68 +640,69 @@ stack_trace(int argc, char **argv) return 0; } - uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; - Thread *thread = NULL; - uint32 oldPageDirectory = 0; - uint32 ebp = x86_get_stack_frame(); + addr_t previousLocations[NUM_PREVIOUS_LOCATIONS]; + Thread* thread = NULL; + phys_addr_t oldPageDirectory = 0; + addr_t bp = x86_get_stack_frame(); int32 num = 0, last = 0; if (!setup_for_thread(argc == threadIndex + 1 ? argv[threadIndex] : NULL, - &thread, &ebp, &oldPageDirectory)) + &thread, &bp, &oldPageDirectory)) return 0; DebuggedThreadSetter threadSetter(thread); if (thread != NULL) { - kprintf("stack trace for thread %ld \"%s\"\n", thread->id, + kprintf("stack trace for thread %" B_PRId32 " \"%s\"\n", thread->id, thread->name); kprintf(" kernel stack: %p to %p\n", - (void *)thread->kernel_stack_base, - (void *)(thread->kernel_stack_top)); + (void*)thread->kernel_stack_base, + (void*)(thread->kernel_stack_top)); if (thread->user_stack_base != 0) { kprintf(" user stack: %p to %p\n", - (void *)thread->user_stack_base, - (void *)(thread->user_stack_base + thread->user_stack_size)); + (void*)thread->user_stack_base, + (void*)(thread->user_stack_base + thread->user_stack_size)); } } - kprintf("frame caller <image>:function + offset\n"); + kprintf("%-*s %-*s <image>:function + offset\n", + B_PRINTF_POINTER_WIDTH, "frame", B_PRINTF_POINTER_WIDTH, "caller"); bool onKernelStack = true; for (int32 callIndex = 0;; callIndex++) { onKernelStack = onKernelStack - && is_kernel_stack_address(thread, ebp); + && is_kernel_stack_address(thread, bp); - if (onKernelStack && is_iframe(thread, ebp)) { - struct iframe *frame = (struct iframe *)ebp; + if (onKernelStack && is_iframe(thread, bp)) { + iframe* frame = (iframe*)bp; print_iframe(frame); - print_stack_frame(thread, frame->ip, ebp, frame->bp, callIndex, + print_stack_frame(thread, frame->ip, bp, frame->bp, callIndex, demangle); - ebp = frame->bp; + bp = frame->bp; } else { - addr_t eip, nextEbp; + addr_t ip, nextBp; - if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) { - kprintf("%08lx -- read fault\n", ebp); + if (get_next_frame_debugger(bp, &nextBp, &ip) != B_OK) { + kprintf("%0*lx -- read fault\n", B_PRINTF_POINTER_WIDTH, bp); break; } - if (eip == 0 || ebp == 0) + if (ip == 0 || bp == 0) break; - print_stack_frame(thread, eip, ebp, nextEbp, callIndex, demangle); - ebp = nextEbp; + print_stack_frame(thread, ip, bp, nextBp, callIndex, demangle); + bp = nextBp; } - if (already_visited(previousLocations, &last, &num, ebp)) { - kprintf("circular stack frame: %p!\n", (void *)ebp); + if (already_visited(previousLocations, &last, &num, bp)) { + kprintf("circular stack frame: %p!\n", (void*)bp); break; } - if (ebp == 0) + if (bp == 0) break; } @@ -677,6 +715,7 @@ stack_trace(int argc, char **argv) } +#ifndef __x86_64__ static void print_call(Thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, int32 argCount) @@ -759,7 +798,7 @@ show_call(int argc, char **argv) } Thread *thread = NULL; - uint32 oldPageDirectory = 0; + phys_addr_t oldPageDirectory = 0; addr_t ebp = x86_get_stack_frame(); int32 argCount = 0; @@ -835,10 +874,11 @@ show_call(int argc, char **argv) return 0; } +#endif static int -dump_iframes(int argc, char **argv) +dump_iframes(int argc, char** argv) { static const char* usage = "usage: %s [ <thread id> ]\n" "Prints the iframe stack for the current, respectively the specified\n" @@ -850,7 +890,7 @@ dump_iframes(int argc, char **argv) return 0; } - Thread *thread = NULL; + Thread* thread = NULL; if (argc < 2) { thread = thread_get_current_thread(); @@ -858,7 +898,7 @@ dump_iframes(int argc, char **argv) thread_id id = strtoul(argv[1], NULL, 0); thread = Thread::GetDebug(id); if (thread == NULL) { - kprintf("could not find thread %ld\n", id); + kprintf("could not find thread %" B_PRId32 "\n", id); return 0; } } else if (argc > 2) { @@ -866,12 +906,14 @@ dump_iframes(int argc, char **argv) return 0; } - if (thread != NULL) - kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name); + if (thread != NULL) { + kprintf("iframes for thread %" B_PRId32 " \"%s\"\n", thread->id, + thread->name); + } DebuggedThreadSetter threadSetter(thread); - struct iframe* frame = find_previous_iframe(thread, x86_get_stack_frame()); + iframe* frame = find_previous_iframe(thread, x86_get_stack_frame()); while (frame != NULL) { print_iframe(frame); frame = get_previous_iframe(thread, frame); @@ -882,17 +924,17 @@ dump_iframes(int argc, char **argv) static bool -is_calling(Thread *thread, addr_t eip, const char *pattern, - addr_t start, addr_t end) +is_calling(Thread* thread, addr_t ip, const char* pattern, addr_t start, + addr_t end) { if (pattern == NULL) - return eip >= start && eip < end; + return ip >= start && ip < end; - if (!IS_KERNEL_ADDRESS(eip)) + if (!IS_KERNEL_ADDRESS(ip)) return false; - const char *symbol; - if (lookup_symbol(thread, eip, NULL, &symbol, NULL, NULL) != B_OK) + const char* symbol; + if (lookup_symbol(thread, ip, NULL, &symbol, NULL, NULL) != B_OK) return false; return strstr(symbol, pattern); @@ -933,9 +975,9 @@ cmd_in_context(int argc, char** argv) } // switch the page directory, if necessary - uint32 oldPageDirectory = 0; + phys_addr_t oldPageDirectory = 0; if (thread != thread_get_current_thread()) { - uint32 newPageDirectory = x86_next_page_directory( + phys_addr_t newPageDirectory = x86_next_page_directory( thread_get_current_thread(), thread); if (newPageDirectory != 0) { @@ -962,7 +1004,7 @@ cmd_in_context(int argc, char** argv) void -arch_debug_save_registers(struct arch_debug_registers* registers) +arch_debug_save_registers(arch_debug_registers* registers) { // get the caller's frame pointer stack_frame* frame = (stack_frame*)x86_get_stack_frame(); @@ -978,14 +1020,14 @@ arch_debug_stack_trace(void) bool -arch_debug_contains_call(Thread *thread, const char *symbol, - addr_t start, addr_t end) +arch_debug_contains_call(Thread* thread, const char* symbol, addr_t start, + addr_t end) { DebuggedThreadSetter threadSetter(thread); - addr_t ebp; + addr_t bp; if (thread == thread_get_current_thread()) - ebp = x86_get_stack_frame(); + bp = x86_get_stack_frame(); else { if (thread->state == B_THREAD_RUNNING) { // The thread is currently running on another CPU. @@ -995,38 +1037,38 @@ arch_debug_contains_call(Thread *thread, const char *symbol, thread->cpu->cpu_num); if (registers == NULL) return false; - ebp = registers->bp; + bp = registers->bp; } else { // thread not running - ebp = thread->arch_info.current_stack.esp[2]; + bp = thread->arch_info.GetFramePointer(); } } for (;;) { - if (!is_kernel_stack_address(thread, ebp)) + if (!is_kernel_stack_address(thread, bp)) break; - if (is_iframe(thread, ebp)) { - struct iframe *frame = (struct iframe *)ebp; + if (is_iframe(thread, bp)) { + iframe* frame = (iframe*)bp; if (is_calling(thread, frame->ip, symbol, start, end)) return true; - ebp = frame->bp; + bp = frame->bp; } else { - addr_t eip, nextEbp; + addr_t ip, nextBp; - if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK - || eip == 0 || ebp == 0) + if (get_next_frame_no_debugger(bp, &nextBp, &ip) != B_OK + || ip == 0 || bp == 0) break; - if (is_calling(thread, eip, symbol, start, end)) + if (is_calling(thread, ip, symbol, start, end)) return true; - ebp = nextEbp; + bp = nextBp; } - if (ebp == 0) + if (bp == 0) break; } @@ -1034,11 +1076,11 @@ arch_debug_contains_call(Thread *thread, const char *symbol, } -void * +void* arch_debug_get_caller(void) { - struct stack_frame *frame = (struct stack_frame *)x86_get_stack_frame(); - return (void *)frame->previous->return_address; + stack_frame* frame = (stack_frame*)x86_get_stack_frame(); + return (void*)frame->previous->return_address; } @@ -1064,39 +1106,39 @@ arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, Thread* thread = thread_get_current_thread(); int32 count = 0; - addr_t ebp = x86_get_stack_frame(); + addr_t bp = x86_get_stack_frame(); bool onKernelStack = true; - while (ebp != 0 && count < maxCount) { + while (bp != 0 && count < maxCount) { onKernelStack = onKernelStack - && is_kernel_stack_address(thread, ebp); + && is_kernel_stack_address(thread, bp); if (!onKernelStack && (flags & STACK_TRACE_USER) == 0) break; - addr_t eip; - addr_t nextEbp; + addr_t ip; + addr_t nextBp; - if (onKernelStack && is_iframe(thread, ebp)) { - struct iframe *frame = (struct iframe*)ebp; - eip = frame->ip; - nextEbp = frame->bp; + if (onKernelStack && is_iframe(thread, bp)) { + iframe* frame = (iframe*)bp; + ip = frame->ip; + nextBp = frame->bp; if (skipIframes > 0) { if (--skipIframes == 0) skipFrames = 0; } } else { - if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK) + if (get_next_frame_no_debugger(bp, &nextBp, &ip) != B_OK) break; } if (skipFrames <= 0 && ((flags & STACK_TRACE_KERNEL) != 0 || onKernelStack)) { - returnAddresses[count++] = eip; + returnAddresses[count++] = ip; } else skipFrames--; - ebp = nextEbp; + bp = nextBp; } return count; @@ -1112,12 +1154,12 @@ arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, void* arch_debug_get_interrupt_pc(bool* _isSyscall) { - struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); + iframe* frame = get_current_iframe(debug_get_debugged_thread()); if (frame == NULL) return NULL; if (_isSyscall != NULL) - *_isSyscall = frame->vector == 99; + *_isSyscall = frame->type == IFRAME_TYPE_SYSCALL; return (void*)(addr_t)frame->ip; } @@ -1129,7 +1171,14 @@ arch_debug_get_interrupt_pc(bool* _isSyscall) void arch_debug_unset_current_thread(void) { +#ifdef __x86_64__ + // Can't just write 0 to the GS base, that will cause the read from %gs:0 + // to fault. Instead point it at a NULL pointer, %gs:0 will get this value. + static Thread* unsetThread = NULL; + x86_write_msr(IA32_MSR_GS_BASE, (addr_t)&unsetThread); +#else x86_write_dr3(NULL); +#endif } @@ -1145,14 +1194,14 @@ status_t arch_set_debug_variable(const char* variableName, uint64 value) { bool settable; - uint32* variable = find_debug_variable(variableName, settable); + size_t* variable = find_debug_variable(variableName, settable); if (variable == NULL) return B_ENTRY_NOT_FOUND; if (!settable) return B_NOT_ALLOWED; - *variable = (uint32)value; + *variable = (size_t)value; return B_OK; } @@ -1161,7 +1210,7 @@ status_t arch_get_debug_variable(const char* variableName, uint64* value) { bool settable; - uint32* variable = find_debug_variable(variableName, settable); + size_t* variable = find_debug_variable(variableName, settable); if (variable == NULL) return B_ENTRY_NOT_FOUND; @@ -1170,6 +1219,12 @@ arch_get_debug_variable(const char* variableName, uint64* value) } +struct gdb_register { + int32 type; + int64 value; +}; + + /*! Writes the contents of the CPU registers at some fixed outer stack frame or iframe into the given buffer in the format expected by gdb. @@ -1183,10 +1238,36 @@ arch_get_debug_variable(const char* variableName, uint64* value) ssize_t arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) { - struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); + iframe* frame = get_current_iframe(debug_get_debugged_thread()); if (frame == NULL) return B_NOT_SUPPORTED; +#ifdef __x86_64__ + // For x86_64 the register order is: + // + // rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, + // r8, r9, r10, r11, r12, r13, r14, r15, + // rip, rflags, cs, ss, ds, es, fs, gs + // + // Annoyingly, GDB wants all the registers as 64-bit values, but then + // RFLAGS and the segment registers as 32-bit values, hence the need for + // the type information. + static const int32 kRegisterCount = 24; + gdb_register registers[kRegisterCount] = { + { B_UINT64_TYPE, frame->ax }, { B_UINT64_TYPE, frame->bx }, + { B_UINT64_TYPE, frame->cx }, { B_UINT64_TYPE, frame->dx }, + { B_UINT64_TYPE, frame->si }, { B_UINT64_TYPE, frame->di }, + { B_UINT64_TYPE, frame->bp }, { B_UINT64_TYPE, frame->sp }, + { B_UINT64_TYPE, frame->r8 }, { B_UINT64_TYPE, frame->r9 }, + { B_UINT64_TYPE, frame->r10 }, { B_UINT64_TYPE, frame->r11 }, + { B_UINT64_TYPE, frame->r12 }, { B_UINT64_TYPE, frame->r13 }, + { B_UINT64_TYPE, frame->r14 }, { B_UINT64_TYPE, frame->r15 }, + { B_UINT64_TYPE, frame->ip }, { B_UINT32_TYPE, frame->flags }, + { B_UINT32_TYPE, frame->cs }, { B_UINT32_TYPE, frame->ss }, + { B_UINT32_TYPE, 0 }, { B_UINT32_TYPE, 0 }, + { B_UINT32_TYPE, 0 }, { B_UINT32_TYPE, 0 }, + }; +#else // For x86 the register order is: // // eax, ecx, edx, ebx, @@ -1195,23 +1276,36 @@ arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) // cs, ss, ds, es, fs, gs // // Note that even though the segment descriptors are actually 16 bits wide, - // gdb requires them as 32 bit integers. Note also that for some reason - // gdb wants the register dump in *big endian* format. + // gdb requires them as 32 bit integers. static const int32 kRegisterCount = 16; - uint32 registers[kRegisterCount] = { - frame->ax, frame->cx, frame->dx, frame->bx, - frame->sp, frame->bp, frame->si, frame->di, - frame->ip, frame->flags, - frame->cs, frame->ds, frame->ds, frame->es, + gdb_register registers[kRegisterCount] = { + { B_UINT32_TYPE, frame->ax }, { B_UINT32_TYPE, frame->cx }, + { B_UINT32_TYPE, frame->dx }, { B_UINT32_TYPE, frame->bx }, + { B_UINT32_TYPE, frame->sp }, { B_UINT32_TYPE, frame->bp }, + { B_UINT32_TYPE, frame->si }, { B_UINT32_TYPE, frame->di }, + { B_UINT32_TYPE, frame->ip }, { B_UINT32_TYPE, frame->flags }, + { B_UINT32_TYPE, frame->cs }, { B_UINT32_TYPE, frame->ds }, // assume ss == ds - frame->fs, frame->gs + { B_UINT32_TYPE, frame->ds }, { B_UINT32_TYPE, frame->es }, + { B_UINT32_TYPE, frame->fs }, { B_UINT32_TYPE, frame->gs }, }; +#endif const char* const bufferStart = buffer; for (int32 i = 0; i < kRegisterCount; i++) { - int result = snprintf(buffer, bufferSize, "%08" B_PRIx32, - B_HOST_TO_BENDIAN_INT32(registers[i])); + // For some reason gdb wants the register dump in *big endian* format. + int result = 0; + switch (registers[i].type) { + case B_UINT64_TYPE: + result = snprintf(buffer, bufferSize, "%016" B_PRIx64, + B_HOST_TO_BENDIAN_INT64(registers[i].value)); + break; + case B_UINT32_TYPE: + result = snprintf(buffer, bufferSize, "%08" B_PRIx32, + B_HOST_TO_BENDIAN_INT32((uint32)registers[i].value)); + break; + } if (result >= (int)bufferSize) return B_BUFFER_OVERFLOW; @@ -1224,7 +1318,7 @@ arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) status_t -arch_debug_init(kernel_args *args) +arch_debug_init(kernel_args* args) { // at this stage, the debugger command system is alive @@ -1234,7 +1328,9 @@ arch_debug_init(kernel_args *args) "Stack crawl for current thread (or any other)"); add_debugger_command("iframe", &dump_iframes, "Dump iframes for the specified thread"); +#ifndef __x86_64__ add_debugger_command("call", &show_call, "Show call with arguments"); +#endif add_debugger_command_etc("in_context", &cmd_in_context, "Executes a command in the context of a given thread", "<thread ID> <command> ...\n" diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index d0a1769..401f9d4 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -108,15 +108,9 @@ x86_get_thread_user_iframe(Thread *thread) if (thread->state == B_THREAD_RUNNING) return NULL; - // Read frame pointer from the thread's stack. -#ifdef __x86_64__ - addr_t bp = thread->arch_info.current_stack[1]; -#else - addr_t bp = thread->arch_info.current_stack.esp[2]; -#endif - // find the user iframe - struct iframe* frame = find_previous_iframe(thread, bp); + struct iframe* frame = find_previous_iframe(thread, + thread->arch_info.GetFramePointer()); while (frame != NULL) { if (IFRAME_IS_USER(frame)) @@ -136,7 +130,7 @@ x86_get_current_iframe(void) phys_addr_t -x86_next_page_directory(Thread *from, Thread *to) +x86_next_page_directory(Thread* from, Thread* to) { VMAddressSpace* toAddressSpace = to->team->address_space; if (from->team->address_space == toAddressSpace) {