From d9c71ffc7ccab61dc11a984ac9d7072aee6757c9 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 8 Mar 2019 12:45:17 +1000 Subject: [PATCH] cfi: fix parsing of function relative pointers Also move this out of `BaseAddresses` so that it's easier to be sure we are setting it correctly. --- examples/dwarfdump.rs | 3 +++ src/read/cfi.rs | 31 ++++++++++------------- src/read/mod.rs | 59 +++++++++++++++++++++---------------------- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index b2e954779..861122d86 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -661,6 +661,9 @@ fn dump_eh_frame( fde.len(), fde.initial_address() + fde.len() )?; + if let Some(gimli::Pointer::Direct(lsda)) = fde.lsda() { + writeln!(w, " lsda: {:#018x}", lsda)?; + } dump_cfi_instructions(w, fde.instructions(), false, register_name)?; writeln!(w)?; } diff --git a/src/read/cfi.rs b/src/read/cfi.rs index 6c31c39bc..8a8ca555c 100644 --- a/src/read/cfi.rs +++ b/src/read/cfi.rs @@ -1,7 +1,6 @@ use crate::boxed::Box; use arrayvec::ArrayVec; use fallible_iterator::FallibleIterator; -use std::cell::RefCell; use std::cmp::{Ord, Ordering}; use std::fmt::Debug; use std::iter::FromIterator; @@ -146,6 +145,7 @@ impl EhFrameHdr { let eh_frame_ptr = parse_encoded_pointer( eh_frame_ptr_enc, &bases.eh_frame_hdr, + None, address_size, &self.0, &mut reader, @@ -153,6 +153,7 @@ impl EhFrameHdr { let fde_count = parse_encoded_pointer( fde_count_enc, &bases.eh_frame_hdr, + None, address_size, &self.0, &mut reader, @@ -248,6 +249,7 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { let pivot = parse_encoded_pointer( self.hdr.table_enc, &bases.eh_frame_hdr, + None, self.hdr.address_size, &self.hdr.section, &mut reader, @@ -278,6 +280,7 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { parse_encoded_pointer( self.hdr.table_enc, &bases.eh_frame_hdr, + None, self.hdr.address_size, &self.hdr.section, &mut reader, @@ -867,10 +870,6 @@ pub struct SectionBaseAddresses { /// For pointers in the `.eh_frame` section, this is generally the /// global pointer, such as the address of the `.got` section. pub data: Option, - - // Unlike the others, the function base is managed internally to the parser - // as we enter and exit FDE parsing. - pub(crate) func: RefCell>, } impl BaseAddresses { @@ -966,10 +965,6 @@ where return Ok(None); } - // Clear any function relative base address, if one was set when parsing - // the last entry. - self.bases.eh_frame.func.borrow_mut().take(); - match parse_cfi_entry(self.bases, &self.section, &mut self.input) { Err(e) => { self.input.empty(); @@ -1135,6 +1130,7 @@ impl Augmentation { let personality = parse_encoded_pointer( encoding, &bases.eh_frame, + None, address_size, section.section(), rest, @@ -1164,6 +1160,7 @@ impl AugmentationData { fn parse( augmentation: &Augmentation, bases: &BaseAddresses, + fde_address: u64, address_size: u8, section: &Section, input: &mut R, @@ -1185,6 +1182,7 @@ impl AugmentationData { let lsda = parse_encoded_pointer( encoding, &bases.eh_frame, + Some(fde_address), address_size, section.section(), rest, @@ -1517,12 +1515,6 @@ impl FrameDescriptionEntry { Section: UnwindSection, F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result>, { - { - let mut func = bases.eh_frame.func.borrow_mut(); - let offset = rest.offset_from(section.section()); - *func = Some(offset.into_u64()); - } - let cie = get_cie(section, bases, cie_pointer)?; let initial_segment = if cie.segment_size > 0 { @@ -1538,6 +1530,7 @@ impl FrameDescriptionEntry { Some(AugmentationData::parse( augmentation, bases, + initial_address, cie.address_size, section, &mut rest, @@ -1572,6 +1565,7 @@ impl FrameDescriptionEntry { let initial_address = parse_encoded_pointer( encoding, &bases.eh_frame, + None, cie.address_size, section.section(), input, @@ -1585,6 +1579,7 @@ impl FrameDescriptionEntry { let address_range = parse_encoded_pointer( encoding.format(), &bases.eh_frame, + None, cie.address_size, section.section(), input, @@ -6154,7 +6149,7 @@ mod tests { initial_address: 0xfeed_face, address_range: 9000, augmentation: Some(AugmentationData { - lsda: Some(Pointer::Direct(1)), + lsda: Some(Pointer::Direct(0xbeef)), }), instructions: EndianSlice::new(&instrs, LittleEndian), }; @@ -6171,8 +6166,8 @@ mod tests { let section = kind.section(§ion); let input = &mut section.section().range_from(10..); - // Adjust the FDE's augmentation to be relative to the section. - fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(19)); + // Adjust the FDE's augmentation to be relative to the function. + fde.augmentation.as_mut().unwrap().lsda = Some(Pointer::Direct(0xfeed_face + 0xbeef)); let result = parse_fde(section, input, |_, _, _| Ok(cie.clone())); assert_eq!(result, Ok(fde)); diff --git a/src/read/mod.rs b/src/read/mod.rs index 1c43ba54c..975461be3 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -624,6 +624,7 @@ impl Pointer { pub(crate) fn parse_encoded_pointer<'bases, R: Reader>( encoding: constants::DwEhPe, bases: &'bases SectionBaseAddresses, + func_base: Option, address_size: u8, section: &R, input: &mut R, @@ -701,8 +702,7 @@ pub(crate) fn parse_encoded_pointer<'bases, R: Reader>( } } constants::DW_EH_PE_funcrel => { - let func = bases.func.borrow(); - if let Some(func) = *func { + if let Some(func) = func_base { let offset = parse_data(encoding, address_size, input)?; Ok(Pointer::new(encoding, func.wrapping_add(offset))) } else { @@ -732,7 +732,6 @@ mod tests { use crate::constants; use crate::endianity::LittleEndian; use crate::test_util::GimliSectionMethods; - use std::cell::RefCell; use test_assembler::{Endian, Section}; #[test] @@ -915,7 +914,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0xf00d_f00d)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -925,7 +924,7 @@ mod tests { fn test_parse_encoded_pointer_pcrel() { let encoding = constants::DW_EH_PE_pcrel; - let bases = BaseAddresses::default().set_eh_frame(0x100); + let bases = BaseAddresses::default().set_eh_frame(0x100).eh_frame; let address_size = 4; let expected_rest = [1, 2, 3, 4]; @@ -939,7 +938,7 @@ mod tests { let mut rest = input.range_from(0x10..); assert_eq!( - parse_encoded_pointer(encoding, &bases.eh_frame, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x111)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -957,7 +956,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Err(Error::PcRelativePointerButSectionBaseIsUndefined) ); } @@ -966,7 +965,7 @@ mod tests { fn test_parse_encoded_pointer_textrel() { let encoding = constants::DW_EH_PE_textrel; - let bases = BaseAddresses::default().set_text(0x10); + let bases = BaseAddresses::default().set_text(0x10).eh_frame; let address_size = 4; let expected_rest = [1, 2, 3, 4]; @@ -979,7 +978,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases.eh_frame, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x11)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -997,7 +996,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Err(Error::TextRelativePointerButTextBaseIsUndefined) ); } @@ -1006,7 +1005,7 @@ mod tests { fn test_parse_encoded_pointer_datarel() { let encoding = constants::DW_EH_PE_datarel; - let bases = BaseAddresses::default().set_got(0x10); + let bases = BaseAddresses::default().set_got(0x10).eh_frame; let address_size = 4; let expected_rest = [1, 2, 3, 4]; @@ -1019,7 +1018,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases.eh_frame, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x11)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1037,7 +1036,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Err(Error::DataRelativePointerButDataBaseIsUndefined) ); } @@ -1046,8 +1045,8 @@ mod tests { fn test_parse_encoded_pointer_funcrel() { let encoding = constants::DW_EH_PE_funcrel; - let mut bases = SectionBaseAddresses::default(); - bases.func = RefCell::new(Some(0x10)); + let bases = SectionBaseAddresses::default(); + let func_base = Some(0x10); let address_size = 4; let expected_rest = [1, 2, 3, 4]; @@ -1060,7 +1059,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, func_base, address_size, &input, &mut rest), Ok(Pointer::Direct(0x11)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1078,7 +1077,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Err(Error::FuncRelativePointerInBadContext) ); } @@ -1099,7 +1098,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x12_3456)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1121,7 +1120,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x1234)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1143,7 +1142,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x1234_5678)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1165,7 +1164,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x1234_5678_1234_5678)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1175,7 +1174,7 @@ mod tests { fn test_parse_encoded_pointer_sleb128() { let encoding = constants::DwEhPe(constants::DW_EH_PE_textrel.0 | constants::DW_EH_PE_sleb128.0); - let bases = BaseAddresses::default().set_text(0x1111_1111); + let bases = BaseAddresses::default().set_text(0x1111_1111).eh_frame; let address_size = 4; let expected_rest = [1, 2, 3, 4]; @@ -1187,7 +1186,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases.eh_frame, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(0x1111_0000)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1210,7 +1209,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(expected as u64)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1233,7 +1232,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(expected as u64)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1256,7 +1255,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Direct(expected as u64)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian)); @@ -1274,7 +1273,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::default()) ); assert_eq!(rest, input); @@ -1292,7 +1291,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Err(Error::UnknownPointerEncoding) ); } @@ -1311,7 +1310,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Err(Error::UnsupportedPointerEncoding) ); } @@ -1332,7 +1331,7 @@ mod tests { let mut rest = input; assert_eq!( - parse_encoded_pointer(encoding, &bases, address_size, &input, &mut rest), + parse_encoded_pointer(encoding, &bases, None, address_size, &input, &mut rest), Ok(Pointer::Indirect(0x1234_5678)) ); assert_eq!(rest, EndianSlice::new(&expected_rest, LittleEndian));