diff --git a/artiq/firmware/libunwind_backtrace/lib.rs b/artiq/firmware/libunwind_backtrace/lib.rs index d1c71cf45..22c55a628 100644 --- a/artiq/firmware/libunwind_backtrace/lib.rs +++ b/artiq/firmware/libunwind_backtrace/lib.rs @@ -32,9 +32,7 @@ pub fn backtrace(f: F) -> Result<(), uw::_Unwind_Reason_Code> trace_context.prev_sp = cur_sp; } - // GetIP gives us the return address, i.e. the address after the delay slot, - // but we're interested in the call instruction. - (trace_context.step_fn)(uw::_Unwind_GetIP(context) - 2 * 4); + (trace_context.step_fn)(uw::_Unwind_GetIP(context)); uw::_URC_NO_REASON } } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 087f69167..f0bef4108 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -313,7 +313,9 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, println!("backtrace for software version {}:", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); let _ = unwind_backtrace::backtrace(|ip| { - println!("{:#08x}", ip); + // Backtrace gives us the return address, i.e. the address after the delay slot, + // but we're interested in the call instruction. + println!("{:#08x}", ip - 2 * 4); }); if config::read_str("panic_reset", |r| r == Ok("1")) { diff --git a/artiq/firmware/runtime/profiler.rs b/artiq/firmware/runtime/profiler.rs index 9765100cc..ac5097dfe 100644 --- a/artiq/firmware/runtime/profiler.rs +++ b/artiq/firmware/runtime/profiler.rs @@ -201,7 +201,7 @@ mod imp { const SKIP_FRAMES: i32 = 3; #[inline(always)] // make the top of backtrace predictable - fn record(profile: &mut Profile, pc: usize) -> Result<(), ()> { + fn record(profile: &mut Profile, exn_pc: usize) -> Result<(), ()> { let mut result = Ok(()); let mut frame = -SKIP_FRAMES; @@ -212,6 +212,12 @@ mod imp { if profile.has_edges() { let mut prev_pc = 0; let _ = backtrace(|pc| { + // Backtrace gives us the return address, i.e. the address after the delay slot, + // but we're interested in the call instruction, *except* when going through + // the frame directly below the exception frame, which has the address that's + // being executed. + let pc = if pc != exn_pc { pc - 2 * 4 } else { pc }; + if frame == 0 { result = result.and_then(|()| profile.record_hit(Address::new(pc))); @@ -221,6 +227,7 @@ mod imp { profile.record_edge(Address::new(pc), Address::new(prev_pc))); } + prev_pc = pc; frame += 1; }); @@ -229,7 +236,7 @@ mod imp { // If we couldn't get anything useful out of a backtrace, at least // record a hit at the exception PC. if frame <= 0 { - result = profile.record_hit(Address::new(pc)); + result = profile.record_hit(Address::new(exn_pc)); } result