use crate::{DebugError, DebugRegisters, StackFrame, get_object_reference};
use bitfield::bitfield;
use probe_rs::{Error, MemoryInterface, RegisterRole, RegisterValue};
use super::{ExceptionInfo, ExceptionInterface};
pub(crate) static EXCEPTION_STACK_REGISTERS: &[RegisterRole] = &[
RegisterRole::Core("R0"),
RegisterRole::Core("R1"),
RegisterRole::Core("R2"),
RegisterRole::Core("R3"),
RegisterRole::Core("R12"),
RegisterRole::ReturnAddress,
RegisterRole::ProgramCounter,
RegisterRole::ProcessorStatus,
];
bitfield! {
pub struct ExcReturn(u32);
impl Debug;
pub is_exception_flag, _: 31, 28;
pub use_standard_stackframe, _: 4;
pub return_to_thread, _: 3;
pub use_process_stack, _: 2;
pub always_0b01, _: 1,0;
}
bitfield! {
#[derive(Copy, Clone)]
pub struct Xpsr(u32);
impl Debug;
pub apsr_n_bit, _: 31;
pub apsr_z_bit, _: 30;
pub apsr_c_bit, _: 29;
pub apsr_v_bit, _: 28;
pub stack_was_realigned, _:9;
pub exception_number, _: 8,0;
}
pub(crate) fn exception_details(
exception_interface: &impl ExceptionInterface,
memory_interface: &mut dyn MemoryInterface,
stackframe_registers: &DebugRegisters,
) -> Result<Option<ExceptionInfo>, DebugError> {
let frame_return_address = get_stack_frame_return_address(stackframe_registers)?;
let frame_return_address = ExcReturn(frame_return_address);
if frame_return_address.is_exception_flag() != 0xF {
return Ok(None);
}
let raw_exception = exception_interface.raw_exception(stackframe_registers)?;
if raw_exception == 1 {
let mut stackframe_registers = stackframe_registers.clone();
for stackframe_register in &mut stackframe_registers.0 {
stackframe_register.value = None;
}
return Ok(Some(ExceptionInfo {
raw_exception,
description: "Reset".to_string(),
handler_frame: StackFrame {
id: get_object_reference(),
function_name: "Reset".to_string(),
source_location: None,
registers: stackframe_registers.clone(),
pc: RegisterValue::U32(0),
frame_base: None,
is_inlined: false,
local_variables: None,
canonical_frame_address: None,
},
}));
}
let mut registers = exception_interface.calling_frame_registers(
memory_interface,
stackframe_registers,
raw_exception,
)?;
let description = exception_interface.exception_description(raw_exception, memory_interface)?;
let exception_frame_pc = registers.get_register_mut_by_role(&RegisterRole::ProgramCounter)?;
let pc_value = exception_frame_pc.value.unwrap();
let mut handler_frame = StackFrame {
id: get_object_reference(),
function_name: description.clone(),
source_location: None,
registers,
pc: pc_value,
frame_base: None,
is_inlined: false,
local_variables: None,
canonical_frame_address: None,
};
let frame_size = if frame_return_address.use_standard_stackframe() {
0x20usize
} else {
0x68
};
let sp = handler_frame
.registers
.get_register_mut_by_role(&RegisterRole::StackPointer)?;
if let Some(sp_value) = sp.value.as_mut() {
sp_value.increment_address(frame_size)?;
}
Ok(Some(ExceptionInfo {
raw_exception,
description,
handler_frame,
}))
}
fn get_stack_frame_return_address(stackframe_registers: &DebugRegisters) -> Result<u32, Error> {
let frame_return_address: u32 = stackframe_registers
.get_return_address()
.ok_or_else(|| {
Error::Register("No Return Address register. Please report this as a bug.".to_string())
})?
.value
.ok_or_else(|| {
Error::Register(
"No value for Return Address register. Please report this as a bug.".to_string(),
)
})?
.try_into()?;
Ok(frame_return_address)
}
pub(crate) fn raw_exception(stackframe_registers: &DebugRegisters) -> Result<u32, Error> {
let mut exception_number = Xpsr(
stackframe_registers.get_register_value_by_role(&RegisterRole::ProcessorStatus)? as u32,
)
.exception_number();
if exception_number == 0
&& stackframe_registers.get_register_value_by_role(&RegisterRole::ReturnAddress)?
== 0xFFFF_FFFF
{
exception_number = 1;
}
Ok(exception_number)
}
pub(crate) fn calling_frame_registers(
memory: &mut dyn MemoryInterface,
stackframe_registers: &DebugRegisters,
) -> Result<DebugRegisters, Error> {
let exception_context_address: u32 =
stackframe_registers.get_register_value_by_role(&RegisterRole::StackPointer)? as u32;
let mut calling_stack_registers = vec![0u32; EXCEPTION_STACK_REGISTERS.len()];
memory.read_32(
(exception_context_address).into(),
&mut calling_stack_registers,
)?;
let mut calling_frame_registers = stackframe_registers.clone();
for (i, register_role) in EXCEPTION_STACK_REGISTERS.iter().enumerate() {
calling_frame_registers
.get_register_mut_by_role(register_role)?
.value = Some(RegisterValue::U32(calling_stack_registers[i]));
}
Ok(calling_frame_registers)
}