96 lines
2.4 KiB
C
96 lines
2.4 KiB
C
/*
|
|
* @author xamidev <xamidev@riseup.net>
|
|
* @brief Stack trace tools
|
|
* @license GPL-3.0-only
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include "kernel.h"
|
|
#include <stddef.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)
|
|
{
|
|
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);
|
|
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;
|
|
}
|
|
|
|
printf("*** end stack trace ***\r\n[end Kernel panic]\r\nHalting system...\x1b[0m");
|
|
}
|
|
|
|
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";
|
|
} |