Stack trace with double linking to get symbol names
This commit is contained in:
75
src/debug/stacktrace.c
Normal file
75
src/debug/stacktrace.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include <stdint.h>
|
||||
#include "kernel.h"
|
||||
|
||||
void debug_stack_trace(unsigned int max_frames)
|
||||
{
|
||||
DEBUG("*** begin stack trace ***");
|
||||
// Thanks GCC :)
|
||||
uintptr_t* rbp = (uintptr_t*)__builtin_frame_address(0);
|
||||
|
||||
for (unsigned int frame=0; frame<max_frames && rbp != NULL; frame++)
|
||||
{
|
||||
// Return address, 1 word above saved rbp
|
||||
uintptr_t rip = rbp[1];
|
||||
uintptr_t offset = 0;
|
||||
const char* name = debug_find_symbol(rip, &offset);
|
||||
DEBUG("[%u] <0x%p> (%s+0x%x)", frame, (void*)rip, name, offset);
|
||||
|
||||
uintptr_t* next_rbp = (uintptr_t*)rbp[0];
|
||||
|
||||
// invalid rbp or we're at the end
|
||||
if (next_rbp <= rbp || next_rbp == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rbp = next_rbp;
|
||||
}
|
||||
DEBUG("*** end stack trace ***");
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t addr;
|
||||
const char *name;
|
||||
} __attribute__((packed)) kernel_symbol_t;
|
||||
|
||||
__attribute__((weak)) extern kernel_symbol_t symbol_table[];
|
||||
__attribute__((weak)) extern uint64_t symbol_count;
|
||||
|
||||
// binary search
|
||||
const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset)
|
||||
{
|
||||
if (!symbol_table || symbol_count == 0)
|
||||
{
|
||||
if (offset) *offset = 0;
|
||||
return "???";
|
||||
}
|
||||
|
||||
int low = 0, high = (int)symbol_count - 1;
|
||||
int best = -1;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
int mid = (low + high) / 2;
|
||||
if (symbol_table[mid].addr <= rip)
|
||||
{
|
||||
best = mid;
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (best != -1)
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
*offset = rip - symbol_table[best].addr;
|
||||
}
|
||||
return symbol_table[best].name;
|
||||
}
|
||||
|
||||
if (offset) *offset = 0;
|
||||
return "unknown";
|
||||
}
|
||||
Reference in New Issue
Block a user