diff --git a/include/sys/amd64/loader/data.h b/include/sys/amd64/loader/data.h index e572d4d..a912e7e 100644 --- a/include/sys/amd64/loader/data.h +++ b/include/sys/amd64/loader/data.h @@ -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]; diff --git a/include/sys/debug.h b/include/sys/debug.h index d936f69..6b6ff94 100644 --- a/include/sys/debug.h +++ b/include/sys/debug.h @@ -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); diff --git a/sys/amd64/entry.S b/sys/amd64/entry.S index 9c77e83..0a9907c 100644 --- a/sys/amd64/entry.S +++ b/sys/amd64/entry.S @@ -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 diff --git a/sys/amd64/hw/exc.c b/sys/amd64/hw/exc.c index 129fdf5..3f84b42 100644 --- a/sys/amd64/hw/exc.c +++ b/sys/amd64/hw/exc.c @@ -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"); } diff --git a/sys/amd64/kernel.c b/sys/amd64/kernel.c index 836d0d8..cf46c17 100644 --- a/sys/amd64/kernel.c +++ b/sys/amd64/kernel.c @@ -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"); } diff --git a/sys/amd64/loader/loader.c b/sys/amd64/loader/loader.c index 8307882..96cc8e7 100644 --- a/sys/amd64/loader/loader.c +++ b/sys/amd64/loader/loader.c @@ -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 diff --git a/sys/debug.c b/sys/debug.c index eb328e5..0412134 100644 --- a/sys/debug.c +++ b/sys/debug.c @@ -4,6 +4,7 @@ #include "sys/attr.h" #include "sys/spin.h" #include "sys/config.h" +#include "sys/elf.h" #include #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 = ""; + } + 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";