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.
This commit is contained in:
Alex Smith
2012-07-13 14:09:09 +01:00
parent e690e5ab3b
commit bcb07a319b
6 changed files with 336 additions and 424 deletions
+10 -3
View File
@@ -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)
@@ -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
-209
View File
@@ -51,215 +51,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)
+1 -1
View File
@@ -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
+297 -201
View File
@@ -1,6 +1,7 @@
/*
* Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
* 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);
kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
isUser ? (uint32*)(frame + 1) : &frame->user_sp);
kprintf(" eax 0x%-9lx ebx 0x%-9lx ecx 0x%-9lx edx 0x%lx\n",
#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 ? (void*)(frame + 1) : (void*)&frame->user_sp);
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"
+3 -9
View File
@@ -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) {