mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Basic implementation of backtraces on panic
This commit is contained in:
parent
6fdd961b61
commit
7708398981
|
@ -6,9 +6,17 @@ build-std-features = ["compiler-builtins-mem"]
|
||||||
target = "thumbv4t-none-eabi"
|
target = "thumbv4t-none-eabi"
|
||||||
|
|
||||||
[target.thumbv4t-none-eabi]
|
[target.thumbv4t-none-eabi]
|
||||||
rustflags = ["-Clink-arg=-Tgba.ld", "-Ctarget-cpu=arm7tdmi"]
|
rustflags = [
|
||||||
|
"-Clink-arg=-Tgba.ld",
|
||||||
|
"-Ctarget-cpu=arm7tdmi",
|
||||||
|
"-Cforce-frame-pointers=yes",
|
||||||
|
]
|
||||||
runner = "mgba-test-runner"
|
runner = "mgba-test-runner"
|
||||||
|
|
||||||
[target.armv4t-none-eabi]
|
[target.armv4t-none-eabi]
|
||||||
rustflags = ["-Clink-arg=-Tgba.ld", "-Ctarget-cpu=arm7tdmi"]
|
rustflags = [
|
||||||
|
"-Clink-arg=-Tgba.ld",
|
||||||
|
"-Ctarget-cpu=arm7tdmi",
|
||||||
|
"-Cforce-frame-pointers=yes",
|
||||||
|
]
|
||||||
runner = "mgba-test-runner"
|
runner = "mgba-test-runner"
|
||||||
|
|
86
agb/src/backtrace.rs
Normal file
86
agb/src/backtrace.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use core::{arch::asm, ops::Index};
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
// only works for code compiled as THUMB
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Default, Debug)]
|
||||||
|
struct Context {
|
||||||
|
registers: [u32; 11],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Frame {
|
||||||
|
pub address: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
enum Register {
|
||||||
|
R0,
|
||||||
|
R1,
|
||||||
|
R2,
|
||||||
|
R3,
|
||||||
|
R4,
|
||||||
|
R5,
|
||||||
|
R6,
|
||||||
|
FP,
|
||||||
|
SP,
|
||||||
|
LR,
|
||||||
|
PC,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<Register> for Context {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn index(&self, index: Register) -> &Self::Output {
|
||||||
|
&self.registers[index as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub(crate) fn unwind_exception() -> Vec<Frame> {
|
||||||
|
let mut context = Context::default();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let context_ptr = (&mut context) as *mut _;
|
||||||
|
|
||||||
|
asm!(
|
||||||
|
"
|
||||||
|
str r0, [r0, #0x00]
|
||||||
|
str r1, [r0, #0x04]
|
||||||
|
str r2, [r0, #0x08]
|
||||||
|
str r3, [r0, #0x0C]
|
||||||
|
str r4, [r0, #0x10]
|
||||||
|
str r5, [r0, #0x14]
|
||||||
|
str r6, [r0, #0x18]
|
||||||
|
str r7, [r0, #0x1C]
|
||||||
|
mov r7, sp
|
||||||
|
str r7, [r0, #0x20]
|
||||||
|
mov r7, lr
|
||||||
|
str r7, [r0, #0x24]
|
||||||
|
mov r7, pc
|
||||||
|
str r7, [r0, #0x28]
|
||||||
|
ldr r7, [r0, #0x1C]
|
||||||
|
",
|
||||||
|
in("r0") context_ptr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut frame_pointer = context[Register::FP];
|
||||||
|
|
||||||
|
let mut frames = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let sp = unsafe { *(frame_pointer as *const u32) };
|
||||||
|
let lr = unsafe { *((frame_pointer as *const u32).add(1)) };
|
||||||
|
|
||||||
|
if sp == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames.push(Frame { address: lr });
|
||||||
|
|
||||||
|
frame_pointer = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames
|
||||||
|
}
|
|
@ -150,6 +150,7 @@ extern crate alloc;
|
||||||
mod agb_alloc;
|
mod agb_alloc;
|
||||||
|
|
||||||
mod agbabi;
|
mod agbabi;
|
||||||
|
mod backtrace;
|
||||||
mod bitarray;
|
mod bitarray;
|
||||||
/// Implements everything relating to things that are displayed on screen.
|
/// Implements everything relating to things that are displayed on screen.
|
||||||
pub mod display;
|
pub mod display;
|
||||||
|
@ -317,11 +318,19 @@ pub mod test_runner {
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic_implementation(info: &core::panic::PanicInfo) -> ! {
|
fn panic_implementation(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
let frames = backtrace::unwind_exception();
|
||||||
|
|
||||||
if let Some(mut mgba) = mgba::Mgba::new() {
|
if let Some(mut mgba) = mgba::Mgba::new() {
|
||||||
mgba.print(format_args!("[failed]"), mgba::DebugLevel::Error)
|
let _ = mgba.print(format_args!("[failed]"), mgba::DebugLevel::Error);
|
||||||
.unwrap();
|
|
||||||
mgba.print(format_args!("Error: {info}"), mgba::DebugLevel::Fatal)
|
for frame in frames {
|
||||||
.unwrap();
|
let _ = mgba.print(
|
||||||
|
format_args!("{:#08x}", frame.address),
|
||||||
|
mgba::DebugLevel::Error,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = mgba.print(format_args!("Error: {info}"), mgba::DebugLevel::Fatal);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
|
|
Loading…
Reference in a new issue