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]
|
||||
rustflags = ["-Clink-arg=-Tgba.ld", "-Ctarget-cpu=arm7tdmi"]
|
||||
rustflags = [
|
||||
"-Clink-arg=-Tgba.ld",
|
||||
"-Ctarget-cpu=arm7tdmi",
|
||||
"-Cforce-frame-pointers=yes",
|
||||
]
|
||||
runner = "mgba-test-runner"
|
||||
|
||||
[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"
|
||||
|
|
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 agbabi;
|
||||
mod backtrace;
|
||||
mod bitarray;
|
||||
/// Implements everything relating to things that are displayed on screen.
|
||||
pub mod display;
|
||||
|
@ -317,11 +318,19 @@ pub mod test_runner {
|
|||
|
||||
#[panic_handler]
|
||||
fn panic_implementation(info: &core::panic::PanicInfo) -> ! {
|
||||
let frames = backtrace::unwind_exception();
|
||||
|
||||
if let Some(mut mgba) = mgba::Mgba::new() {
|
||||
mgba.print(format_args!("[failed]"), mgba::DebugLevel::Error)
|
||||
.unwrap();
|
||||
mgba.print(format_args!("Error: {info}"), mgba::DebugLevel::Fatal)
|
||||
.unwrap();
|
||||
let _ = mgba.print(format_args!("[failed]"), mgba::DebugLevel::Error);
|
||||
|
||||
for frame in frames {
|
||||
let _ = mgba.print(
|
||||
format_args!("{:#08x}", frame.address),
|
||||
mgba::DebugLevel::Error,
|
||||
);
|
||||
}
|
||||
|
||||
let _ = mgba.print(format_args!("Error: {info}"), mgba::DebugLevel::Fatal);
|
||||
}
|
||||
|
||||
loop {}
|
||||
|
|
Loading…
Reference in a new issue