mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
panic: print backtrace on panic
Panics currently lack backtraces, which are a very useful thing to have. Make the profiling backtrace function generic and print backtraces using it.
This commit is contained in:
@@ -68,39 +68,27 @@ static void init_intel_pmc(void) {
|
||||
arch_apic_init_perf();
|
||||
}
|
||||
|
||||
static uint8_t get_backtrace(context_t *context, uintptr_t *data) {
|
||||
if (IS_USER_ADDRESS(context->rip))
|
||||
return 0;
|
||||
static bool backtrace_fn(void *context, void *ip) {
|
||||
uint8_t *data = context;
|
||||
|
||||
data[0] = context->rip;
|
||||
if (data[0] == 255)
|
||||
return false;
|
||||
|
||||
uint64_t *rbp = (uint64_t *)context->rbp;
|
||||
uint8_t done = 1;
|
||||
uintptr_t *trace = (uintptr_t *)&data[1];
|
||||
trace[data[0]] = (uintptr_t)ip;
|
||||
data[0] += 1;
|
||||
|
||||
for (;;) {
|
||||
if (IS_USER_ADDRESS(rbp) || done == 255)
|
||||
break;
|
||||
|
||||
uint64_t rip = *(rbp + 1);
|
||||
if (IS_USER_ADDRESS(rip))
|
||||
break;
|
||||
|
||||
data[done++] = rip - 1;
|
||||
rbp = (uint64_t *)*rbp;
|
||||
}
|
||||
|
||||
return done;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intel_irq(context_t *context) {
|
||||
if ((rdmsr(MSR_PERF_GLOBAL_STATUS) & INTEL_TSC_INDEX_OFFSET) == 0)
|
||||
return false;
|
||||
|
||||
uint8_t data[1 + sizeof(uintptr_t) * 256];
|
||||
|
||||
uint8_t size = get_backtrace(context, (uintptr_t *)(data + 1));
|
||||
*data = size;
|
||||
profiling_insert(size, data);
|
||||
uint8_t data[1 + sizeof(uintptr_t) * 255];
|
||||
data[0] = 0;
|
||||
arch_get_backtrace(context, backtrace_fn, data);
|
||||
profiling_insert(data[0], data);
|
||||
|
||||
arch_apic_init_perf(); // SDM LVT figure says a PMC irq masks itself, so unmask it
|
||||
reset_intel_pmc();
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <arch/backtrace.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static bool valid_rip(void *rip) {
|
||||
if ((uint64_t)rip < (uint64_t)0xffffffff80000000)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO 5-level paging support?
|
||||
static bool valid_frame(void *frame, void *old_frame) {
|
||||
if ((uint64_t)frame < (uint64_t)0xffff800000000000)
|
||||
return false;
|
||||
|
||||
if ((uint64_t)frame >= (uint64_t)0xffffffff80000000)
|
||||
return false;
|
||||
|
||||
if ((uint64_t)old_frame >= (uint64_t)frame)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void arch_get_backtrace(context_t *cpu_context, backtrace_fn_t fn, void *context) {
|
||||
if (!valid_rip((void *)cpu_context->rip))
|
||||
return;
|
||||
|
||||
if (!fn(context, (void *)cpu_context->rip))
|
||||
return;
|
||||
|
||||
size_t loops = 0;
|
||||
uint64_t *rbp = (uint64_t *)cpu_context->rbp;
|
||||
uint64_t *old_frame = NULL;
|
||||
for (;;) {
|
||||
if (!valid_frame(rbp, old_frame))
|
||||
return;
|
||||
|
||||
void *rip = (void *)*(rbp + 1);
|
||||
if (!valid_rip(rip))
|
||||
return;
|
||||
|
||||
if (!fn(context, rip))
|
||||
return;
|
||||
|
||||
old_frame = rbp;
|
||||
rbp = (uint64_t *)*rbp;
|
||||
|
||||
if (++loops == 256)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef _ARCH_BACKTRACE_H
|
||||
#define _ARCH_BACKTRACE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <arch/context.h>
|
||||
|
||||
typedef bool (*backtrace_fn_t)(void *ctx, void *ip);
|
||||
|
||||
void arch_get_backtrace(context_t *cpu_context, backtrace_fn_t fn, void *context);
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,18 @@
|
||||
#include <arch/smp.h>
|
||||
#include <printf.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <arch/backtrace.h>
|
||||
|
||||
static bool paniced = false;
|
||||
|
||||
static bool step_backtrace(void *, void *ip) {
|
||||
printf("%p\n", ip);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_backtrace(context_t *context, void *) {
|
||||
arch_get_backtrace(context, step_backtrace, NULL);
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void _panic(char *msg, context_t *ctx) {
|
||||
interrupt_set(false);
|
||||
@@ -17,5 +29,16 @@ __attribute__((noreturn)) void _panic(char *msg, context_t *ctx) {
|
||||
if (ctx)
|
||||
PRINT_CTX(ctx);
|
||||
|
||||
if (!paniced) {
|
||||
paniced = true;
|
||||
printf("backtrace:\n");
|
||||
if (ctx == NULL)
|
||||
arch_context_saveandcall(print_backtrace, NULL, NULL);
|
||||
else
|
||||
print_backtrace(ctx, NULL);
|
||||
} else {
|
||||
printf("!! DOUBLE PANIC !!\n");
|
||||
}
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user