diff --git a/benches/bench.rs b/benches/bench.rs index fb29df77..4cb27d2c 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -468,7 +468,7 @@ fn bench_evaluating_debug_info_expressions(b: &mut test::Bencher) { }); } -fn debug_loc_expressions( +fn debug_loc_expressions>( debug_info: &DebugInfo, debug_abbrev: &DebugAbbrev, debug_addr: &DebugAddr, @@ -702,7 +702,7 @@ mod cfi { }); } - fn instrs_len( + fn instrs_len>( eh_frame: &EhFrame, bases: &BaseAddresses, fde: &FrameDescriptionEntry, @@ -712,7 +712,7 @@ mod cfi { .expect("fold over instructions OK") } - fn get_fde_with_longest_cfi_instructions( + fn get_fde_with_longest_cfi_instructions>( eh_frame: &EhFrame, bases: &BaseAddresses, ) -> FrameDescriptionEntry { diff --git a/crates/examples/src/bin/dwarfdump.rs b/crates/examples/src/bin/dwarfdump.rs index a837e190..3a11b9de 100644 --- a/crates/examples/src/bin/dwarfdump.rs +++ b/crates/examples/src/bin/dwarfdump.rs @@ -3,7 +3,7 @@ use fallible_iterator::FallibleIterator; use gimli::{Section, UnitHeader, UnitOffset, UnitSectionOffset, UnitType, UnwindSection}; -use object::{Object, ObjectSection}; +use object::{Object, ObjectSection, ObjectSymbol}; use regex::bytes::Regex; use std::borrow::Cow; use std::cmp; @@ -24,6 +24,7 @@ enum Error { Gimli(gimli::Error), Object(object::read::Error), Io, + Local(&'static str), } impl fmt::Display for Error { @@ -33,7 +34,7 @@ impl fmt::Display for Error { } } -fn writeln_error( +fn writeln_error<'a, W: Write, R: Reader<'a>>( w: &mut W, dwarf: &gimli::Dwarf, err: Error, @@ -47,6 +48,7 @@ fn writeln_error( Error::Gimli(err) => dwarf.format_error(err), Error::Object(err) => format!("{}:{:?}", "An object error occurred while reading", err), Error::Io => "An I/O error occurred while writing.".to_string(), + Error::Local(err) => err.to_string(), } ) } @@ -147,12 +149,12 @@ where } #[derive(Debug, Default)] -struct RelocationMap(object::read::RelocationMap); +struct RelocationMap(HashMap); impl RelocationMap { - fn add(&mut self, file: &object::File, section: &object::Section) { + fn add_all(&mut self, file: &object::File, section: &object::Section) { for (offset, relocation) in section.relocations() { - if let Err(e) = self.0.add(file, offset, relocation) { + if let Err(e) = self.add(file, offset, relocation) { eprintln!( "Relocation error for section {} at offset 0x{:08x}: {}", section.name().unwrap(), @@ -162,23 +164,185 @@ impl RelocationMap { } } } + + fn add( + &mut self, + file: &object::File, + offset: u64, + relocation: object::Relocation, + ) -> Result<()> { + let mut entry = RelocationMapEntry { + name: None, + implicit_addend: relocation.has_implicit_addend(), + addend: relocation.addend() as u64, + }; + match relocation.kind() { + object::RelocationKind::Absolute => match relocation.target() { + object::RelocationTarget::Symbol(symbol_idx) => { + let symbol = file.symbol_by_index(symbol_idx)?; + entry.name = if symbol.kind() == object::SymbolKind::Section { + let section_index = symbol.section().index().unwrap(); + let section = file.section_by_index(section_index)?; + Some(section.name()?.into()) + } else { + Some(symbol.name()?.into()) + }; + entry.addend = symbol.address().wrapping_add(entry.addend); + } + object::RelocationTarget::Section(section_idx) => { + let section = file.section_by_index(section_idx)?; + // DWARF parsers expect references to DWARF sections to be section offsets, + // not addresses. Addresses are useful for everything else. + if section.kind() != object::SectionKind::Debug { + entry.addend = section.address().wrapping_add(entry.addend); + } + } + _ => { + return Err(Error::Local("Unsupported relocation target")); + } + }, + _ => { + return Err(Error::Local("Unsupported relocation type")); + } + } + if self.0.insert(offset, entry).is_some() { + return Err(Error::Local("Multiple relocations for offset")); + } + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct RelocationMapEntry { + name: Option, + implicit_addend: bool, + addend: u64, +} + +impl RelocationMapEntry { + fn addend(&self, value: u64) -> u64 { + if self.implicit_addend { + // Use the explicit addend too, because it may have the symbol value. + value.wrapping_add(self.addend) + } else { + self.addend + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum Address<'a> { + Constant(u64), + Symbol { name: &'a str, addend: u64 }, +} + +impl Default for Address<'_> { + fn default() -> Self { + Address::Constant(0) + } +} + +impl fmt::LowerHex for Address<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Address::Constant(address) => write!(f, "{:#x}", address), + Address::Symbol { name, addend } => write!(f, "{}+{:#x}", name, addend), + } + } +} + +impl gimli::ReaderAddress for Address<'_> { + type Length = u64; + + fn default_size() -> u8 { + mem::size_of::() as u8 + } + + fn max_size() -> u8 { + 8 + } + + fn size(address_bytes: u8) -> gimli::Result { + u64::size(address_bytes) + } + + fn address(_address: u64, _size: u8) -> gimli::Result { + unimplemented!() + } + + fn length(length: u64, size: u8) -> gimli::Result { + u64::length(length, size) + } + + fn add(self, offset: u64, size: u8) -> gimli::Result { + // Be more liberal for the purposes of dwarfdump. + Ok(self.wrapping_add(offset, size)) + } + + fn wrapping_add(self, offset: u64, size: u8) -> Self { + let mask = u64::ones(size); + match self { + Address::Constant(address) => Address::Constant(address.wrapping_add(offset) & mask), + Address::Symbol { name, addend } => Address::Symbol { + name, + addend: addend.wrapping_add(offset) & mask, + }, + } + } + + fn offset_from(self, _address: Self) -> gimli::Result { + Err(gimli::Error::UnsupportedAddressOffset) + } + + fn constant(self) -> Option { + match self { + Address::Constant(address) => Some(address), + Address::Symbol { .. } => None, + } + } + + fn zeroes() -> Self { + Address::Constant(0) + } + + fn ones(size: u8) -> Self { + Address::Constant(u64::ones(size)) + } } impl<'a> gimli::read::Relocate for &'a RelocationMap { - fn relocate_address(&self, offset: usize, value: u64) -> gimli::Result { - Ok(self.0.relocate(offset as u64, value)) + type ToAddress = Address<'a>; + + fn relocate_address(&self, offset: usize, value: u64) -> gimli::Result> { + let offset = offset as u64; + let address = if let Some(relocation) = self.0.get(&offset) { + let addend = relocation.addend(value); + if let Some(name) = relocation.name.as_ref() { + Address::Symbol { name, addend } + } else { + Address::Constant(addend) + } + } else { + Address::Constant(value) + }; + Ok(address) } fn relocate_offset(&self, offset: usize, value: usize) -> gimli::Result { - ::from_u64(self.0.relocate(offset as u64, value as u64)) + let offset = offset as u64; + if let Some(relocation) = self.0.get(&offset) { + ::from_u64(relocation.addend(value as u64)) + } else { + Ok(value) + } } } type Relocate<'a, R> = gimli::RelocateReader; -trait Reader: gimli::Reader + Send + Sync {} +trait Reader<'a>: gimli::Reader> + Send + Sync {} -impl<'a, R: gimli::Reader + Send + Sync> Reader for Relocate<'a, R> {} +impl<'a, T: gimli::Reader> + Send + Sync> Reader<'a> for T {} #[derive(Default)] struct Flags<'a> { @@ -410,7 +574,7 @@ fn load_file_section<'input, 'arena, Endian: gimli::Endianity>( Some(ref section) => { // DWO sections never have relocations, so don't bother. if !is_dwo { - relocations.add(file, section); + relocations.add_all(file, section); } section.uncompressed_data()? } @@ -535,7 +699,7 @@ where Ok(()) } -fn dump_eh_frame( +fn dump_eh_frame<'a, R: Reader<'a>, W: Write>( w: &mut W, file: &object::File, mut eh_frame: gimli::EhFrame, @@ -572,16 +736,16 @@ fn dump_eh_frame( let mut bases = gimli::BaseAddresses::default(); if let Some(section) = file.section_by_name(".eh_frame_hdr") { - bases = bases.set_eh_frame_hdr(section.address()); + bases = bases.set_eh_frame_hdr(Address::Constant(section.address())); } if let Some(section) = file.section_by_name(".eh_frame") { - bases = bases.set_eh_frame(section.address()); + bases = bases.set_eh_frame(Address::Constant(section.address())); } if let Some(section) = file.section_by_name(".text") { - bases = bases.set_text(section.address()); + bases = bases.set_text(Address::Constant(section.address())); } if let Some(section) = file.section_by_name(".got") { - bases = bases.set_got(section.address()); + bases = bases.set_got(Address::Constant(section.address())); } // TODO: Print "__eh_frame" here on macOS, and more generally use the @@ -681,7 +845,7 @@ fn dump_eh_frame( } } -fn dump_pointer(w: &mut W, p: gimli::Pointer) -> Result<()> { +fn dump_pointer(w: &mut W, p: gimli::Pointer>) -> Result<()> { match p { gimli::Pointer::Direct(p) => { write!(w, "{:#x}", p)?; @@ -694,7 +858,7 @@ fn dump_pointer(w: &mut W, p: gimli::Pointer) -> Result<()> { } #[allow(clippy::unneeded_field_pattern)] -fn dump_cfi_instructions( +fn dump_cfi_instructions<'a, R: Reader<'a>, W: Write>( w: &mut W, mut insns: gimli::CallFrameInstructionIter, is_initial: bool, @@ -890,7 +1054,7 @@ fn dump_cfi_instructions( } } -fn dump_dwp( +fn dump_dwp<'a, R: Reader<'a>, W: Write + Send>( w: &mut W, dwp: &gimli::DwarfPackage, dwo_parent: &gimli::Dwarf, @@ -947,7 +1111,7 @@ where Ok(()) } -fn dump_dwp_sections( +fn dump_dwp_sections<'a, R: Reader<'a>, W: Write + Send>( w: &mut W, dwp: &gimli::DwarfPackage, dwo_parent: &gimli::Dwarf, @@ -978,7 +1142,7 @@ where Ok(()) } -fn dump_info( +fn dump_info<'a, R: Reader<'a>, W: Write + Send>( w: &mut W, dwarf: &gimli::Dwarf, dwo_parent_units: Option<&HashMap>>, @@ -1013,7 +1177,7 @@ where parallel_output(w, 16, units, process_unit) } -fn dump_types( +fn dump_types<'a, R: Reader<'a>, W: Write>( w: &mut W, dwarf: &gimli::Dwarf, dwo_parent_units: Option<&HashMap>>, @@ -1028,7 +1192,7 @@ fn dump_types( Ok(()) } -fn dump_unit( +fn dump_unit<'a, R: Reader<'a>, W: Write>( w: &mut W, header: UnitHeader, dwarf: &gimli::Dwarf, @@ -1107,7 +1271,7 @@ fn spaces(buf: &mut String, len: usize) -> &str { // " GOFF=0x{:08x}" adds exactly 16 spaces. const GOFF_SPACES: usize = 16; -fn write_offset( +fn write_offset<'a, R: Reader<'a>, W: Write>( w: &mut W, unit: &gimli::Unit, offset: gimli::UnitOffset, @@ -1125,7 +1289,7 @@ fn write_offset( Ok(()) } -fn dump_entries( +fn dump_entries<'a, R: Reader<'a>, W: Write>( w: &mut W, unit: gimli::UnitRef, flags: &Flags, @@ -1181,7 +1345,7 @@ fn dump_entries( Ok(()) } -fn dump_attr_value( +fn dump_attr_value<'a, R: Reader<'a>, W: Write>( w: &mut W, attr: &gimli::Attribute, unit: gimli::UnitRef, @@ -1423,7 +1587,7 @@ fn dump_type_signature(w: &mut W, signature: gimli::DebugTypeSignature Ok(()) } -fn dump_file_index( +fn dump_file_index<'a, R: Reader<'a>, W: Write>( w: &mut W, file_index: u64, unit: gimli::UnitRef, @@ -1461,7 +1625,7 @@ fn dump_file_index( Ok(()) } -fn dump_exprloc( +fn dump_exprloc<'a, R: Reader<'a>, W: Write>( w: &mut W, unit: gimli::UnitRef, data: &gimli::Expression, @@ -1500,7 +1664,7 @@ fn dump_exprloc( Ok(()) } -fn dump_op( +fn dump_op<'a, R: Reader<'a>, W: Write>( w: &mut W, unit: gimli::UnitRef, mut pc: R, @@ -1681,7 +1845,7 @@ fn dump_op( Ok(()) } -fn dump_range(w: &mut W, range: Option) -> Result<()> { +fn dump_range(w: &mut W, range: Option>) -> Result<()> { if let Some(range) = range { write!(w, " [{:#x}, {:#x}]", range.begin, range.end)?; } else { @@ -1690,7 +1854,7 @@ fn dump_range(w: &mut W, range: Option) -> Result<()> { Ok(()) } -fn dump_loc_list( +fn dump_loc_list<'a, R: Reader<'a>, W: Write>( w: &mut W, offset: gimli::LocationListsOffset, unit: gimli::UnitRef, @@ -1756,8 +1920,13 @@ fn dump_loc_list( begin, end, ref data, + } => { + write!(w, "", begin, end)?; + dump_range(w, range)?; + dump_exprloc(w, unit, data)?; + writeln!(w)?; } - | gimli::RawLocListEntry::OffsetPair { + gimli::RawLocListEntry::OffsetPair { begin, end, ref data, @@ -1797,7 +1966,7 @@ fn dump_loc_list( Ok(()) } -fn dump_range_list( +fn dump_range_list<'a, R: Reader<'a>, W: Write>( w: &mut W, offset: gimli::RangeListsOffset, unit: gimli::UnitRef, @@ -1847,8 +2016,12 @@ fn dump_range_list( dump_range(w, range)?; writeln!(w)?; } - gimli::RawRngListEntry::AddressOrOffsetPair { begin, end } - | gimli::RawRngListEntry::OffsetPair { begin, end } => { + gimli::RawRngListEntry::AddressOrOffsetPair { begin, end } => { + write!(w, "", begin, end)?; + dump_range(w, range)?; + writeln!(w)?; + } + gimli::RawRngListEntry::OffsetPair { begin, end } => { write!(w, "", begin, end)?; dump_range(w, range)?; writeln!(w)?; @@ -1868,7 +2041,7 @@ fn dump_range_list( Ok(()) } -fn dump_line(w: &mut W, dwarf: &gimli::Dwarf) -> Result<()> { +fn dump_line<'a, R: Reader<'a>, W: Write>(w: &mut W, dwarf: &gimli::Dwarf) -> Result<()> { let mut iter = dwarf.units(); while let Some(header) = iter.next()? { writeln!( @@ -1898,7 +2071,10 @@ fn dump_line(w: &mut W, dwarf: &gimli::Dwarf) -> Result< Ok(()) } -fn dump_line_program(w: &mut W, unit: gimli::UnitRef) -> Result<()> { +fn dump_line_program<'a, R: Reader<'a>, W: Write>( + w: &mut W, + unit: gimli::UnitRef, +) -> Result<()> { if let Some(program) = unit.line_program.clone() { { let header = program.header(); @@ -2136,7 +2312,7 @@ fn dump_line_program(w: &mut W, unit: gimli::UnitRef) -> Ok(()) } -fn dump_pubnames( +fn dump_pubnames<'a, R: Reader<'a>, W: Write>( w: &mut W, debug_pubnames: &gimli::DebugPubNames, debug_info: &gimli::DebugInfo, @@ -2168,7 +2344,7 @@ fn dump_pubnames( Ok(()) } -fn dump_pubtypes( +fn dump_pubtypes<'a, R: Reader<'a>, W: Write>( w: &mut W, debug_pubtypes: &gimli::DebugPubTypes, debug_info: &gimli::DebugInfo, @@ -2200,7 +2376,7 @@ fn dump_pubtypes( Ok(()) } -fn dump_aranges( +fn dump_aranges<'a, R: Reader<'a>, W: Write>( w: &mut W, debug_aranges: &gimli::DebugAranges, ) -> Result<()> { diff --git a/crates/examples/src/bin/simple.rs b/crates/examples/src/bin/simple.rs index 18d9a2b9..b1d594d0 100644 --- a/crates/examples/src/bin/simple.rs +++ b/crates/examples/src/bin/simple.rs @@ -18,6 +18,8 @@ use std::{borrow, env, error, fs}; struct RelocationMap(object::read::RelocationMap); impl<'a> gimli::read::Relocate for &'a RelocationMap { + type ToAddress = u64; + fn relocate_address(&self, offset: usize, value: u64) -> gimli::Result { Ok(self.0.relocate(offset as u64, value)) } diff --git a/src/read/addr.rs b/src/read/addr.rs index fc2fbabd..52f4d78f 100644 --- a/src/read/addr.rs +++ b/src/read/addr.rs @@ -30,7 +30,7 @@ impl DebugAddr { address_size: u8, base: DebugAddrBase, index: DebugAddrIndex, - ) -> Result { + ) -> Result { let input = &mut self.section.clone(); input.skip(base.0)?; input.skip(R::Offset::from_u64( diff --git a/src/read/aranges.rs b/src/read/aranges.rs index fd9f8353..beab4bea 100644 --- a/src/read/aranges.rs +++ b/src/read/aranges.rs @@ -248,7 +248,7 @@ impl ArangeEntryIter { /// when iteration is complete and all aranges have already been parsed and /// yielded. If an error occurs while parsing the next arange, then this error /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`. - pub fn next(&mut self) -> Result> { + pub fn next(&mut self) -> Result>> { if self.input.is_empty() { return Ok(None); } @@ -269,7 +269,7 @@ impl ArangeEntryIter { #[cfg(feature = "fallible-iterator")] impl fallible_iterator::FallibleIterator for ArangeEntryIter { - type Item = ArangeEntry; + type Item = ArangeEntry; type Error = Error; fn next(&mut self) -> ::core::result::Result, Self::Error> { @@ -279,14 +279,14 @@ impl fallible_iterator::FallibleIterator for ArangeEntryIter { /// A single parsed arange. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct ArangeEntry { - range: Range, - length: u64, +pub struct ArangeEntry { + range: Range, + length: A::Length, } -impl ArangeEntry { +impl ArangeEntry { /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange. - fn parse(input: &mut R, encoding: Encoding) -> Result> { + fn parse>(input: &mut R, encoding: Encoding) -> Result> { let address_size = encoding.address_size; let tuple_length = R::Offset::from_u8(2 * address_size); @@ -296,35 +296,35 @@ impl ArangeEntry { } let begin = input.read_address(address_size)?; - let length = input.read_address(address_size)?; + let length = input.read_address_range(address_size)?; // Calculate end now so that we can handle overflow. - let end = begin.add_sized(length, address_size)?; + let end = begin.add(length, address_size)?; let range = Range { begin, end }; - match (begin, length) { + match (range.begin == A::default(), length.into()) { // This is meant to be a null terminator, but in practice it can occur // before the end, possibly due to a linker omitting a function and // leaving an unrelocated entry. - (0, 0) => Self::parse(input, encoding), + (true, 0) => Self::parse(input, encoding), _ => Ok(Some(ArangeEntry { range, length })), } } /// Return the beginning address of this arange. #[inline] - pub fn address(&self) -> u64 { + pub fn address(&self) -> A { self.range.begin } /// Return the length of this arange. #[inline] - pub fn length(&self) -> u64 { + pub fn length(&self) -> A::Length { self.length } /// Return the range. #[inline] - pub fn range(&self) -> Range { + pub fn range(&self) -> Range { self.range } } diff --git a/src/read/cfi.rs b/src/read/cfi.rs index 9941f72c..b7435236 100644 --- a/src/read/cfi.rs +++ b/src/read/cfi.rs @@ -45,7 +45,7 @@ impl DebugFrame { /// This defaults to the native word size. /// This is only used if the CIE version is less than 4. pub fn set_address_size(&mut self, address_size: u8) { - self.address_size = address_size + self.address_size = address_size; } /// Set the vendor extensions to use. @@ -114,7 +114,7 @@ pub struct ParsedEhFrameHdr { address_size: u8, section: R, - eh_frame_ptr: Pointer, + eh_frame_ptr: Pointer, fde_count: u64, table_enc: DwEhPe, table: R, @@ -132,7 +132,12 @@ where impl EhFrameHdr { /// Parses this `EhFrameHdr` to a `ParsedEhFrameHdr`. - pub fn parse(&self, bases: &BaseAddresses, address_size: u8) -> Result> { + pub fn parse( + &self, + bases: &BaseAddresses, + address_size: u8, + ) -> Result> { + let address_size = R::address_size(address_size)?; let mut reader = self.0.clone(); let version = reader.read_u8()?; if version != 1 { @@ -163,7 +168,7 @@ impl EhFrameHdr { if fde_count_enc != fde_count_enc.format() { return Err(Error::UnsupportedPointerEncoding); } - fde_count = parse_encoded_value(fde_count_enc, ¶meters, &mut reader)?; + fde_count = parse_encoded_value(fde_count_enc, ¶meters, &mut reader)?.into(); } Ok(ParsedEhFrameHdr { @@ -196,7 +201,7 @@ impl From for EhFrameHdr { impl ParsedEhFrameHdr { /// Returns the address of the binary's `.eh_frame` section. - pub fn eh_frame_ptr(&self) -> Pointer { + pub fn eh_frame_ptr(&self) -> Pointer { self.eh_frame_ptr } @@ -229,13 +234,13 @@ impl ParsedEhFrameHdr { pub struct EhHdrTableIter<'a, 'bases, R: Reader> { hdr: &'a ParsedEhFrameHdr, table: R, - bases: &'bases BaseAddresses, + bases: &'bases BaseAddresses, remain: u64, } impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> { /// Yield the next entry in the `EhHdrTableIter`. - pub fn next(&mut self) -> Result> { + pub fn next(&mut self) -> Result, Pointer)>> { if self.remain == 0 { return Ok(None); } @@ -253,7 +258,7 @@ impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> { Ok(Some((from, to))) } /// Yield the nth entry in the `EhHdrTableIter` - pub fn nth(&mut self, n: usize) -> Result> { + pub fn nth(&mut self, n: usize) -> Result, Pointer)>> { use core::convert::TryFrom; let size = match self.hdr.table_enc.format() { constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { @@ -275,7 +280,7 @@ impl<'a, 'bases, R: Reader> EhHdrTableIter<'a, 'bases, R> { #[cfg(feature = "fallible-iterator")] impl<'a, 'bases, R: Reader> fallible_iterator::FallibleIterator for EhHdrTableIter<'a, 'bases, R> { - type Item = (Pointer, Pointer); + type Item = (Pointer, Pointer); type Error = Error; fn next(&mut self) -> Result> { EhHdrTableIter::next(self) @@ -307,7 +312,10 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { /// The `initial location` represents the first address that the targeted FDE /// is able to decode. The `address` is the address of the FDE in the `.eh_frame` section. /// The `address` can be converted with `EhHdrTable::pointer_to_offset` and `EhFrame::fde_from_offset` to an FDE. - pub fn iter<'bases>(&self, bases: &'bases BaseAddresses) -> EhHdrTableIter<'_, 'bases, R> { + pub fn iter<'bases>( + &self, + bases: &'bases BaseAddresses, + ) -> EhHdrTableIter<'_, 'bases, R> { EhHdrTableIter { hdr: self.hdr, bases, @@ -321,7 +329,14 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { /// this function **will** return a pointer to any other FDE that's close by. /// /// To be sure, you **must** call `contains` on the FDE. - pub fn lookup(&self, address: u64, bases: &BaseAddresses) -> Result { + pub fn lookup( + &self, + address: R::Address, + bases: &BaseAddresses, + ) -> Result> + where + R::Address: Ord, + { let size = match self.hdr.table_enc.format() { constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => { return Err(Error::VariableLengthSearchTable); @@ -376,12 +391,13 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { /// Convert a `Pointer` to a section offset. /// /// This does not support indirect pointers. - pub fn pointer_to_offset(&self, ptr: Pointer) -> Result> { + pub fn pointer_to_offset(&self, ptr: Pointer) -> Result> { let ptr = ptr.direct()?; let eh_frame_ptr = self.hdr.eh_frame_ptr().direct()?; // Calculate the offset in the EhFrame section - R::Offset::from_u64(ptr - eh_frame_ptr).map(EhFrameOffset) + let offset = ptr.offset_from(eh_frame_ptr)?; + R::Offset::from_u64(offset.into()).map(EhFrameOffset) } /// Returns a parsed FDE for the given address, or `NoUnwindInfoForAddress` @@ -407,16 +423,17 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { pub fn fde_for_address( &self, frame: &EhFrame, - bases: &BaseAddresses, - address: u64, + bases: &BaseAddresses, + address: R::Address, get_cie: F, ) -> Result> where F: FnMut( &EhFrame, - &BaseAddresses, + &BaseAddresses, EhFrameOffset, ) -> Result>, + R::Address: Ord, { let fdeptr = self.lookup(address, bases)?; let offset = self.pointer_to_offset(fdeptr)?; @@ -433,17 +450,18 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { #[deprecated(note = "Method renamed to fde_for_address; use that instead.")] pub fn lookup_and_parse( &self, - address: u64, - bases: &BaseAddresses, + address: R::Address, + bases: &BaseAddresses, frame: EhFrame, get_cie: F, ) -> Result> where F: FnMut( &EhFrame, - &BaseAddresses, + &BaseAddresses, EhFrameOffset, ) -> Result>, + R::Address: Ord, { self.fde_for_address(&frame, bases, address, get_cie) } @@ -456,18 +474,19 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { pub fn unwind_info_for_address<'ctx, F, S>( &self, frame: &EhFrame, - bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext, - address: u64, + bases: &BaseAddresses, + ctx: &'ctx mut UnwindContext, + address: R::Address, get_cie: F, - ) -> Result<&'ctx UnwindTableRow> + ) -> Result<&'ctx UnwindTableRow> where F: FnMut( &EhFrame, - &BaseAddresses, + &BaseAddresses, EhFrameOffset, ) -> Result>, - S: UnwindContextStorage, + R::Address: Ord, + S: UnwindContextStorage, { let fde = self.fde_for_address(frame, bases, address, get_cie)?; fde.unwind_info_for_address(frame, bases, ctx, address) @@ -496,7 +515,7 @@ impl EhFrame { /// /// This defaults to the native word size. pub fn set_address_size(&mut self, address_size: u8) { - self.address_size = address_size + self.address_size = address_size; } /// Set the vendor extensions to use. @@ -643,7 +662,10 @@ pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { /// /// Can be [used with /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - fn entries<'bases>(&self, bases: &'bases BaseAddresses) -> CfiEntriesIter<'bases, Self, R> { + fn entries<'bases>( + &self, + bases: &'bases BaseAddresses, + ) -> CfiEntriesIter<'bases, Self, R> { CfiEntriesIter { section: self.clone(), bases, @@ -654,7 +676,7 @@ pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { /// Parse the `CommonInformationEntry` at the given offset. fn cie_from_offset( &self, - bases: &BaseAddresses, + bases: &BaseAddresses, offset: Self::Offset, ) -> Result> { let offset = UnwindOffset::into(offset); @@ -666,7 +688,7 @@ pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { /// Parse the `PartialFrameDescriptionEntry` at the given offset. fn partial_fde_from_offset<'bases>( &self, - bases: &'bases BaseAddresses, + bases: &'bases BaseAddresses, offset: Self::Offset, ) -> Result> { let offset = UnwindOffset::into(offset); @@ -678,12 +700,16 @@ pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { /// Parse the `FrameDescriptionEntry` at the given offset. fn fde_from_offset( &self, - bases: &BaseAddresses, + bases: &BaseAddresses, offset: Self::Offset, get_cie: F, ) -> Result> where - F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, + F: FnMut( + &Self, + &BaseAddresses, + Self::Offset, + ) -> Result>, { let partial = self.partial_fde_from_offset(bases, offset)?; partial.parse(get_cie) @@ -702,12 +728,17 @@ pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { /// to do a binary search with `EhFrameHdr::fde_for_address` instead. fn fde_for_address( &self, - bases: &BaseAddresses, - address: u64, + bases: &BaseAddresses, + address: R::Address, mut get_cie: F, ) -> Result> where - F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, + F: FnMut( + &Self, + &BaseAddresses, + Self::Offset, + ) -> Result>, + R::Address: Ord, { let mut entries = self.entries(bases); while let Some(entry) = entries.next()? { @@ -772,14 +803,19 @@ pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { #[inline] fn unwind_info_for_address<'ctx, F, S>( &self, - bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext, - address: u64, + bases: &BaseAddresses, + ctx: &'ctx mut UnwindContext, + address: R::Address, get_cie: F, - ) -> Result<&'ctx UnwindTableRow> + ) -> Result<&'ctx UnwindTableRow> where - F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, - S: UnwindContextStorage, + F: FnMut( + &Self, + &BaseAddresses, + Self::Offset, + ) -> Result>, + R::Address: Ord, + S: UnwindContextStorage, { let fde = self.fde_for_address(bases, address, get_cie)?; fde.unwind_info_for_address(self, bases, ctx, address) @@ -893,12 +929,12 @@ impl UnwindSection for EhFrame { /// # } /// ``` #[derive(Clone, Default, Debug, PartialEq, Eq)] -pub struct BaseAddresses { +pub struct BaseAddresses { /// The base addresses to use for pointers in the `.eh_frame_hdr` section. - pub eh_frame_hdr: SectionBaseAddresses, + pub eh_frame_hdr: SectionBaseAddresses, /// The base addresses to use for pointers in the `.eh_frame` section. - pub eh_frame: SectionBaseAddresses, + pub eh_frame: SectionBaseAddresses, } /// Optional base addresses for the relative `DW_EH_PE_*` encoded pointers @@ -906,13 +942,13 @@ pub struct BaseAddresses { /// /// See `BaseAddresses` for methods that are helpful in setting these addresses. #[derive(Clone, Default, Debug, PartialEq, Eq)] -pub struct SectionBaseAddresses { +pub struct SectionBaseAddresses { /// The address of the section containing the pointer. - pub section: Option, + pub section: Option, /// The base address for text relative pointers. /// This is generally the address of the `.text` section. - pub text: Option, + pub text: Option, /// The base address for data relative pointers. /// @@ -921,13 +957,13 @@ 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, + pub data: Option, } -impl BaseAddresses { +impl BaseAddresses { /// Set the `.eh_frame_hdr` section base address. #[inline] - pub fn set_eh_frame_hdr(mut self, addr: u64) -> Self { + pub fn set_eh_frame_hdr(mut self, addr: T) -> Self { self.eh_frame_hdr.section = Some(addr); self.eh_frame_hdr.data = Some(addr); self @@ -935,14 +971,14 @@ impl BaseAddresses { /// Set the `.eh_frame` section base address. #[inline] - pub fn set_eh_frame(mut self, addr: u64) -> Self { + pub fn set_eh_frame(mut self, addr: T) -> Self { self.eh_frame.section = Some(addr); self } /// Set the `.text` section base address. #[inline] - pub fn set_text(mut self, addr: u64) -> Self { + pub fn set_text(mut self, addr: T) -> Self { self.eh_frame_hdr.text = Some(addr); self.eh_frame.text = Some(addr); self @@ -950,7 +986,7 @@ impl BaseAddresses { /// Set the `.got` section base address. #[inline] - pub fn set_got(mut self, addr: u64) -> Self { + pub fn set_got(mut self, addr: T) -> Self { self.eh_frame.data = Some(addr); self } @@ -1002,7 +1038,7 @@ where Section: UnwindSection, { section: Section, - bases: &'bases BaseAddresses, + bases: &'bases BaseAddresses, input: R, } @@ -1061,7 +1097,7 @@ where } fn parse_cfi_entry<'bases, Section, R>( - bases: &'bases BaseAddresses, + bases: &'bases BaseAddresses, section: &Section, input: &mut R, ) -> Result>> @@ -1122,7 +1158,7 @@ where /// /// [ehframe]: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub struct Augmentation { +pub struct Augmentation { /// > A 'L' may be present at any position after the first character of the /// > string. This character may only be present if 'z' is the first character /// > of the string. If present, it indicates the presence of one argument in @@ -1141,7 +1177,7 @@ pub struct Augmentation { /// > represents the pointer encoding used for the second argument, which is /// > the address of a personality routine handler. The size of the /// > personality routine pointer is specified by the pointer encoding used. - personality: Option<(constants::DwEhPe, Pointer)>, + personality: Option<(constants::DwEhPe, Pointer)>, /// > A 'R' may be present at any position after the first character of the /// > string. This character may only be present if 'z' is the first character @@ -1154,16 +1190,16 @@ pub struct Augmentation { is_signal_trampoline: bool, } -impl Augmentation { +impl Augmentation { fn parse( augmentation_str: &mut R, - bases: &BaseAddresses, + bases: &BaseAddresses, address_size: u8, section: &Section, input: &mut R, - ) -> Result + ) -> Result where - R: Reader, + R: Reader
, Section: UnwindSection, { debug_assert!( @@ -1223,16 +1259,16 @@ impl Augmentation { /// Parsed augmentation data for a `FrameDescriptEntry`. #[derive(Clone, Debug, Default, PartialEq, Eq)] -struct AugmentationData { - lsda: Option, +struct AugmentationData { + lsda: Option>, } -impl AugmentationData { - fn parse( - augmentation: &Augmentation, +impl AugmentationData { + fn parse>( + augmentation: &Augmentation, encoding_parameters: &PointerEncodingParameters<'_, R>, input: &mut R, - ) -> Result { + ) -> Result { // In theory, we should be iterating over the original augmentation // string, interpreting each character, and reading the appropriate bits // out of the augmentation data as we go. However, the only character @@ -1254,10 +1290,14 @@ impl AugmentationData { /// > Frame Description Entries. There is at least one CIE in every non-empty /// > `.debug_frame` section. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct CommonInformationEntry::Offset> -where +pub struct CommonInformationEntry< + R, + Offset = ::Offset, + Address = ::Address, +> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { /// The offset of this entry from the start of its containing section. offset: Offset, @@ -1275,7 +1315,7 @@ where version: u8, /// The parsed augmentation, if any. - augmentation: Option, + augmentation: Option>, /// > The size of a target address in this CIE and any FDEs that use it, in /// > bytes. If a compilation unit exists for this frame, its address size @@ -1310,7 +1350,7 @@ where impl CommonInformationEntry { fn parse>( - bases: &BaseAddresses, + bases: &BaseAddresses, section: &Section, input: &mut R, ) -> Result> { @@ -1325,7 +1365,7 @@ impl CommonInformationEntry { offset: R::Offset, length: R::Offset, format: Format, - bases: &BaseAddresses, + bases: &BaseAddresses, section: &Section, mut rest: R, ) -> Result> { @@ -1421,7 +1461,7 @@ impl CommonInformationEntry { pub fn instructions<'a, Section>( &self, section: &'a Section, - bases: &'a BaseAddresses, + bases: &'a BaseAddresses, ) -> CallFrameInstructionIter<'a, R> where Section: UnwindSection, @@ -1457,7 +1497,7 @@ impl CommonInformationEntry { /// /// The only augmentation understood by `gimli` is that which is defined by /// `.eh_frame`. - pub fn augmentation(&self) -> Option<&Augmentation> { + pub fn augmentation(&self) -> Option<&Augmentation> { self.augmentation.as_ref() } @@ -1473,13 +1513,13 @@ impl CommonInformationEntry { /// Return the encoding and address of the personality routine handler /// for this CIE's FDEs. - pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> { + pub fn personality_with_encoding(&self) -> Option<(constants::DwEhPe, Pointer)> { self.augmentation.as_ref().and_then(|a| a.personality) } /// Return the address of the personality routine handler /// for this CIE's FDEs. - pub fn personality(&self) -> Option { + pub fn personality(&self) -> Option> { self.augmentation .as_ref() .and_then(|a| a.personality) @@ -1531,7 +1571,7 @@ where cie_offset: Section::Offset, rest: R, section: Section, - bases: &'bases BaseAddresses, + bases: &'bases BaseAddresses, } impl<'bases, Section, R> PartialFrameDescriptionEntry<'bases, Section, R> @@ -1541,7 +1581,7 @@ where { fn parse_partial( section: &Section, - bases: &'bases BaseAddresses, + bases: &'bases BaseAddresses, input: &mut R, ) -> Result> { match parse_cfi_entry(bases, section, input)? { @@ -1558,7 +1598,11 @@ where /// you've already parsed, etc.) pub fn parse(&self, get_cie: F) -> Result> where - F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result>, + F: FnMut( + &Section, + &BaseAddresses, + Section::Offset, + ) -> Result>, { FrameDescriptionEntry::parse_rest( self.offset, @@ -1593,10 +1637,15 @@ where /// A `FrameDescriptionEntry` is a set of CFA instructions for an address range. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct FrameDescriptionEntry::Offset> -where +pub struct FrameDescriptionEntry< + R, + Offset = ::Offset, + Address = ::Address, + AddressLength = <::Address as ReaderAddress>::Length, +> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { /// The start of this entry within its containing section. offset: Offset, @@ -1613,18 +1662,18 @@ where /// that is associated with this FDE." /// /// This is the CIE at that offset. - cie: CommonInformationEntry, + cie: CommonInformationEntry, /// > The address of the first location associated with this table entry. If /// > the segment_size field of this FDE's CIE is non-zero, the initial /// > location is preceded by a segment selector of the given length. - initial_address: u64, + initial_address: Address, /// "The number of bytes of program instructions described by this entry." - address_range: u64, + address_range: AddressLength, /// The parsed augmentation data, if we have any. - augmentation: Option, + augmentation: Option>, /// "A sequence of table defining instructions that are described below." /// @@ -1641,12 +1690,16 @@ impl FrameDescriptionEntry { cie_pointer: Section::Offset, mut rest: R, section: &Section, - bases: &BaseAddresses, + bases: &BaseAddresses, mut get_cie: F, ) -> Result> where Section: UnwindSection, - F: FnMut(&Section, &BaseAddresses, Section::Offset) -> Result>, + F: FnMut( + &Section, + &BaseAddresses, + Section::Offset, + ) -> Result>, { let cie = get_cie(section, bases, cie_pointer)?; @@ -1688,7 +1741,7 @@ impl FrameDescriptionEntry { input: &mut R, cie: &CommonInformationEntry, parameters: &PointerEncodingParameters<'_, R>, - ) -> Result<(u64, u64)> { + ) -> Result<(R::Address, ::Length)> { let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding); if let Some(encoding) = encoding { // Ignore indirection. @@ -1697,7 +1750,7 @@ impl FrameDescriptionEntry { Ok((initial_address, address_range)) } else { let initial_address = input.read_address(cie.address_size)?; - let address_range = input.read_address(cie.address_size)?; + let address_range = input.read_address_range(cie.address_size)?; Ok((initial_address, address_range)) } } @@ -1707,12 +1760,12 @@ impl FrameDescriptionEntry { pub fn rows<'a, 'ctx, Section, S>( &self, section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, ) -> Result> where Section: UnwindSection, - S: UnwindContextStorage, + S: UnwindContextStorage, { UnwindTable::new(section, bases, ctx, self) } @@ -1726,13 +1779,14 @@ impl FrameDescriptionEntry { pub fn unwind_info_for_address<'ctx, Section, S>( &self, section: &Section, - bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext, - address: u64, - ) -> Result<&'ctx UnwindTableRow> + bases: &BaseAddresses, + ctx: &'ctx mut UnwindContext, + address: R::Address, + ) -> Result<&'ctx UnwindTableRow> where Section: UnwindSection, - S: UnwindContextStorage, + R::Address: Ord, + S: UnwindContextStorage, { let mut table = self.rows(section, bases, ctx)?; while let Some(row) = table.next_row()? { @@ -1778,7 +1832,7 @@ impl FrameDescriptionEntry { pub fn instructions<'a, Section>( &self, section: &'a Section, - bases: &'a BaseAddresses, + bases: &'a BaseAddresses, ) -> CallFrameInstructionIter<'a, R> where Section: UnwindSection, @@ -1796,8 +1850,8 @@ impl FrameDescriptionEntry { } } - /// The first address for which this entry has unwind information for. - pub fn initial_address(&self) -> u64 { + /// The first address that this entry has unwind information for. + pub fn initial_address(&self) -> R::Address { self.initial_address } @@ -1805,14 +1859,14 @@ impl FrameDescriptionEntry { /// /// This uses wrapping arithmetic, so the result may be less than /// `initial_address`. - pub fn end_address(&self) -> u64 { + pub fn end_address(&self) -> R::Address { self.initial_address - .wrapping_add_sized(self.address_range, self.cie.address_size) + .wrapping_add(self.address_range, self.cie.address_size) } /// The number of bytes of instructions that this entry has unwind /// information for. - pub fn len(&self) -> u64 { + pub fn len(&self) -> ::Length { self.address_range } @@ -1821,13 +1875,16 @@ impl FrameDescriptionEntry { /// /// This is equivalent to `entry.initial_address() <= address < /// entry.initial_address() + entry.len()`. - pub fn contains(&self, address: u64) -> bool { + pub fn contains(&self, address: R::Address) -> bool + where + R::Address: Ord, + { self.initial_address() <= address && address < self.end_address() } /// The address of this FDE's language-specific data area (LSDA), if it has /// any. - pub fn lsda(&self) -> Option { + pub fn lsda(&self) -> Option> { self.augmentation.as_ref().and_then(|a| a.lsda) } @@ -1841,7 +1898,7 @@ impl FrameDescriptionEntry { /// handler. The personality routine does language-specific clean up when /// unwinding the stack frames with the intent to not run them again. #[inline] - pub fn personality(&self) -> Option { + pub fn personality(&self) -> Option> { self.cie().personality() } } @@ -1879,12 +1936,12 @@ You may want to supply your own storage type for one of the following reasons: /// # /// struct StoreOnStack; /// -/// impl UnwindContextStorage for StoreOnStack { +/// impl UnwindContextStorage for StoreOnStack { /// type Rules = [(Register, RegisterRule); 192]; -/// type Stack = [UnwindTableRow; 4]; +/// type Stack = [UnwindTableRow; 4]; /// } /// -/// let mut ctx = UnwindContext::<_, StoreOnStack>::new_in(); +/// let mut ctx = UnwindContext::<_, _, StoreOnStack>::new_in(); /// /// // Initialize the context by evaluating the CIE's initial instruction program, /// // and generate the unwind table. @@ -1896,14 +1953,14 @@ You may want to supply your own storage type for one of the following reasons: /// # unreachable!() /// # } /// ``` -pub trait UnwindContextStorage: Sized { +pub trait UnwindContextStorage: Sized { /// The storage used for register rules in a unwind table row. /// /// Note that this is nested within the stack. type Rules: ArrayLike)>; /// The storage used for unwind table row stack. - type Stack: ArrayLike>; + type Stack: ArrayLike>; } #[cfg(feature = "read")] @@ -1912,9 +1969,9 @@ const MAX_RULES: usize = 192; const MAX_UNWIND_STACK_DEPTH: usize = 4; #[cfg(feature = "read")] -impl UnwindContextStorage for StoreOnHeap { +impl UnwindContextStorage for StoreOnHeap { type Rules = [(Register, RegisterRule); MAX_RULES]; - type Stack = Box<[UnwindTableRow; MAX_UNWIND_STACK_DEPTH]>; + type Stack = Box<[UnwindTableRow; MAX_UNWIND_STACK_DEPTH]>; } /// Common context needed when evaluating the call frame unwinding information. @@ -1951,10 +2008,11 @@ impl UnwindContextStorage for StoreOnHeap { /// # } /// ``` #[derive(Clone, PartialEq, Eq)] -pub struct UnwindContext +pub struct UnwindContext where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { // Stack of rows. The last row is the row currently being built by the // program. There is always at least one row. The vast majority of CFI @@ -1974,10 +2032,11 @@ where is_initialized: bool, } -impl Debug for UnwindContext +impl Debug for UnwindContext where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("UnwindContext") @@ -1988,10 +2047,11 @@ where } } -impl Default for UnwindContext +impl Default for UnwindContext where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn default() -> Self { Self::new_in() @@ -2010,10 +2070,11 @@ impl UnwindContext { /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations, if an non-allocating storage is used. -impl UnwindContext +impl UnwindContext where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { /// Construct a new call frame unwinding context. pub fn new_in() -> Self { @@ -2030,11 +2091,11 @@ where fn initialize( &mut self, section: &Section, - bases: &BaseAddresses, + bases: &BaseAddresses, cie: &CommonInformationEntry, ) -> Result<()> where - R: Reader, + R: Reader, Section: UnwindSection, { // Always reset because previous initialization failure may leave dirty state. @@ -2055,11 +2116,11 @@ where self.is_initialized = false; } - fn row(&self) -> &UnwindTableRow { + fn row(&self) -> &UnwindTableRow { self.stack.last().unwrap() } - fn row_mut(&mut self) -> &mut UnwindTableRow { + fn row_mut(&mut self) -> &mut UnwindTableRow { self.stack.last_mut().unwrap() } @@ -2082,11 +2143,11 @@ where Ok(()) } - fn start_address(&self) -> u64 { + fn start_address(&self) -> A { self.row().start_address } - fn set_start_address(&mut self, start_address: u64) { + fn set_start_address(&mut self, start_address: A) { let row = self.row_mut(); row.start_address = start_address; } @@ -2196,17 +2257,17 @@ where pub struct UnwindTable<'a, 'ctx, R, S = StoreOnHeap> where R: Reader, - S: UnwindContextStorage, + S: UnwindContextStorage, { code_alignment_factor: Wrapping, data_alignment_factor: Wrapping, address_size: u8, - next_start_address: u64, - last_end_address: u64, + next_start_address: R::Address, + last_end_address: R::Address, returned_last_row: bool, current_row_valid: bool, instructions: CallFrameInstructionIter<'a, R>, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, } /// # Signal Safe Methods @@ -2216,14 +2277,14 @@ where impl<'a, 'ctx, R, S> UnwindTable<'a, 'ctx, R, S> where R: Reader, - S: UnwindContextStorage, + S: UnwindContextStorage, { /// Construct a new `UnwindTable` for the given /// `FrameDescriptionEntry`'s CFI unwinding program. pub fn new>( section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, fde: &FrameDescriptionEntry, ) -> Result { ctx.initialize(section, bases, fde.cie())?; @@ -2232,8 +2293,8 @@ where fn new_for_fde>( section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, fde: &FrameDescriptionEntry, ) -> Self { assert!(ctx.stack.len() >= 1); @@ -2252,8 +2313,8 @@ where fn new_for_cie>( section: &'a Section, - bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, + bases: &'a BaseAddresses, + ctx: &'ctx mut UnwindContext, cie: &CommonInformationEntry, ) -> Self { assert!(ctx.stack.len() >= 1); @@ -2261,8 +2322,8 @@ where code_alignment_factor: Wrapping(cie.code_alignment_factor()), data_alignment_factor: Wrapping(cie.data_alignment_factor()), address_size: cie.address_size, - next_start_address: 0, - last_end_address: 0, + next_start_address: R::Address::zeroes(), + last_end_address: R::Address::zeroes(), returned_last_row: false, current_row_valid: false, instructions: cie.instructions(section, bases), @@ -2275,7 +2336,7 @@ where /// /// Unfortunately, this cannot be used with `FallibleIterator` because of /// the restricted lifetime of the yielded item. - pub fn next_row(&mut self) -> Result>> { + pub fn next_row(&mut self) -> Result>> { assert!(self.ctx.stack.len() >= 1); self.ctx.set_start_address(self.next_start_address); self.current_row_valid = false; @@ -2308,7 +2369,7 @@ where } /// Returns the current row with the lifetime of the context. - pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow> { + pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow> { if self.current_row_valid { Some(self.ctx.row()) } else { @@ -2318,7 +2379,10 @@ where /// Evaluate one call frame instruction. Return `Ok(true)` if the row is /// complete, `Ok(false)` otherwise. - fn evaluate(&mut self, instruction: CallFrameInstruction) -> Result { + fn evaluate( + &mut self, + instruction: CallFrameInstruction, + ) -> Result { use crate::CallFrameInstruction::*; match instruction { @@ -2335,10 +2399,8 @@ where } AdvanceLoc { delta } => { let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor; - self.next_start_address = self - .ctx - .start_address() - .add_sized(delta.0, self.address_size)?; + let delta = R::Address::length(delta.0, self.address_size)?; + self.next_start_address = self.ctx.start_address().add(delta, self.address_size)?; self.ctx.row_mut().end_address = self.next_start_address; return Ok(true); } @@ -2530,18 +2592,20 @@ where // - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-aarch64/dwarf-config.h#L32 // - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-arm/dwarf-config.h#L31 // - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-mips/dwarf-config.h#L31 -struct RegisterRuleMap +struct RegisterRuleMap where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { rules: ArrayVec, } -impl Debug for RegisterRuleMap +impl Debug for RegisterRuleMap where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RegisterRuleMap") @@ -2550,10 +2614,11 @@ where } } -impl Clone for RegisterRuleMap +impl Clone for RegisterRuleMap where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn clone(&self) -> Self { Self { @@ -2562,10 +2627,11 @@ where } } -impl Default for RegisterRuleMap +impl Default for RegisterRuleMap where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn default() -> Self { RegisterRuleMap { @@ -2578,10 +2644,11 @@ where /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. -impl RegisterRuleMap +impl RegisterRuleMap where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn is_default(&self) -> bool { self.rules.is_empty() @@ -2630,10 +2697,11 @@ where } } -impl<'a, R, S> FromIterator<&'a (Register, RegisterRule)> for RegisterRuleMap +impl<'a, R, A, S> FromIterator<&'a (Register, RegisterRule)> for RegisterRuleMap where R: 'a + ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn from_iter(iter: T) -> Self where @@ -2651,10 +2719,11 @@ where } } -impl PartialEq for RegisterRuleMap +impl PartialEq for RegisterRuleMap where - T: ReaderOffset + PartialEq, - S: UnwindContextStorage, + T: ReaderOffset, + A: ReaderAddress, + S: UnwindContextStorage, { fn eq(&self, rhs: &Self) -> bool { for &(reg, ref rule) in &*self.rules { @@ -2675,10 +2744,11 @@ where } } -impl Eq for RegisterRuleMap +impl Eq for RegisterRuleMap where - T: ReaderOffset + Eq, - S: UnwindContextStorage, + T: ReaderOffset, + A: ReaderAddress, + S: UnwindContextStorage, { } @@ -2699,22 +2769,24 @@ impl<'iter, T: ReaderOffset> Iterator for RegisterRuleIter<'iter, T> { /// A row in the virtual unwind table that describes how to find the values of /// the registers in the *previous* frame for a range of PC addresses. #[derive(PartialEq, Eq)] -pub struct UnwindTableRow +pub struct UnwindTableRow where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { - start_address: u64, - end_address: u64, + start_address: A, + end_address: A, saved_args_size: u64, cfa: CfaRule, - registers: RegisterRuleMap, + registers: RegisterRuleMap, } -impl Debug for UnwindTableRow +impl Debug for UnwindTableRow where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("UnwindTableRow") @@ -2727,10 +2799,11 @@ where } } -impl Clone for UnwindTableRow +impl Clone for UnwindTableRow where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn clone(&self) -> Self { Self { @@ -2743,15 +2816,16 @@ where } } -impl Default for UnwindTableRow +impl Default for UnwindTableRow where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn default() -> Self { UnwindTableRow { - start_address: 0, - end_address: 0, + start_address: A::zeroes(), + end_address: A::zeroes(), saved_args_size: 0, cfa: Default::default(), registers: Default::default(), @@ -2759,20 +2833,21 @@ where } } -impl UnwindTableRow +impl UnwindTableRow where T: ReaderOffset, - S: UnwindContextStorage, + A: ReaderAddress, + S: UnwindContextStorage, { fn is_default(&self) -> bool { - self.start_address == 0 - && self.end_address == 0 + self.start_address == A::zeroes() + && self.end_address == A::zeroes() && self.cfa.is_default() && self.registers.is_default() } /// Get the starting PC address that this row applies to. - pub fn start_address(&self) -> u64 { + pub fn start_address(&self) -> A { self.start_address } @@ -2783,13 +2858,16 @@ where /// registers for all PCs where `row.start_address() <= PC < /// row.end_address()`. This row does NOT describe how to recover registers /// when `PC == row.end_address()`. - pub fn end_address(&self) -> u64 { + pub fn end_address(&self) -> A { self.end_address } /// Return `true` if the given `address` is within this row's address range, /// `false` otherwise. - pub fn contains(&self, address: u64) -> bool { + pub fn contains(&self, address: A) -> bool + where + A: Ord, + { self.start_address <= address && address < self.end_address } @@ -2962,7 +3040,7 @@ impl RegisterRule { /// A parsed call frame instruction. #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] -pub enum CallFrameInstruction { +pub enum CallFrameInstruction { // 6.4.2.1 Row Creation Methods /// > 1. DW_CFA_set_loc /// > @@ -2975,7 +3053,7 @@ pub enum CallFrameInstruction { /// > by a segment selector of the given length. SetLoc { /// The target address. - address: u64, + address: A, }, /// The `AdvanceLoc` instruction is used for all of `DW_CFA_advance_loc` and @@ -3261,13 +3339,13 @@ pub enum CallFrameInstruction { const CFI_INSTRUCTION_HIGH_BITS_MASK: u8 = 0b1100_0000; const CFI_INSTRUCTION_LOW_BITS_MASK: u8 = !CFI_INSTRUCTION_HIGH_BITS_MASK; -impl CallFrameInstruction { - fn parse>( +impl CallFrameInstruction { + fn parse>( input: &mut R, address_encoding: Option, parameters: &PointerEncodingParameters<'_, R>, vendor: Vendor, - ) -> Result> { + ) -> Result { let instruction = input.read_u8()?; let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK; @@ -3481,7 +3559,7 @@ pub struct CallFrameInstructionIter<'a, R: Reader> { impl<'a, R: Reader> CallFrameInstructionIter<'a, R> { /// Parse the next call frame instruction. - pub fn next(&mut self) -> Result>> { + pub fn next(&mut self) -> Result>> { if self.input.is_empty() { return Ok(None); } @@ -3503,7 +3581,7 @@ impl<'a, R: Reader> CallFrameInstructionIter<'a, R> { #[cfg(feature = "fallible-iterator")] impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstructionIter<'a, R> { - type Item = CallFrameInstruction; + type Item = CallFrameInstruction; type Error = Error; fn next(&mut self) -> ::core::result::Result, Self::Error> { @@ -3578,9 +3656,9 @@ fn parse_pointer_encoding(input: &mut R) -> Result /// A decoded pointer. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Pointer { +pub enum Pointer { /// This value is the decoded pointer value. - Direct(u64), + Direct(T), /// This value is *not* the pointer value, but points to the address of /// where the real pointer value lives. In other words, deref this pointer @@ -3588,19 +3666,19 @@ pub enum Pointer { /// /// Chase this pointer at your own risk: do you trust the DWARF data it came /// from? - Indirect(u64), + Indirect(T), } -impl Default for Pointer { +impl Default for Pointer { #[inline] fn default() -> Self { - Pointer::Direct(0) + Pointer::Direct(T::default()) } } -impl Pointer { +impl Pointer { #[inline] - fn new(encoding: constants::DwEhPe, address: u64) -> Pointer { + fn new(encoding: constants::DwEhPe, address: T) -> Self { if encoding.is_indirect() { Pointer::Indirect(address) } else { @@ -3610,7 +3688,7 @@ impl Pointer { /// Return the direct pointer value. #[inline] - pub fn direct(self) -> Result { + pub fn direct(self) -> Result { match self { Pointer::Direct(p) => Ok(p), Pointer::Indirect(_) => Err(Error::UnsupportedPointerEncoding), @@ -3619,7 +3697,7 @@ impl Pointer { /// Return the pointer value, discarding indirectness information. #[inline] - pub fn pointer(self) -> u64 { + pub fn pointer(self) -> T { match self { Pointer::Direct(p) | Pointer::Indirect(p) => p, } @@ -3628,8 +3706,8 @@ impl Pointer { #[derive(Clone, Debug)] struct PointerEncodingParameters<'a, R: Reader> { - bases: &'a SectionBaseAddresses, - func_base: Option, + bases: &'a SectionBaseAddresses, + func_base: Option, address_size: u8, section: &'a R, } @@ -3638,7 +3716,7 @@ fn parse_encoded_pointer( encoding: constants::DwEhPe, parameters: &PointerEncodingParameters<'_, R>, input: &mut R, -) -> Result { +) -> Result> { // TODO: check this once only in parse_pointer_encoding if !encoding.is_valid_encoding() { return Err(Error::UnknownPointerEncoding(encoding)); @@ -3649,12 +3727,15 @@ fn parse_encoded_pointer( } let base = match encoding.application() { - constants::DW_EH_PE_absptr => 0, + constants::DW_EH_PE_absptr => R::Address::zeroes(), constants::DW_EH_PE_pcrel => { if let Some(section_base) = parameters.bases.section { - let offset_from_section = input.offset_from(parameters.section); - section_base - .wrapping_add_sized(offset_from_section.into_u64(), parameters.address_size) + // Determine the section offset of the input. + let offset_from_section = input.offset_from(parameters.section).into_u64(); + // Convert that to an address offset, and add it to the base address. + let relative_address = + R::Address::length(offset_from_section, parameters.address_size)?; + section_base.add(relative_address, parameters.address_size)? } else { return Err(Error::PcRelativePointerButSectionBaseIsUndefined); } @@ -3687,7 +3768,7 @@ fn parse_encoded_pointer( let offset = parse_encoded_value(encoding, parameters, input)?; Ok(Pointer::new( encoding, - base.wrapping_add_sized(offset, parameters.address_size), + base.wrapping_add(offset, parameters.address_size), )) } @@ -3695,10 +3776,10 @@ fn parse_encoded_value( encoding: constants::DwEhPe, parameters: &PointerEncodingParameters<'_, R>, input: &mut R, -) -> Result { - match encoding.format() { +) -> Result<::Length> { + let value = match encoding.format() { // Unsigned variants. - constants::DW_EH_PE_absptr => input.read_address(parameters.address_size), + constants::DW_EH_PE_absptr => return input.read_address_range(parameters.address_size), constants::DW_EH_PE_uleb128 => input.read_uleb128(), constants::DW_EH_PE_udata2 => input.read_u16().map(u64::from), constants::DW_EH_PE_udata4 => input.read_u32().map(u64::from), @@ -3715,7 +3796,8 @@ fn parse_encoded_value( // That was all of the valid encoding formats. _ => unreachable!(), - } + }?; + R::Address::length(value, parameters.address_size) } #[cfg(test)] @@ -3735,6 +3817,28 @@ mod tests { use core::mem; use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum}; + /// Ensure that `FrameDescriptionEntry` is covariant wrt R. + #[test] + fn test_fde_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>( + x: FrameDescriptionEntry>, + ) -> FrameDescriptionEntry> { + x + } + } + + /// Ensure that `CommonInformationEntry` is covariant wrt R. + #[test] + fn test_cie_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>( + x: CommonInformationEntry>, + ) -> CommonInformationEntry> { + x + } + } + // Ensure each test tries to read the same section kind that it wrote. #[derive(Clone, Copy)] struct SectionKind
(PhantomData
); @@ -3784,7 +3888,7 @@ mod tests { R: Reader, Section: UnwindSection, O: UnwindOffset, - F: FnMut(&Section, &BaseAddresses, O) -> Result>, + F: FnMut(&Section, &BaseAddresses, O) -> Result>, { let bases = Default::default(); match parse_cfi_entry(&bases, §ion, input) { @@ -4593,7 +4697,7 @@ mod tests { fn parse_cfi_instruction( input: &mut R, address_size: u8, - ) -> Result> { + ) -> Result> { let section = input.clone(); let parameters = &PointerEncodingParameters { bases: &SectionBaseAddresses::default(), diff --git a/src/read/dwarf.rs b/src/read/dwarf.rs index d61d76f1..79540416 100644 --- a/src/read/dwarf.rs +++ b/src/read/dwarf.rs @@ -14,9 +14,9 @@ use crate::read::{ DebugLineStr, DebugLoc, DebugLocLists, DebugRanges, DebugRngLists, DebugStr, DebugStrOffsets, DebugTuIndex, DebugTypes, DebugTypesUnitHeadersIter, DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, Error, IncompleteLineProgram, IndexSectionId, LocListIter, - LocationLists, Range, RangeLists, RawLocListIter, RawRngListIter, Reader, ReaderOffset, - ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitIndex, UnitIndexSectionIterator, - UnitOffset, UnitType, + LocationLists, Range, RangeLists, RawLocListIter, RawRngListIter, Reader, ReaderAddress, + ReaderOffset, ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitIndex, + UnitIndexSectionIterator, UnitOffset, UnitType, }; /// All of the commonly used DWARF sections. @@ -421,9 +421,10 @@ impl Dwarf { } /// Return the address at the given index. - pub fn address(&self, unit: &Unit, index: DebugAddrIndex) -> Result { + pub fn address(&self, unit: &Unit, index: DebugAddrIndex) -> Result { + let address_size = unit.encoding().address_size; self.debug_addr - .get_address(unit.encoding().address_size, unit.addr_base, index) + .get_address(address_size, unit.addr_base, index) } /// Try to return an attribute value as an address. @@ -435,7 +436,11 @@ impl Dwarf { /// /// then return the address. /// Returns `None` for other forms. - pub fn attr_address(&self, unit: &Unit, attr: AttributeValue) -> Result> { + pub fn attr_address( + &self, + unit: &Unit, + attr: AttributeValue, + ) -> Result> { match attr { AttributeValue::Addr(addr) => Ok(Some(addr)), AttributeValue::DebugAddrIndex(index) => self.address(unit, index).map(Some), @@ -543,6 +548,7 @@ impl Dwarf { unit: &Unit, entry: &DebuggingInformationEntry<'_, '_, R>, ) -> Result> { + let address_size = unit.encoding().address_size; let mut low_pc = None; let mut high_pc = None; let mut size = None; @@ -556,7 +562,9 @@ impl Dwarf { ); } constants::DW_AT_high_pc => match attr.value() { - AttributeValue::Udata(val) => size = Some(val), + AttributeValue::Udata(val) => { + size = Some(R::Address::length(val, address_size)?); + } attr => { high_pc = Some( self.attr_address(unit, attr)? @@ -573,7 +581,9 @@ impl Dwarf { } } let range = low_pc.and_then(|begin| { - let end = size.map(|size| begin + size).or(high_pc); + let end = size + .and_then(|size| begin.add(size, address_size).ok()) + .or(high_pc); // TODO: perhaps return an error if `end` is `None` end.map(|end| Range { begin, end }) }); @@ -1097,13 +1107,14 @@ impl DwarfPackage { /// All of the commonly used information for a unit in the `.debug_info` or `.debug_types` /// sections. #[derive(Debug)] -pub struct Unit::Offset> +pub struct Unit::Offset, Address = ::Address> where - R: Reader, + R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { /// The header of the unit. - pub header: UnitHeader, + pub header: UnitHeader, /// The parsed abbreviations for the unit. pub abbreviations: Arc, @@ -1115,7 +1126,7 @@ where pub comp_dir: Option, /// The `DW_AT_low_pc` attribute of the unit. Defaults to 0. - pub low_pc: u64, + pub low_pc: Address, /// The `DW_AT_str_offsets_base` attribute of the unit. Defaults to 0. pub str_offsets_base: DebugStrOffsetsBase, @@ -1130,7 +1141,7 @@ where pub rnglists_base: DebugRngListsBase, /// The line number program of the unit. - pub line_program: Option>, + pub line_program: Option>, /// The DWO ID of a skeleton unit or split compilation unit. pub dwo_id: Option, @@ -1159,7 +1170,7 @@ impl Unit { abbreviations, name: None, comp_dir: None, - low_pc: 0, + low_pc: R::Address::zeroes(), str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file( header.encoding(), dwarf.file_type, @@ -1419,14 +1430,14 @@ impl<'a, R: Reader> UnitRef<'a, R> { } /// Return the address at the given index. - pub fn address(&self, index: DebugAddrIndex) -> Result { + pub fn address(&self, index: DebugAddrIndex) -> Result { self.dwarf.address(self.unit, index) } /// Try to return an attribute value as an address. /// /// See [`Dwarf::attr_address`] for more information. - pub fn attr_address(&self, attr: AttributeValue) -> Result> { + pub fn attr_address(&self, attr: AttributeValue) -> Result> { self.dwarf.attr_address(self.unit, attr) } @@ -1588,7 +1599,7 @@ pub struct RangeIter(RangeIterInner); #[derive(Debug)] enum RangeIterInner { - Single(Option), + Single(Option>), List(RngListIter), } @@ -1600,7 +1611,7 @@ impl Default for RangeIter { impl RangeIter { /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result> { + pub fn next(&mut self) -> Result>> { match self.0 { RangeIterInner::Single(ref mut range) => Ok(range.take()), RangeIterInner::List(ref mut list) => list.next(), @@ -1610,7 +1621,7 @@ impl RangeIter { #[cfg(feature = "fallible-iterator")] impl fallible_iterator::FallibleIterator for RangeIter { - type Item = Range; + type Item = Range; type Error = Error; #[inline] diff --git a/src/read/endian_reader.rs b/src/read/endian_reader.rs index 5e65b4d1..f6c9166c 100644 --- a/src/read/endian_reader.rs +++ b/src/read/endian_reader.rs @@ -6,13 +6,14 @@ use alloc::string::String; use alloc::sync::Arc; use core::fmt::Debug; use core::hash::{Hash, Hasher}; +use core::marker::PhantomData; use core::ops::{Deref, Index, Range, RangeFrom, RangeTo}; use core::slice; use core::str; use stable_deref_trait::CloneStableDeref; use crate::endianity::Endianity; -use crate::read::{Error, Reader, ReaderOffsetId, Result}; +use crate::read::{Error, Reader, ReaderAddress, ReaderOffsetId, Result}; /// A reference counted, non-thread-safe slice of bytes and associated /// endianity. @@ -26,7 +27,7 @@ use crate::read::{Error, Reader, ReaderOffsetId, Result}; /// # let _ = reader; /// # } /// ``` -pub type EndianRcSlice = EndianReader>; +pub type EndianRcSlice = EndianReader, Address>; /// An atomically reference counted, thread-safe slice of bytes and associated /// endianity. @@ -40,7 +41,7 @@ pub type EndianRcSlice = EndianReader>; /// # let _ = reader; /// # } /// ``` -pub type EndianArcSlice = EndianReader>; +pub type EndianArcSlice = EndianReader, Address>; /// An easy way to define a custom `Reader` implementation with a reference to a /// generic buffer of bytes and an associated endianity. @@ -117,35 +118,60 @@ pub type EndianArcSlice = EndianReader>; /// pub type MmapFileReader = gimli::EndianReader; /// # fn test(_: &MmapFileReader) { } /// ``` -#[derive(Debug, Clone, Copy)] -pub struct EndianReader +#[derive(Debug)] +pub struct EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { range: SubRange, endian: Endian, + // While an `EndianReader` could work with any integer address type, + // the `Reader` trait requires a specific address type. + address: PhantomData
, } -impl PartialEq> for EndianReader +impl Clone for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug + Clone, +{ + fn clone(&self) -> Self { + EndianReader { + range: self.range.clone(), + endian: self.endian, + address: PhantomData, + } + } +} + +impl Copy for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug + Copy, +{ +} + +impl PartialEq> + for EndianReader where Endian: Endianity, T1: CloneStableDeref + Debug, T2: CloneStableDeref + Debug, { - fn eq(&self, rhs: &EndianReader) -> bool { + fn eq(&self, rhs: &EndianReader) -> bool { self.bytes() == rhs.bytes() } } -impl Eq for EndianReader +impl Eq for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { } -impl Hash for EndianReader +impl Hash for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, @@ -231,17 +257,39 @@ where } } -impl EndianReader +impl EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + /// Construct a new `EndianReader` with the given bytes. + /// + /// This constructor uses the default address type of `u64`. + #[inline] + pub fn new(bytes: T, endian: Endian) -> Self { + EndianReader { + range: SubRange::new(bytes), + endian, + address: PhantomData, + } + } +} + +impl EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, { /// Construct a new `EndianReader` with the given bytes. + /// + /// This constructor allows the address type to be customized instead + /// of defaulting to `u64`. #[inline] - pub fn new(bytes: T, endian: Endian) -> EndianReader { + pub fn new_custom(bytes: T, endian: Endian) -> Self { EndianReader { range: SubRange::new(bytes), endian, + address: PhantomData, } } @@ -258,7 +306,7 @@ where /// implement `Index>` to return a new `EndianReader` the way we /// would like to. Instead, we abandon fancy indexing operators and have these /// plain old methods. -impl EndianReader +impl EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, @@ -281,7 +329,7 @@ where /// # Panics /// /// Panics if the range is out of bounds. - pub fn range(&self, idx: Range) -> EndianReader { + pub fn range(&self, idx: Range) -> EndianReader { let mut r = self.clone(); r.range.skip(idx.start); r.range.truncate(idx.len()); @@ -306,7 +354,7 @@ where /// # Panics /// /// Panics if the range is out of bounds. - pub fn range_from(&self, idx: RangeFrom) -> EndianReader { + pub fn range_from(&self, idx: RangeFrom) -> EndianReader { let mut r = self.clone(); r.range.skip(idx.start); r @@ -330,14 +378,14 @@ where /// # Panics /// /// Panics if the range is out of bounds. - pub fn range_to(&self, idx: RangeTo) -> EndianReader { + pub fn range_to(&self, idx: RangeTo) -> EndianReader { let mut r = self.clone(); r.range.truncate(idx.end); r } } -impl Index for EndianReader +impl Index for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, @@ -348,7 +396,7 @@ where } } -impl Index> for EndianReader +impl Index> for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, @@ -359,7 +407,7 @@ where } } -impl Deref for EndianReader +impl Deref for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, @@ -370,13 +418,15 @@ where } } -impl Reader for EndianReader +impl Reader for EndianReader where Endian: Endianity, T: CloneStableDeref + Debug, + Address: ReaderAddress, { type Endian = Endian; type Offset = usize; + type Address = Address; #[inline] fn endian(&self) -> Endian { @@ -404,7 +454,7 @@ where } #[inline] - fn offset_from(&self, base: &EndianReader) -> usize { + fn offset_from(&self, base: &Self) -> usize { let base_ptr = base.bytes().as_ptr() as usize; let ptr = self.bytes().as_ptr() as usize; debug_assert!(base_ptr <= ptr); diff --git a/src/read/endian_slice.rs b/src/read/endian_slice.rs index 03351429..95ac3b73 100644 --- a/src/read/endian_slice.rs +++ b/src/read/endian_slice.rs @@ -5,32 +5,60 @@ use alloc::borrow::Cow; #[cfg(feature = "read")] use alloc::string::String; use core::fmt; +use core::marker::PhantomData; use core::ops::{Deref, Range, RangeFrom, RangeTo}; use core::str; use crate::endianity::Endianity; -use crate::read::{Error, Reader, ReaderOffsetId, Result}; +use crate::read::{Error, Reader, ReaderAddress, ReaderOffsetId, Result}; /// A `&[u8]` slice with endianity metadata. /// /// This implements the `Reader` trait, which is used for all reading of DWARF sections. #[derive(Default, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EndianSlice<'input, Endian> +pub struct EndianSlice<'input, Endian, Address = u64> where Endian: Endianity, { slice: &'input [u8], endian: Endian, + // While an `EndianSlice` could work with any integer address type, + // the `Reader` trait requires a specific address type. + address: PhantomData
, } -impl<'input, Endian> EndianSlice<'input, Endian> +impl<'input, Endian> EndianSlice<'input, Endian, u64> where Endian: Endianity, { /// Construct a new `EndianSlice` with the given slice and endianity. + /// + /// This constructor uses the default address type of `u64`. #[inline] - pub fn new(slice: &'input [u8], endian: Endian) -> EndianSlice<'input, Endian> { - EndianSlice { slice, endian } + pub fn new(slice: &'input [u8], endian: Endian) -> Self { + EndianSlice { + slice, + endian, + address: PhantomData, + } + } +} + +impl<'input, Endian, Address> EndianSlice<'input, Endian, Address> +where + Endian: Endianity, +{ + /// Construct a new `EndianSlice` with the given slice and endianity. + /// + /// This constructor allows the address type to be customized instead + /// of defaulting to `u64`. + #[inline] + pub fn new_custom(slice: &'input [u8], endian: Endian) -> Self { + EndianSlice { + slice, + endian, + address: PhantomData, + } } /// Return a reference to the raw slice. @@ -54,7 +82,10 @@ where pub fn split_at( &self, idx: usize, - ) -> (EndianSlice<'input, Endian>, EndianSlice<'input, Endian>) { + ) -> ( + EndianSlice<'input, Endian, Address>, + EndianSlice<'input, Endian, Address>, + ) { (self.range_to(..idx), self.range_from(idx..)) } @@ -67,7 +98,7 @@ where /// Return the offset of the start of the slice relative to the start /// of the given slice. #[inline] - pub fn offset_from(&self, base: EndianSlice<'input, Endian>) -> usize { + pub fn offset_from(&self, base: EndianSlice<'input, Endian, Address>) -> usize { let base_ptr = base.slice.as_ptr() as usize; let ptr = self.slice.as_ptr() as usize; debug_assert!(base_ptr <= ptr); @@ -90,7 +121,13 @@ where pub fn to_string_lossy(&self) -> Cow<'input, str> { String::from_utf8_lossy(self.slice) } +} +impl<'input, Endian, Address> EndianSlice<'input, Endian, Address> +where + Endian: Endianity, + Address: ReaderAddress, +{ #[inline] fn read_slice(&mut self, len: usize) -> Result<&'input [u8]> { if self.slice.len() < len { @@ -109,7 +146,7 @@ where /// implement `Index>` to return a new `EndianSlice` the way we would /// like to. Instead, we abandon fancy indexing operators and have these plain /// old methods. -impl<'input, Endian> EndianSlice<'input, Endian> +impl<'input, Endian, Address> EndianSlice<'input, Endian, Address> where Endian: Endianity, { @@ -124,10 +161,11 @@ where /// assert_eq!(endian_slice.range(1..3), /// EndianSlice::new(&slice[1..3], LittleEndian)); /// ``` - pub fn range(&self, idx: Range) -> EndianSlice<'input, Endian> { + pub fn range(&self, idx: Range) -> EndianSlice<'input, Endian, Address> { EndianSlice { slice: &self.slice[idx], endian: self.endian, + address: PhantomData, } } @@ -142,10 +180,11 @@ where /// assert_eq!(endian_slice.range_from(2..), /// EndianSlice::new(&slice[2..], LittleEndian)); /// ``` - pub fn range_from(&self, idx: RangeFrom) -> EndianSlice<'input, Endian> { + pub fn range_from(&self, idx: RangeFrom) -> EndianSlice<'input, Endian, Address> { EndianSlice { slice: &self.slice[idx], endian: self.endian, + address: PhantomData, } } @@ -160,15 +199,16 @@ where /// assert_eq!(endian_slice.range_to(..3), /// EndianSlice::new(&slice[..3], LittleEndian)); /// ``` - pub fn range_to(&self, idx: RangeTo) -> EndianSlice<'input, Endian> { + pub fn range_to(&self, idx: RangeTo) -> EndianSlice<'input, Endian, Address> { EndianSlice { slice: &self.slice[idx], endian: self.endian, + address: PhantomData, } } } -impl<'input, Endian> Deref for EndianSlice<'input, Endian> +impl<'input, Endian, Address> Deref for EndianSlice<'input, Endian, Address> where Endian: Endianity, { @@ -178,7 +218,7 @@ where } } -impl<'input, Endian: Endianity> fmt::Debug for EndianSlice<'input, Endian> { +impl<'input, Endian: Endianity, Address> fmt::Debug for EndianSlice<'input, Endian, Address> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> core::result::Result<(), fmt::Error> { fmt.debug_tuple("EndianSlice") .field(&self.endian) @@ -216,12 +256,14 @@ impl fmt::Debug for DebugLen { } } -impl<'input, Endian> Reader for EndianSlice<'input, Endian> +impl<'input, Endian, Address> Reader for EndianSlice<'input, Endian, Address> where Endian: Endianity, + Address: ReaderAddress, { type Endian = Endian; type Offset = usize; + type Address = Address; #[inline] fn endian(&self) -> Endian { @@ -294,7 +336,11 @@ where #[inline] fn split(&mut self, len: usize) -> Result { let slice = self.read_slice(len)?; - Ok(EndianSlice::new(slice, self.endian)) + Ok(EndianSlice { + slice, + endian: self.endian, + address: self.address, + }) } #[cfg(not(feature = "read"))] @@ -336,6 +382,15 @@ mod tests { use super::*; use crate::endianity::NativeEndian; + /// Ensure that `Unit` is covariant wrt R. + #[test] + fn test_endian_slice_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>(x: EndianSlice<'a, E>) -> EndianSlice<'b, E> { + x + } + } + #[test] fn test_endian_slice_split_at() { let endian = NativeEndian; diff --git a/src/read/line.rs b/src/read/line.rs index fc7e0532..8d4acf01 100644 --- a/src/read/line.rs +++ b/src/read/line.rs @@ -165,14 +165,15 @@ pub type StateMachine = LineRows; /// to expand the byte-coded instruction stream into a matrix of line number /// information." -- Section 6.2.1 #[derive(Debug, Clone)] -pub struct LineRows::Offset> +pub struct LineRows::Offset, Address = ::Address> where Program: LineProgram, R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { program: Program, - row: LineRow, + row: LineRow
, instructions: LineInstructions, } @@ -230,7 +231,9 @@ where /// /// Unfortunately, the references mean that this cannot be a /// `FallibleIterator`. - pub fn next_row(&mut self) -> Result, &LineRow)>> { + pub fn next_row( + &mut self, + ) -> Result, &LineRow)>> { // Perform any reset that was required after copying the previous row. self.row.reset(self.program.header()); @@ -260,14 +263,15 @@ where /// Deprecated. `Opcode` has been renamed to `LineInstruction`. #[deprecated(note = "Opcode has been renamed to LineInstruction, use that instead.")] -pub type Opcode = LineInstruction::Offset>; +pub type Opcode = LineInstruction::Offset, ::Address>; /// A parsed line number program instruction. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LineInstruction::Offset> +pub enum LineInstruction::Offset, Address = ::Address> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { /// > ### 6.2.5.1 Special Opcodes /// > @@ -383,11 +387,11 @@ where /// > All of the other line number program opcodes that affect the address /// > register add a delta to it. This instruction stores a relocatable value /// > into it instead. - SetAddress(u64), + SetAddress(Address), /// Defines a new source file in the line number program and appends it to /// the line number program header's list of source files. - DefineFile(FileEntry), + DefineFile(FileEntry), /// "The DW_LNE_set_discriminator opcode takes a single parameter, an /// unsigned LEB128 integer. It sets the discriminator register to the new @@ -577,9 +581,9 @@ pub type LineNumberRow = LineRow; /// /// Each row is a copy of the registers of the state machine, as defined in section 6.2.2. #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct LineRow { +pub struct LineRow { tombstone: bool, - address: u64, + address: A, op_index: Wrapping, file: u64, line: Wrapping, @@ -593,14 +597,14 @@ pub struct LineRow { discriminator: u64, } -impl LineRow { +impl LineRow { /// Create a line number row in the initial state for the given program. - pub fn new(header: &LineProgramHeader) -> Self { + pub fn new>(header: &LineProgramHeader) -> Self { LineRow { // "At the beginning of each sequence within a line number program, the // state of the registers is:" -- Section 6.2.2 tombstone: false, - address: 0, + address: R::Address::zeroes(), op_index: Wrapping(0), file: 1, line: Wrapping(1), @@ -623,7 +627,7 @@ impl LineRow { /// "The program-counter value corresponding to a machine instruction /// generated by the compiler." #[inline] - pub fn address(&self) -> u64 { + pub fn address(&self) -> A { self.address } @@ -751,7 +755,7 @@ impl LineRow { ) -> Result where Program: LineProgram, - R: Reader, + R: Reader
, { Ok(match instruction { LineInstruction::Special(opcode) => { @@ -801,7 +805,8 @@ impl LineRow { LineInstruction::FixedAddPc(operand) => { if !self.tombstone { let address_size = program.header().address_size(); - self.address = self.address.add_sized(u64::from(operand), address_size)?; + let offset = A::length(operand.into(), address_size)?; + self.address = self.address.add(offset, address_size)?; self.op_index.0 = 0; } false @@ -828,8 +833,7 @@ impl LineRow { } LineInstruction::SetAddress(address) => { - let tombstone_address = u64::ones_sized(program.header().encoding.address_size); - self.tombstone = address == tombstone_address; + self.tombstone = address == A::ones(program.header().encoding.address_size); if !self.tombstone { if address < self.address { return Err(Error::InvalidAddressRange); @@ -860,7 +864,7 @@ impl LineRow { /// Perform any reset that was required after copying the previous row. #[inline] - pub fn reset(&mut self, header: &LineProgramHeader) { + pub fn reset>(&mut self, header: &LineProgramHeader) { if self.end_sequence { // Previous instruction was EndSequence, so reset everything // as specified in Section 6.2.5.3. @@ -892,7 +896,7 @@ impl LineRow { } /// Step 2 of section 6.2.5.1 - fn apply_operation_advance( + fn apply_operation_advance>( &mut self, operation_advance: u64, header: &LineProgramHeader, @@ -919,9 +923,9 @@ impl LineRow { minimum_instruction_length * (op_index_with_advance / maximum_operations_per_instruction) }; - self.address = self - .address - .add_sized(address_advance.0, header.address_size())?; + let address_size = header.address_size(); + let address_advance = A::length(address_advance.0, address_size)?; + self.address = self.address.add(address_advance, address_size)?; Ok(()) } @@ -931,7 +935,7 @@ impl LineRow { } /// Section 6.2.5.1 - fn exec_special_opcode( + fn exec_special_opcode>( &mut self, opcode: u8, header: &LineProgramHeader, @@ -973,10 +977,10 @@ pub type LineNumberSequence = LineSequence; pub struct LineSequence { /// The first address that is covered by this sequence within the line number /// program. - pub start: u64, + pub start: R::Address, /// The first address that is *not* covered by this sequence within the line /// number program. - pub end: u64, + pub end: R::Address, instructions: LineInstructions, } @@ -989,10 +993,11 @@ pub type LineNumberProgramHeader = LineProgramHeader; /// A header for a line number program in the `.debug_line` section, as defined /// in section 6.2.4 of the standard. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct LineProgramHeader::Offset> +pub struct LineProgramHeader::Offset, Address = ::Address> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { encoding: Encoding, offset: DebugLineOffset, @@ -1022,7 +1027,7 @@ where /// > of the compilation. /// > /// > The last entry is followed by a single null byte. - include_directories: Vec>, + include_directories: Vec>, /// "A sequence of file entry format descriptions." file_name_entry_format: Vec, @@ -1030,7 +1035,7 @@ where /// "Entries in this sequence describe source files that contribute to the /// line number information for this compilation unit or is used in other /// contexts." - file_names: Vec>, + file_names: Vec>, /// The encoded line program instructions. program_buf: R, @@ -1039,7 +1044,7 @@ where comp_dir: Option, /// The primary source file. - comp_file: Option>, + comp_file: Option>, } impl LineProgramHeader @@ -1404,12 +1409,16 @@ pub type IncompleteLineNumberProgram = IncompleteLineProgram::Offset> -where +pub struct IncompleteLineProgram< + R, + Offset = ::Offset, + Address = ::Address, +> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { - header: LineProgramHeader, + header: LineProgramHeader, } impl IncompleteLineProgram @@ -1473,7 +1482,7 @@ where sequences.push(LineSequence { // In theory one could have multiple DW_LNE_end_sequence instructions // in a row. - start: sequence_start_addr.unwrap_or(0), + start: sequence_start_addr.unwrap_or_default(), end: sequence_end_addr, instructions: instructions.remove_trailing(&rows.instructions)?, }); @@ -1545,17 +1554,18 @@ where /// An entry in the `LineProgramHeader`'s `file_names` set. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct FileEntry::Offset> +pub struct FileEntry::Offset, Address = ::Address> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { - path_name: AttributeValue, + path_name: AttributeValue, directory_index: u64, timestamp: u64, size: u64, md5: [u8; 16], - source: Option>, + source: Option>, } impl FileEntry @@ -2932,14 +2942,26 @@ mod tests { /// Ensure that `LineRows` is covariant wrt R. /// This only needs to compile. - #[allow(dead_code, unreachable_code, unused_variables)] - #[allow(clippy::diverging_sub_expression)] - fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8]) - where - 'a: 'b, - { - let a: &OneShotLineRows> = unimplemented!(); - let _: &OneShotLineRows> = a; + #[test] + fn test_line_rows_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>( + x: OneShotLineRows>, + ) -> OneShotLineRows> { + x + } + } + + /// Ensure that `LineInstruction` is covariant wrt R. + /// This only needs to compile. + #[test] + fn test_line_instruction_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>( + x: LineInstruction>, + ) -> LineInstruction> { + x + } } #[test] diff --git a/src/read/lists.rs b/src/read/lists.rs index 9b23fc8b..62c13473 100644 --- a/src/read/lists.rs +++ b/src/read/lists.rs @@ -14,7 +14,7 @@ impl ListsHeader { #[inline] fn size(self) -> u8 { // initial_length + version + address_size + segment_selector_size + offset_entry_count - ListsHeader::size_for_encoding(self.encoding) + Self::size_for_encoding(self.encoding) } /// Return the serialized size of the table header. diff --git a/src/read/loclists.rs b/src/read/loclists.rs index a2874687..0807bc11 100644 --- a/src/read/loclists.rs +++ b/src/read/loclists.rs @@ -202,7 +202,7 @@ impl LocationLists { &self, offset: LocationListsOffset, unit_encoding: Encoding, - base_address: u64, + base_address: R::Address, debug_addr: &DebugAddr, debug_addr_base: DebugAddrBase, ) -> Result> { @@ -221,7 +221,7 @@ impl LocationLists { &self, offset: LocationListsOffset, unit_encoding: Encoding, - base_address: u64, + base_address: R::Address, debug_addr: &DebugAddr, debug_addr_base: DebugAddrBase, ) -> Result> { @@ -338,16 +338,16 @@ pub enum RawLocListEntry { /// A location from DWARF version <= 4. AddressOrOffsetPair { /// Start of range. May be an address or an offset. - begin: u64, + begin: R::Address, /// End of range. May be an address or an offset. - end: u64, + end: R::Address, /// expression data: Expression, }, /// DW_LLE_base_address BaseAddress { /// base address - addr: u64, + addr: R::Address, }, /// DW_LLE_base_addressx BaseAddressx { @@ -375,9 +375,9 @@ pub enum RawLocListEntry { /// DW_LLE_offset_pair OffsetPair { /// start of range - begin: u64, + begin: ::Length, /// end of range - end: u64, + end: ::Length, /// expression data: Expression, }, @@ -389,16 +389,16 @@ pub enum RawLocListEntry { /// DW_LLE_start_end StartEnd { /// start of range - begin: u64, + begin: R::Address, /// end of range - end: u64, + end: R::Address, /// expression data: Expression, }, /// DW_LLE_start_length StartLength { /// start of range - begin: u64, + begin: R::Address, /// length of range length: u64, /// expression @@ -420,12 +420,13 @@ fn parse_data(input: &mut R, encoding: Encoding) -> Result RawLocListEntry { /// Parse a location list entry from `.debug_loclists` fn parse(input: &mut R, encoding: Encoding, format: LocListsFormat) -> Result> { + let address_size = encoding.address_size; Ok(match format { LocListsFormat::Bare => { - let range = RawRange::parse(input, encoding.address_size)?; + let range = RawRange::parse(input, address_size)?; if range.is_end() { None - } else if range.is_base_address(encoding.address_size) { + } else if range.is_base_address(address_size) { Some(RawLocListEntry::BaseAddress { addr: range.end }) } else { let len = R::Offset::from_u16(input.read_u16()?); @@ -458,23 +459,23 @@ impl RawLocListEntry { data: parse_data(input, encoding)?, }), constants::DW_LLE_offset_pair => Some(RawLocListEntry::OffsetPair { - begin: input.read_uleb128()?, - end: input.read_uleb128()?, + begin: R::Address::length(input.read_uleb128()?, address_size)?, + end: R::Address::length(input.read_uleb128()?, address_size)?, data: parse_data(input, encoding)?, }), constants::DW_LLE_default_location => Some(RawLocListEntry::DefaultLocation { data: parse_data(input, encoding)?, }), constants::DW_LLE_base_address => Some(RawLocListEntry::BaseAddress { - addr: input.read_address(encoding.address_size)?, + addr: input.read_address(address_size)?, }), constants::DW_LLE_start_end => Some(RawLocListEntry::StartEnd { - begin: input.read_address(encoding.address_size)?, - end: input.read_address(encoding.address_size)?, + begin: input.read_address(address_size)?, + end: input.read_address(address_size)?, data: parse_data(input, encoding)?, }), constants::DW_LLE_start_length => Some(RawLocListEntry::StartLength { - begin: input.read_address(encoding.address_size)?, + begin: input.read_address(address_size)?, length: input.read_uleb128()?, data: parse_data(input, encoding)?, }), @@ -535,7 +536,7 @@ impl fallible_iterator::FallibleIterator for RawLocListIter { #[derive(Debug)] pub struct LocListIter { raw: RawLocListIter, - base_address: u64, + base_address: R::Address, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, } @@ -544,7 +545,7 @@ impl LocListIter { /// Construct a `LocListIter`. fn new( raw: RawLocListIter, - base_address: u64, + base_address: R::Address, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, ) -> LocListIter { @@ -557,7 +558,7 @@ impl LocListIter { } #[inline] - fn get_address(&self, index: DebugAddrIndex) -> Result { + fn get_address(&self, index: DebugAddrIndex) -> Result { self.debug_addr .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) } @@ -594,9 +595,13 @@ impl LocListIter { raw_loc: RawLocListEntry, ) -> Result>> { let address_size = self.raw.encoding.address_size; - let mask = u64::ones_sized(address_size); + let mask = R::Address::ones(address_size); let tombstone = if self.raw.encoding.version <= 4 { - mask - 1 + // mask - 1 + mask.wrapping_add( + R::Address::length(-1i64 as u64, address_size)?, + address_size, + ) } else { mask }; @@ -621,23 +626,37 @@ impl LocListIter { data, } => { let begin = self.get_address(begin)?; - let end = begin.wrapping_add_sized(length, address_size); + let length = R::Address::length(length, address_size)?; + let end = begin.wrapping_add(length, address_size); (Range { begin, end }, data) } RawLocListEntry::DefaultLocation { data } => ( Range { - begin: 0, - end: u64::MAX, + begin: R::Address::zeroes(), + end: R::Address::ones(address_size), }, data, ), - RawLocListEntry::AddressOrOffsetPair { begin, end, data } - | RawLocListEntry::OffsetPair { begin, end, data } => { + RawLocListEntry::AddressOrOffsetPair { begin, end, data } => { if self.base_address == tombstone { return Ok(None); } - let mut range = Range { begin, end }; - range.add_base_address(self.base_address, self.raw.encoding.address_size); + let range = if self.base_address == R::Address::zeroes() { + // This is an address pair. + Range { begin, end } + } else if let (Some(begin), Some(end)) = (begin.constant(), end.constant()) { + // This is an offset pair. + Range { begin, end }.add_base_address(self.base_address, address_size) + } else { + return Err(Error::InvalidAddressRangeOffset); + }; + (range, data) + } + RawLocListEntry::OffsetPair { begin, end, data } => { + if self.base_address == tombstone { + return Ok(None); + } + let range = Range { begin, end }.add_base_address(self.base_address, address_size); (range, data) } RawLocListEntry::StartEnd { begin, end, data } => (Range { begin, end }, data), @@ -646,7 +665,8 @@ impl LocListIter { length, data, } => { - let end = begin.wrapping_add_sized(length, address_size); + let length = R::Address::length(length, address_size)?; + let end = begin.wrapping_add(length, address_size); (Range { begin, end }, data) } }; @@ -673,7 +693,7 @@ impl fallible_iterator::FallibleIterator for LocListIter { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct LocationListEntry { /// The address range that this location is valid for. - pub range: Range, + pub range: Range, /// The data containing a single location description. pub data: Expression, @@ -881,7 +901,7 @@ mod tests { Ok(Some(LocationListEntry { range: Range { begin: 0, - end: u64::MAX, + end: 0xffff_ffff, }, data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)), })) diff --git a/src/read/mod.rs b/src/read/mod.rs index 5731e7fe..1b9b29a4 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -386,6 +386,8 @@ pub enum Error { UnknownCallFrameInstruction(constants::DwCfa), /// The end of an address range was before the beginning. InvalidAddressRange, + /// An address range offset was an address instead of an offset. + InvalidAddressRangeOffset, /// An address calculation overflowed. /// /// This is returned in cases where the address is expected to be @@ -401,6 +403,8 @@ pub enum Error { NoUnwindInfoForAddress, /// An offset value was larger than the maximum supported value. UnsupportedOffset, + /// An address offset could not be determined. + UnsupportedAddressOffset, /// The given pointer encoding is either unknown or invalid. UnknownPointerEncoding(constants::DwEhPe), /// Did not find an entry at the given offset. @@ -548,6 +552,9 @@ impl Error { Error::InvalidAddressRange => { "The end of an address range must not be before the beginning." } + Error::InvalidAddressRangeOffset => { + "An address range offset was an address instead of an offset." + } Error::AddressOverflow => "An address calculation overflowed.", Error::CfiInstructionInInvalidContext => { "Encountered a call frame instruction in a context in which it is not valid." @@ -560,6 +567,7 @@ impl Error { Error::UnsupportedOffset => { "An offset value was larger than the maximum supported value." } + Error::UnsupportedAddressOffset => "An address offset could not be determined.", Error::UnknownPointerEncoding(_) => { "The given pointer encoding is either unknown or invalid." } diff --git a/src/read/op.rs b/src/read/op.rs index 0094f805..a34b9961 100644 --- a/src/read/op.rs +++ b/src/read/op.rs @@ -33,10 +33,11 @@ pub enum DieReference { /// example, both `DW_OP_deref` and `DW_OP_xderef` are represented /// using `Operation::Deref`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Operation::Offset> +pub enum Operation::Offset, Address = ::Address> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { /// Dereference the topmost value of the stack. Deref { @@ -226,7 +227,7 @@ where /// Represents `DW_OP_addr`. Address { /// The offset to add. - address: u64, + address: Address, }, /// Read the address at the given index in `.debug_addr, relocate the address if needed, /// and push it on the stack. @@ -707,9 +708,7 @@ where constants::DW_OP_stack_value => Ok(Operation::StackValue), constants::DW_OP_implicit_pointer | constants::DW_OP_GNU_implicit_pointer => { let value = if encoding.version == 2 { - bytes - .read_address(encoding.address_size) - .and_then(Offset::from_u64)? + bytes.read_sized_offset(encoding.address_size)? } else { bytes.read_offset(encoding.format)? }; @@ -902,7 +901,7 @@ pub enum EvaluationResult { /// The `Evaluation` needs an address to be relocated to proceed further. /// Once the caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_relocated_address`. - RequiresRelocatedAddress(u64), + RequiresRelocatedAddress(R::Address), /// The `Evaluation` needs an address from the `.debug_addr` section. /// This address may also need to be relocated. /// Once the caller determines what value to provide it should resume the @@ -1170,7 +1169,7 @@ impl> Evaluation { max_iterations: None, iteration: 0, state: EvaluationState::Start(None), - addr_mask: u64::ones_sized(encoding.address_size), + addr_mask: u64::ones(encoding.address_size), stack: Default::default(), expression_stack: Default::default(), pc, @@ -2016,12 +2015,23 @@ mod tests { use super::*; use crate::common::Format; use crate::constants; - use crate::endianity::LittleEndian; + use crate::endianity::{Endianity, LittleEndian}; use crate::leb128; use crate::read::{EndianSlice, Error, Result, UnitOffset}; use crate::test_util::GimliSectionMethods; use test_assembler::{Endian, Section}; + /// Ensure that `Operation` is covariant wrt R. + #[test] + fn test_operation_variance() { + /// This only needs to compile. + fn _f<'a: 'b, 'b, E: Endianity>( + x: Operation>, + ) -> Operation> { + x + } + } + fn encoding4() -> Encoding { Encoding { format: Format::Dwarf32, diff --git a/src/read/reader.rs b/src/read/reader.rs index b1654feb..1fb8c3ca 100644 --- a/src/read/reader.rs +++ b/src/read/reader.rs @@ -3,6 +3,7 @@ use alloc::borrow::Cow; use core::convert::TryInto; use core::fmt::Debug; use core::hash::Hash; +use core::mem; use core::ops::{Add, AddAssign, Sub}; use crate::common::Format; @@ -18,7 +19,7 @@ use crate::read::{Error, Result}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ReaderOffsetId(pub u64); -/// A trait for offsets with a DWARF section. +/// A trait for offsets within a DWARF section. /// /// This allows consumers to choose a size that is appropriate for their address space. pub trait ReaderOffset: @@ -189,47 +190,254 @@ impl ReaderOffset for usize { /// A trait for addresses within a DWARF section. /// -/// Currently this is a simple extension trait for `u64`, but it may be expanded -/// in the future to support user-defined address types. -pub(crate) trait ReaderAddress: Sized { - /// Add a length to an address of the given size. +/// This allows consumers to choose a size that is appropriate for their machine, +/// or to use a type that includes symbol information. +/// +/// The `u64` implementation allows for addresses up to 64 bits in size, +/// with the size determined by the DWARF data. +/// +/// The [`Address32`] and [`Address64`] implementations allow for addresses +/// of exactly 32 or 64 bits in size, respectively. +pub trait ReaderAddress: Debug + Default + Copy + Eq + Ord { + /// The type used to store the length of an address range. + type Length: Debug + Default + Copy + Eq + From + Into; + + /// The default address size to use. This will usually be the native address size. + fn default_size() -> u8; + + /// The maximum address size supported by this type. + fn max_size() -> u8; + + /// Convert a u8 to an address size. + /// + /// This will return an error if the size is not supported. + fn size(bytes: u8) -> Result; + + /// Convert a u64 to an address. + fn address(address: u64, size: u8) -> Result; + + /// Convert a u64 to a length of an address range. + /// + /// Returns an error if the length is too large for the address size, + /// but allows for the possibility that the length is a negative value. + fn length(length: u64, size: u8) -> Result; + + /// Add a length to an address. /// /// Returns an error for overflow. - fn add_sized(self, length: u64, size: u8) -> Result; + fn add(self, length: Self::Length, size: u8) -> Result; /// Add a length to an address of the given size. /// /// Wraps the result to the size of the address to allow for the possibility /// that the length is a negative value. - fn wrapping_add_sized(self, length: u64, size: u8) -> Self; + fn wrapping_add(self, length: Self::Length, size: u8) -> Self; + + /// Calculate the distance between two addresses. + /// + /// Returns an error if the distance is negative or cannot be determined. + fn offset_from(self, address: Self) -> Result; + + /// If the address is a constant, return it. + fn constant(self) -> Option; + + /// The all-zeroes value of the address type. + fn zeroes() -> Self; /// The all-ones value of an address of the given size. - fn ones_sized(size: u8) -> Self; + fn ones(size: u8) -> Self; } impl ReaderAddress for u64 { - #[inline] - fn add_sized(self, length: u64, size: u8) -> Result { - let address = self.checked_add(length).ok_or(Error::AddressOverflow)?; - let mask = Self::ones_sized(size); + type Length = u64; + + fn default_size() -> u8 { + mem::size_of::() as u8 + } + + fn max_size() -> u8 { + 8 + } + + fn size(address_bytes: u8) -> Result { + match address_bytes { + 1 | 2 | 4 | 8 => Ok(address_bytes), + _ => Err(Error::UnsupportedAddressSize(address_bytes)), + } + } + + fn address(address: u64, size: u8) -> Result { + let mask = Self::ones(size); if address & !mask != 0 { return Err(Error::AddressOverflow); } Ok(address) } - #[inline] - fn wrapping_add_sized(self, length: u64, size: u8) -> Self { - let mask = Self::ones_sized(size); - self.wrapping_add(length) & mask + fn length(length: u64, size: u8) -> Result { + let mask = Self::ones(size); + if (length & !mask != 0) && (length & !mask != !mask) { + return Err(Error::AddressOverflow); + } + Ok(length & mask) } - #[inline] - fn ones_sized(size: u8) -> Self { + fn add(self, offset: Self::Length, size: u8) -> Result { + let address = self.checked_add(offset).ok_or(Error::AddressOverflow)?; + Self::address(address, size) + } + + fn wrapping_add(self, offset: Self::Length, size: u8) -> Self { + let mask = Self::ones(size); + self.wrapping_add(offset) & mask + } + + fn offset_from(self, address: Self) -> Result { + self.checked_sub(address) + .ok_or(Error::UnsupportedAddressOffset) + } + + fn constant(self) -> Option { + Some(self) + } + + fn zeroes() -> Self { + 0 + } + + fn ones(size: u8) -> Self { !0 >> (64 - size * 8) } } +/// A 32-bit address. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Address32(pub u32); + +impl ReaderAddress for Address32 { + type Length = u32; + + fn default_size() -> u8 { + 4 + } + + fn max_size() -> u8 { + 4 + } + + fn size(address_bytes: u8) -> Result { + match address_bytes { + 4 => Ok(4), + _ => Err(Error::UnsupportedAddressSize(address_bytes)), + } + } + + fn address(address: u64, size: u8) -> Result { + let mask = u64::from(Self::ones(size).0); + if address & !mask != 0 { + return Err(Error::AddressOverflow); + } + Ok(Address32(address as u32)) + } + + fn length(length: u64, size: u8) -> Result { + let mask = u64::from(Self::ones(size).0); + if (length & !mask != 0) && (length & !mask != !mask) { + return Err(Error::AddressOverflow); + } + Ok(length as u32) + } + + fn add(self, offset: Self::Length, _size: u8) -> Result { + self.0 + .checked_add(offset) + .map(Address32) + .ok_or(Error::AddressOverflow) + } + + fn wrapping_add(self, offset: Self::Length, _size: u8) -> Self { + Address32(self.0.wrapping_add(offset)) + } + + fn offset_from(self, address: Self) -> Result { + self.0 + .checked_sub(address.0) + .ok_or(Error::UnsupportedAddressOffset) + } + + fn constant(self) -> Option { + Some(self.0) + } + + fn zeroes() -> Self { + Address32(0) + } + + fn ones(_size: u8) -> Self { + Address32(!0) + } +} + +/// A 64-bit address. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Address64(pub u64); + +impl ReaderAddress for Address64 { + type Length = u64; + + fn default_size() -> u8 { + 8 + } + + fn max_size() -> u8 { + 8 + } + + fn size(address_bytes: u8) -> Result { + match address_bytes { + 8 => Ok(8), + _ => Err(Error::UnsupportedAddressSize(address_bytes)), + } + } + + fn address(address: u64, _size: u8) -> Result { + Ok(Address64(address)) + } + + fn length(length: u64, _size: u8) -> Result { + Ok(length) + } + + fn add(self, offset: Self::Length, _size: u8) -> Result { + self.0 + .checked_add(offset) + .map(Address64) + .ok_or(Error::AddressOverflow) + } + + fn wrapping_add(self, offset: Self::Length, _size: u8) -> Self { + Address64(self.0.wrapping_add(offset)) + } + + fn offset_from(self, address: Self) -> Result { + self.0 + .checked_sub(address.0) + .ok_or(Error::UnsupportedAddressOffset) + } + + fn constant(self) -> Option { + Some(self.0) + } + + fn zeroes() -> Self { + Address64(0) + } + + fn ones(_size: u8) -> Self { + Address64(!0) + } +} + #[cfg(not(feature = "read"))] pub(crate) mod seal_if_no_alloc { #[derive(Debug)] @@ -259,9 +467,12 @@ pub trait Reader: Debug + Clone { /// The endianity of bytes that are read. type Endian: Endianity; - /// The type used for offsets and lengths. + /// The type used for offsets and lengths in the DWARF section data. type Offset: ReaderOffset; + /// The type used for target machine addresses. + type Address: ReaderAddress; + /// Return the endianity of bytes that are read. fn endian(&self) -> Self::Endian; @@ -495,24 +706,51 @@ pub trait Reader: Debug + Clone { } } + /// Validate an address size. + /// + /// This uses [`ReaderAddress::size`] to validate the size. + fn address_size(size: u8) -> Result { + Self::Address::size(size) + } + /// Read a byte and validate it as an address size. + /// + /// This uses [`Reader::address_size`] to validate the size. fn read_address_size(&mut self) -> Result { - let size = self.read_u8()?; - match size { - 1 | 2 | 4 | 8 => Ok(size), - _ => Err(Error::UnsupportedAddressSize(size)), - } + self.read_u8().and_then(Self::address_size) } - /// Read an address-sized integer, and return it as a `u64`. - fn read_address(&mut self, address_size: u8) -> Result { - match address_size { - 1 => self.read_u8().map(u64::from), - 2 => self.read_u16().map(u64::from), - 4 => self.read_u32().map(u64::from), + /// Read an address-sized integer. + /// + /// This uses [`ReaderAddress::address`] to convert the integer into an address. + /// Implementations of `Reader` should override this method if a different + /// conversion is needed. + fn read_address(&mut self, address_size: u8) -> Result { + let address = match address_size { + 1 => self.read_u8().map(Into::into), + 2 => self.read_u16().map(Into::into), + 4 => self.read_u32().map(Into::into), 8 => self.read_u64(), otherwise => Err(Error::UnsupportedAddressSize(otherwise)), - } + }?; + Self::Address::address(address, address_size) + } + + /// Read the length of an address range. + /// + /// This uses [`ReaderAddress::length`] to convert the integer into a length. + fn read_address_range( + &mut self, + address_size: u8, + ) -> Result<::Length> { + let range = match address_size { + 1 => self.read_u8().map(Into::into), + 2 => self.read_u16().map(Into::into), + 4 => self.read_u32().map(Into::into), + 8 => self.read_u64(), + otherwise => Err(Error::UnsupportedAddressSize(otherwise)), + }?; + Self::Address::length(range, address_size) } /// Parse a word-sized integer according to the DWARF format. diff --git a/src/read/relocate.rs b/src/read/relocate.rs index d26c2bf8..2410d6b5 100644 --- a/src/read/relocate.rs +++ b/src/read/relocate.rs @@ -3,15 +3,18 @@ use alloc::borrow::Cow; use core::fmt::Debug; use crate::common::Format; -use crate::read::{Reader, ReaderOffset, ReaderOffsetId, Result}; +use crate::read::{Reader, ReaderAddress, ReaderOffset, ReaderOffsetId, Result}; /// Trait for relocating addresses and offsets while reading a section. -pub trait Relocate { +pub trait Relocate { + /// The type of a relocated address. + type ToAddress: ReaderAddress; + /// Relocate an address which was read from the given section offset. - fn relocate_address(&self, offset: T, value: u64) -> Result; + fn relocate_address(&self, offset: Offset, value: FromAddress) -> Result; /// Relocate a value which was read from the given section offset. - fn relocate_offset(&self, offset: T, value: T) -> Result; + fn relocate_offset(&self, offset: Offset, value: Offset) -> Result; } /// A `Reader` which applies relocations to addresses and offsets. @@ -20,7 +23,11 @@ pub trait Relocate { /// such as those in a relocatable object file. /// It is generally not used for reading sections in an executable file. #[derive(Debug, Clone)] -pub struct RelocateReader, T: Relocate> { +pub struct RelocateReader +where + R: Reader, + T: Relocate, +{ section: R, reader: R, relocate: T, @@ -28,8 +35,8 @@ pub struct RelocateReader, T: Relocate> { impl RelocateReader where - R: Reader, - T: Relocate, + R: Reader, + T: Relocate, { /// Create a new `RelocateReader` which applies relocations to the given section reader. pub fn new(section: R, relocate: T) -> Self { @@ -44,13 +51,14 @@ where impl Reader for RelocateReader where - R: Reader, - T: Relocate + Debug + Clone, + R: Reader, + T: Relocate + Debug + Clone, { type Endian = R::Endian; type Offset = R::Offset; + type Address = T::ToAddress; - fn read_address(&mut self, address_size: u8) -> Result { + fn read_address(&mut self, address_size: u8) -> Result { let offset = self.reader.offset_from(&self.section); let value = self.reader.read_address(address_size)?; self.relocate.relocate_address(offset, value) diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index fa08a1aa..eb72e154 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -219,7 +219,7 @@ impl RangeLists { &self, offset: RangeListsOffset, unit_encoding: Encoding, - base_address: u64, + base_address: R::Address, debug_addr: &DebugAddr, debug_addr_base: DebugAddrBase, ) -> Result> { @@ -310,18 +310,18 @@ pub struct RawRngListIter { /// A raw entry in .debug_rnglists #[derive(Clone, Debug)] -pub enum RawRngListEntry { +pub enum RawRngListEntry { /// A range from DWARF version <= 4. AddressOrOffsetPair { /// Start of range. May be an address or an offset. - begin: u64, + begin: A, /// End of range. May be an address or an offset. - end: u64, + end: A, }, /// DW_RLE_base_address BaseAddress { /// base address - addr: u64, + addr: A, }, /// DW_RLE_base_addressx BaseAddressx { @@ -345,39 +345,40 @@ pub enum RawRngListEntry { /// DW_RLE_offset_pair OffsetPair { /// start of range - begin: u64, + begin: A::Length, /// end of range - end: u64, + end: A::Length, }, /// DW_RLE_start_end StartEnd { /// start of range - begin: u64, + begin: A, /// end of range - end: u64, + end: A, }, /// DW_RLE_start_length StartLength { /// start of range - begin: u64, + begin: A, /// length of range length: u64, }, } -impl RawRngListEntry { +impl RawRngListEntry { /// Parse a range entry from `.debug_rnglists` - fn parse>( + fn parse>( input: &mut R, encoding: Encoding, format: RangeListsFormat, ) -> Result> { + let address_size = encoding.address_size; Ok(match format { RangeListsFormat::Bare => { - let range = RawRange::parse(input, encoding.address_size)?; + let range = RawRange::parse(input, address_size)?; if range.is_end() { None - } else if range.is_base_address(encoding.address_size) { + } else if range.is_base_address(address_size) { Some(RawRngListEntry::BaseAddress { addr: range.end }) } else { Some(RawRngListEntry::AddressOrOffsetPair { @@ -400,18 +401,18 @@ impl RawRngListEntry { length: input.read_uleb128()?, }), constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair { - begin: input.read_uleb128()?, - end: input.read_uleb128()?, + begin: R::Address::length(input.read_uleb128()?, address_size)?, + end: R::Address::length(input.read_uleb128()?, address_size)?, }), constants::DW_RLE_base_address => Some(RawRngListEntry::BaseAddress { - addr: input.read_address(encoding.address_size)?, + addr: input.read_address(address_size)?, }), constants::DW_RLE_start_end => Some(RawRngListEntry::StartEnd { - begin: input.read_address(encoding.address_size)?, - end: input.read_address(encoding.address_size)?, + begin: input.read_address(address_size)?, + end: input.read_address(address_size)?, }), constants::DW_RLE_start_length => Some(RawRngListEntry::StartLength { - begin: input.read_address(encoding.address_size)?, + begin: input.read_address(address_size)?, length: input.read_uleb128()?, }), entry => { @@ -433,7 +434,7 @@ impl RawRngListIter { } /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result>> { + pub fn next(&mut self) -> Result>> { if self.input.is_empty() { return Ok(None); } @@ -455,7 +456,7 @@ impl RawRngListIter { #[cfg(feature = "fallible-iterator")] impl fallible_iterator::FallibleIterator for RawRngListIter { - type Item = RawRngListEntry; + type Item = RawRngListEntry; type Error = Error; fn next(&mut self) -> ::core::result::Result, Self::Error> { @@ -471,7 +472,7 @@ impl fallible_iterator::FallibleIterator for RawRngListIter { #[derive(Debug)] pub struct RngListIter { raw: RawRngListIter, - base_address: u64, + base_address: R::Address, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, } @@ -480,7 +481,7 @@ impl RngListIter { /// Construct a `RngListIter`. fn new( raw: RawRngListIter, - base_address: u64, + base_address: R::Address, debug_addr: DebugAddr, debug_addr_base: DebugAddrBase, ) -> RngListIter { @@ -493,13 +494,13 @@ impl RngListIter { } #[inline] - fn get_address(&self, index: DebugAddrIndex) -> Result { + fn get_address(&self, index: DebugAddrIndex) -> Result { self.debug_addr .get_address(self.raw.encoding.address_size, self.debug_addr_base, index) } /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result> { + pub fn next(&mut self) -> Result>> { loop { let raw_range = match self.raw.next()? { Some(range) => range, @@ -517,7 +518,7 @@ impl RngListIter { /// /// The raw range should be passed to `convert_range`. #[doc(hidden)] - pub fn next_raw(&mut self) -> Result>> { + pub fn next_raw(&mut self) -> Result>> { self.raw.next() } @@ -525,11 +526,18 @@ impl RngListIter { /// /// The raw range should have been obtained from `next_raw`. #[doc(hidden)] - pub fn convert_raw(&mut self, raw_range: RawRngListEntry) -> Result> { + pub fn convert_raw( + &mut self, + raw_range: RawRngListEntry, + ) -> Result>> { let address_size = self.raw.encoding.address_size; - let mask = u64::ones_sized(address_size); + let mask = R::Address::ones(address_size); let tombstone = if self.raw.encoding.version <= 4 { - mask - 1 + // mask - 1 + mask.wrapping_add( + R::Address::length(-1i64 as u64, address_size)?, + address_size, + ) } else { mask }; @@ -550,21 +558,34 @@ impl RngListIter { } RawRngListEntry::StartxLength { begin, length } => { let begin = self.get_address(begin)?; - let end = begin.wrapping_add_sized(length, address_size); + let length = R::Address::length(length, address_size)?; + let end = begin.wrapping_add(length, address_size); Range { begin, end } } - RawRngListEntry::AddressOrOffsetPair { begin, end } - | RawRngListEntry::OffsetPair { begin, end } => { + RawRngListEntry::AddressOrOffsetPair { begin, end } => { + if self.base_address == tombstone { + return Ok(None); + } + if self.base_address == R::Address::zeroes() { + // This is an address pair. + Range { begin, end } + } else if let (Some(begin), Some(end)) = (begin.constant(), end.constant()) { + // This is an offset pair. + Range { begin, end }.add_base_address(self.base_address, address_size) + } else { + return Err(Error::InvalidAddressRangeOffset); + } + } + RawRngListEntry::OffsetPair { begin, end } => { if self.base_address == tombstone { return Ok(None); } - let mut range = Range { begin, end }; - range.add_base_address(self.base_address, self.raw.encoding.address_size); - range + Range { begin, end }.add_base_address(self.base_address, address_size) } RawRngListEntry::StartEnd { begin, end } => Range { begin, end }, RawRngListEntry::StartLength { begin, length } => { - let end = begin.wrapping_add_sized(length, address_size); + let length = R::Address::length(length, address_size)?; + let end = begin.wrapping_add(length, address_size); Range { begin, end } } }; @@ -579,7 +600,7 @@ impl RngListIter { #[cfg(feature = "fallible-iterator")] impl fallible_iterator::FallibleIterator for RngListIter { - type Item = Range; + type Item = Range; type Error = Error; fn next(&mut self) -> ::core::result::Result, Self::Error> { @@ -589,19 +610,19 @@ impl fallible_iterator::FallibleIterator for RngListIter { /// A raw address range from the `.debug_ranges` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct RawRange { +pub(crate) struct RawRange { /// The beginning address of the range. - pub begin: u64, + pub begin: A, /// The first address past the end of the range. - pub end: u64, + pub end: A, } -impl RawRange { +impl RawRange { /// Check if this is a range end entry. #[inline] pub fn is_end(&self) -> bool { - self.begin == 0 && self.end == 0 + self.begin == A::zeroes() && self.end == A::zeroes() } /// Check if this is a base address selection entry. @@ -610,12 +631,15 @@ impl RawRange { /// range entries are relative to. #[inline] pub fn is_base_address(&self, address_size: u8) -> bool { - self.begin == u64::ones_sized(address_size) + self.begin == A::ones(address_size) } /// Parse an address range entry from `.debug_ranges` or `.debug_loc`. #[inline] - pub fn parse(input: &mut R, address_size: u8) -> Result { + pub fn parse>( + input: &mut R, + address_size: u8, + ) -> Result> { let begin = input.read_address(address_size)?; let end = input.read_address(address_size)?; let range = RawRange { begin, end }; @@ -625,20 +649,29 @@ impl RawRange { /// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Range { +pub struct Range { /// The beginning address of the range. - pub begin: u64, + pub begin: T, /// The first address past the end of the range. - pub end: u64, + pub end: T, } -impl Range { +impl Range { /// Add a base address to this range. + /// + /// This uses wrapping arithmetic to allow for the possibility of negative + /// values for either the range or the base address. #[inline] - pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) { - self.begin = base_address.wrapping_add_sized(self.begin, address_size); - self.end = base_address.wrapping_add_sized(self.end, address_size); + #[must_use] + pub(crate) fn add_base_address>( + self, + base_address: A, + address_size: u8, + ) -> Range { + let begin = base_address.wrapping_add(self.begin, address_size); + let end = base_address.wrapping_add(self.end, address_size); + Range { begin, end } } } @@ -1100,20 +1133,23 @@ mod tests { #[test] fn test_raw_range() { let range = RawRange { - begin: 0, + begin: 0u64, end: 0xffff_ffff, }; assert!(!range.is_end()); assert!(!range.is_base_address(4)); assert!(!range.is_base_address(8)); - let range = RawRange { begin: 0, end: 0 }; + let range = RawRange { + begin: 0u64, + end: 0, + }; assert!(range.is_end()); assert!(!range.is_base_address(4)); assert!(!range.is_base_address(8)); let range = RawRange { - begin: 0xffff_ffff, + begin: 0xffff_ffffu64, end: 0, }; assert!(!range.is_end()); @@ -1121,7 +1157,7 @@ mod tests { assert!(!range.is_base_address(8)); let range = RawRange { - begin: 0xffff_ffff_ffff_ffff, + begin: 0xffff_ffff_ffff_ffffu64, end: 0, }; assert!(!range.is_end()); diff --git a/src/read/unit.rs b/src/read/unit.rs index 29581208..1711c2ba 100644 --- a/src/read/unit.rs +++ b/src/read/unit.rs @@ -15,7 +15,7 @@ use crate::endianity::Endianity; use crate::read::abbrev::get_attribute_size; use crate::read::{ Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, DebugStr, EndianSlice, Error, - Expression, Reader, ReaderOffset, Result, Section, UnitOffset, + Expression, Reader, ReaderAddress, ReaderOffset, Result, Section, UnitOffset, }; impl DebugTypesOffset { @@ -300,10 +300,11 @@ where /// The common fields for the headers of compilation units and /// type units. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct UnitHeader::Offset> +pub struct UnitHeader::Offset, Address = ::Address> where - R: Reader, + R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { encoding: Encoding, unit_length: Offset, @@ -314,10 +315,11 @@ where } /// Static methods. -impl UnitHeader +impl UnitHeader where - R: Reader, + R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { /// Construct a new `UnitHeader`. pub fn new( @@ -930,13 +932,14 @@ where // for their data. This gives better code generation in `parse_attribute`. #[repr(u64)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum AttributeValue::Offset> +pub enum AttributeValue::Offset, Address = ::Address> where R: Reader, Offset: ReaderOffset, + Address: ReaderAddress, { /// "Refers to some location in the address space of the described program." - Addr(u64), + Addr(Address), /// A slice of an arbitrary number of bytes. Block(R), diff --git a/src/write/cfi.rs b/src/write/cfi.rs index 8d0a5205..02479027 100644 --- a/src/write/cfi.rs +++ b/src/write/cfi.rs @@ -612,7 +612,7 @@ pub(crate) mod convert { convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult where - R: Reader, + R: Reader, Section: read::UnwindSection, Section::Offset: read::UnwindOffset, { @@ -658,7 +658,7 @@ pub(crate) mod convert { convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult where - R: Reader, + R: Reader, Section: read::UnwindSection, Section::Offset: read::UnwindOffset, { @@ -710,7 +710,7 @@ pub(crate) mod convert { convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult where - R: Reader, + R: Reader, Section: read::UnwindSection, Section::Offset: read::UnwindOffset, { @@ -757,7 +757,7 @@ pub(crate) mod convert { offset: &mut u32, ) -> ConvertResult> where - R: Reader, + R: Reader, Section: read::UnwindSection, { let convert_expression = diff --git a/src/write/dwarf.rs b/src/write/dwarf.rs index ea507126..07e7a982 100644 --- a/src/write/dwarf.rs +++ b/src/write/dwarf.rs @@ -118,7 +118,7 @@ pub(crate) mod convert { /// `Address::Constant(address)`. For relocatable addresses, it is the caller's /// responsibility to determine the symbol and addend corresponding to the address /// and return `Address::Symbol { symbol, addend }`. - pub fn from>( + pub fn from>( dwarf: &read::Dwarf, convert_address: &dyn Fn(u64) -> Option
, ) -> ConvertResult { diff --git a/src/write/line.rs b/src/write/line.rs index 7c47db81..8c522c1e 100644 --- a/src/write/line.rs +++ b/src/write/line.rs @@ -1004,7 +1004,7 @@ mod convert { /// Create a line number program by reading the data from the given program. /// /// Return the program and a mapping from file index to `FileId`. - pub fn from>( + pub fn from>( mut from_program: read::IncompleteLineProgram, dwarf: &read::Dwarf, line_strings: &mut write::LineStringTable, @@ -1179,7 +1179,7 @@ mod convert { } impl LineString { - fn from>( + fn from>( from_attr: read::AttributeValue, dwarf: &read::Dwarf, line_strings: &mut write::LineStringTable, diff --git a/src/write/loc.rs b/src/write/loc.rs index bd180087..84876d4a 100644 --- a/src/write/loc.rs +++ b/src/write/loc.rs @@ -303,7 +303,7 @@ mod convert { impl LocationList { /// Create a location list by reading the data from the give location list iter. - pub(crate) fn from>( + pub(crate) fn from>( mut from: read::RawLocListIter, context: &ConvertUnitContext<'_, R>, ) -> ConvertResult { diff --git a/src/write/op.rs b/src/write/op.rs index 1181a04e..37ffecb5 100644 --- a/src/write/op.rs +++ b/src/write/op.rs @@ -844,7 +844,7 @@ pub(crate) mod convert { impl Expression { /// Create an expression from the input expression. - pub fn from>( + pub fn from>( from_expression: read::Expression, encoding: Encoding, dwarf: Option<&read::Dwarf>, diff --git a/src/write/range.rs b/src/write/range.rs index 602658b1..53e4a404 100644 --- a/src/write/range.rs +++ b/src/write/range.rs @@ -219,7 +219,7 @@ mod convert { impl RangeList { /// Create a range list by reading the data from the give range list iter. - pub(crate) fn from>( + pub(crate) fn from>( mut from: read::RawRngListIter, context: &ConvertUnitContext<'_, R>, ) -> ConvertResult { diff --git a/src/write/unit.rs b/src/write/unit.rs index 53b392e1..ed3a0ba9 100644 --- a/src/write/unit.rs +++ b/src/write/unit.rs @@ -1478,7 +1478,7 @@ pub(crate) mod convert { use crate::write::{self, ConvertError, ConvertResult, LocationList, RangeList}; use std::collections::HashMap; - pub(crate) struct ConvertUnit> { + pub(crate) struct ConvertUnit> { from_unit: read::Unit, base_id: BaseId, encoding: Encoding, @@ -1487,7 +1487,7 @@ pub(crate) mod convert { root: UnitEntryId, } - pub(crate) struct ConvertUnitContext<'a, R: Reader> { + pub(crate) struct ConvertUnitContext<'a, R: Reader> { pub dwarf: &'a read::Dwarf, pub unit: &'a read::Unit, pub line_strings: &'a mut write::LineStringTable, @@ -1512,7 +1512,7 @@ pub(crate) mod convert { /// `Address::Constant(address)`. For relocatable addresses, it is the caller's /// responsibility to determine the symbol and addend corresponding to the address /// and return `Address::Symbol { symbol, addend }`. - pub fn from>( + pub fn from>( dwarf: &read::Dwarf, line_strings: &mut write::LineStringTable, strings: &mut write::StringTable, @@ -1555,7 +1555,7 @@ pub(crate) mod convert { /// Create a unit by reading the data in the input sections. /// /// Does not add entry attributes. - pub(crate) fn convert_entries>( + pub(crate) fn convert_entries>( from_header: read::UnitHeader, unit_id: UnitId, entry_ids: &mut HashMap, @@ -1597,7 +1597,7 @@ pub(crate) mod convert { } /// Create entry attributes by reading the data in the input sections. - fn convert_attributes>( + fn convert_attributes>( unit: ConvertUnit, entry_ids: &HashMap, dwarf: &read::Dwarf, @@ -1664,7 +1664,7 @@ pub(crate) mod convert { /// Create an entry by reading the data in the input sections. /// /// Does not add the entry attributes. - fn convert_entry>( + fn convert_entry>( from: read::EntriesTreeNode<'_, '_, '_, R>, from_unit: &read::Unit, base_id: BaseId, @@ -1697,7 +1697,7 @@ pub(crate) mod convert { } /// Create an entry's attributes by reading the data in the input sections. - fn convert_attributes>( + fn convert_attributes>( &mut self, context: &mut ConvertUnitContext<'_, R>, entry_offsets: &[read::UnitOffset], @@ -1719,7 +1719,7 @@ pub(crate) mod convert { impl Attribute { /// Create an attribute by reading the data in the given sections. - pub(crate) fn from>( + pub(crate) fn from>( context: &mut ConvertUnitContext<'_, R>, from: &read::Attribute, ) -> ConvertResult> { @@ -1733,7 +1733,7 @@ pub(crate) mod convert { impl AttributeValue { /// Create an attribute value by reading the data in the given sections. - pub(crate) fn from>( + pub(crate) fn from>( context: &mut ConvertUnitContext<'_, R>, from: read::AttributeValue, ) -> ConvertResult> {