diff --git a/core/main.c b/core/main.c index f4f46b2..7cb2dc9 100644 --- a/core/main.c +++ b/core/main.c @@ -159,6 +159,9 @@ void kmain(unsigned long magic, unsigned long addr) } } + if (CHECK_FLAG(mbi->flags, 5)) { + stackSymbolSetup(mbi); + } if (CHECK_FLAG(mbi->flags, 6)) { memMapAvailable = 1; } diff --git a/core/stack.c b/core/stack.c index 929323e..e6563ce 100644 --- a/core/stack.c +++ b/core/stack.c @@ -1,7 +1,94 @@ #include "stack.h" +#include "elf.h" #include "klibc.h" +#include "paging.h" #include "types.h" +/** Defined in linker.ld script **/ +extern char __multiboot_data_start; +extern char __multiboot_data_end; +static size_t multibootDataSize; +static size_t multibootUsage; + +/** Initialized at 'StackSymbolSetup'. */ +static Elf32_Sym_t *elfSymtab; +static size_t elfSymtabSize; + +static const char *elfStrtab; +static size_t elfStrtabSize; + +static void *stackSaveSection(const void *addr, size_t size, const char *sectionName) +{ + if (size > (multibootDataSize - multibootUsage)) { + printf("No enough room to store %s (%d/%d). Increase multiboot_data section size", + sectionName, size, (multibootDataSize - multibootUsage)); + return NULL; + } + void *destAddr = (void *)&__multiboot_data_start + multibootUsage; + + memcpy((void *)destAddr, addr, size); + multibootUsage += size; + + return destAddr; +} + +/** + * Copy the symbols table and string table from a multiboot information. + * We need to copy them as they are loaded by the bootloader and could be override as soon + * as we play with memory around our loaded kernel. + * As special ELF section is allocated for this purpose. + */ +void stackSymbolSetup(multiboot_info_t *mbi) +{ + /** Get the section header table as an array of section headers. */ + Elf32_Shdr_t *sht = (Elf32_Shdr_t *)mbi->u.elf_sec.addr; + size_t sec_len = (size_t)mbi->u.elf_sec.num; + assert(mbi->u.elf_sec.size == sizeof(Elf32_Shdr_t)); + multibootDataSize = &__multiboot_data_end - &__multiboot_data_start; + multibootUsage = 0; + + /** + * The section header at index 'shndx' in the table is a meta section + * header. It contains a list of section header names in the table. We + * should look for section header names ".symtab" & ".strtab". + */ + const char *sh_names = (const char *)sht[mbi->u.elf_sec.shndx].sh_addr; + + /** Loop through the table and look for ".symtab" & ".strtab". */ + for (size_t i = 0; i < sec_len; ++i) { + const char *name = sh_names + sht[i].sh_name; + + if (strcmp(name, ".symtab") == 0) { + assert(sht[i].sh_type == SHT_SYMTAB); + elfSymtab = stackSaveSection((void *)sht[i].sh_addr, sht[i].sh_size, name); + if (elfSymtab) + elfSymtabSize = sht[i].sh_size; + + } else if (strcmp(name, ".strtab") == 0) { + assert(sht[i].sh_type == SHT_STRTAB); + elfStrtab = stackSaveSection((void *)sht[i].sh_addr, sht[i].sh_size, name); + if (elfStrtab) + elfStrtabSize = sht[i].sh_size; + } + } +} + +/** Look up an address in symbols map and return its function name or NULL. */ +static const char *lookupSymbolName(uint32_t addr) +{ + size_t symtab_len = elfSymtabSize / sizeof(Elf32_Sym_t); + + for (size_t i = 0; i < symtab_len; ++i) { + if ((ELF_SYM_TYPE(elfSymtab[i].st_info) == ELF_SYM_TYPE_FUNC) && + (addr >= elfSymtab[i].st_value) && + (addr <= elfSymtab[i].st_value + elfSymtab[i].st_size)) { + return elfStrtab + elfSymtab[i].st_name; + } + } + + return NULL; +} + void printStackTrace(unsigned int maxFrames) { #ifdef DEBUG @@ -21,7 +108,12 @@ void printStackTrace(unsigned int maxFrames) break; } unsigned int *arguments = ebp + 2; - printf("[%d] 0x%x (", frame, eip); + const char *functionName = lookupSymbolName(eip); + if (functionName != NULL) { + printf("[%d] %s (", frame, functionName); + } else { + printf("[%d] 0x%x (", frame, eip); + } int nbArg = 0; do { if ((_stack_bottom <= (vaddr_t)arguments) && ((vaddr_t)arguments <= _stack_top)) { diff --git a/core/stack.h b/core/stack.h index a0d6136..2363783 100644 --- a/core/stack.h +++ b/core/stack.h @@ -1,6 +1,8 @@ #pragma once +#include "multiboot.h" #include "types.h" extern vaddr_t _stack_bottom; extern vaddr_t _stack_top; void printStackTrace(unsigned int maxFrame); +void stackSymbolSetup(multiboot_info_t *mbi); diff --git a/linker.ld b/linker.ld index c59a4ce..fe5f9b1 100644 --- a/linker.ld +++ b/linker.ld @@ -39,6 +39,12 @@ SECTIONS *(.bss) } + .multiboot_data : { + __multiboot_data_size = 48k; + __multiboot_data_start = .; + . = . + __multiboot_data_size; + __multiboot_data_end = .; + } __ld_kernel_end = .; /* The compiler may produce other sections, by default it will put them in