Add symbol table handling and debug backtrace
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
|
||||
struct amd64_loader_data {
|
||||
uint32_t multiboot_info_ptr;
|
||||
uint32_t symtab_ptr;
|
||||
uint32_t symtab_size;
|
||||
uint32_t strtab_ptr;
|
||||
uint32_t strtab_size;
|
||||
uint32_t initrd_ptr;
|
||||
uint32_t initrd_len;
|
||||
char cmdline[KERNEL_CMDLINE_MAX];
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
#define kfatal(f, ...) debugf(DEBUG_FATAL, "\033[41m" DEBUG_BASE_FMT f "\033[0m", DEBUG_BASE_ARGS, ##__VA_ARGS__)
|
||||
#define kprint(l, f, ...) debugf(l, DEBUG_BASE_FMT f, DEBUG_BASE_ARGS, ##__VA_ARGS__)
|
||||
|
||||
void debug_symbol_table_set(uintptr_t symtab, uintptr_t strtab, size_t symtab_size, size_t strtab_size);
|
||||
int debug_symbol_find(uintptr_t addr, const char **name, uintptr_t *base);
|
||||
void debug_backtrace(uintptr_t rbp, int depth, int limit);
|
||||
|
||||
void fmtsiz(char *buf, size_t sz);
|
||||
|
||||
void debugc(int level, char c);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.section .text
|
||||
// Args:
|
||||
// %rdi - Address of loader's information struct
|
||||
.type _start, %function
|
||||
.global _start
|
||||
_start:
|
||||
cli
|
||||
@@ -11,12 +12,15 @@ _start:
|
||||
call _init
|
||||
movq %rbx, %rdi
|
||||
|
||||
xorq %rbp, %rbp
|
||||
pushq %rbp
|
||||
call kernel_main
|
||||
|
||||
1:
|
||||
cli
|
||||
hlt
|
||||
jmp 1b
|
||||
.size _start, . - _start
|
||||
|
||||
// Entrypoint for AP bootstrap code
|
||||
.global kernel_stacks_top
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
#include "sys/debug.h"
|
||||
#include "sys/panic.h"
|
||||
|
||||
#define X86_EXCEPTION_PF 14
|
||||
|
||||
#define X86_PF_EXEC (1 << 5)
|
||||
#define X86_PF_USER (1 << 2)
|
||||
#define X86_PF_WRITE (1 << 1)
|
||||
#define X86_PF_PRESENT (1 << 0)
|
||||
|
||||
#define X86_FLAGS_CF (1 << 0)
|
||||
#define X86_FLAGS_PF (1 << 2)
|
||||
#define X86_FLAGS_AF (1 << 4)
|
||||
@@ -56,5 +63,37 @@ void amd64_exception(struct amd64_exception_frame *frame) {
|
||||
(frame->rflags & X86_FLAGS_IF) ? 'I' : '-',
|
||||
(frame->rflags & X86_FLAGS_TF) ? 'T' : '-');
|
||||
|
||||
if (frame->exc_no == X86_EXCEPTION_PF) {
|
||||
uintptr_t cr2;
|
||||
asm volatile ("movq %%cr2, %0":"=r"(cr2));
|
||||
|
||||
kfatal("Page fault info:\n");
|
||||
kfatal("Fault address: %p\n", cr2);
|
||||
|
||||
if (frame->exc_code & X86_PF_EXEC) {
|
||||
kfatal(" - Instruction fetch\n");
|
||||
} else {
|
||||
if (frame->exc_code & X86_PF_WRITE) {
|
||||
kfatal(" - Write operation\n");
|
||||
} else {
|
||||
kfatal(" - Read operation\n");
|
||||
}
|
||||
}
|
||||
if (frame->exc_code & X86_PF_PRESENT) {
|
||||
kfatal(" - Refers to non-present page\n");
|
||||
}
|
||||
if (frame->exc_code & X86_PF_USER) {
|
||||
kfatal(" - Userspace\n");
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t sym_base;
|
||||
const char *sym_name;
|
||||
if (debug_symbol_find(frame->rip, &sym_name, &sym_base) == 0) {
|
||||
kfatal(" Backtrace:\n");
|
||||
kfatal("0: %p <%s + %04x>\n", frame->rip, sym_name, frame->rip - sym_base);
|
||||
debug_backtrace(frame->rbp, 1, 10);
|
||||
}
|
||||
|
||||
panic("Exception without resolution\n");
|
||||
}
|
||||
|
||||
+5
-5
@@ -35,6 +35,11 @@ void kernel_main(struct amd64_loader_data *data) {
|
||||
data = (struct amd64_loader_data *) MM_VIRTUALIZE(data);
|
||||
multiboot_info = (multiboot_info_t *) MM_VIRTUALIZE(data->multiboot_info_ptr);
|
||||
|
||||
if (data->symtab_ptr) {
|
||||
kinfo("Kernel symbol table at %p\n", MM_VIRTUALIZE(data->symtab_ptr));
|
||||
debug_symbol_table_set(MM_VIRTUALIZE(data->symtab_ptr), MM_VIRTUALIZE(data->strtab_ptr), data->symtab_size, data->strtab_size);
|
||||
}
|
||||
|
||||
// Parse kernel command line
|
||||
kernel_set_cmdline(data->cmdline);
|
||||
|
||||
@@ -56,11 +61,6 @@ void kernel_main(struct amd64_loader_data *data) {
|
||||
|
||||
amd64_apic_init();
|
||||
|
||||
//#pragma GCC diagnostic ignored "-Wdiv-by-zero"
|
||||
// uint32_t *addr = (uint32_t *) 0x110000000;
|
||||
// *addr = 1;
|
||||
//#pragma GCC diagnostic pop
|
||||
|
||||
while (1) {
|
||||
asm volatile ("sti; hlt");
|
||||
}
|
||||
|
||||
@@ -45,10 +45,29 @@ static uint64_t elf_load(uintptr_t src) {
|
||||
Elf64_Shdr *shdrs = (Elf64_Shdr *) (src + (uintptr_t) ehdr->e_shoff);
|
||||
const char *shstrtabd = (const char *) (src + (uintptr_t) shdrs[ehdr->e_shstrndx].sh_offset);
|
||||
|
||||
loader_data.strtab_ptr = 0;
|
||||
loader_data.strtab_size = 0;
|
||||
loader_data.symtab_ptr = 0;
|
||||
loader_data.symtab_size = 0;
|
||||
|
||||
for (size_t i = 0; i < (size_t) ehdr->e_shnum; ++i) {
|
||||
Elf64_Shdr *shdr = &shdrs[i];
|
||||
const char *name = &shstrtabd[shdr->sh_name];
|
||||
|
||||
if (shdr->sh_type == SHT_SYMTAB && !strcmp(name, ".symtab")) {
|
||||
loader_data.symtab_ptr = (uint32_t) shdr->sh_offset + src;
|
||||
loader_data.symtab_size = (uint32_t) shdr->sh_size;
|
||||
}
|
||||
|
||||
if (shdr->sh_type == SHT_STRTAB && !strcmp(name, ".strtab")) {
|
||||
puts("Strtab section: ");
|
||||
puts(name);
|
||||
putc('\n');
|
||||
|
||||
loader_data.strtab_ptr = (uint32_t) shdr->sh_offset + src;
|
||||
loader_data.strtab_size = (uint32_t) shdr->sh_size;
|
||||
}
|
||||
|
||||
if (shdr->sh_flags & SHF_ALLOC) {
|
||||
if (!strcmp(name, ".note.gnu.property")) {
|
||||
// Fuck you, gcc
|
||||
|
||||
+73
@@ -4,6 +4,7 @@
|
||||
#include "sys/attr.h"
|
||||
#include "sys/spin.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/elf.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(ARCH_AMD64)
|
||||
@@ -11,6 +12,78 @@
|
||||
#include "sys/amd64/hw/rs232.h"
|
||||
#endif
|
||||
|
||||
////
|
||||
|
||||
static uintptr_t g_symtab_ptr = 0;
|
||||
static uintptr_t g_strtab_ptr = 0;
|
||||
static size_t g_symtab_size = 0;
|
||||
static size_t g_strtab_size = 0;
|
||||
|
||||
void debug_symbol_table_set(uintptr_t s0, uintptr_t s1, size_t z0, size_t z1) {
|
||||
g_symtab_ptr = s0;
|
||||
g_symtab_size = z0;
|
||||
g_strtab_ptr = s1;
|
||||
g_strtab_size = z1;
|
||||
}
|
||||
|
||||
int debug_symbol_find(uintptr_t addr, const char **name, uintptr_t *base) {
|
||||
if (g_symtab_ptr && g_strtab_ptr) {
|
||||
size_t offset = 0;
|
||||
Elf64_Sym *sym;
|
||||
|
||||
while (offset < g_symtab_size) {
|
||||
sym = (Elf64_Sym *) (g_symtab_ptr + offset);
|
||||
|
||||
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) {
|
||||
if (sym->st_value <= addr && sym->st_value + sym->st_size >= addr) {
|
||||
*base = sym->st_value;
|
||||
if (sym->st_name < g_strtab_size) {
|
||||
*name = (const char *) (g_strtab_ptr + sym->st_name);
|
||||
} else {
|
||||
*name = "<invalid>";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
offset += sizeof(Elf64_Sym);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void debug_backtrace(uintptr_t rbp, int depth, int limit) {
|
||||
// Typical layout:
|
||||
// rbp + 08 == rip
|
||||
// rbp + 00 == rbp_1
|
||||
|
||||
if (!limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t rip = ((uintptr_t *) rbp)[1];
|
||||
uintptr_t rbp_next = ((uintptr_t *) rbp)[0];
|
||||
|
||||
uintptr_t base;
|
||||
const char *name;
|
||||
|
||||
if (debug_symbol_find(rip, &name, &base) == 0) {
|
||||
kfatal("%d: %p <%s + %04x>\n", depth, rip, name, rip - base);
|
||||
} else {
|
||||
kfatal("%d: %p (unknown)\n", depth, rip);
|
||||
}
|
||||
|
||||
if (rbp_next == 0) {
|
||||
kfatal("-- End of frame chain\n");
|
||||
return;
|
||||
}
|
||||
|
||||
debug_backtrace(rbp_next, depth + 1, limit - 1);
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
static const char *s_debug_xs_set0 = "0123456789abcdef";
|
||||
static const char *s_debug_xs_set1 = "0123456789ABCDEF";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user