Files
zinnia/core/panic.c
T

74 lines
1.8 KiB
C

#include <zinnia/alloc.h>
#include <zinnia/initgraph.h>
#include <zinnia/irq.h>
#include <zinnia/ksyms.h>
#include <zinnia/panic.h>
#include <zinnia/percpu.h>
#include <zinnia/print.h>
#include <stdarg.h>
#include <stdint.h>
#define panic_log(msg, ...) kprintf("[ !!!! ] \e[31m" msg "\e[0m", ##__VA_ARGS__)
static void print_backtrace() {
constexpr size_t max_depth = 32;
void** fp = __builtin_frame_address(0);
panic_log("Backtrace:\n");
for (size_t i = 0; i < max_depth; i++) {
if (!fp || (uintptr_t)fp < mem_hhdm_base || (uintptr_t)fp % alignof(void*))
break;
void* ret = fp[1];
if (!ret)
break;
const char* name;
size_t offset;
// The return address may already point past the end of a noreturn call.
if (ksym_lookup((uintptr_t)ret - 1, &name, &offset))
panic_log(" #%zu [%p] %s+0x%zx\n", i, ret, name, offset + 1);
else
panic_log(" #%zu [%p] <\?\?\?>\n", i, ret);
void** next = fp[0];
if (next <= fp)
break;
fp = next;
}
}
[[noreturn]]
void panic(const char* msg, ...) {
// TODO: Stop all other CPUs with IPI.
irq_set_state(false);
struct percpu* cpu = percpu_get();
struct task* current = cpu->sched.current;
kprintf(
"[ !!!! ] \e[31m"
"Kernel panic on CPU %zu (T%zu, \"%s\"):\e[0m\n",
cpu->id,
current ? current->id : 0,
current ? current->name : nullptr
);
kprintf("[ !!!! ] \e[31m");
va_list args;
va_start(args, msg);
kvprintf(msg, args);
va_end(args);
kprintf("\e[0m");
print_backtrace();
panic_log("End of panic message\n");
initgraph_panic();
while (true) {
irq_wait();
}
}