diff --git a/arch/x86/config/kernel32.ld b/arch/x86/config/kernel32.ld index 38e8fa3..668ec85 100644 --- a/arch/x86/config/kernel32.ld +++ b/arch/x86/config/kernel32.ld @@ -34,6 +34,11 @@ SECTIONS { .text ALIGN(4K) : AT(ADDR(.text) - KERNBASE) { _text_start = .; + /* put all ISRs into one contiguous region so the + * stack unwinder knows when to stop unwinding */ + _isr_start = .; + KEEP(*(.text.isr)) + _isr_end = .; *(.text .text.* .gnu.linkonce.t.*) _text_end = .; } diff --git a/arch/x86/config/kernel64.ld b/arch/x86/config/kernel64.ld index 2e22a76..f0f18bd 100644 --- a/arch/x86/config/kernel64.ld +++ b/arch/x86/config/kernel64.ld @@ -34,6 +34,11 @@ SECTIONS { .text ALIGN(PAGE_SIZE) : AT(ADDR(.text) - KERNBASE) { _text_start = .; + /* put all ISRs into one contiguous region so the + * stack unwinder knows when to stop unwinding */ + _isr_start = .; + KEEP(*(.text.isr)) + _isr_end = .; *(.text .text.* .gnu.linkonce.t.*) _text_end = .; } diff --git a/arch/x86/config/toolchain.cmake b/arch/x86/config/toolchain.cmake index e05fe5b..349328c 100644 --- a/arch/x86/config/toolchain.cmake +++ b/arch/x86/config/toolchain.cmake @@ -26,7 +26,8 @@ set(CMAKE_RANLIB ${TOOLCHAIN_PATH}/${CMAKE_EXECUTABLE_PREFIX}ranlib${CMAK set(CMAKE_SZE ${TOOLCHAIN_PATH}/${CMAKE_EXECUTABLE_PREFIX}szr${CMAKE_EXECUTABLE_SUFFIX} CACHE INTERNAL "") set(CMAKE_STRIP ${TOOLCHAIN_PATH}/${CMAKE_EXECUTABLE_PREFIX}strip${CMAKE_EXECUTABLE_SUFFIX} CACHE INTERNAL "") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_toolchain_common_flags} -mcmodel=kernel -mno-red-zone -mno-mmx -mno-sse -msoft-float") +# XXX ktrace_print() currently relies on -fno-omit-frame-pointer +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_toolchain_common_flags} -mcmodel=kernel -mno-red-zone -mno-mmx -mno-sse -msoft-float -fno-omit-frame-pointer") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${_toolchain_common_flags}") set(CMAKE_C_COMPILER_TARGET ${_toolchain_triple}) set(CMAKE_ASM_COMPILER_TARGET ${_toolchain_triple}) diff --git a/arch/x86/sys/amd64/irq.S b/arch/x86/sys/amd64/irq.S index 6c637e0..20cbc5d 100644 --- a/arch/x86/sys/amd64/irq.S +++ b/arch/x86/sys/amd64/irq.S @@ -18,13 +18,14 @@ .extern irq_table /* there is probably a fancy CPU feature for this, but idk */ -irq_count: +L_DATA(irq_count) .long 0 +L_END(irq_count) .text /* bool in_irq(void); */ -ASM_ENTRY(in_irq) +ENTRY(in_irq) movabsq $irq_count, %rdx xor %eax, %eax mov %eax, %ecx @@ -32,10 +33,12 @@ ASM_ENTRY(in_irq) testl %ecx, (%rdx) setne %al retq -ASM_END(in_irq) +END(in_irq) + + .section .text.isr .macro gen_irq num -ASM_ENTRY(_x86_isr_irq\num ) +ENTRY(_x86_isr_irq\num ) push %rax push %rcx push %rdx @@ -53,7 +56,7 @@ ASM_ENTRY(_x86_isr_irq\num ) movabsq $(irq_table + \num * 8), %rax callq *%rax jmp leave_irq -ASM_END(_x86_isr_irq\num ) +END(_x86_isr_irq\num ) .endm gen_irq 0 @@ -73,8 +76,7 @@ ASM_END(_x86_isr_irq\num ) gen_irq 14 gen_irq 15 - .align 4 -leave_irq: +L_ENTRY(leave_irq) movabsq $irq_count, %rax decl (%rax) pop %r11 @@ -87,5 +89,4 @@ leave_irq: pop %rcx pop %rax iretq - - .size leave_irq, . - leave_irq +L_END(leave_irq) diff --git a/arch/x86/sys/amd64/ktrace.c b/arch/x86/sys/amd64/ktrace.c index 42e5c13..62249b3 100644 --- a/arch/x86/sys/amd64/ktrace.c +++ b/arch/x86/sys/amd64/ktrace.c @@ -1,18 +1,29 @@ /* Copyright (C) 2021 fef . All rights reserved. */ -#include - #include #include +#include -void ktrace_print(void) +__naked void ktrace_print(void) { - void **rbp; - __asm__ volatile("movq (%%rbp), %0" : "=r"(rbp)); + __asm__ volatile( +" movq %rbp, %rdi \n" +" jmp ktrace_print_from \n" + ); +} +void ktrace_print_from(void *frame) +{ + void **rbp = (void **)frame; kprintf("Stack trace:\n"); - while (rbp >= (void **)KERNBASE) { + + /* XXX Rather than spitting out raw addresses, parse the kernel image's + * ELF sections to figure out what the address actually belongs to */ + while (rbp >= (void **)image_start && rbp < (void **)image_end) { + /* caller return address is immediately above the stack frame */ kprintf(" %p\n", rbp[1]); + if (rbp[1] >= isr_start && rbp[1] < isr_end) + break; rbp = *rbp; } } diff --git a/arch/x86/sys/amd64/trap.S b/arch/x86/sys/amd64/trap.S index 3e7300c..e72d955 100644 --- a/arch/x86/sys/amd64/trap.S +++ b/arch/x86/sys/amd64/trap.S @@ -4,7 +4,7 @@ #include - .text + .section .text.isr /* * push all registers except %rsi to the stack, and store a pointer to the @@ -64,7 +64,7 @@ .macro gen_isr_noerror name .extern x86_isr_\name -ASM_ENTRY(_x86_isr_\name ) +ENTRY(_x86_isr_\name ) cld pushq %rsi prepare_trap_entry @@ -74,7 +74,7 @@ ASM_ENTRY(_x86_isr_\name ) prepare_trap_leave popq %rsi iretq -ASM_END(_x86_isr_\name ) +END(_x86_isr_\name ) .endm /* @@ -85,7 +85,7 @@ ASM_END(_x86_isr_\name ) */ .macro gen_isr_error name .extern x86_isr_\name -ASM_ENTRY(_x86_isr_\name ) +ENTRY(_x86_isr_\name ) cld /* @@ -103,7 +103,7 @@ ASM_ENTRY(_x86_isr_\name ) prepare_trap_leave popq %rsi iretq -ASM_END(_x86_isr_\name ) +END(_x86_isr_\name ) .endm gen_isr_noerror divide_error diff --git a/arch/x86/sys/i386/CMakeLists.txt b/arch/x86/sys/i386/CMakeLists.txt index 0ee3c06..9068a0e 100644 --- a/arch/x86/sys/i386/CMakeLists.txt +++ b/arch/x86/sys/i386/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources(gay_arch PRIVATE idt.S irq.S + ktrace.c switch.S systm.c trap.S diff --git a/arch/x86/sys/i386/irq.S b/arch/x86/sys/i386/irq.S index 025d5e1..0706c04 100644 --- a/arch/x86/sys/i386/irq.S +++ b/arch/x86/sys/i386/irq.S @@ -12,21 +12,24 @@ .extern irq_table /* there is probably a fancy CPU feature for this, but idk */ -irq_count: +L_DATA(irq_count) .byte 0 +L_END(irq_count) .text /* bool in_irq(void); */ -ASM_ENTRY(in_irq) +ENTRY(in_irq) xor %eax, %eax cmpb $0, irq_count setne %al ret -ASM_END(in_irq) +END(in_irq) + + .section .text.isr .macro gen_irq num -ASM_ENTRY(_x86_isr_irq\num ) +ENTRY(_x86_isr_irq\num ) push %eax push %ecx push %edx @@ -39,7 +42,7 @@ ASM_ENTRY(_x86_isr_irq\num ) add $4, %esp #endif jmp leave_irq -ASM_END(_x86_isr_irq\num ) +END(_x86_isr_irq\num ) .endm gen_irq 0 @@ -59,12 +62,10 @@ ASM_END(_x86_isr_irq\num ) gen_irq 14 gen_irq 15 - .align 4 -leave_irq: +L_ENTRY(leave_irq) decb irq_count pop %edx pop %ecx pop %eax iret - - .size leave_irq, . - leave_irq +L_END(leave_irq) diff --git a/arch/x86/sys/i386/ktrace.c b/arch/x86/sys/i386/ktrace.c new file mode 100644 index 0000000..6d29cea --- /dev/null +++ b/arch/x86/sys/i386/ktrace.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2021 fef . All rights reserved. */ + +#include +#include +#include + +__naked void ktrace_print(void) +{ + __asm__ volatile( +" pushl %ebp \n" +" call ktrace_print_from \n" +" ret \n" + ); +} + +void ktrace_print_from(void *frame) +{ + void **ebp = (void **)frame; + kprintf("Stack trace:\n"); + + /* XXX Rather than spitting out raw addresses, parse the kernel image's + * ELF sections to figure out what the address actually belongs to */ + while (ebp >= (void **)image_start && ebp < (void **)image_end) { + /* caller return address is immediately above the stack frame */ + kprintf(" %p\n", ebp[1]); + if (rbp[1] >= isr_start && rbp[1] < isr_end) + break; + rbp = *rbp; + } +} diff --git a/arch/x86/sys/i386/trap.S b/arch/x86/sys/i386/trap.S index 754c508..c3378ab 100644 --- a/arch/x86/sys/i386/trap.S +++ b/arch/x86/sys/i386/trap.S @@ -4,7 +4,7 @@ #include - .text + .section .text.isr /* * Low level trap entry points, this is what gets put into the IDT. @@ -19,7 +19,7 @@ .macro gen_isr_noerror name .extern x86_isr_\name -ASM_ENTRY(_x86_isr_\name ) +ENTRY(_x86_isr_\name ) cld pushal mov %esp, %eax @@ -29,7 +29,7 @@ ASM_ENTRY(_x86_isr_\name ) add $4, %esp popal iretl -ASM_END(_x86_isr_\name ) +END(_x86_isr_\name ) .endm /* @@ -43,7 +43,7 @@ ASM_END(_x86_isr_\name ) */ .macro gen_isr_error name .extern x86_isr_\name -ASM_ENTRY(_x86_isr_\name ) +ENTRY(_x86_isr_\name ) cld pushal mov %esp, %eax @@ -63,7 +63,7 @@ ASM_ENTRY(_x86_isr_\name ) popal add $4, %esp /* "pop" the hardware error code from the stack */ iretl -ASM_END(_x86_isr_\name ) +END(_x86_isr_\name ) .endm gen_isr_noerror divide_error diff --git a/include/gay/cdefs.h b/include/gay/cdefs.h index 28e2061..94adf23 100644 --- a/include/gay/cdefs.h +++ b/include/gay/cdefs.h @@ -51,6 +51,8 @@ */ #define __alloc_size(argn) __attribute__(( alloc_size(argn) )) +#define __naked __attribute(( naked )) + #define __noreturn __attribute__(( noreturn )) /** @@ -81,7 +83,7 @@ #define __pure2 __attribute__(( const )) /** @brief Put the annotated symbol in a specific section. */ -#define __section(name) __attribute__(( section(#name) )) +#define __section(name) __attribute__(( section(name) )) /** @brief Mark the symbol as used, even if it really isn't. */ #define __used __attribute__(( used )) diff --git a/include/gay/ktrace.h b/include/gay/ktrace.h index 2c4778c..4d8e273 100644 --- a/include/gay/ktrace.h +++ b/include/gay/ktrace.h @@ -3,4 +3,9 @@ #pragma once /** @brief Print a full stack trace to the kernel log, starting from the caller. */ +__asmlink void ktrace_print(void); + +/** @brief Print a full stack trace to the kernel log, starting from `frame`. */ +__asmlink +void ktrace_print_from(void *frame);