diff --git a/yak-kernel/CMakeLists.txt b/yak-kernel/CMakeLists.txt index 8faf2c0..70c3a0f 100644 --- a/yak-kernel/CMakeLists.txt +++ b/yak-kernel/CMakeLists.txt @@ -11,6 +11,7 @@ if (NOT ${CMAKE_C_COMPILER_ID} STREQUAL "Clang") endif () # Define global options +option(USE_DEBUG "Enable debug code" ON) option(USE_LIMINE "Enable support for the limine boot protocol" ON) # Find builtins @@ -57,10 +58,17 @@ if (NOT ${USE_LIMINE}) endif () # Find sources -file(GLOB KERNEL_SOURCES src/rt/*.c src/ulibc/*.c) +file(GLOB KERNEL_SOURCES + src/rt/*.c + src/ulibc/*.c) file(GLOB PLATFORM_GENERIC_SOURCES src/platform/generic/*.c) +if (${USE_DEBUG}) + add_definitions(-DUSE_DEBUG) + file(GLOB DEBUG_KERNEL_SOURCES src/rt/debug/*.c) +endif () if (${USE_LIMINE}) + add_definitions(-DUSE_LIMINE) file(GLOB LIMINE_KERNEL_SOURCES src/rt/limine/*.c) endif () if (NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/${CMAKE_SYSTEM_PROCESSOR}) @@ -77,6 +85,7 @@ file(GLOB CRTN src/platform/generic/crt/crtn.c) set(KERNEL_SOURCE_FILES ${KERNEL_SOURCES} ${LIMINE_KERNEL_SOURCES} + ${DEBUG_KERNEL_SOURCES} ${PLATFORM_GENERIC_SOURCES} ${PLATFORM_SPECIFIC_SOURCES} ${PLATFORM_SPECIFIC_ASM_SOURCES} diff --git a/yak-kernel/include/elf.h b/yak-kernel/include/elf.h new file mode 100644 index 0000000..520b730 --- /dev/null +++ b/yak-kernel/include/elf.h @@ -0,0 +1,167 @@ +// +// Created by rick on 07-03-21. +// + +#ifndef NEW_KERNEL_ELF_H +#define NEW_KERNEL_ELF_H + +#include + +// \x7FELF (little endian) +#define ELF_MAGIC 0x464C457F + +#define ELF_CLASS_32 1 +#define ELF_CLASS_64 2 + +#define ELF_ENDIAN_LITTLE 1 +#define ELF_ENDIAN_BIG 2 + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b, t) (((b)<<4)+((t)&0xf)) + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +struct elf_file_header { + uint32_t ei_magic; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_osabi; + uint8_t ei_abiversion; + uint64_t: 56; // 7 bytes padding + union { + struct { + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; + } elf32 __attribute((packed)); + struct { + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; + } elf64 __attribute((packed)); + }; +} __attribute((packed)); + +struct elf32_program_header { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +} __attribute((packed)); + +struct elf64_program_header { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} __attribute((packed)); + +struct elf32_section_header { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addr_align; + uint32_t sh_ent_size; +} __attribute((packed)); + +struct elf64_section_header { + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint64_t sh_addr_align; + uint64_t sh_ent_size; +} __attribute((packed)); + +struct elf32_symtab_entry { + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + uint8_t st_info; + uint8_t st_other; + uint16_t st_shndx; +} __attribute((packed)); + +struct elf64_symtab_entry { + uint32_t st_name; + uint8_t st_info; + uint8_t st_other; + uint16_t st_shndx; + uint64_t st_value; + uint64_t st_size; +} __attribute((packed)); + +#endif //NEW_KERNEL_ELF_H diff --git a/yak-kernel/include/yak/rt/debug/debug.h b/yak-kernel/include/yak/rt/debug/debug.h new file mode 100644 index 0000000..f3fe2e6 --- /dev/null +++ b/yak-kernel/include/yak/rt/debug/debug.h @@ -0,0 +1,14 @@ +// +// Created by rick on 08-03-21. +// + +#ifndef NEW_KERNEL_DEBUG_H +#define NEW_KERNEL_DEBUG_H + +#include + +void debug_store_info(void *kernel); + +void debug_backtrace(bool do_sync); + +#endif //NEW_KERNEL_DEBUG_H diff --git a/yak-kernel/include/yak/rt/kprint.h b/yak-kernel/include/yak/rt/kprint.h index abbaa4b..13cddb5 100644 --- a/yak-kernel/include/yak/rt/kprint.h +++ b/yak-kernel/include/yak/rt/kprint.h @@ -7,7 +7,9 @@ typedef void (*print_function)(char c); -void kprint_now(char* msg); +void kprint(const char* msg); + +void kprint_now(const char* msg); void kprint_putc_now(char c); diff --git a/yak-kernel/src/platform/x86_64/platform.c b/yak-kernel/src/platform/x86_64/platform.c index 9afcefa..565514b 100644 --- a/yak-kernel/src/platform/x86_64/platform.c +++ b/yak-kernel/src/platform/x86_64/platform.c @@ -5,7 +5,7 @@ #include void platform_init() { - printf("Init X86_64"); + printf("Init X86_64\n"); } void __attribute__((noreturn)) halt_forever() { diff --git a/yak-kernel/src/rt/debug/debug.c b/yak-kernel/src/rt/debug/debug.c new file mode 100644 index 0000000..2746187 --- /dev/null +++ b/yak-kernel/src/rt/debug/debug.c @@ -0,0 +1,123 @@ +// +// Created by rick on 08-03-21. +// + +#include +#include +#include +#include + +#include +#include + +static uintptr_t kernel_start; +static struct elf64_section_header *elf_headers = NULL; +static struct elf64_section_header *elf_shstrtab = NULL; +static struct elf64_section_header *elf_symtab = NULL; +static struct elf64_section_header *elf_strtab = NULL; +static uint32_t elf_header_cnt; + +struct stackframe { + struct stackframe *ebp; + uintptr_t eip; +}; + +char *debug_get_shstrtab_entry(uint32_t ndx) { + if (elf_shstrtab == NULL) { + return NULL; + } + if (ndx > elf_shstrtab->sh_size) { + return NULL; + } + return ((char *) kernel_start + elf_shstrtab->sh_offset + ndx); +} + +char *debug_get_strtab_entry(uint32_t ndx) { + if (elf_strtab == NULL) { + return NULL; + } + if (ndx > elf_strtab->sh_size) { + return NULL; + } + return ((char *) kernel_start + elf_strtab->sh_offset + ndx); +} + +void debug_find_sections(uint32_t shndx) { + elf_shstrtab = &elf_headers[shndx]; + for (uint32_t i = 0; i < elf_header_cnt; ++i) { + struct elf64_section_header *current = &elf_headers[i]; + char *name = debug_get_shstrtab_entry(current->sh_name); + if (name == NULL) { + printf("Name was NULL\n"); + continue; + } + if (strcmp(name, ".symtab") == 0) { + elf_symtab = current; + continue; + } + if (strcmp(name, ".strtab") == 0) { + elf_strtab = current; + continue; + } + } +} + +void debug_store_info(void *kernel) { + struct elf_file_header* elf_header = (struct elf_file_header*)kernel; + if (elf_header->ei_magic != ELF_MAGIC) { + printf("Unsupported magic for kernel header\n"); + return; + } + // todo support other then 64 little + if (elf_header->ei_class != ELF_CLASS_64 || elf_header->ei_data != ELF_ENDIAN_LITTLE) { + printf("Kernel not a 64bit little endian elf\n"); + return; + } + + + if (elf_header->elf64.e_shentsize != sizeof(struct elf64_section_header)) { + printf("Elf section headers not correct size\n"); + } + + kernel_start = (uintptr_t) kernel; + elf_headers = (struct elf64_section_header *) (kernel_start + elf_header->elf64.e_shoff); + elf_header_cnt = elf_header->elf64.e_shnum; + debug_find_sections(elf_header->elf64.e_shstrndx); +} + +struct elf64_symtab_entry *debug_get_entry_for_addr(uintptr_t addr) { + if (elf_symtab == NULL) { + return NULL; + } + struct elf64_symtab_entry *first = (struct elf64_symtab_entry *) (kernel_start + elf_symtab->sh_offset); + uint32_t num = elf_symtab->sh_size / sizeof(struct elf64_symtab_entry); + for (uint32_t i = 0; i < num; ++i) { + // only functions for now + if (ELF32_ST_TYPE(first[i].st_info) != STT_FUNC) { + continue; + } + if (addr >= first[i].st_value && addr < (first[i].st_value + first[i].st_size)) { + return &first[i]; + } + } + return NULL; +} + +void debug_backtrace(bool do_sync) { + // todo support non-x86 + struct stackframe *frame = __builtin_frame_address(0); + void (*printer)(const char *) = do_sync ? kprint_now : kprint; + printer("\n\n## Stack Trace ##\n"); + char msg[1024] = {0}; + while (frame->ebp != NULL) { + struct elf64_symtab_entry *entry = debug_get_entry_for_addr(frame->eip); + if (entry == NULL) { + snprintf(msg, 1024,"#unknown (%lx)\n", frame->eip); + } else { + snprintf(msg, 1024, "%s (%lx)\n", debug_get_strtab_entry(entry->st_name), frame->eip); + }; + printer(msg); + frame = frame->ebp; + } + printer("\n"); +} diff --git a/yak-kernel/src/rt/kmain.c b/yak-kernel/src/rt/kmain.c index 829156d..b2f61f4 100644 --- a/yak-kernel/src/rt/kmain.c +++ b/yak-kernel/src/rt/kmain.c @@ -1,6 +1,6 @@ #include #include -#include "yak/platform/generic/platform.h" +#include void kmain() { _init(); diff --git a/yak-kernel/src/rt/kprint.c b/yak-kernel/src/rt/kprint.c index bd67fad..15d6386 100644 --- a/yak-kernel/src/rt/kprint.c +++ b/yak-kernel/src/rt/kprint.c @@ -9,8 +9,13 @@ print_function print_functions[MAX_PRINT_FUNCTIONS] = {0}; -void kprint_now(char* msg) { - char* m = msg; +void kprint(const char* msg) { + // todo async + kprint_now(msg); +} + +void kprint_now(const char* msg) { + const char* m = msg; while (*m != 0) { kprint_putc_now(*m); m++; diff --git a/yak-kernel/src/rt/limine/limine.c b/yak-kernel/src/rt/limine/limine.c index 83d3070..8b7ea83 100644 --- a/yak-kernel/src/rt/limine/limine.c +++ b/yak-kernel/src/rt/limine/limine.c @@ -5,8 +5,10 @@ #include #include #include -#include + +#include #include +#include static struct limine_bootloader_info_request limine_bootloader_info_request = { .id = LIMINE_BOOTLOADER_INFO_REQUEST, @@ -110,5 +112,9 @@ void limine_init() { printf("Booted using limine from an unknown bootloader\n"); } + if (limine_kernel_file_request.response != NULL) { + debug_store_info(limine_kernel_file_request.response->kernel_file->address); + } + kmain(); } diff --git a/yak-kernel/src/rt/panic.c b/yak-kernel/src/rt/panic.c index 87d8623..d8da991 100644 --- a/yak-kernel/src/rt/panic.c +++ b/yak-kernel/src/rt/panic.c @@ -3,13 +3,18 @@ // #include -#include "yak/rt/kprint.h" -#include "yak/platform/generic/platform.h" +#include +#include +#ifdef USE_DEBUG +#include +#endif void __attribute__((__noreturn__)) panic(char *reason) { - kprint_now(reason); +#ifdef USE_DEBUG + debug_backtrace(true); +#endif - // todo stack trace + kprint_now(reason); halt_forever(); } \ No newline at end of file