use std::ops::ControlFlow;
use crate::{
debug::{
exception_handling::{ExceptionInfo, ExceptionInterface},
unwind_pc_without_debuginfo, DebugError, DebugInfo, DebugRegisters, StackFrame,
},
MemoryInterface, RegisterRole, RegisterValue,
};
pub struct XtensaExceptionHandler;
impl ExceptionInterface for XtensaExceptionHandler {
fn exception_details(
&self,
_memory: &mut dyn MemoryInterface,
_stackframe_registers: &DebugRegisters,
_debug_info: &DebugInfo,
) -> Result<Option<ExceptionInfo>, DebugError> {
Ok(None)
}
fn calling_frame_registers(
&self,
_memory: &mut dyn MemoryInterface,
_stackframe_registers: &crate::debug::DebugRegisters,
_raw_exception: u32,
) -> Result<crate::debug::DebugRegisters, DebugError> {
Err(DebugError::NotImplemented("calling frame registers"))
}
fn raw_exception(
&self,
_stackframe_registers: &crate::debug::DebugRegisters,
) -> Result<u32, DebugError> {
Err(DebugError::NotImplemented("raw exception"))
}
fn exception_description(
&self,
_raw_exception: u32,
_memory: &mut dyn MemoryInterface,
) -> Result<String, DebugError> {
Err(DebugError::NotImplemented("exception description"))
}
fn unwind_without_debuginfo(
&self,
unwind_registers: &mut DebugRegisters,
frame_pc: u64,
stack_frames: &[StackFrame],
instruction_set: Option<crate::InstructionSet>,
memory: &mut dyn MemoryInterface,
) -> ControlFlow<Option<DebugError>> {
unwind_pc_without_debuginfo(
unwind_registers,
frame_pc,
stack_frames,
instruction_set,
memory,
)?;
let Ok(fp) = unwind_registers.get_register_value_by_role(&RegisterRole::FramePointer)
else {
return ControlFlow::Break(None);
};
let sp = unwind_registers
.get_register_value_by_role(&RegisterRole::StackPointer)
.unwrap();
if sp.abs_diff(fp) >= 1024 * 1024 {
return ControlFlow::Continue(());
}
let mut stack_frame = [0; 2];
if let Err(e) = memory.read_32(fp - 16, &mut stack_frame) {
return ControlFlow::Break(Some(e.into()));
}
let [caller_ra, caller_sp] = stack_frame;
let unwound_fp = unwind_registers
.get_register_mut_by_role(&RegisterRole::FramePointer)
.unwrap();
unwound_fp.value = Some(RegisterValue::from(caller_sp));
let unwound_ra = unwind_registers
.get_register_mut_by_role(&RegisterRole::ReturnAddress)
.unwrap();
unwound_ra.value = Some(RegisterValue::from(caller_ra));
ControlFlow::Continue(())
}
}