diff --git a/src/aarch64/dwarf.rs b/src/aarch64/dwarf.rs index 1861e03..9b49f7a 100644 --- a/src/aarch64/dwarf.rs +++ b/src/aarch64/dwarf.rs @@ -11,6 +11,7 @@ use crate::dwarf::{ eval_cfa_rule, eval_register_rule, ConversionError, DwarfUnwindRegs, DwarfUnwinderError, DwarfUnwinding, }; +use crate::FrameAddress; impl DwarfUnwindRegs for UnwindRegsAarch64 { fn get(&self, register: Register) -> Option { @@ -79,7 +80,9 @@ impl DwarfUnwinding for ArchAarch64 { regs.set_sp(cfa); regs.set_lr(lr); - Ok(UnwindResult::Uncacheable(lr)) + Ok(UnwindResult::Uncacheable( + FrameAddress::from_return_address(lr), + )) } fn rule_if_uncovered_by_fde() -> Self::UnwindRule { diff --git a/src/aarch64/pe.rs b/src/aarch64/pe.rs index 2c1e0d2..9843bcf 100644 --- a/src/aarch64/pe.rs +++ b/src/aarch64/pe.rs @@ -4,10 +4,11 @@ use crate::unwind_result::UnwindResult; impl PeUnwinding for ArchAarch64 { fn unwind_frame( - _sections: PeSections, - _address: u32, - _regs: &mut Self::UnwindRegs, - _read_stack: &mut F, + sections: PeSections, + address: u32, + regs: &mut Self::UnwindRegs, + is_first_frame: bool, + read_stack: &mut F, ) -> Result, PeUnwinderError> where F: FnMut(u64) -> Result, diff --git a/src/aarch64/unwinder.rs b/src/aarch64/unwinder.rs index 96bf02b..4fc8bd3 100644 --- a/src/aarch64/unwinder.rs +++ b/src/aarch64/unwinder.rs @@ -54,7 +54,7 @@ impl, P: AllocationPolicy> Unwinder for UnwinderAarch regs: &mut UnwindRegsAarch64, cache: &mut CacheAarch64, read_stack: &mut F, - ) -> Result, Error> + ) -> Result, Error> where F: FnMut(u64) -> Result, { diff --git a/src/pe.rs b/src/pe.rs index 2e2ca0b..0a2dd38 100644 --- a/src/pe.rs +++ b/src/pe.rs @@ -71,6 +71,7 @@ pub trait PeUnwinding: Arch { sections: PeSections, address: u32, regs: &mut Self::UnwindRegs, + is_first_frame: bool, read_stack: &mut F, ) -> Result, PeUnwinderError> where diff --git a/src/unwind_result.rs b/src/unwind_result.rs index 57f6aae..fadd412 100644 --- a/src/unwind_result.rs +++ b/src/unwind_result.rs @@ -1,5 +1,7 @@ +use crate::FrameAddress; + #[derive(Debug, Clone)] pub enum UnwindResult { ExecRule(R), - Uncacheable(u64), + Uncacheable(Option), } diff --git a/src/unwinder.rs b/src/unwinder.rs index 667f485..b657468 100644 --- a/src/unwinder.rs +++ b/src/unwinder.rs @@ -66,7 +66,7 @@ pub trait Unwinder { regs: &mut Self::UnwindRegs, cache: &mut Self::Cache, read_stack: &mut F, - ) -> Result, Error> + ) -> Result, Error> where F: FnMut(u64) -> Result; @@ -164,8 +164,6 @@ impl<'u, 'c, 'r, U: Unwinder + ?Sized, F: FnMut(u64) -> Result> }; match next { Some(return_address) => { - let return_address = FrameAddress::from_return_address(return_address) - .ok_or(Error::ReturnAddressIsNull)?; self.state = UnwindIteratorState::Unwinding(return_address); Ok(Some(return_address)) } @@ -308,7 +306,7 @@ impl< cache: &mut Cache, read_stack: &mut F, callback: G, - ) -> Result, Error> + ) -> Result, Error> where F: FnMut(u64) -> Result, G: FnOnce( @@ -327,7 +325,9 @@ impl< .lookup(lookup_address, self.modules_generation) { CacheResult::Hit(unwind_rule) => { - return unwind_rule.exec(is_first_frame, regs, read_stack); + return Ok(unwind_rule + .exec(is_first_frame, regs, read_stack)? + .and_then(FrameAddress::from_return_address)); } CacheResult::Miss(handle) => handle, }; @@ -345,9 +345,7 @@ impl< read_stack, ) { Ok(UnwindResult::ExecRule(rule)) => rule, - Ok(UnwindResult::Uncacheable(return_address)) => { - return Ok(Some(return_address)) - } + Ok(UnwindResult::Uncacheable(return_address)) => return Ok(return_address), Err(_err) => { // eprintln!("Unwinder error: {}", err); A::UnwindRule::fallback_rule() @@ -356,7 +354,9 @@ impl< } }; cache.rule_cache.insert(cache_handle, unwind_rule); - unwind_rule.exec(is_first_frame, regs, read_stack) + Ok(unwind_rule + .exec(is_first_frame, regs, read_stack)? + .and_then(FrameAddress::from_return_address)) } pub fn unwind_frame( @@ -365,7 +365,7 @@ impl< regs: &mut A::UnwindRegs, cache: &mut Cache, read_stack: &mut F, - ) -> Result, Error> + ) -> Result, Error> where F: FnMut(u64) -> Result, { @@ -538,6 +538,7 @@ impl< }, rel_lookup_address, regs, + is_first_frame, read_stack, )?, ModuleUnwindDataInternal::None => return Err(UnwinderError::NoModuleUnwindData), diff --git a/src/x86_64/dwarf.rs b/src/x86_64/dwarf.rs index a7d2ac7..04c56d7 100644 --- a/src/x86_64/dwarf.rs +++ b/src/x86_64/dwarf.rs @@ -9,6 +9,7 @@ use crate::dwarf::{ DwarfUnwinding, }; use crate::unwind_result::UnwindResult; +use crate::FrameAddress; impl DwarfUnwindRegs for UnwindRegsX86_64 { fn get(&self, register: Register) -> Option { @@ -74,7 +75,9 @@ impl DwarfUnwinding for ArchX86_64 { regs.set_bp(new_bp); regs.set_sp(cfa); - Ok(UnwindResult::Uncacheable(return_address)) + Ok(UnwindResult::Uncacheable( + FrameAddress::from_return_address(return_address), + )) } fn rule_if_uncovered_by_fde() -> Self::UnwindRule { diff --git a/src/x86_64/pe.rs b/src/x86_64/pe.rs index 2392542..596a536 100644 --- a/src/x86_64/pe.rs +++ b/src/x86_64/pe.rs @@ -8,6 +8,7 @@ use crate::pe::{PeSections, PeUnwinderError, PeUnwinding}; use crate::unwind_result::UnwindResult; use std::ops::ControlFlow; +use crate::FrameAddress; use pe_unwind_info::x86_64::{ FunctionEpilogInstruction, FunctionTableEntries, Register, UnwindInfo, UnwindInfoTrailer, UnwindOperation, UnwindState, @@ -97,6 +98,7 @@ impl PeUnwinding for ArchX86_64 { sections: PeSections, address: u32, regs: &mut Self::UnwindRegs, + is_first_frame: bool, read_stack: &mut F, ) -> Result, PeUnwinderError> where @@ -117,53 +119,58 @@ impl PeUnwinding for ArchX86_64 { UnwindInfo::parse(sections.unwind_info_memory_at_rva(unwind_info_address)?) .ok_or(PeUnwinderError::UnwindInfoParseError)?; - // Check whether the address is in the function epilog. If so, we need to - // simulate the remaining epilog instructions (unwind codes don't account for - // unwinding from the epilog). We only need to check this for the first unwind info (if - // there are chained infos). - let bytes = (function.end_address.get() - address) as usize; - let instruction = §ions.text_memory_at_rva(address)?[..bytes]; - if let Ok(epilog_instructions) = - FunctionEpilogInstruction::parse_sequence(instruction, unwind_info.frame_register()) - { - // If the epilog is an optional AddSP followed by Pops, we can return a cache - // rule. - if let Some(rule) = - UnwindRuleX86_64::for_sequence_of_offset_or_pop(epilog_instructions.iter()) + if is_first_frame { + // Check whether the address is in the function epilog. If so, we need to + // simulate the remaining epilog instructions (unwind codes don't account for + // unwinding from the epilog). We only need to check this for the first unwind info (if + // there are chained infos). + let bytes = (function.end_address.get() - address) as usize; + let instruction = §ions.text_memory_at_rva(address)?[..bytes]; + if let Ok(epilog_instructions) = + FunctionEpilogInstruction::parse_sequence(instruction, unwind_info.frame_register()) { - return Ok(UnwindResult::ExecRule(rule)); - } + // If the epilog is an optional AddSP followed by Pops, we can return a cache + // rule. + if let Some(rule) = + UnwindRuleX86_64::for_sequence_of_offset_or_pop(epilog_instructions.iter()) + { + return Ok(UnwindResult::ExecRule(rule)); + } - for instruction in epilog_instructions.iter() { - match instruction { - FunctionEpilogInstruction::AddSP(offset) => { - let rsp = regs.get(Reg::RSP); - regs.set(Reg::RSP, rsp + *offset as u64); - } - FunctionEpilogInstruction::AddSPFromFP(offset) => { - let fp = unwind_info - .frame_register() - .expect("invalid fp register offset"); - let fp = convert_pe_register(fp); - let fp = regs.get(fp); - regs.set(Reg::RSP, fp + *offset as u64); - } - FunctionEpilogInstruction::Pop(reg) => { - let rsp = regs.get(Reg::RSP); - let val = read_stack_err(read_stack, rsp)?; - regs.set(convert_pe_register(*reg), val); - regs.set(Reg::RSP, rsp + 8); + for instruction in epilog_instructions.iter() { + match instruction { + FunctionEpilogInstruction::AddSP(offset) => { + let rsp = regs.get(Reg::RSP); + regs.set(Reg::RSP, rsp + *offset as u64); + } + FunctionEpilogInstruction::AddSPFromFP(offset) => { + let fp = unwind_info + .frame_register() + .expect("invalid fp register offset"); + let fp = convert_pe_register(fp); + let fp = regs.get(fp); + regs.set(Reg::RSP, fp + *offset as u64); + } + FunctionEpilogInstruction::Pop(reg) => { + let rsp = regs.get(Reg::RSP); + let val = read_stack_err(read_stack, rsp)?; + regs.set(convert_pe_register(*reg), val); + regs.set(Reg::RSP, rsp + 8); + } } } - } - let rsp = regs.get(Reg::RSP); - let ra = read_stack_err(read_stack, rsp)?; - regs.set(Reg::RSP, rsp + 8); + let rsp = regs.get(Reg::RSP); + let ra = read_stack_err(read_stack, rsp)?; + regs.set(Reg::RSP, rsp + 8); - return Ok(UnwindResult::Uncacheable(ra)); + return Ok(UnwindResult::Uncacheable( + FrameAddress::from_return_address(ra), + )); + } } + // Get all chained UnwindInfo and resolve errors when collecting. let chained_info = std::iter::successors(Some(Ok(unwind_info)), |info| { let Ok(info) = info else { @@ -207,7 +214,9 @@ impl PeUnwinding for ArchX86_64 { .resolve_operation(&mut state, &op) .ok_or(PeUnwinderError::MissingStackData(None))? { - return Ok(UnwindResult::Uncacheable(ra)); + return Ok(UnwindResult::Uncacheable(Some( + FrameAddress::from_instruction_pointer(ra), + ))); } } @@ -215,6 +224,8 @@ impl PeUnwinding for ArchX86_64 { let ra = read_stack_err(read_stack, rsp)?; regs.set(Reg::RSP, rsp + 8); - Ok(UnwindResult::Uncacheable(ra)) + Ok(UnwindResult::Uncacheable( + FrameAddress::from_return_address(ra), + )) } } diff --git a/src/x86_64/unwinder.rs b/src/x86_64/unwinder.rs index b765411..8f7da07 100644 --- a/src/x86_64/unwinder.rs +++ b/src/x86_64/unwinder.rs @@ -55,7 +55,7 @@ impl, P: AllocationPolicy> Unwinder for UnwinderX86_6 regs: &mut UnwindRegsX86_64, cache: &mut CacheX86_64, read_stack: &mut F, - ) -> Result, Error> + ) -> Result, Error> where F: FnMut(u64) -> Result, { diff --git a/tests/integration_tests/linux.rs b/tests/integration_tests/linux.rs index 4caee3b..06f226a 100644 --- a/tests/integration_tests/linux.rs +++ b/tests/integration_tests/linux.rs @@ -55,7 +55,7 @@ fn test_plt_cfa_expr() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x123456))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x123456))); assert_eq!(regs.sp(), 0x38); assert_eq!(regs.bp(), 0x345); } @@ -117,7 +117,10 @@ fn test_pthread_cfa_expr() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x7f54b14fc000 + 0x9436))); + assert_eq!( + res, + Ok(FrameAddress::from_return_address(0x7f54b14fc000 + 0x9436)) + ); assert_eq!(regs.sp(), 0x10); assert_eq!(regs.bp(), 0x120); @@ -127,7 +130,10 @@ fn test_pthread_cfa_expr() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x7f54b14fc000 + 0x8c2c))); + assert_eq!( + res, + Ok(FrameAddress::from_return_address(0x7f54b14fc000 + 0x8c2c)) + ); assert_eq!(regs.sp(), 0x90); assert_eq!(regs.bp(), 0x120); @@ -139,7 +145,7 @@ fn test_pthread_cfa_expr() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0xbe7042))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0xbe7042))); assert_eq!(regs.sp(), 0x130); assert_eq!(regs.bp(), 0x1234); } @@ -170,7 +176,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -184,7 +190,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -196,7 +202,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -208,7 +214,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x5b4))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x5b4))); assert_eq!(regs.sp(), 0x40); assert_eq!(regs.fp(), 0x40); assert_eq!(regs.lr(), 0x5b4); @@ -220,7 +226,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x5b4))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x5b4))); assert_eq!(regs.sp(), 0x40); assert_eq!(regs.fp(), 0x40); assert_eq!(regs.lr(), 0x5b4); @@ -232,7 +238,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x5b4))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x5b4))); assert_eq!(regs.sp(), 0x40); assert_eq!(regs.fp(), 0x40); assert_eq!(regs.lr(), 0x5b4); @@ -242,7 +248,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -254,7 +260,7 @@ fn test_no_eh_frame_hdr() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -317,7 +323,7 @@ fn test_epilogue_bp_already_popped() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x123456))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x123456))); assert_eq!(regs.sp(), 0x338); assert_eq!(regs.bp(), 0x348); } @@ -372,7 +378,7 @@ fn test_libc_syscall_no_fde() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x123456))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x123456))); assert_eq!(regs.sp(), 0x338); assert_eq!(regs.bp(), 0x348); } diff --git a/tests/integration_tests/macos.rs b/tests/integration_tests/macos.rs index ef5ceed..2ae8098 100644 --- a/tests/integration_tests/macos.rs +++ b/tests/integration_tests/macos.rs @@ -44,7 +44,10 @@ fn test_basic() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x1003fc000 + 0xe4830))); + assert_eq!( + res, + Ok(FrameAddress::from_return_address(0x1003fc000 + 0xe4830)) + ); assert_eq!(regs.sp(), 0x10); let res = unwinder.unwind_frame( FrameAddress::from_return_address(0x1003fc000 + 0xe4830).unwrap(), @@ -52,7 +55,10 @@ fn test_basic() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x1003fc000 + 0x100dc4))); + assert_eq!( + res, + Ok(FrameAddress::from_return_address(0x1003fc000 + 0x100dc4)) + ); assert_eq!(regs.sp(), 0x30); assert_eq!(regs.fp(), 0x40); let res = unwinder.unwind_frame( @@ -61,7 +67,10 @@ fn test_basic() { &mut cache, &mut read_stack, ); - assert_eq!(res, Ok(Some(0x1003fc000 + 0x12ca28))); + assert_eq!( + res, + Ok(FrameAddress::from_return_address(0x1003fc000 + 0x12ca28)) + ); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); let res = unwinder.unwind_frame( @@ -253,7 +262,10 @@ fn test_epilogue() { &mut read_stack, ); // The result after unwinding should always be the same. - assert_eq!(res, Ok(Some(0x1003fc000 + 0xe4830))); + assert_eq!( + res, + Ok(FrameAddress::from_return_address(0x1003fc000 + 0xe4830)) + ); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); }; @@ -348,7 +360,7 @@ fn test_prologue_nofp() { &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); // The result after unwinding should always be the same. - assert_eq!(res, Ok(Some(0xe4830))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0xe4830))); assert_eq!(regs.sp(), 0x140); assert_eq!(regs.fp(), 0x1e0); }; @@ -449,7 +461,7 @@ fn test_prologue_fp() { &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); // The result after unwinding should always be the same. - assert_eq!(res, Ok(Some(0x10030))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x10030))); assert_eq!(regs.sp(), 0x140); assert_eq!(regs.fp(), 0x10029); }; @@ -494,7 +506,7 @@ fn test_prologue_fp_2() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x10030))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x10030))); assert_eq!(regs.sp(), 0x80); assert_eq!(regs.fp(), 0x10029); } @@ -546,7 +558,7 @@ fn test_prologue_epilogue_x86_64_fp() { &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); // The result after unwinding should always be the same. - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x140); assert_eq!(regs.bp(), 0x160); }; @@ -646,7 +658,7 @@ fn test_prologue_epilogue_tail_call_x86_64_nofp() { &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); // The result after unwinding should always be the same. - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x100); assert_eq!(regs.bp(), 0x120); }; @@ -743,7 +755,7 @@ fn test_prologue_epilogue_rbp_x86_64_nofp() { &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); // The result after unwinding should always be the same. - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x100); assert_eq!(regs.bp(), 0x120); }; @@ -842,7 +854,7 @@ fn test_frameless_indirect_x86_64_nofp() { &mut cache, &mut |addr| s.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x1000); assert_eq!(regs.bp(), 0x1020); } @@ -897,7 +909,7 @@ fn test_uncovered_x86_64_fp() { &mut cache, &mut |addr| s.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x100); assert_eq!(regs.bp(), 0x120); @@ -909,7 +921,7 @@ fn test_uncovered_x86_64_fp() { &mut cache, &mut |addr| s.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x100); assert_eq!(regs.bp(), 0x120); } @@ -940,7 +952,7 @@ fn test_prologue_x86_64_sub_with_32_bit_immediate() { &mut cache, &mut |addr| s.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x200); assert_eq!(regs.bp(), 0x220); } @@ -971,7 +983,7 @@ fn test_stubs_x86_64() { &mut cache, &mut |addr| s.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x100); assert_eq!(regs.bp(), 0x120); } @@ -1004,7 +1016,7 @@ fn test_stubs_x86_64_xul() { &mut cache, &mut |addr| s.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x12345))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x12345))); assert_eq!(regs.sp(), 0x100); assert_eq!(regs.bp(), 0x120); } @@ -1058,7 +1070,7 @@ fn test_go_zdebug_frame() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -1071,7 +1083,7 @@ fn test_go_zdebug_frame() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -1084,7 +1096,7 @@ fn test_go_zdebug_frame() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); // assert_eq!(regs.fp(), 0x70); // Go debug_frame does not say how to restore fp assert_eq!(regs.lr(), 0x1234); @@ -1096,7 +1108,7 @@ fn test_go_zdebug_frame() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); // assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234); @@ -1108,7 +1120,7 @@ fn test_go_zdebug_frame() { &mut cache, &mut |addr| stack.get((addr / 8) as usize).cloned().ok_or(()), ); - assert_eq!(res, Ok(Some(0x1234))); + assert_eq!(res, Ok(FrameAddress::from_return_address(0x1234))); assert_eq!(regs.sp(), 0x50); // assert_eq!(regs.fp(), 0x70); assert_eq!(regs.lr(), 0x1234);