mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +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();
|
arch_apic_init_perf();
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_backtrace(context_t *context, uintptr_t *data) {
|
static bool backtrace_fn(void *context, void *ip) {
|
||||||
if (IS_USER_ADDRESS(context->rip))
|
uint8_t *data = context;
|
||||||
return 0;
|
|
||||||
|
|
||||||
data[0] = context->rip;
|
if (data[0] == 255)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint64_t *rbp = (uint64_t *)context->rbp;
|
uintptr_t *trace = (uintptr_t *)&data[1];
|
||||||
uint8_t done = 1;
|
trace[data[0]] = (uintptr_t)ip;
|
||||||
|
data[0] += 1;
|
||||||
|
|
||||||
for (;;) {
|
return true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool intel_irq(context_t *context) {
|
static bool intel_irq(context_t *context) {
|
||||||
if ((rdmsr(MSR_PERF_GLOBAL_STATUS) & INTEL_TSC_INDEX_OFFSET) == 0)
|
if ((rdmsr(MSR_PERF_GLOBAL_STATUS) & INTEL_TSC_INDEX_OFFSET) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint8_t data[1 + sizeof(uintptr_t) * 256];
|
uint8_t data[1 + sizeof(uintptr_t) * 255];
|
||||||
|
data[0] = 0;
|
||||||
uint8_t size = get_backtrace(context, (uintptr_t *)(data + 1));
|
arch_get_backtrace(context, backtrace_fn, data);
|
||||||
*data = size;
|
profiling_insert(data[0], data);
|
||||||
profiling_insert(size, data);
|
|
||||||
|
|
||||||
arch_apic_init_perf(); // SDM LVT figure says a PMC irq masks itself, so unmask it
|
arch_apic_init_perf(); // SDM LVT figure says a PMC irq masks itself, so unmask it
|
||||||
reset_intel_pmc();
|
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 <arch/smp.h>
|
||||||
#include <printf.h>
|
#include <printf.h>
|
||||||
#include <kernel/interrupt.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) {
|
__attribute__((noreturn)) void _panic(char *msg, context_t *ctx) {
|
||||||
interrupt_set(false);
|
interrupt_set(false);
|
||||||
@@ -17,5 +29,16 @@ __attribute__((noreturn)) void _panic(char *msg, context_t *ctx) {
|
|||||||
if (ctx)
|
if (ctx)
|
||||||
PRINT_CTX(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 (;;);
|
for (;;);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user