Files
pepperOS/src/debug/stacktrace.c

103 lines
2.6 KiB
C

/*
* @author xamidev <xamidev@riseup.net>
* @brief Stack trace tools
* @license GPL-3.0-only
*/
#include <stdint.h>
#include "kernel.h"
extern struct init_status init;
/*
* debug_stack_trace - Prints the stack trace
* @max_frames: Maximum amount of stack frames to walk
*
* Walks back the stack and gets all return values (RIP)
* and prints them to the DEBUG interface.
*/
void debug_stack_trace(unsigned int max_frames)
{
DEBUG("*** begin stack trace ***");
if (init.terminal) {
printf("\r\n\x1b[48;5;232m\x1b[38;5;231m*** begin stack trace ***\r\n");
}
// 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);
if (init.terminal) {
printf("[%u] <0x%p> (%s+0x%x)\r\n", 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;
}
if (init.terminal) {
printf("*** end stack trace ***[0m");
}
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;
/*
* debug_find_symbol - Finds the symbol name associated to an address
* @rip: Pointer to executable code
* @offset: Out pointer to reference the offset in the found function, if any
*
* Return:
* <symbol name> - symbol name
* "???" - no symbol table found
* "unknown" - symbol table found, but address isn't in the table
*/
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";
}