diff --git a/arch/amd64/kernel.c b/arch/amd64/kernel.c index 8121ceb..5c9f0df 100644 --- a/arch/amd64/kernel.c +++ b/arch/amd64/kernel.c @@ -86,43 +86,7 @@ void kernel_early_init(void) { cpuid_init(); if (multiboot_tag_sections) { - kinfo("Loading kernel symbols\n"); - kinfo("%u section headers:\n", multiboot_tag_sections->num); - size_t string_section_offset = multiboot_tag_sections->shndx * multiboot_tag_sections->entsize; - Elf64_Shdr *string_section_hdr = (Elf64_Shdr *) &multiboot_tag_sections->sections[string_section_offset]; - const char *shstrtab = (const char *) MM_VIRTUALIZE(string_section_hdr->sh_addr); - Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL; - - for (size_t i = 0; i < multiboot_tag_sections->num; ++i) { - Elf64_Shdr *shdr = (Elf64_Shdr *) &multiboot_tag_sections->sections[i * multiboot_tag_sections->entsize]; - const char *name = &shstrtab[shdr->sh_name]; - switch (shdr->sh_type) { - case SHT_SYMTAB: - if (symtab_shdr) { - panic("Kernel image has 2+ symbol tables\n"); - } - symtab_shdr = shdr; - break; - case SHT_STRTAB: - if (strcmp(name, ".strtab")) { - break; - } - if (strtab_shdr) { - panic("kernel image has 2+ string tables\n"); - } - strtab_shdr = shdr; - break; - default: - break; - } - } - - if (symtab_shdr && strtab_shdr) { - uintptr_t symtab_ptr = MM_VIRTUALIZE(symtab_shdr->sh_addr); - uintptr_t strtab_ptr = MM_VIRTUALIZE(strtab_shdr->sh_addr); - - debug_symbol_table_set(symtab_ptr, strtab_ptr, symtab_shdr->sh_size, strtab_shdr->sh_size); - } + debug_symbol_table_multiboot2(multiboot_tag_sections); } if (multiboot_tag_cmdline) { diff --git a/include/sys/debug.h b/include/sys/debug.h index 0ea96c5..346ce2e 100644 --- a/include/sys/debug.h +++ b/include/sys/debug.h @@ -38,7 +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__) +struct multiboot_tag_elf_sections; + void debug_symbol_table_set(uintptr_t symtab, uintptr_t strtab, size_t symtab_size, size_t strtab_size); +void debug_symbol_table_multiboot2(struct multiboot_tag_elf_sections *tag); int debug_symbol_find(uintptr_t addr, const char **name, uintptr_t *base); int debug_symbol_find_by_name(const char *name, uintptr_t *value); void debug_backtrace(uintptr_t rbp, int depth, int limit); diff --git a/include/sys/string.h b/include/sys/string.h index 8782694..c056406 100644 --- a/include/sys/string.h +++ b/include/sys/string.h @@ -5,6 +5,14 @@ #pragma once #include "sys/types.h" +// A macro to properly read data from misaligned pointers, byte by byte +// May be slower, but at least UBSan doesn't complain +#define realigned(base, field) ({ \ + typeof(base->field) __v0; \ + memcpy(&__v0, (void *) (base) + offsetof(typeof(*base), field), sizeof(__v0)); \ + __v0; \ + }) + #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) diff --git a/sys/debug.c b/sys/debug.c index 2438297..687d962 100644 --- a/sys/debug.c +++ b/sys/debug.c @@ -1,3 +1,4 @@ +#include "arch/amd64/multiboot2.h" #include "sys/string.h" #include "sys/debug.h" #include "sys/ctype.h" @@ -6,6 +7,8 @@ #include "sys/config.h" #include "sys/elf.h" #include "sys/assert.h" +#include "sys/mm.h" + #include #if defined(ARCH_AMD64) @@ -20,6 +23,52 @@ static uintptr_t g_strtab_ptr = 0; static size_t g_symtab_size = 0; static size_t g_strtab_size = 0; +// Multiboot2-loaded sections are misaligned for some reason +void debug_symbol_table_multiboot2(struct multiboot_tag_elf_sections *tag) { + kinfo("Loading kernel symbols\n"); + kinfo("%u section headers:\n", tag->num); + size_t string_section_offset = tag->shndx * tag->entsize; + Elf64_Shdr *string_section_hdr = (Elf64_Shdr *) &tag->sections[string_section_offset]; + const char *shstrtab = (const char *) MM_VIRTUALIZE(realigned(string_section_hdr, sh_addr)); + + Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL; + + for (size_t i = 0; i < tag->num; ++i) { + Elf64_Shdr *shdr = (Elf64_Shdr *) &tag->sections[i * tag->entsize]; + const char *name = &shstrtab[realigned(shdr, sh_name)]; + + switch (realigned(shdr, sh_type)) { + case SHT_SYMTAB: + if (symtab_shdr) { + panic("Kernel image has 2+ symbol tables\n"); + } + symtab_shdr = shdr; + break; + case SHT_STRTAB: + if (strcmp(name, ".strtab")) { + break; + } + if (strtab_shdr) { + panic("kernel image has 2+ string tables\n"); + } + strtab_shdr = shdr; + break; + default: + break; + } + } + + if (symtab_shdr && strtab_shdr) { + uintptr_t symtab_ptr = MM_VIRTUALIZE(realigned(symtab_shdr, sh_addr)); + uintptr_t strtab_ptr = MM_VIRTUALIZE(realigned(strtab_shdr, sh_addr)); + + debug_symbol_table_set(symtab_ptr, + strtab_ptr, + realigned(symtab_shdr, sh_size), + realigned(strtab_shdr, sh_size)); + } +} + 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; diff --git a/sys/mod.c b/sys/mod.c index e8263c0..b88b31f 100644 --- a/sys/mod.c +++ b/sys/mod.c @@ -143,7 +143,11 @@ static int elf_rela_apply(void *image, uintptr_t base, Elf64_Shdr *shdrs, Elf64_ switch (ELF64_R_TYPE(rela->r_info)) { case R_X86_64_64: - *((uint64_t *) value_ptr) = (uint64_t) (value + (intptr_t) rela->r_addend); + { + uint64_t src = (uint64_t) (value + (intptr_t) rela->r_addend); + // value_ptr most likely will be unaligned + memcpy(value_ptr, &src, sizeof(uint64_t)); + } break; case R_X86_64_PLT32: // Treat this the same as PC32 case R_X86_64_PC32: diff --git a/sys/ubsan.c b/sys/ubsan.c index 4c058fd..2ba91d9 100644 --- a/sys/ubsan.c +++ b/sys/ubsan.c @@ -2,8 +2,8 @@ #include "sys/panic.h" #include "sys/debug.h" -//#define UBSAN_ABORT 1 -#undef UBSAN_ABORT +#define UBSAN_ABORT 1 +//#undef UBSAN_ABORT struct source_location { const char *file; @@ -123,7 +123,7 @@ void __ubsan_handle_vla_bound_not_positive(void *data_raw, struct type_mismatch_info { struct source_location location; struct type_descriptor *type; - uintptr_t alignment; + uint8_t alignment; uint8_t type_check_kind; }; void __ubsan_handle_type_mismatch_v1(struct type_mismatch_info *type_mismatch, @@ -135,7 +135,7 @@ void __ubsan_handle_type_mismatch_v1(struct type_mismatch_info *type_mismatch, } else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment)) { // Most useful on architectures with stricter memory alignment requirements, like ARM. - kfatal("Unaligned memory access\n"); + kfatal("Unaligned memory access: %p\n", pointer); } else { kfatal("Insufficient size:\n"); if (type_mismatch->type_check_kind < sizeof(Type_Check_Kinds) / sizeof(Type_Check_Kinds[0])) {