From 4ee1bd3ed7e0bee2db0998b3030cffdd35ffd896 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 10 Jan 2019 14:11:12 +1000 Subject: [PATCH 01/12] read: implement .debug_str_offsets support --- examples/dwarfdump.rs | 33 ++++++++++++++++++++++---- src/common.rs | 8 +++++++ src/read/dwarf.rs | 8 +++++-- src/read/loclists.rs | 3 +-- src/read/rnglists.rs | 3 +-- src/read/str.rs | 55 +++++++++++++++++++++++++++++++++++++++++-- src/read/unit.rs | 36 +++++++++++++++++++++++++++- src/write/unit.rs | 48 +++++++++++++++++++++++++++++-------- 8 files changed, 171 insertions(+), 23 deletions(-) diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index 796d05a50..080271194 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -533,6 +533,7 @@ where let debug_info = load_section(&arena, file, endian); let debug_line = load_section(&arena, file, endian); let debug_str = load_section(&arena, file, endian); + let debug_str_offsets = load_section(&arena, file, endian); let debug_types = load_section(&arena, file, endian); let debug_loc = load_section(&arena, file, endian); @@ -549,6 +550,7 @@ where debug_info, debug_line, debug_str, + debug_str_offsets, debug_str_sup: no_reader.clone().into(), debug_types, locations, @@ -982,6 +984,7 @@ struct Unit { line_program: Option>, comp_dir: Option, comp_name: Option, + str_offsets_base: gimli::DebugStrOffsetsBase, } fn spaces(buf: &mut String, len: usize) -> &str { @@ -1010,6 +1013,8 @@ fn dump_entries( line_program: None, comp_dir: None, comp_name: None, + // Defaults to 0 for GNU extensions + str_offsets_base: gimli::DebugStrOffsetsBase(0), }; let mut spaces_buf = String::new(); @@ -1063,6 +1068,11 @@ fn dump_entries( ) .ok(), _ => None, + }; + if let Some(gimli::AttributeValue::DebugStrOffsetsBase(base)) = + entry.attr_value(gimli::DW_AT_str_offsets_base)? + { + unit.str_offsets_base = base; } } @@ -1188,10 +1198,10 @@ fn dump_attr_value( writeln!(w, "<0x{:08x}>", offset)?; } gimli::AttributeValue::DebugInfoRef(gimli::DebugInfoOffset(offset)) => { - writeln!(w, "", offset)?; + writeln!(w, "<.debug_info+0x{:08x}>", offset)?; } gimli::AttributeValue::DebugInfoRefSup(gimli::DebugInfoOffset(offset)) => { - writeln!(w, "", offset)?; + writeln!(w, "<.debug_info(sup)+0x{:08x}>", offset)?; } gimli::AttributeValue::DebugLineRef(gimli::DebugLineOffset(offset)) => { writeln!(w, "0x{:08x}", offset)?; @@ -1214,11 +1224,26 @@ fn dump_attr_value( if let Ok(s) = dwarf.debug_str.get_str(offset) { writeln!(w, "{}", s.to_string_lossy()?)?; } else { - writeln!(w, "", offset.0)?; + writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?; } } gimli::AttributeValue::DebugStrRefSup(offset) => { - writeln!(w, "", offset.0)?; + writeln!(w, "<.debug_str(sup)+0x{:08x}>", offset.0)?; + } + gimli::AttributeValue::DebugStrOffsetsBase(base) => { + writeln!(w, "<.debug_str_offsets+0x{:08x}>", base.0)?; + } + gimli::AttributeValue::DebugStrOffsetsIndex(index) => { + let offset = dwarf.debug_str_offsets.get_str_offset( + unit.format, + unit.str_offsets_base, + index, + )?; + if let Ok(s) = dwarf.debug_str.get_str(offset) { + writeln!(w, "{}", s.to_string_lossy()?)?; + } else { + writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?; + } } gimli::AttributeValue::String(s) => { writeln!(w, "{}", s.to_string_lossy()?)?; diff --git a/src/common.rs b/src/common.rs index bad65e43b..836caabb6 100644 --- a/src/common.rs +++ b/src/common.rs @@ -64,6 +64,14 @@ pub struct RangeListsOffset(pub T); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugStrOffset(pub T); +/// An offset to a set of entries in the `.debug_str_offsets` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugStrOffsetsBase(pub T); + +/// An index into a set of entries in the `.debug_str_offsets` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugStrOffsetsIndex(pub T); + /// An offset into the `.debug_types` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DebugTypesOffset(pub T); diff --git a/src/read/dwarf.rs b/src/read/dwarf.rs index 27cd516bd..3d2d78124 100644 --- a/src/read/dwarf.rs +++ b/src/read/dwarf.rs @@ -1,8 +1,9 @@ use constants; use read::{ Abbreviations, Attribute, AttributeValue, CompilationUnitHeader, CompilationUnitHeadersIter, - DebugAbbrev, DebugInfo, DebugLine, DebugStr, DebugTypes, Error, IncompleteLineNumberProgram, - LocationLists, RangeLists, Reader, Result, TypeUnitHeader, TypeUnitHeadersIter, + DebugAbbrev, DebugInfo, DebugLine, DebugStr, DebugStrOffsets, DebugTypes, Error, + IncompleteLineNumberProgram, LocationLists, RangeLists, Reader, Result, TypeUnitHeader, + TypeUnitHeadersIter, }; use Endianity; @@ -29,6 +30,9 @@ where /// The `.debug_str` section. pub debug_str: DebugStr, + /// The `.debug_str_offsets` section. + pub debug_str_offsets: DebugStrOffsets, + /// The `.debug_str` section for a supplementary object file. pub debug_str_sup: DebugStr, diff --git a/src/read/loclists.rs b/src/read/loclists.rs index 2c9f9f7be..6be8493b4 100644 --- a/src/read/loclists.rs +++ b/src/read/loclists.rs @@ -8,8 +8,7 @@ use read::{ Section, }; -/// The `DebugLoc` struct represents the DWARF strings -/// found in the `.debug_loc` section. +/// The raw contents of the `.debug_loc` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugLoc { pub(crate) debug_loc_section: R, diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index 095f95052..df016c83d 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -9,8 +9,7 @@ use read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AddressIndex(pub u64); -/// The `DebugRanges` struct represents the DWARF strings -/// found in the `.debug_ranges` section. +/// The raw contents of the `.debug_ranges` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugRanges { pub(crate) debug_ranges_section: R, diff --git a/src/read/str.rs b/src/read/str.rs index b9e869cb9..fef9a6589 100644 --- a/src/read/str.rs +++ b/src/read/str.rs @@ -1,6 +1,7 @@ -use common::DebugStrOffset; +use common::{DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex}; use endianity::Endianity; -use read::{EndianSlice, Reader, Result, Section}; +use read::{EndianSlice, Reader, ReaderOffset, Result, Section}; +use Format; /// The `DebugStr` struct represents the DWARF strings /// found in the `.debug_str` section. @@ -63,3 +64,53 @@ impl From for DebugStr { DebugStr { debug_str_section } } } + +/// The raw contents of the `.debug_str_offsets` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugStrOffsets { + section: R, +} + +impl DebugStrOffsets { + // TODO: add an iterator over the sets of entries in the section. + // This is not needed for common usage of the section though. + + /// Returns the `.debug_str` offset at the given `base` and `index`. + /// + /// A set of entries in the `.debug_str_offsets` section consists of a header + /// followed by a series of string table offsets. + /// + /// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE. + /// This is an offset that points to the first entry following the header. + /// + /// The `index` is the value of a `DW_FORM_strx` attribute. + /// + /// The `format` must be the DWARF format of the compilation unit. This format must + /// match the header. However, note that we do not parse the header to validate this, + /// since locating the header is unreliable, and the GNU extensions do not emit it. + pub fn get_str_offset( + &self, + format: Format, + base: DebugStrOffsetsBase, + index: DebugStrOffsetsIndex, + ) -> Result> { + let input = &mut self.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(format.word_size()), + )?)?; + input.read_offset(format).map(DebugStrOffset) + } +} + +impl Section for DebugStrOffsets { + fn section_name() -> &'static str { + ".debug_str_offsets" + } +} + +impl From for DebugStrOffsets { + fn from(section: R) -> Self { + DebugStrOffsets { section } + } +} diff --git a/src/read/unit.rs b/src/read/unit.rs index 3da9ae24a..cb45ed782 100644 --- a/src/read/unit.rs +++ b/src/read/unit.rs @@ -7,7 +7,8 @@ use std::{u16, u8}; use common::{ DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugStrOffset, - DebugTypeSignature, DebugTypesOffset, Format, LocationListsOffset, RangeListsOffset, + DebugStrOffsetsBase, DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, Format, + LocationListsOffset, RangeListsOffset, }; use constants; use endianity::Endianity; @@ -1025,6 +1026,12 @@ pub enum AttributeValue { /// An offset into the `.debug_str` section of the supplementary object file. DebugStrRefSup(DebugStrOffset), + /// An offset to a set of entries in the `.debug_str_offsets` section. + DebugStrOffsetsBase(DebugStrOffsetsBase), + + /// An index into a set of entries in the `.debug_str_offsets` section. + DebugStrOffsetsIndex(DebugStrOffsetsIndex), + /// A slice of bytes representing a string. Does not include a final null byte. /// Not guaranteed to be UTF-8 or anything like that. String(R), @@ -1177,6 +1184,13 @@ impl Attribute { macro_rules! string { () => {}; } + macro_rules! stroffsetsptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(offset)); + } + }; + } // Perform the allowed class conversions for each attribute name. match self.name { @@ -1488,6 +1502,9 @@ impl Attribute { constants::DW_AT_linkage_name => { string!(); } + constants::DW_AT_str_offsets_base => { + stroffsetsptr!(); + } _ => {} } self.value.clone() @@ -1795,6 +1812,23 @@ pub(crate) fn parse_attribute<'unit, 'abbrev, R: Reader>( AttributeValue::DebugStrRefSup(DebugStrOffset(offset)) } constants::DW_FORM_implicit_const => AttributeValue::Sdata(spec.implicit_const_value()), + constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx1 => { + let index = input.read_u8().map(R::Offset::from_u8)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + constants::DW_FORM_strx2 => { + let index = input.read_u16().map(R::Offset::from_u16)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } + // TODO: constants::DW_FORM_strx3 + constants::DW_FORM_strx4 => { + let index = input.read_u32().map(R::Offset::from_u32)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } _ => { return Err(Error::UnknownForm); } diff --git a/src/write/unit.rs b/src/write/unit.rs index a94cf5eba..4b27efe6c 100644 --- a/src/write/unit.rs +++ b/src/write/unit.rs @@ -4,7 +4,7 @@ use vec::Vec; use common::{ DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugStrOffset, - DebugTypeSignature, Format, LocationListsOffset, RangeListsOffset, + DebugStrOffsetsBase, DebugTypeSignature, Format, LocationListsOffset, RangeListsOffset, }; use constants; use write::{ @@ -1051,6 +1051,7 @@ mod convert { pub convert_address: &'a Fn(u64) -> Option
, pub line_program: Option<(DebugLineOffset, LineProgramId)>, pub line_program_files: Vec, + pub str_offsets_base: DebugStrOffsetsBase, } impl UnitTable { @@ -1137,6 +1138,7 @@ mod convert { let from_root = from_tree.root()?; let mut line_program = None; let mut line_program_files = Vec::new(); + let mut str_offsets_base = DebugStrOffsetsBase(0); { let from_root = from_root.entry(); let comp_dir = from_root @@ -1156,6 +1158,11 @@ mod convert { line_program = Some((offset, line_programs.add(program))); line_program_files = files; } + if let Some(read::AttributeValue::DebugStrOffsetsBase(base)) = + from_root.attr_value(constants::DW_AT_str_offsets_base)? + { + str_offsets_base = base; + } } let mut context = ConvertUnitContext { dwarf, @@ -1163,6 +1170,7 @@ mod convert { convert_address, line_program, line_program_files, + str_offsets_base, }; let root = DebuggingInformationEntry::from( &mut context, @@ -1207,8 +1215,7 @@ mod convert { if from_attr.name() == constants::DW_AT_sibling { // This may point to a null entry, so we have to treat it differently. entry.set_sibling(true); - } else { - let attr = Attribute::from(context, &from_attr, from_unit)?; + } else if let Some(attr) = Attribute::from(context, &from_attr, from_unit)? { entry.set(attr.name, attr.value); } } @@ -1238,12 +1245,12 @@ mod convert { context: &mut ConvertUnitContext, from: &read::Attribute, from_unit: &read::CompilationUnitHeader, - ) -> ConvertResult { + ) -> ConvertResult> { let value = AttributeValue::from(context, from.value(), from_unit)?; - Ok(Attribute { + Ok(value.map(|value| Attribute { name: from.name(), value, - }) + })) } } @@ -1253,7 +1260,7 @@ mod convert { context: &mut ConvertUnitContext, from: read::AttributeValue, from_unit: &read::CompilationUnitHeader, - ) -> ConvertResult { + ) -> ConvertResult> { let to = match from { read::AttributeValue::Addr(val) => match (context.convert_address)(val) { Some(val) => AttributeValue::Address(val), @@ -1304,6 +1311,21 @@ mod convert { AttributeValue::StringRef(id) } read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val), + read::AttributeValue::DebugStrOffsetsBase(_base) => { + // We convert all string offsets to `.debug_str` references, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugStrOffsetsIndex(index) => { + let offset = context.dwarf.debug_str_offsets.get_str_offset( + from_unit.format(), + context.str_offsets_base, + index, + )?; + let r = context.dwarf.debug_str.get_str(offset)?; + let id = context.strings.add(r.to_slice()?); + AttributeValue::StringRef(id) + } read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()), read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val), read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val), @@ -1330,7 +1352,7 @@ mod convert { return Err(ConvertError::InvalidAttributeValue); } }; - Ok(to) + Ok(Some(to)) } } } @@ -1851,10 +1873,13 @@ mod tests { convert_address: &|address| Some(Address::Absolute(address)), line_program: None, line_program_files: Vec::new(), + str_offsets_base: DebugStrOffsetsBase(0), }; let convert_attr = - Attribute::from(&mut context, &read_attr, &from_comp_unit).unwrap(); + Attribute::from(&mut context, &read_attr, &from_comp_unit) + .unwrap() + .unwrap(); assert_eq!(convert_attr, attr); } } @@ -2264,10 +2289,13 @@ mod tests { convert_address: &|address| Some(Address::Absolute(address)), line_program: Some((line_program_offset, line_program_id)), line_program_files: line_program_files.clone(), + str_offsets_base: DebugStrOffsetsBase(0), }; let convert_attr = - Attribute::from(&mut context, &read_attr, &from_comp_unit).unwrap(); + Attribute::from(&mut context, &read_attr, &from_comp_unit) + .unwrap() + .unwrap(); assert_eq!(convert_attr, attr); } } From 0f62905e2b50dda2a26a19e8e9bdb943d5c0d6e9 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 10 Jan 2019 18:11:18 +1000 Subject: [PATCH 02/12] read: implement .debug_addr support --- examples/dwarfdump.rs | 18 +++++++++++++++ src/common.rs | 8 +++++++ src/read/addr.rs | 53 +++++++++++++++++++++++++++++++++++++++++++ src/read/dwarf.rs | 5 +++- src/read/mod.rs | 3 +++ src/read/unit.rs | 39 ++++++++++++++++++++++++++++--- src/write/unit.rs | 31 +++++++++++++++++++++++-- 7 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 src/read/addr.rs diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index 080271194..2a5844248 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -530,6 +530,7 @@ where // The type of each section variable is inferred from its use below. let debug_abbrev = load_section(&arena, file, endian); + let debug_addr = load_section(&arena, file, endian); let debug_info = load_section(&arena, file, endian); let debug_line = load_section(&arena, file, endian); let debug_str = load_section(&arena, file, endian); @@ -547,6 +548,7 @@ where let dwarf = gimli::Dwarf { endian, debug_abbrev, + debug_addr, debug_info, debug_line, debug_str, @@ -985,6 +987,7 @@ struct Unit { comp_dir: Option, comp_name: Option, str_offsets_base: gimli::DebugStrOffsetsBase, + addr_base: gimli::DebugAddrBase, } fn spaces(buf: &mut String, len: usize) -> &str { @@ -1015,6 +1018,7 @@ fn dump_entries( comp_name: None, // Defaults to 0 for GNU extensions str_offsets_base: gimli::DebugStrOffsetsBase(0), + addr_base: gimli::DebugAddrBase(0), }; let mut spaces_buf = String::new(); @@ -1074,6 +1078,11 @@ fn dump_entries( { unit.str_offsets_base = base; } + if let Some(gimli::AttributeValue::DebugAddrBase(base)) = + entry.attr_value(gimli::DW_AT_addr_base)? + { + unit.addr_base = base; + } } let mut attrs = entry.attrs(); @@ -1194,6 +1203,15 @@ fn dump_attr_value( gimli::AttributeValue::SecOffset(offset) => { writeln!(w, "0x{:08x}", offset)?; } + gimli::AttributeValue::DebugAddrBase(base) => { + writeln!(w, "<.debug_addr+0x{:08x}>", base.0)?; + } + gimli::AttributeValue::DebugAddrIndex(index) => { + let address = dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, index)?; + writeln!(w, "0x{:08x}", address)?; + } gimli::AttributeValue::UnitRef(gimli::UnitOffset(offset)) => { writeln!(w, "<0x{:08x}>", offset)?; } diff --git a/src/common.rs b/src/common.rs index 836caabb6..a9299dbb4 100644 --- a/src/common.rs +++ b/src/common.rs @@ -38,6 +38,14 @@ pub struct Register(pub u16); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DebugAbbrevOffset(pub T); +/// An offset to a set of entries in the `.debug_addr` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugAddrBase(pub T); + +/// An index into a set of addresses in the `.debug_addr` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugAddrIndex(pub T); + /// An offset into the `.debug_info` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct DebugInfoOffset(pub T); diff --git a/src/read/addr.rs b/src/read/addr.rs new file mode 100644 index 000000000..d128eaad9 --- /dev/null +++ b/src/read/addr.rs @@ -0,0 +1,53 @@ +use common::{DebugAddrBase, DebugAddrIndex}; +use read::{Reader, ReaderOffset, Result, Section}; + +/// The raw contents of the `.debug_addr` section. +#[derive(Debug, Default, Clone, Copy)] +pub struct DebugAddr { + section: R, +} + +impl DebugAddr { + // TODO: add an iterator over the sets of addresses in the section. + // This is not needed for common usage of the section though. + + /// Returns the address at the given `base` and `index`. + /// + /// A set of addresses in the `.debug_addr` section consists of a header + /// followed by a series of addresses. + /// + /// The `base` must be the `DW_AT_addr_base` value from the compilation unit DIE. + /// This is an offset that points to the first address following the header. + /// + /// The `index` is the value of a `DW_FORM_addrx` attribute. + /// + /// The `address_size` must be the size of the address for the compilation unit. + /// This value must also match the header. However, note that we do not parse the + /// header to validate this, since locating the header is unreliable, and the GNU + /// extensions do not emit it. + pub fn get_address( + &self, + address_size: u8, + base: DebugAddrBase, + index: DebugAddrIndex, + ) -> Result { + let input = &mut self.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(address_size), + )?)?; + input.read_address(address_size) + } +} + +impl Section for DebugAddr { + fn section_name() -> &'static str { + ".debug_addr" + } +} + +impl From for DebugAddr { + fn from(section: R) -> Self { + DebugAddr { section } + } +} diff --git a/src/read/dwarf.rs b/src/read/dwarf.rs index 3d2d78124..69d0e9ee3 100644 --- a/src/read/dwarf.rs +++ b/src/read/dwarf.rs @@ -1,7 +1,7 @@ use constants; use read::{ Abbreviations, Attribute, AttributeValue, CompilationUnitHeader, CompilationUnitHeadersIter, - DebugAbbrev, DebugInfo, DebugLine, DebugStr, DebugStrOffsets, DebugTypes, Error, + DebugAbbrev, DebugAddr, DebugInfo, DebugLine, DebugStr, DebugStrOffsets, DebugTypes, Error, IncompleteLineNumberProgram, LocationLists, RangeLists, Reader, Result, TypeUnitHeader, TypeUnitHeadersIter, }; @@ -21,6 +21,9 @@ where /// The `.debug_abbrev` section. pub debug_abbrev: DebugAbbrev, + /// The `.debug_addr` section. + pub debug_addr: DebugAddr, + /// The `.debug_info` section. pub debug_info: DebugInfo, diff --git a/src/read/mod.rs b/src/read/mod.rs index 4878c76e9..62eab7c19 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -8,6 +8,9 @@ use std::{error, io}; use common::Register; use constants; +mod addr; +pub use self::addr::*; + mod cfi; pub use self::cfi::*; diff --git a/src/read/unit.rs b/src/read/unit.rs index cb45ed782..3420897da 100644 --- a/src/read/unit.rs +++ b/src/read/unit.rs @@ -6,9 +6,9 @@ use std::ops::{Range, RangeFrom, RangeTo}; use std::{u16, u8}; use common::{ - DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugStrOffset, - DebugStrOffsetsBase, DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, Format, - LocationListsOffset, RangeListsOffset, + DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset, + DebugMacinfoOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, + DebugTypeSignature, DebugTypesOffset, Format, LocationListsOffset, RangeListsOffset, }; use constants; use endianity::Endianity; @@ -995,6 +995,12 @@ pub enum AttributeValue { /// depends on context. SecOffset(R::Offset), + /// An offset to a set of addresses in the `.debug_addr` section. + DebugAddrBase(DebugAddrBase), + + /// An index into a set of addresses in the `.debug_addr` section. + DebugAddrIndex(DebugAddrIndex), + /// An offset into the current compilation unit. UnitRef(UnitOffset), @@ -1125,6 +1131,13 @@ impl Attribute { macro_rules! address { () => {}; } + macro_rules! addrptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugAddrBase(DebugAddrBase(offset)); + } + }; + } macro_rules! block { () => {}; } @@ -1505,6 +1518,9 @@ impl Attribute { constants::DW_AT_str_offsets_base => { stroffsetsptr!(); } + constants::DW_AT_addr_base => { + addrptr!(); + } _ => {} } self.value.clone() @@ -1829,6 +1845,23 @@ pub(crate) fn parse_attribute<'unit, 'abbrev, R: Reader>( let index = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } + constants::DW_FORM_addrx | constants::DW_FORM_GNU_addr_index => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + constants::DW_FORM_addrx1 => { + let index = input.read_u8().map(R::Offset::from_u8)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + constants::DW_FORM_addrx2 => { + let index = input.read_u16().map(R::Offset::from_u16)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } + // TODO: constants::DW_FORM_addrx3 + constants::DW_FORM_addrx4 => { + let index = input.read_u32().map(R::Offset::from_u32)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } _ => { return Err(Error::UnknownForm); } diff --git a/src/write/unit.rs b/src/write/unit.rs index 4b27efe6c..1c0baa2c0 100644 --- a/src/write/unit.rs +++ b/src/write/unit.rs @@ -3,8 +3,9 @@ use std::{slice, usize}; use vec::Vec; use common::{ - DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugStrOffset, - DebugStrOffsetsBase, DebugTypeSignature, Format, LocationListsOffset, RangeListsOffset, + DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, + DebugStrOffset, DebugStrOffsetsBase, DebugTypeSignature, Format, LocationListsOffset, + RangeListsOffset, }; use constants; use write::{ @@ -1052,6 +1053,7 @@ mod convert { pub line_program: Option<(DebugLineOffset, LineProgramId)>, pub line_program_files: Vec, pub str_offsets_base: DebugStrOffsetsBase, + pub addr_base: DebugAddrBase, } impl UnitTable { @@ -1139,6 +1141,7 @@ mod convert { let mut line_program = None; let mut line_program_files = Vec::new(); let mut str_offsets_base = DebugStrOffsetsBase(0); + let mut addr_base = DebugAddrBase(0); { let from_root = from_root.entry(); let comp_dir = from_root @@ -1163,6 +1166,11 @@ mod convert { { str_offsets_base = base; } + if let Some(read::AttributeValue::DebugAddrBase(base)) = + from_root.attr_value(constants::DW_AT_addr_base)? + { + addr_base = base; + } } let mut context = ConvertUnitContext { dwarf, @@ -1171,6 +1179,7 @@ mod convert { line_program, line_program_files, str_offsets_base, + addr_base, }; let root = DebuggingInformationEntry::from( &mut context, @@ -1280,6 +1289,22 @@ mod convert { } // TODO: it would be nice to preserve the flag form. read::AttributeValue::Flag(val) => AttributeValue::Flag(val), + read::AttributeValue::DebugAddrBase(_base) => { + // We convert all address indices to addresses, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugAddrIndex(index) => { + let val = context.dwarf.debug_addr.get_address( + from_unit.address_size(), + context.addr_base, + index, + )?; + match (context.convert_address)(val) { + Some(val) => AttributeValue::Address(val), + None => return Err(ConvertError::InvalidAddress), + } + } read::AttributeValue::UnitRef(val) => { AttributeValue::DebugInfoRef(val.to_debug_info_offset(from_unit)) } @@ -1874,6 +1899,7 @@ mod tests { line_program: None, line_program_files: Vec::new(), str_offsets_base: DebugStrOffsetsBase(0), + addr_base: DebugAddrBase(0), }; let convert_attr = @@ -2290,6 +2316,7 @@ mod tests { line_program: Some((line_program_offset, line_program_id)), line_program_files: line_program_files.clone(), str_offsets_base: DebugStrOffsetsBase(0), + addr_base: DebugAddrBase(0), }; let convert_attr = From b42b23a3072889a447a6f899b77fab8064ea182f Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 10 Jan 2019 21:51:51 +1000 Subject: [PATCH 03/12] read: implement DW_FORM_loclistx and DW_FORM_rnglistx --- examples/dwarfdump.rs | 30 +++++++++++++++++++++++ src/common.rs | 16 +++++++++++++ src/read/loclists.rs | 53 ++++++++++++++++++++++++++++------------- src/read/rnglists.rs | 53 +++++++++++++++++++++++++++-------------- src/read/unit.rs | 55 +++++++++++++++++++++++++++++++++++++++---- src/write/unit.rs | 50 ++++++++++++++++++++++++++++++++++++--- 6 files changed, 214 insertions(+), 43 deletions(-) diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index 2a5844248..ee65edc7c 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -988,6 +988,8 @@ struct Unit { comp_name: Option, str_offsets_base: gimli::DebugStrOffsetsBase, addr_base: gimli::DebugAddrBase, + loclists_base: gimli::DebugLocListsBase, + rnglists_base: gimli::DebugRngListsBase, } fn spaces(buf: &mut String, len: usize) -> &str { @@ -1019,6 +1021,8 @@ fn dump_entries( // Defaults to 0 for GNU extensions str_offsets_base: gimli::DebugStrOffsetsBase(0), addr_base: gimli::DebugAddrBase(0), + loclists_base: gimli::DebugLocListsBase(0), + rnglists_base: gimli::DebugRngListsBase(0), }; let mut spaces_buf = String::new(); @@ -1083,6 +1087,16 @@ fn dump_entries( { unit.addr_base = base; } + if let Some(gimli::AttributeValue::DebugLocListsBase(base)) = + entry.attr_value(gimli::DW_AT_loclists_base)? + { + unit.loclists_base = base; + } + if let Some(gimli::AttributeValue::DebugRngListsBase(base)) = + entry.attr_value(gimli::DW_AT_rnglists_base)? + { + unit.rnglists_base = base; + } } let mut attrs = entry.attrs(); @@ -1227,6 +1241,14 @@ fn dump_attr_value( gimli::AttributeValue::LocationListsRef(offset) => { dump_loc_list(w, &dwarf.locations, offset, unit)?; } + gimli::AttributeValue::DebugLocListsBase(base) => { + writeln!(w, "<.debug_loclists+0x{:08x}>", base.0)?; + } + gimli::AttributeValue::DebugLocListsIndex(index) => { + let offset = dwarf.locations.get_offset(unit.loclists_base, index)?; + writeln!(w, "0x{:08x}", offset.0)?; + dump_loc_list(w, &dwarf.locations, offset, unit)?; + } gimli::AttributeValue::DebugMacinfoRef(gimli::DebugMacinfoOffset(offset)) => { writeln!(w, "{}", offset)?; } @@ -1234,6 +1256,14 @@ fn dump_attr_value( writeln!(w, "0x{:08x}", offset.0)?; dump_range_list(w, &dwarf.ranges, offset, unit)?; } + gimli::AttributeValue::DebugRngListsBase(base) => { + writeln!(w, "<.debug_rnglists+0x{:08x}>", base.0)?; + } + gimli::AttributeValue::DebugRngListsIndex(index) => { + let offset = dwarf.ranges.get_offset(unit.rnglists_base, index)?; + writeln!(w, "0x{:08x}", offset.0)?; + dump_range_list(w, &dwarf.ranges, offset, unit)?; + } gimli::AttributeValue::DebugTypesRef(signature) => { dump_type_signature(w, signature, dwarf.endian)?; writeln!(w, " ")?; diff --git a/src/common.rs b/src/common.rs index a9299dbb4..b4c892772 100644 --- a/src/common.rs +++ b/src/common.rs @@ -59,6 +59,14 @@ pub struct DebugLineOffset(pub T); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct LocationListsOffset(pub T); +/// An offset to a set of location list offsets in the `.debug_loclists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugLocListsBase(pub T); + +/// An index into a set of location list offsets in the `.debug_loclists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugLocListsIndex(pub T); + /// An offset into the `.debug_macinfo` section. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct DebugMacinfoOffset(pub T); @@ -68,6 +76,14 @@ pub struct DebugMacinfoOffset(pub T); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct RangeListsOffset(pub T); +/// An offset to a set of range list offsets in the `.debug_rnglists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugRngListsBase(pub T); + +/// An index into a set of range list offsets in the `.debug_rnglists` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DebugRngListsIndex(pub T); + /// An offset into the `.debug_str` section. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DebugStrOffset(pub T); diff --git a/src/read/loclists.rs b/src/read/loclists.rs index 6be8493b4..2f40d36c0 100644 --- a/src/read/loclists.rs +++ b/src/read/loclists.rs @@ -1,6 +1,6 @@ use fallible_iterator::FallibleIterator; -use common::{Format, LocationListsOffset}; +use common::{DebugLocListsBase, DebugLocListsIndex, Format, LocationListsOffset}; use constants; use endianity::Endianity; use read::{ @@ -11,7 +11,7 @@ use read::{ /// The raw contents of the `.debug_loc` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugLoc { - pub(crate) debug_loc_section: R, + pub(crate) section: R, } impl<'input, Endian> DebugLoc> @@ -32,8 +32,8 @@ where /// # let read_debug_loc_section_somehow = || &buf; /// let debug_loc = DebugLoc::new(read_debug_loc_section_somehow(), LittleEndian); /// ``` - pub fn new(debug_loc_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_loc_section, endian)) + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) } } @@ -44,8 +44,8 @@ impl Section for DebugLoc { } impl From for DebugLoc { - fn from(debug_loc_section: R) -> Self { - DebugLoc { debug_loc_section } + fn from(section: R) -> Self { + DebugLoc { section } } } @@ -53,7 +53,7 @@ impl From for DebugLoc { /// found in the `.debug_loclists` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugLocLists { - debug_loclists_section: R, + section: R, } impl<'input, Endian> DebugLocLists> @@ -74,8 +74,8 @@ where /// # let read_debug_loclists_section_somehow = || &buf; /// let debug_loclists = DebugLocLists::new(read_debug_loclists_section_somehow(), LittleEndian); /// ``` - pub fn new(debug_loclists_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_loclists_section, endian)) + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) } } @@ -86,10 +86,8 @@ impl Section for DebugLocLists { } impl From for DebugLocLists { - fn from(debug_loclists_section: R) -> Self { - DebugLocLists { - debug_loclists_section, - } + fn from(section: R) -> Self { + DebugLocLists { section } } } @@ -157,7 +155,7 @@ impl LocationLists { debug_loc: DebugLoc, debug_loclists: DebugLocLists, ) -> Result> { - let mut input = debug_loclists.debug_loclists_section.clone(); + let mut input = debug_loclists.section.clone(); let header = if input.is_empty() { LocListsHeader::default() } else { @@ -211,14 +209,14 @@ impl LocationLists { address_size: u8, ) -> Result> { if unit_version < 5 { - let mut input = self.debug_loc.debug_loc_section.clone(); + let mut input = self.debug_loc.section.clone(); input.skip(offset.0)?; Ok(RawLocListIter::new(input, unit_version, address_size)) } else { if offset.0 < R::Offset::from_u8(self.header.size()) { return Err(Error::OffsetOutOfBounds); } - let mut input = self.debug_loclists.debug_loclists_section.clone(); + let mut input = self.debug_loclists.section.clone(); input.skip(offset.0)?; Ok(RawLocListIter::new( input, @@ -227,6 +225,27 @@ impl LocationLists { )) } } + + /// Returns the `.debug_loclists` offset at the given `base` and `index`. + /// + /// The `base` must be the `DW_AT_loclists_base` value from the compilation unit DIE. + /// This is an offset that points to the first entry following the header. + /// + /// The `index` is the value of a `DW_FORM_loclistx` attribute. + pub fn get_offset( + &self, + base: DebugLocListsBase, + index: DebugLocListsIndex, + ) -> Result> { + let input = &mut self.debug_loclists.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(self.header.format.word_size()), + )?)?; + input + .read_offset(self.header.format) + .map(|x| LocationListsOffset(base.0 + x)) + } } /// A raw iterator over a location list. @@ -311,7 +330,7 @@ fn parse_data(input: &mut R) -> Result> { } impl RawLocListEntry { - /// Parse a range entry from `.debug_rnglists` + /// Parse a location list entry from `.debug_loclists` fn parse(input: &mut R, version: u16, address_size: u8) -> Result> { if version < 5 { let range = RawRange::parse(input, address_size)?; diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index df016c83d..14fa69e3b 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -1,6 +1,6 @@ use fallible_iterator::FallibleIterator; -use common::{Format, RangeListsOffset}; +use common::{DebugRngListsBase, DebugRngListsIndex, Format, RangeListsOffset}; use constants; use endianity::Endianity; use read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section}; @@ -12,7 +12,7 @@ pub struct AddressIndex(pub u64); /// The raw contents of the `.debug_ranges` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugRanges { - pub(crate) debug_ranges_section: R, + pub(crate) section: R, } impl<'input, Endian> DebugRanges> @@ -33,8 +33,8 @@ where /// # let read_debug_ranges_section_somehow = || &buf; /// let debug_ranges = DebugRanges::new(read_debug_ranges_section_somehow(), LittleEndian); /// ``` - pub fn new(debug_ranges_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_ranges_section, endian)) + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) } } @@ -45,10 +45,8 @@ impl Section for DebugRanges { } impl From for DebugRanges { - fn from(debug_ranges_section: R) -> Self { - DebugRanges { - debug_ranges_section, - } + fn from(section: R) -> Self { + DebugRanges { section } } } @@ -56,7 +54,7 @@ impl From for DebugRanges { /// `.debug_rnglists` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugRngLists { - debug_rnglists_section: R, + section: R, } impl<'input, Endian> DebugRngLists> @@ -78,8 +76,8 @@ where /// let debug_rnglists = /// DebugRngLists::new(read_debug_rnglists_section_somehow(), LittleEndian); /// ``` - pub fn new(debug_rnglists_section: &'input [u8], endian: Endian) -> Self { - Self::from(EndianSlice::new(debug_rnglists_section, endian)) + pub fn new(section: &'input [u8], endian: Endian) -> Self { + Self::from(EndianSlice::new(section, endian)) } } @@ -90,10 +88,8 @@ impl Section for DebugRngLists { } impl From for DebugRngLists { - fn from(debug_rnglists_section: R) -> Self { - DebugRngLists { - debug_rnglists_section, - } + fn from(section: R) -> Self { + DebugRngLists { section } } } @@ -161,7 +157,7 @@ impl RangeLists { debug_ranges: DebugRanges, debug_rnglists: DebugRngLists, ) -> Result> { - let mut input = debug_rnglists.debug_rnglists_section.clone(); + let mut input = debug_rnglists.section.clone(); let header = if input.is_empty() { RngListsHeader::default() } else { @@ -214,14 +210,14 @@ impl RangeLists { address_size: u8, ) -> Result> { if unit_version < 5 { - let mut input = self.debug_ranges.debug_ranges_section.clone(); + let mut input = self.debug_ranges.section.clone(); input.skip(offset.0)?; Ok(RawRngListIter::new(input, unit_version, address_size)) } else { if offset.0 < R::Offset::from_u8(self.header.size()) { return Err(Error::OffsetOutOfBounds); } - let mut input = self.debug_rnglists.debug_rnglists_section.clone(); + let mut input = self.debug_rnglists.section.clone(); input.skip(offset.0)?; Ok(RawRngListIter::new( input, @@ -230,6 +226,27 @@ impl RangeLists { )) } } + + /// Returns the `.debug_rnglists` offset at the given `base` and `index`. + /// + /// The `base` must be the `DW_AT_rnglists_base` value from the compilation unit DIE. + /// This is an offset that points to the first entry following the header. + /// + /// The `index` is the value of a `DW_FORM_rnglistx` attribute. + pub fn get_offset( + &self, + base: DebugRngListsBase, + index: DebugRngListsIndex, + ) -> Result> { + let input = &mut self.debug_rnglists.section.clone(); + input.skip(base.0)?; + input.skip(R::Offset::from_u64( + index.0.into_u64() * u64::from(self.header.format.word_size()), + )?)?; + input + .read_offset(self.header.format) + .map(|x| RangeListsOffset(base.0 + x)) + } } /// A raw iterator over an address range list. diff --git a/src/read/unit.rs b/src/read/unit.rs index 3420897da..74aaea7e7 100644 --- a/src/read/unit.rs +++ b/src/read/unit.rs @@ -7,7 +7,8 @@ use std::{u16, u8}; use common::{ DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset, - DebugMacinfoOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, + DebugLocListsBase, DebugLocListsIndex, DebugMacinfoOffset, DebugRngListsBase, + DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, Format, LocationListsOffset, RangeListsOffset, }; use constants; @@ -1017,12 +1018,24 @@ pub enum AttributeValue { /// An offset into either the `.debug_loc` section or the `.debug_loclists` section. LocationListsRef(LocationListsOffset), + /// An offset to a set of offsets in the `.debug_loclists` section. + DebugLocListsBase(DebugLocListsBase), + + /// An index into a set of offsets in the `.debug_loclists` section. + DebugLocListsIndex(DebugLocListsIndex), + /// An offset into the `.debug_macinfo` section. DebugMacinfoRef(DebugMacinfoOffset), /// An offset into the `.debug_ranges` section. RangeListsRef(RangeListsOffset), + /// An offset to a set of offsets in the `.debug_rnglists` section. + DebugRngListsBase(DebugRngListsBase), + + /// An index into a set of offsets in the `.debug_rnglists` section. + DebugRngListsIndex(DebugRngListsIndex), + /// A type signature. DebugTypesRef(DebugTypeSignature), @@ -1163,17 +1176,26 @@ impl Attribute { macro_rules! flag { () => {}; } + macro_rules! lineptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugLineRef(DebugLineOffset(offset)); + } + }; + } + // This also covers `loclist` in DWARF version 5. macro_rules! loclistptr { () => { + // DebugLocListsIndex is also an allowed form in DWARF version 5. if let Some(offset) = self.offset_value() { return AttributeValue::LocationListsRef(LocationListsOffset(offset)); } }; } - macro_rules! lineptr { + macro_rules! loclistsptr { () => { if let Some(offset) = self.offset_value() { - return AttributeValue::DebugLineRef(DebugLineOffset(offset)); + return AttributeValue::DebugLocListsBase(DebugLocListsBase(offset)); } }; } @@ -1184,15 +1206,24 @@ impl Attribute { } }; } + macro_rules! reference { + () => {}; + } + // This also covers `rnglist` in DWARF version 5. macro_rules! rangelistptr { () => { + // DebugRngListsIndex is also an allowed form in DWARF version 5. if let Some(offset) = self.offset_value() { return AttributeValue::RangeListsRef(RangeListsOffset(offset)); } }; } - macro_rules! reference { - () => {}; + macro_rules! rnglistsptr { + () => { + if let Some(offset) = self.offset_value() { + return AttributeValue::DebugRngListsBase(DebugRngListsBase(offset)); + } + }; } macro_rules! string { () => {}; @@ -1521,6 +1552,12 @@ impl Attribute { constants::DW_AT_addr_base => { addrptr!(); } + constants::DW_AT_rnglists_base => { + rnglistsptr!(); + } + constants::DW_AT_loclists_base => { + loclistsptr!(); + } _ => {} } self.value.clone() @@ -1862,6 +1899,14 @@ pub(crate) fn parse_attribute<'unit, 'abbrev, R: Reader>( let index = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) } + constants::DW_FORM_loclistx => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugLocListsIndex(DebugLocListsIndex(index)) + } + constants::DW_FORM_rnglistx => { + let index = input.read_uleb128().and_then(R::Offset::from_u64)?; + AttributeValue::DebugRngListsIndex(DebugRngListsIndex(index)) + } _ => { return Err(Error::UnknownForm); } diff --git a/src/write/unit.rs b/src/write/unit.rs index 1c0baa2c0..253ac150a 100644 --- a/src/write/unit.rs +++ b/src/write/unit.rs @@ -3,9 +3,9 @@ use std::{slice, usize}; use vec::Vec; use common::{ - DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, - DebugStrOffset, DebugStrOffsetsBase, DebugTypeSignature, Format, LocationListsOffset, - RangeListsOffset, + DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLineOffset, DebugLocListsBase, + DebugMacinfoOffset, DebugRngListsBase, DebugStrOffset, DebugStrOffsetsBase, DebugTypeSignature, + Format, LocationListsOffset, RangeListsOffset, }; use constants; use write::{ @@ -1054,6 +1054,8 @@ mod convert { pub line_program_files: Vec, pub str_offsets_base: DebugStrOffsetsBase, pub addr_base: DebugAddrBase, + pub loclists_base: DebugLocListsBase, + pub rnglists_base: DebugRngListsBase, } impl UnitTable { @@ -1142,6 +1144,8 @@ mod convert { let mut line_program_files = Vec::new(); let mut str_offsets_base = DebugStrOffsetsBase(0); let mut addr_base = DebugAddrBase(0); + let mut loclists_base = DebugLocListsBase(0); + let mut rnglists_base = DebugRngListsBase(0); { let from_root = from_root.entry(); let comp_dir = from_root @@ -1171,6 +1175,16 @@ mod convert { { addr_base = base; } + if let Some(read::AttributeValue::DebugLocListsBase(base)) = + from_root.attr_value(constants::DW_AT_loclists_base)? + { + loclists_base = base; + } + if let Some(read::AttributeValue::DebugRngListsBase(base)) = + from_root.attr_value(constants::DW_AT_rnglists_base)? + { + rnglists_base = base; + } } let mut context = ConvertUnitContext { dwarf, @@ -1180,6 +1194,8 @@ mod convert { line_program_files, str_offsets_base, addr_base, + loclists_base, + rnglists_base, }; let root = DebuggingInformationEntry::from( &mut context, @@ -1328,7 +1344,31 @@ mod convert { read::AttributeValue::LocationListsRef(val) => { AttributeValue::LocationListsRef(val) } + read::AttributeValue::DebugLocListsBase(_base) => { + // We convert all location list indices to offsets, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugLocListsIndex(index) => { + let offset = context + .dwarf + .locations + .get_offset(context.loclists_base, index)?; + AttributeValue::LocationListsRef(offset) + } read::AttributeValue::RangeListsRef(val) => AttributeValue::RangeListsRef(val), + read::AttributeValue::DebugRngListsBase(_base) => { + // We convert all range list indices to offsets, + // so this is unneeded. + return Ok(None); + } + read::AttributeValue::DebugRngListsIndex(index) => { + let offset = context + .dwarf + .ranges + .get_offset(context.rnglists_base, index)?; + AttributeValue::RangeListsRef(offset) + } read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val), read::AttributeValue::DebugStrRef(offset) => { let r = context.dwarf.debug_str.get_str(offset)?; @@ -1900,6 +1940,8 @@ mod tests { line_program_files: Vec::new(), str_offsets_base: DebugStrOffsetsBase(0), addr_base: DebugAddrBase(0), + loclists_base: DebugLocListsBase(0), + rnglists_base: DebugRngListsBase(0), }; let convert_attr = @@ -2317,6 +2359,8 @@ mod tests { line_program_files: line_program_files.clone(), str_offsets_base: DebugStrOffsetsBase(0), addr_base: DebugAddrBase(0), + loclists_base: DebugLocListsBase(0), + rnglists_base: DebugRngListsBase(0), }; let convert_attr = From 8179ec667fed1bd27bfa508b3fe72446188044c0 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 11 Jan 2019 13:20:50 +1000 Subject: [PATCH 04/12] test_util: use existing D32/D64 methods instead of e32/u64 --- src/read/cfi.rs | 121 ++++++++++++++++++----------------------------- src/test_util.rs | 28 +---------- 2 files changed, 46 insertions(+), 103 deletions(-) diff --git a/src/read/cfi.rs b/src/read/cfi.rs index a1f302bbd..10cfb5908 100644 --- a/src/read/cfi.rs +++ b/src/read/cfi.rs @@ -3361,7 +3361,6 @@ mod tests { trait CfiSectionMethods: GimliSectionMethods { fn cie<'aug, 'input, E, T>( self, - endian: Endian, augmentation: Option<&'aug str>, cie: &mut CommonInformationEntry>, ) -> Self @@ -3371,7 +3370,6 @@ mod tests { T::Offset: UnwindOffset; fn fde<'a, 'input, E, T, L>( self, - endian: Endian, cie_offset: L, fde: &mut FrameDescriptionEntry>, ) -> Self @@ -3385,7 +3383,6 @@ mod tests { impl CfiSectionMethods for Section { fn cie<'aug, 'input, E, T>( self, - endian: Endian, augmentation: Option<&'aug str>, cie: &mut CommonInformationEntry>, ) -> Self @@ -3400,16 +3397,10 @@ mod tests { let end = Label::new(); let section = match cie.format { - Format::Dwarf32 => self - .e32(endian, &length) - .mark(&start) - .e32(endian, 0xffff_ffff), + Format::Dwarf32 => self.D32(&length).mark(&start).D32(0xffff_ffff), Format::Dwarf64 => { - let section = self.e32(endian, 0xffff_ffff); - section - .e64(endian, &length) - .mark(&start) - .e64(endian, 0xffff_ffff_ffff_ffff) + let section = self.D32(0xffff_ffff); + section.D64(&length).mark(&start).D64(0xffff_ffff_ffff_ffff) } }; @@ -3443,7 +3434,6 @@ mod tests { fn fde<'a, 'input, E, T, L>( self, - endian: Endian, cie_offset: L, fde: &mut FrameDescriptionEntry>, ) -> Self @@ -3462,35 +3452,30 @@ mod tests { let section = match T::cie_offset_encoding(fde.format) { CieOffsetEncoding::U32 => { - let section = self.e32(endian, &length).mark(&start); + let section = self.D32(&length).mark(&start); match cie_offset.to_labelornum() { - LabelOrNum::Label(ref l) => section.e32(endian, l), - LabelOrNum::Num(o) => section.e32(endian, o as u32), + LabelOrNum::Label(ref l) => section.D32(l), + LabelOrNum::Num(o) => section.D32(o as u32), } } CieOffsetEncoding::U64 => { - let section = self.e32(endian, 0xffff_ffff); - section - .e64(endian, &length) - .mark(&start) - .e64(endian, cie_offset) + let section = self.D32(0xffff_ffff); + section.D64(&length).mark(&start).D64(cie_offset) } }; let section = match fde.cie.segment_size { 0 => section, - 4 => section.e32(endian, fde.initial_segment as u32), - 8 => section.e64(endian, fde.initial_segment), + 4 => section.D32(fde.initial_segment as u32), + 8 => section.D64(fde.initial_segment), x => panic!("Unsupported test segment size: {}", x), }; let section = match fde.cie.address_size { 4 => section - .e32(endian, fde.initial_address() as u32) - .e32(endian, fde.len() as u32), - 8 => section - .e64(endian, fde.initial_address()) - .e64(endian, fde.len()), + .D32(fde.initial_address() as u32) + .D32(fde.len() as u32), + 8 => section.D64(fde.initial_address()).D64(fde.len()), x => panic!("Unsupported address size: {}", x), }; @@ -3513,11 +3498,11 @@ mod tests { // Augmentation data length let section = section.uleb(u64::from(fde.cie.address_size)); match fde.cie.address_size { - 4 => section.e32(endian, { + 4 => section.D32({ let x: u64 = lsda.into(); x as u32 }), - 8 => section.e64(endian, { + 8 => section.D64({ let x: u64 = lsda.into(); x }), @@ -3615,7 +3600,7 @@ mod tests { phantom: PhantomData, }; - let section = Section::with_endian(Endian::Little).cie(Endian::Little, None, &mut cie); + let section = Section::with_endian(Endian::Little).cie(None, &mut cie); assert_parse_cie::(section, 4, Err(Error::UnknownVersion(99))); } @@ -3676,7 +3661,7 @@ mod tests { }; let section = Section::with_endian(Endian::Little) - .cie(Endian::Little, None, &mut cie) + .cie(None, &mut cie) .append_bytes(&expected_rest); assert_parse_cie( @@ -3721,7 +3706,7 @@ mod tests { phantom: PhantomData, }; - let section = Section::with_endian(Endian::Little).cie(Endian::Little, None, &mut cie); + let section = Section::with_endian(Endian::Little).cie(None, &mut cie); let mut contents = section.get_contents().unwrap(); @@ -3818,7 +3803,7 @@ mod tests { }; let section = Section::with_endian(Endian::Little) - .fde(Endian::Little, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); @@ -3870,7 +3855,7 @@ mod tests { }; let section = Section::with_endian(Endian::Little) - .fde(Endian::Little, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); @@ -3922,7 +3907,7 @@ mod tests { }; let section = Section::with_endian(Endian::Little) - .fde(Endian::Little, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); @@ -3961,7 +3946,7 @@ mod tests { }; let section = Section::with_endian(Endian::Big) - .cie(Endian::Big, None, &mut cie) + .cie(None, &mut cie) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); let rest = &mut EndianSlice::new(§ion, BigEndian); @@ -4008,7 +3993,7 @@ mod tests { }; let section = Section::with_endian(Endian::Big) - .fde(Endian::Big, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&expected_rest); let section = section.get_contents().unwrap(); @@ -4082,9 +4067,9 @@ mod tests { // with all the CIEs always having he correct length. let section = Section::with_endian(Endian::Big) .mark(&cie1_location) - .cie(Endian::Big, None, &mut cie1) + .cie(None, &mut cie1) .mark(&cie2_location) - .cie(Endian::Big, None, &mut cie2); + .cie(None, &mut cie2); let mut fde1 = DebugFrameFde { offset: 0, @@ -4110,11 +4095,9 @@ mod tests { instructions: EndianSlice::new(&expected_instrs4, BigEndian), }; - let section = section.fde(Endian::Big, &cie1_location, &mut fde1).fde( - Endian::Big, - &cie2_location, - &mut fde2, - ); + let section = section + .fde(&cie1_location, &mut fde1) + .fde(&cie2_location, &mut fde2); section.start().set_const(0); @@ -4188,7 +4171,7 @@ mod tests { let section = Section::with_endian(Endian::Little) .append_bytes(&filler) .mark(&cie_location) - .cie(Endian::Little, None, &mut cie) + .cie(None, &mut cie) .append_bytes(&filler); section.start().set_const(0); @@ -5515,9 +5498,9 @@ mod tests { // with all the CIEs always having he correct length. let section = Section::with_endian(Endian::Big) .mark(&cie1_location) - .cie(Endian::Big, None, &mut cie1) + .cie(None, &mut cie1) .mark(&cie2_location) - .cie(Endian::Big, None, &mut cie2); + .cie(None, &mut cie2); let mut fde1 = DebugFrameFde { offset: 0, @@ -5543,11 +5526,9 @@ mod tests { instructions: EndianSlice::new(&instrs4, BigEndian), }; - let section = section.fde(Endian::Big, &cie1_location, &mut fde1).fde( - Endian::Big, - &cie2_location, - &mut fde2, - ); + let section = section + .fde(&cie1_location, &mut fde1) + .fde(&cie2_location, &mut fde2); section.start().set_const(0); let contents = section.get_contents().unwrap(); @@ -5766,7 +5747,7 @@ mod tests { let section = Section::with_endian(Endian::Little) .append_repeated(0, 16) .mark(&start_of_cie) - .cie(Endian::Little, None, &mut cie) + .cie(None, &mut cie) .mark(&end_of_cie); let mut fde1 = EhFrameFde { @@ -5798,17 +5779,9 @@ mod tests { let section = section // +4 for the FDE length before the CIE offset. .mark(&start_of_fde1) - .fde( - Endian::Little, - (&start_of_fde1 - &start_of_cie + 4) as u64, - &mut fde1, - ) + .fde((&start_of_fde1 - &start_of_cie + 4) as u64, &mut fde1) .mark(&start_of_fde2) - .fde( - Endian::Little, - (&start_of_fde2 - &start_of_cie + 4) as u64, - &mut fde2, - ); + .fde((&start_of_fde2 - &start_of_cie + 4) as u64, &mut fde2); section.start().set_const(0); let section = section.get_contents().unwrap(); @@ -5927,7 +5900,7 @@ mod tests { let section = Section::with_endian(Endian::Little) .append_repeated(0, 16) .mark(&start_of_cie) - .cie(Endian::Little, None, &mut cie) + .cie(None, &mut cie) .mark(&end_of_cie); let mut fde = EhFrameFde { @@ -5944,11 +5917,7 @@ mod tests { let section = section // +4 for the FDE length before the CIE offset. - .fde( - Endian::Little, - (&end_of_cie - &start_of_cie + 4) as u64, - &mut fde, - ); + .fde((&end_of_cie - &start_of_cie + 4) as u64, &mut fde); section.start().set_const(0); let section = section.get_contents().unwrap(); @@ -5990,9 +5959,9 @@ mod tests { }; let section = Section::with_endian(Endian::Little) - .cie(Endian::Little, None, &mut cie) + .cie(None, &mut cie) .mark(&end_of_cie) - .fde(Endian::Little, 99_999_999_999_999, &mut fde); + .fde(99_999_999_999_999, &mut fde); section.start().set_const(0); let section = section.get_contents().unwrap(); @@ -6206,7 +6175,7 @@ mod tests { let rest = [1, 2, 3, 4]; let section = Section::with_endian(Endian::Little) - .fde(Endian::Little, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); @@ -6243,7 +6212,7 @@ mod tests { let rest = [1, 2, 3, 4]; let section = Section::with_endian(Endian::Little) - .fde(Endian::Little, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); @@ -6283,7 +6252,7 @@ mod tests { let rest = [1, 2, 3, 4]; let section = Section::with_endian(Endian::Little) - .fde(Endian::Little, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); @@ -6326,7 +6295,7 @@ mod tests { let section = Section::with_endian(Endian::Little) .append_repeated(10, 10) - .fde(Endian::Little, cie_offset, &mut fde) + .fde(cie_offset, &mut fde) .append_bytes(&rest) .get_contents() .unwrap(); diff --git a/src/test_util.rs b/src/test_util.rs index c38ecce83..141ccc062 100644 --- a/src/test_util.rs +++ b/src/test_util.rs @@ -4,41 +4,15 @@ extern crate test_assembler; use vec::Vec; -use self::test_assembler::{Endian, Section, ToLabelOrNum}; +use self::test_assembler::Section; use leb128; pub trait GimliSectionMethods { - fn e32<'a, T>(self, endian: Endian, val: T) -> Self - where - T: ToLabelOrNum<'a, u32>; - fn e64<'a, T>(self, endian: Endian, val: T) -> Self - where - T: ToLabelOrNum<'a, u64>; fn sleb(self, val: i64) -> Self; fn uleb(self, val: u64) -> Self; } impl GimliSectionMethods for Section { - fn e32<'a, T>(self, endian: Endian, val: T) -> Self - where - T: ToLabelOrNum<'a, u32>, - { - match endian { - Endian::Little => self.L32(val), - Endian::Big => self.B32(val), - } - } - - fn e64<'a, T>(self, endian: Endian, val: T) -> Self - where - T: ToLabelOrNum<'a, u64>, - { - match endian { - Endian::Little => self.L64(val), - Endian::Big => self.B64(val), - } - } - fn sleb(self, val: i64) -> Self { let mut buf = Vec::new(); let written = leb128::write::signed(&mut buf, val).unwrap(); From 3995d578d9dab04b2b2eb734b20c1082083858f6 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 11 Jan 2019 16:16:23 +1000 Subject: [PATCH 05/12] read: add tests for various offset/address tables --- src/read/addr.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++ src/read/loclists.rs | 39 +++++++++++++++++++++++++++++++++++ src/read/rnglists.rs | 39 +++++++++++++++++++++++++++++++++++ src/read/str.rs | 45 ++++++++++++++++++++++++++++++++++++++++ src/test_util.rs | 20 +++++++++++++++++- 5 files changed, 191 insertions(+), 1 deletion(-) diff --git a/src/read/addr.rs b/src/read/addr.rs index d128eaad9..d4e771981 100644 --- a/src/read/addr.rs +++ b/src/read/addr.rs @@ -51,3 +51,52 @@ impl From for DebugAddr { DebugAddr { section } } } + +#[cfg(test)] +mod tests { + extern crate test_assembler; + + use self::test_assembler::{Endian, Label, LabelMaker, Section}; + use super::*; + use read::EndianSlice; + use test_util::GimliSectionMethods; + use {Format, LittleEndian}; + + #[test] + fn test_get_address() { + for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { + for address_size in [4, 8].iter().cloned() { + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(5) + .D8(address_size) + .D8(0) + .mark(&first); + for i in 0..20 { + section = section.word(address_size, 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + + let section = section.get_contents().unwrap(); + let debug_addr = DebugAddr::from(EndianSlice::new(§ion, LittleEndian)); + let base = DebugAddrBase((&first - &zero) as usize); + + assert_eq!( + debug_addr.get_address(address_size, base, DebugAddrIndex(0)), + Ok(1000) + ); + assert_eq!( + debug_addr.get_address(address_size, base, DebugAddrIndex(19)), + Ok(1019) + ); + } + } + } +} diff --git a/src/read/loclists.rs b/src/read/loclists.rs index 2f40d36c0..29f30f291 100644 --- a/src/read/loclists.rs +++ b/src/read/loclists.rs @@ -1122,4 +1122,43 @@ mod tests { otherwise => panic!("Unexpected result: {:?}", otherwise), } } + + #[test] + fn test_get_offset() { + for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(5) + .D8(4) + .D8(0) + .D32(20) + .mark(&first); + for i in 0..20 { + section = section.word(format.word_size(), 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + let section = section.get_contents().unwrap(); + + let debug_loc = DebugLoc::from(EndianSlice::new(&[], LittleEndian)); + let debug_loclists = DebugLocLists::from(EndianSlice::new(§ion, LittleEndian)); + let locations = LocationLists::new(debug_loc, debug_loclists).unwrap(); + + let base = DebugLocListsBase((&first - &zero) as usize); + assert_eq!( + locations.get_offset(base, DebugLocListsIndex(0)), + Ok(LocationListsOffset(base.0 + 1000)) + ); + assert_eq!( + locations.get_offset(base, DebugLocListsIndex(19)), + Ok(LocationListsOffset(base.0 + 1019)) + ); + } + } } diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index 14fa69e3b..5e0d1a7f9 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -1068,4 +1068,43 @@ mod tests { otherwise => panic!("Unexpected result: {:?}", otherwise), } } + + #[test] + fn test_get_offset() { + for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(5) + .D8(4) + .D8(0) + .D32(20) + .mark(&first); + for i in 0..20 { + section = section.word(format.word_size(), 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + let section = section.get_contents().unwrap(); + + let debug_ranges = DebugRanges::from(EndianSlice::new(&[], LittleEndian)); + let debug_rnglists = DebugRngLists::from(EndianSlice::new(§ion, LittleEndian)); + let ranges = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); + + let base = DebugRngListsBase((&first - &zero) as usize); + assert_eq!( + ranges.get_offset(base, DebugRngListsIndex(0)), + Ok(RangeListsOffset(base.0 + 1000)) + ); + assert_eq!( + ranges.get_offset(base, DebugRngListsIndex(19)), + Ok(RangeListsOffset(base.0 + 1019)) + ); + } + } } diff --git a/src/read/str.rs b/src/read/str.rs index fef9a6589..9ac55d368 100644 --- a/src/read/str.rs +++ b/src/read/str.rs @@ -114,3 +114,48 @@ impl From for DebugStrOffsets { DebugStrOffsets { section } } } + +#[cfg(test)] +mod tests { + extern crate test_assembler; + + use self::test_assembler::{Endian, Label, LabelMaker, Section}; + use super::*; + use test_util::GimliSectionMethods; + use LittleEndian; + + #[test] + fn test_get_str_offset() { + for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { + let zero = Label::new(); + let length = Label::new(); + let start = Label::new(); + let first = Label::new(); + let end = Label::new(); + let mut section = Section::with_endian(Endian::Little) + .mark(&zero) + .initial_length(format, &length, &start) + .D16(5) + .D16(0) + .mark(&first); + for i in 0..20 { + section = section.word(format.word_size(), 1000 + i); + } + section = section.mark(&end); + length.set_const((&end - &start) as u64); + + let section = section.get_contents().unwrap(); + let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian)); + let base = DebugStrOffsetsBase((&first - &zero) as usize); + + assert_eq!( + debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)), + Ok(DebugStrOffset(1000)) + ); + assert_eq!( + debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)), + Ok(DebugStrOffset(1019)) + ); + } + } +} diff --git a/src/test_util.rs b/src/test_util.rs index 141ccc062..1602f17a0 100644 --- a/src/test_util.rs +++ b/src/test_util.rs @@ -4,12 +4,15 @@ extern crate test_assembler; use vec::Vec; -use self::test_assembler::Section; +use self::test_assembler::{Label, Section}; use leb128; +use Format; pub trait GimliSectionMethods { fn sleb(self, val: i64) -> Self; fn uleb(self, val: u64) -> Self; + fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self; + fn word(self, size: u8, val: u64) -> Self; } impl GimliSectionMethods for Section { @@ -24,4 +27,19 @@ impl GimliSectionMethods for Section { let written = leb128::write::unsigned(&mut buf, val).unwrap(); self.append_bytes(&buf[0..written]) } + + fn initial_length(self, format: Format, length: &Label, start: &Label) -> Self { + match format { + Format::Dwarf32 => self.D32(length).mark(start), + Format::Dwarf64 => self.D32(0xffff_ffff).D64(length).mark(start), + } + } + + fn word(self, size: u8, val: u64) -> Self { + match size { + 4 => self.D32(val as u32), + 8 => self.D64(val), + _ => panic!("unsupported word size"), + } + } } From df819cfab66fa9f6582ac03b6ba85c604ba05fb2 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 14 Jan 2019 13:58:49 +1000 Subject: [PATCH 06/12] Add Reader::read_uint --- examples/dwarfdump.rs | 7 ++----- src/endianity.rs | 14 ++++++++++++++ src/read/endian_reader.rs | 14 ++++---------- src/read/endian_slice.rs | 14 ++++---------- src/read/reader.rs | 23 ++++++++++++++++++++++- 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index ee65edc7c..9c1aa8dd1 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -324,11 +324,8 @@ impl<'a, R: gimli::Reader> gimli::Reader for Relocate<'a, R> { } #[inline] - fn read_u8_array(&mut self) -> gimli::Result - where - A: Sized + Default + AsMut<[u8]>, - { - self.reader.read_u8_array() + fn read_slice(&mut self, buf: &mut [u8]) -> gimli::Result<()> { + self.reader.read_slice(buf) } } diff --git a/src/endianity.rs b/src/endianity.rs index 25c7614f6..132795a17 100644 --- a/src/endianity.rs +++ b/src/endianity.rs @@ -57,6 +57,20 @@ pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq { } } + /// Read an unsigned n-bytes integer u64. + /// + /// # Panics + /// + /// Panics when `buf.len() < 1` or `buf.len() > 8`. + #[inline] + fn read_uint(&mut self, buf: &[u8]) -> u64 { + if self.is_big_endian() { + byteorder::BigEndian::read_uint(buf, buf.len()) + } else { + byteorder::LittleEndian::read_uint(buf, buf.len()) + } + } + /// Reads a signed 16 bit integer from `buf`. /// /// # Panics diff --git a/src/read/endian_reader.rs b/src/read/endian_reader.rs index 643002365..04330a0e7 100644 --- a/src/read/endian_reader.rs +++ b/src/read/endian_reader.rs @@ -4,7 +4,6 @@ use borrow::Cow; use rc::Rc; use stable_deref_trait::CloneStableDeref; use std::fmt::Debug; -use std::mem; use std::ops::{Deref, Index, Range, RangeFrom, RangeTo}; use std::slice; use std::str; @@ -441,15 +440,10 @@ where } #[inline] - fn read_u8_array(&mut self) -> Result - where - A: Sized + Default + AsMut<[u8]>, - { - let len = mem::size_of::(); - let slice = self.range.read_slice(len)?; - let mut val = Default::default(); - >::as_mut(&mut val).clone_from_slice(slice); - Ok(val) + fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { + let slice = self.range.read_slice(buf.len())?; + buf.clone_from_slice(slice); + Ok(()) } } diff --git a/src/read/endian_slice.rs b/src/read/endian_slice.rs index 22bb6611c..9b7086361 100644 --- a/src/read/endian_slice.rs +++ b/src/read/endian_slice.rs @@ -1,7 +1,6 @@ //! Working with byte slices that have an associated endianity. use borrow::Cow; -use std::mem; use std::ops::{Deref, Index, Range, RangeFrom, RangeTo}; use std::str; use string::String; @@ -286,15 +285,10 @@ where } #[inline] - fn read_u8_array(&mut self) -> Result - where - A: Sized + Default + AsMut<[u8]>, - { - let len = mem::size_of::(); - let slice = self.read_slice(len)?; - let mut val = Default::default(); - >::as_mut(&mut val).clone_from_slice(slice); - Ok(val) + fn read_slice(&mut self, buf: &mut [u8]) -> Result<()> { + let slice = self.read_slice(buf.len())?; + buf.clone_from_slice(slice); + Ok(()) } } diff --git a/src/read/reader.rs b/src/read/reader.rs index 88e6b89b5..1cb0c3a26 100644 --- a/src/read/reader.rs +++ b/src/read/reader.rs @@ -261,10 +261,19 @@ pub trait Reader: Debug + Clone { /// Does not advance the reader. fn to_string_lossy(&self) -> Result>; + /// Read a u8 slice. + fn read_slice(&mut self, buf: &mut [u8]) -> Result<()>; + /// Read a u8 array. + #[inline] fn read_u8_array(&mut self) -> Result where - A: Sized + Default + AsMut<[u8]>; + A: Sized + Default + AsMut<[u8]>, + { + let mut val = Default::default(); + self.read_slice(>::as_mut(&mut val))?; + Ok(val) + } /// Return true if the number of bytes remaining is zero. #[inline] @@ -342,6 +351,18 @@ pub trait Reader: Debug + Clone { Ok(self.endian().read_f64(&a)) } + /// Read an unsigned n-bytes integer u64. + /// + /// # Panics + /// + /// Panics when nbytes < 1 or nbytes > 8 + #[inline] + fn read_uint(&mut self, n: usize) -> Result { + let mut buf = [0; 8]; + self.read_slice(&mut buf[..n])?; + Ok(self.endian().read_uint(&buf[..n])) + } + /// Read a null-terminated slice, and return it (excluding the null). fn read_null_terminated_slice(&mut self) -> Result { let idx = self.find(0)?; From 35b9e7f88f601e2dda043a6e245f194032c0ae5e Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 14 Jan 2019 14:02:42 +1000 Subject: [PATCH 07/12] read: implement DW_FORM_strx3 and DW_FORM_addrx3 --- src/read/unit.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/read/unit.rs b/src/read/unit.rs index 74aaea7e7..f6fdf8656 100644 --- a/src/read/unit.rs +++ b/src/read/unit.rs @@ -1877,7 +1877,10 @@ pub(crate) fn parse_attribute<'unit, 'abbrev, R: Reader>( let index = input.read_u16().map(R::Offset::from_u16)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) } - // TODO: constants::DW_FORM_strx3 + constants::DW_FORM_strx3 => { + let index = input.read_uint(3).and_then(R::Offset::from_u64)?; + AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) + } constants::DW_FORM_strx4 => { let index = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index)) @@ -1894,7 +1897,10 @@ pub(crate) fn parse_attribute<'unit, 'abbrev, R: Reader>( let index = input.read_u16().map(R::Offset::from_u16)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) } - // TODO: constants::DW_FORM_addrx3 + constants::DW_FORM_addrx3 => { + let index = input.read_uint(3).and_then(R::Offset::from_u64)?; + AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) + } constants::DW_FORM_addrx4 => { let index = input.read_u32().map(R::Offset::from_u32)?; AttributeValue::DebugAddrIndex(DebugAddrIndex(index)) From 3192084356ffeb69ad7109c7cec74795d1064ed6 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 14 Jan 2019 14:18:09 +1000 Subject: [PATCH 08/12] read: add tests for indexed forms of attributes --- src/read/unit.rs | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/src/read/unit.rs b/src/read/unit.rs index f6fdf8656..29cc318a3 100644 --- a/src/read/unit.rs +++ b/src/read/unit.rs @@ -3511,6 +3511,38 @@ mod tests { AttributeValue::Data8(([8, 7, 6, 5, 4, 3, 2, 1], endian)), AttributeValue::Udata(0x0102_0304_0506_0708), ), + ( + 4, + constants::DW_AT_str_offsets_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugStrOffsetsBase(DebugStrOffsetsBase(0x0102_0304)), + ), + ( + 4, + constants::DW_AT_addr_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugAddrBase(DebugAddrBase(0x0102_0304)), + ), + ( + 4, + constants::DW_AT_rnglists_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugRngListsBase(DebugRngListsBase(0x0102_0304)), + ), + ( + 4, + constants::DW_AT_loclists_base, + constants::DW_FORM_sec_offset, + data4, + AttributeValue::SecOffset(0x0102_0304), + AttributeValue::DebugLocListsBase(DebugLocListsBase(0x0102_0304)), + ), ]; for test in tests.iter() { @@ -4026,6 +4058,138 @@ mod tests { test_parse_attribute(&buf, 8, &unit, form, value); } + #[test] + fn test_parse_attribute_strx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_strx; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx1() { + let buf = [0x01, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx1; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x01)); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx2() { + let buf = [0x01, 0x02, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx2; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0201)); + test_parse_attribute(&buf, 2, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx3() { + let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx3; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x03_0201)); + test_parse_attribute(&buf, 3, &unit, form, value); + } + + #[test] + fn test_parse_attribute_strx4() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_strx4; + let value = AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_addrx; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx1() { + let buf = [0x01, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx1; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x01)); + test_parse_attribute(&buf, 1, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx2() { + let buf = [0x01, 0x02, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx2; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0201)); + test_parse_attribute(&buf, 2, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx3() { + let buf = [0x01, 0x02, 0x03, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx3; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x03_0201)); + test_parse_attribute(&buf, 3, &unit, form, value); + } + + #[test] + fn test_parse_attribute_addrx4() { + let buf = [0x01, 0x02, 0x03, 0x04, 0x99, 0x99]; + let unit = test_parse_attribute_unit(4, Format::Dwarf64, LittleEndian); + let form = constants::DW_FORM_addrx4; + let value = AttributeValue::DebugAddrIndex(DebugAddrIndex(0x0403_0201)); + test_parse_attribute(&buf, 4, &unit, form, value); + } + + #[test] + fn test_parse_attribute_loclistx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_loclistx; + let value = AttributeValue::DebugLocListsIndex(DebugLocListsIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + + #[test] + fn test_parse_attribute_rnglistx() { + let mut buf = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + let bytes_written = { + let mut writable = &mut buf[..]; + leb128::write::unsigned(&mut writable, 4097).expect("should write ok") + }; + + let unit = test_parse_attribute_unit_default(); + let form = constants::DW_FORM_rnglistx; + let value = AttributeValue::DebugRngListsIndex(DebugRngListsIndex(4097)); + test_parse_attribute(&buf, bytes_written, &unit, form, value); + } + #[test] fn test_parse_attribute_indirect() { let mut buf = [0; 100]; From ff5d1356039d8d6ea60be178bcb98bb2168e292c Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 14 Jan 2019 14:59:30 +1000 Subject: [PATCH 09/12] read: handle indexed addresses in location lists --- benches/bench.rs | 39 +++++-- examples/dwarfdump.rs | 74 ++++++++++-- src/read/loclists.rs | 260 +++++++++++++++++++++++++++++++++++++----- tests/parse_self.rs | 18 ++- 4 files changed, 344 insertions(+), 47 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index a4351224b..c48b603dd 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -4,9 +4,10 @@ extern crate gimli; extern crate test; use gimli::{ - AttributeValue, DebugAbbrev, DebugAranges, DebugInfo, DebugLine, DebugLineOffset, DebugLoc, - DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, EntriesTreeNode, - Expression, Format, LittleEndian, LocationLists, Operation, RangeLists, Reader, + AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine, + DebugLineOffset, DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, + DebugRngLists, EndianSlice, EntriesTreeNode, Expression, Format, LittleEndian, LocationLists, + Operation, RangeLists, Reader, ReaderOffset, }; use std::env; use std::fs::File; @@ -224,6 +225,9 @@ fn bench_parsing_debug_loc(b: &mut test::Bencher) { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); + let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); @@ -266,7 +270,14 @@ fn bench_parsing_debug_loc(b: &mut test::Bencher) { b.iter(|| { for &(offset, version, address_size, base_address) in &*offsets { let mut locs = loclists - .locations(offset, version, address_size, base_address) + .locations( + offset, + version, + address_size, + base_address, + &debug_addr, + debug_addr_base, + ) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { test::black_box(loc); @@ -404,8 +415,11 @@ fn bench_evaluating_debug_info_expressions(b: &mut test::Bencher) { fn debug_loc_expressions( debug_info: &DebugInfo, debug_abbrev: &DebugAbbrev, + debug_addr: &DebugAddr, loclists: &LocationLists, ) -> Vec<(Expression, u8, Format)> { + let debug_addr_base = DebugAddrBase(R::Offset::from_u8(0)); + let mut expressions = Vec::new(); let mut iter = debug_info.units(); @@ -435,7 +449,14 @@ fn debug_loc_expressions( while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() { let mut locs = loclists - .locations(offset, unit.version(), unit.address_size(), low_pc) + .locations( + offset, + unit.version(), + unit.address_size(), + low_pc, + debug_addr, + debug_addr_base, + ) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { expressions.push((loc.data, unit.address_size(), unit.format())); @@ -456,12 +477,14 @@ fn bench_parsing_debug_loc_expressions(b: &mut test::Bencher) { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); + let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists).expect("Should parse loclists"); - let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &loclists); + let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists); b.iter(|| { for &(expression, address_size, format) in &*expressions { @@ -482,12 +505,14 @@ fn bench_evaluating_debug_loc_expressions(b: &mut test::Bencher) { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); + let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists).expect("Should parse loclists"); - let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &loclists); + let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists); b.iter(|| { for &(expression, address_size, format) in &*expressions { diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index 9c1aa8dd1..02034cf77 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -1236,7 +1236,7 @@ fn dump_attr_value( writeln!(w, "0x{:08x}", offset)?; } gimli::AttributeValue::LocationListsRef(offset) => { - dump_loc_list(w, &dwarf.locations, offset, unit)?; + dump_loc_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugLocListsBase(base) => { writeln!(w, "<.debug_loclists+0x{:08x}>", base.0)?; @@ -1244,7 +1244,7 @@ fn dump_attr_value( gimli::AttributeValue::DebugLocListsIndex(index) => { let offset = dwarf.locations.get_offset(unit.loclists_base, index)?; writeln!(w, "0x{:08x}", offset.0)?; - dump_loc_list(w, &dwarf.locations, offset, unit)?; + dump_loc_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugMacinfoRef(gimli::DebugMacinfoOffset(offset)) => { writeln!(w, "{}", offset)?; @@ -1582,14 +1582,22 @@ fn dump_op( fn dump_loc_list( w: &mut W, - loclists: &gimli::LocationLists, offset: gimli::LocationListsOffset, unit: &Unit, + dwarf: &gimli::Dwarf, ) -> Result<()> { - let raw_locations = loclists.raw_locations(offset, unit.version, unit.address_size)?; + let raw_locations = dwarf + .locations + .raw_locations(offset, unit.version, unit.address_size)?; let raw_locations: Vec<_> = raw_locations.collect()?; - let mut locations = - loclists.locations(offset, unit.version, unit.address_size, unit.base_address)?; + let mut locations = dwarf.locations.locations( + offset, + unit.version, + unit.address_size, + unit.base_address, + &dwarf.debug_addr, + unit.addr_base, + )?; writeln!( w, @@ -1603,6 +1611,57 @@ fn dump_loc_list( gimli::RawLocListEntry::BaseAddress { addr } => { writeln!(w, "", addr)?; } + gimli::RawLocListEntry::BaseAddressx { addr } => { + let addr_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, addr)?; + writeln!(w, "", addr.0, addr_val)?; + } + gimli::RawLocListEntry::StartxEndx { + begin, + end, + ref data, + } => { + let begin_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, begin)?; + let end_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, end)?; + let location = locations.next()?.unwrap(); + write!( + w, + "", + begin.0, begin_val, location.range.begin, end.0, end_val, location.range.end + )?; + dump_exprloc(w, data, unit)?; + writeln!(w)?; + } + gimli::RawLocListEntry::StartxLength { + begin, + length, + ref data, + } => { + let begin_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, begin)?; + let location = locations.next()?.unwrap(); + write!( + w, + "", + begin.0, begin_val, location.range.begin, length, location.range.end + )?; + dump_exprloc(w, data, unit)?; + writeln!(w)?; + } gimli::RawLocListEntry::OffsetPair { begin, end, @@ -1656,9 +1715,6 @@ fn dump_loc_list( dump_exprloc(w, data, unit)?; writeln!(w)?; } - _ => { - panic!("AddressIndex not handled, should already have errored out"); - } }; } Ok(()) diff --git a/src/read/loclists.rs b/src/read/loclists.rs index 29f30f291..518ec9cdb 100644 --- a/src/read/loclists.rs +++ b/src/read/loclists.rs @@ -1,10 +1,13 @@ use fallible_iterator::FallibleIterator; -use common::{DebugLocListsBase, DebugLocListsIndex, Format, LocationListsOffset}; +use common::{ + DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, Format, + LocationListsOffset, +}; use constants; use endianity::Endianity; use read::{ - AddressIndex, EndianSlice, Error, Expression, Range, RawRange, Reader, ReaderOffset, Result, + DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader, ReaderOffset, Result, Section, }; @@ -185,10 +188,14 @@ impl LocationLists { unit_version: u16, address_size: u8, base_address: u64, + debug_addr: &DebugAddr, + debug_addr_base: DebugAddrBase, ) -> Result> { Ok(LocListIter::new( self.raw_locations(offset, unit_version, address_size)?, base_address, + debug_addr.clone(), + debug_addr_base, )) } @@ -270,21 +277,21 @@ pub enum RawLocListEntry { /// DW_LLE_base_addressx BaseAddressx { /// base address - addr: AddressIndex, + addr: DebugAddrIndex, }, /// DW_LLE_startx_endx StartxEndx { /// start of range - begin: AddressIndex, + begin: DebugAddrIndex, /// end of range - end: AddressIndex, + end: DebugAddrIndex, /// expression data: Expression, }, /// DW_LLE_startx_length StartxLength { /// start of range - begin: AddressIndex, + begin: DebugAddrIndex, /// length of range length: u64, /// expression @@ -351,15 +358,15 @@ impl RawLocListEntry { Ok(match constants::DwLle(input.read_u8()?) { constants::DW_LLE_end_of_list => None, constants::DW_LLE_base_addressx => Some(RawLocListEntry::BaseAddressx { - addr: AddressIndex(input.read_uleb128()?), + addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), }), constants::DW_LLE_startx_endx => Some(RawLocListEntry::StartxEndx { - begin: AddressIndex(input.read_uleb128()?), - end: AddressIndex(input.read_uleb128()?), + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), data: parse_data(input)?, }), constants::DW_LLE_startx_length => Some(RawLocListEntry::StartxLength { - begin: AddressIndex(input.read_uleb128()?), + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), length: input.read_uleb128()?, data: parse_data(input)?, }), @@ -440,12 +447,30 @@ impl FallibleIterator for RawLocListIter { pub struct LocListIter { raw: RawLocListIter, base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, } impl LocListIter { /// Construct a `LocListIter`. - fn new(raw: RawLocListIter, base_address: u64) -> LocListIter { - LocListIter { raw, base_address } + fn new( + raw: RawLocListIter, + base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> LocListIter { + LocListIter { + raw, + base_address, + debug_addr, + debug_addr_base, + } + } + + #[inline] + fn get_address(&self, index: DebugAddrIndex) -> Result { + self.debug_addr + .get_address(self.raw.address_size, self.debug_addr_base, index) } /// Advance the iterator to the next location. @@ -461,6 +486,24 @@ impl LocListIter { self.base_address = addr; continue; } + RawLocListEntry::BaseAddressx { addr } => { + self.base_address = self.get_address(addr)?; + continue; + } + RawLocListEntry::StartxEndx { begin, end, data } => { + let begin = self.get_address(begin)?; + let end = self.get_address(end)?; + (Range { begin, end }, data) + } + RawLocListEntry::StartxLength { + begin, + length, + data, + } => { + let begin = self.get_address(begin)?; + let end = begin + length; + (Range { begin, end }, data) + } RawLocListEntry::DefaultLocation { data } => ( Range { begin: 0, @@ -485,10 +528,6 @@ impl LocListIter { }, data, ), - _ => { - // We don't support AddressIndex-based entries yet - return Err(Error::UnsupportedAddressIndex); - } }; if range.begin > range.end { @@ -532,6 +571,15 @@ mod tests { #[test] fn test_loclists_32() { + let section = Section::with_endian(Endian::Little) + .L32(0x0300_0000) + .L32(0x0301_0300) + .L32(0x0301_0400) + .L32(0x0301_0500); + let buf = section.get_contents().unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let start = Label::new(); let first = Label::new(); let size = Label::new(); @@ -564,6 +612,13 @@ mod tests { .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9) // A DefaultLocation .L8(5).uleb(4).L32(10) + // A BaseAddressx + OffsetPair + .L8(1).uleb(0) + .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11) + // A StartxEndx + .L8(2).uleb(1).uleb(2).uleb(4).L32(12) + // A StartxLength + .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) // A range end. .L8(0) // Some extra data. @@ -575,7 +630,9 @@ mod tests { let debug_loclists = DebugLocLists::new(&buf, LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); let offset = LocationListsOffset((&first - &start) as usize); - let mut locations = loclists.locations(offset, 5, 0, 0x0100_0000).unwrap(); + let mut locations = loclists + .locations(offset, 5, 0, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal location. assert_eq!( @@ -683,18 +740,70 @@ mod tests { })) ); + // A BaseAddressx + OffsetPair + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0301_0100, + end: 0x0301_0200, + }, + data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)), + })) + ); + + // A StartxEndx + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0301_0300, + end: 0x0301_0400, + }, + data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)), + })) + ); + + // A StartxLength + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0301_0500, + end: 0x0301_0600, + }, + data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)), + })) + ); + // A location list end. assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. let mut locations = loclists - .locations(LocationListsOffset(buf.len()), 5, 0, 0x0100_0000) + .locations( + LocationListsOffset(buf.len()), + 5, + 0, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } #[test] fn test_loclists_64() { + let section = Section::with_endian(Endian::Little) + .L64(0x0300_0000) + .L64(0x0301_0300) + .L64(0x0301_0400) + .L64(0x0301_0500); + let buf = section.get_contents().unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let start = Label::new(); let first = Label::new(); let size = Label::new(); @@ -728,6 +837,13 @@ mod tests { .L8(4).uleb(0).uleb(0xffff_ffff).uleb(4).L32(9) // A DefaultLocation .L8(5).uleb(4).L32(10) + // A BaseAddressx + OffsetPair + .L8(1).uleb(0) + .L8(4).uleb(0x10100).uleb(0x10200).uleb(4).L32(11) + // A StartxEndx + .L8(2).uleb(1).uleb(2).uleb(4).L32(12) + // A StartxLength + .L8(3).uleb(3).uleb(0x100).uleb(4).L32(13) // A range end. .L8(0) // Some extra data. @@ -739,7 +855,9 @@ mod tests { let debug_loclists = DebugLocLists::new(&buf, LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); let offset = LocationListsOffset((&first - &start) as usize); - let mut locations = loclists.locations(offset, 5, 0, 0x0100_0000).unwrap(); + let mut locations = loclists + .locations(offset, 5, 0, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal location. assert_eq!( @@ -847,12 +965,55 @@ mod tests { })) ); + // A BaseAddressx + OffsetPair + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0301_0100, + end: 0x0301_0200, + }, + data: Expression(EndianSlice::new(&[11, 0, 0, 0], LittleEndian)), + })) + ); + + // A StartxEndx + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0301_0300, + end: 0x0301_0400, + }, + data: Expression(EndianSlice::new(&[12, 0, 0, 0], LittleEndian)), + })) + ); + + // A StartxLength + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0301_0500, + end: 0x0301_0600, + }, + data: Expression(EndianSlice::new(&[13, 0, 0, 0], LittleEndian)), + })) + ); + // A location list end. assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. let mut locations = loclists - .locations(LocationListsOffset(buf.len()), 5, 0, 0x0100_0000) + .locations( + LocationListsOffset(buf.len()), + 5, + 0, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } @@ -891,7 +1052,11 @@ mod tests { let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); let offset = LocationListsOffset((&first - &start) as usize); let version = 4; - let mut locations = loclists.locations(offset, version, 4, 0x0100_0000).unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let mut locations = loclists + .locations(offset, version, 4, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal location. assert_eq!( @@ -968,7 +1133,14 @@ mod tests { // An offset at the end of buf. let mut locations = loclists - .locations(LocationListsOffset(buf.len()), version, 4, 0x0100_0000) + .locations( + LocationListsOffset(buf.len()), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } @@ -1007,7 +1179,11 @@ mod tests { let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); let offset = LocationListsOffset((&first - &start) as usize); let version = 4; - let mut locations = loclists.locations(offset, version, 8, 0x0100_0000).unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let mut locations = loclists + .locations(offset, version, 8, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal location. assert_eq!( @@ -1084,7 +1260,14 @@ mod tests { // An offset at the end of buf. let mut locations = loclists - .locations(LocationListsOffset(buf.len()), version, 8, 0x0100_0000) + .locations( + LocationListsOffset(buf.len()), + version, + 8, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(locations.next(), Ok(None)); } @@ -1103,21 +1286,44 @@ mod tests { let debug_loclists = DebugLocLists::new(&[], LittleEndian); let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); let version = 4; + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); // An invalid location range. let mut locations = loclists - .locations(LocationListsOffset(0x0), version, 4, 0x0100_0000) + .locations( + LocationListsOffset(0x0), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); // An invalid location range after wrapping. let mut locations = loclists - .locations(LocationListsOffset(14), version, 4, 0x0100_0000) + .locations( + LocationListsOffset(14), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); // An invalid offset. - match loclists.locations(LocationListsOffset(buf.len() + 1), version, 4, 0x0100_0000) { + match loclists.locations( + LocationListsOffset(buf.len() + 1), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) { Err(Error::UnexpectedEof) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } diff --git a/tests/parse_self.rs b/tests/parse_self.rs index ee322b802..2f4dd7701 100644 --- a/tests/parse_self.rs +++ b/tests/parse_self.rs @@ -1,9 +1,9 @@ extern crate gimli; use gimli::{ - AttributeValue, DebugAbbrev, DebugAranges, DebugInfo, DebugLine, DebugLoc, DebugLocLists, - DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, DebugStr, Expression, Format, - LittleEndian, LocationLists, Operation, RangeLists, Reader, + AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine, + DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, DebugStr, + EndianSlice, Expression, Format, LittleEndian, LocationLists, Operation, RangeLists, Reader, }; use std::collections::hash_map::HashMap; use std::env; @@ -177,6 +177,9 @@ fn test_parse_self_debug_loc() { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); + let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let debug_loc = read_section("debug_loc"); let debug_loc = DebugLoc::new(&debug_loc, LittleEndian); let debug_loclists = DebugLocLists::new(&[], LittleEndian); @@ -209,7 +212,14 @@ fn test_parse_self_debug_loc() { while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let AttributeValue::LocationListsRef(offset) = attr.value() { let mut locs = loclists - .locations(offset, unit.version(), unit.address_size(), low_pc) + .locations( + offset, + unit.version(), + unit.address_size(), + low_pc, + &debug_addr, + debug_addr_base, + ) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { assert!(loc.range.begin <= loc.range.end); From db16150c609ecd6a47764eef16b3d1927fdbe92a Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 14 Jan 2019 18:12:17 +1000 Subject: [PATCH 10/12] read: handle indexed addresses in range lists --- benches/bench.rs | 12 +- examples/dwarfdump.rs | 68 +++++++++-- src/read/rnglists.rs | 255 ++++++++++++++++++++++++++++++++++++------ tests/parse_self.rs | 12 +- 4 files changed, 301 insertions(+), 46 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index c48b603dd..6fb2a604d 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -294,6 +294,9 @@ fn bench_parsing_debug_ranges(b: &mut test::Bencher) { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); + let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let debug_ranges = read_section("debug_ranges"); let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian); let debug_rnglists = DebugRngLists::new(&[], LittleEndian); @@ -336,7 +339,14 @@ fn bench_parsing_debug_ranges(b: &mut test::Bencher) { b.iter(|| { for &(offset, version, address_size, base_address) in &*offsets { let mut ranges = rnglists - .ranges(offset, version, address_size, base_address) + .ranges( + offset, + version, + address_size, + base_address, + &debug_addr, + debug_addr_base, + ) .expect("Should parse ranges OK"); while let Some(range) = ranges.next().expect("Should parse next range") { test::black_box(range); diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index 02034cf77..45a1f33b6 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -1251,7 +1251,7 @@ fn dump_attr_value( } gimli::AttributeValue::RangeListsRef(offset) => { writeln!(w, "0x{:08x}", offset.0)?; - dump_range_list(w, &dwarf.ranges, offset, unit)?; + dump_range_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugRngListsBase(base) => { writeln!(w, "<.debug_rnglists+0x{:08x}>", base.0)?; @@ -1259,7 +1259,7 @@ fn dump_attr_value( gimli::AttributeValue::DebugRngListsIndex(index) => { let offset = dwarf.ranges.get_offset(unit.rnglists_base, index)?; writeln!(w, "0x{:08x}", offset.0)?; - dump_range_list(w, &dwarf.ranges, offset, unit)?; + dump_range_list(w, offset, unit, dwarf)?; } gimli::AttributeValue::DebugTypesRef(signature) => { dump_type_signature(w, signature, dwarf.endian)?; @@ -1722,13 +1722,22 @@ fn dump_loc_list( fn dump_range_list( w: &mut W, - rnglists: &gimli::RangeLists, offset: gimli::RangeListsOffset, unit: &Unit, + dwarf: &gimli::Dwarf, ) -> Result<()> { - let raw_ranges = rnglists.raw_ranges(offset, unit.version, unit.address_size)?; + let raw_ranges = dwarf + .ranges + .raw_ranges(offset, unit.version, unit.address_size)?; let raw_ranges: Vec<_> = raw_ranges.collect()?; - let mut ranges = rnglists.ranges(offset, unit.version, unit.address_size, unit.base_address)?; + let mut ranges = dwarf.ranges.ranges( + offset, + unit.version, + unit.address_size, + unit.base_address, + &dwarf.debug_addr, + unit.addr_base, + )?; writeln!( w, "\t\tranges: {} at {} offset {} (0x{:08x})", @@ -1747,6 +1756,52 @@ fn dump_range_list( gimli::RawRngListEntry::BaseAddress { addr } => { writeln!(w, "", addr)?; } + gimli::RawRngListEntry::BaseAddressx { addr } => { + let addr_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, addr)?; + writeln!(w, "", addr.0, addr_val)?; + } + gimli::RawRngListEntry::StartxEndx { begin, end } => { + let begin_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, begin)?; + let end_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, end)?; + let range = if begin_val == end_val { + gimli::Range { + begin: begin_val, + end: end_val, + } + } else { + ranges.next()?.unwrap() + }; + writeln!( + w, + "", + begin.0, begin_val, range.begin, end.0, end_val, range.end + )?; + } + gimli::RawRngListEntry::StartxLength { begin, length } => { + let begin_val = + dwarf + .debug_addr + .get_address(unit.address_size, unit.addr_base, begin)?; + let range = ranges.next()?.unwrap(); + writeln!( + w, + "", + begin.0, begin_val, range.begin, length, range.end + )?; + } gimli::RawRngListEntry::OffsetPair { begin, end } => { let range = ranges.next()?.unwrap(); writeln!( @@ -1781,9 +1836,6 @@ fn dump_range_list( begin, range.begin, length, range.end )?; } - _ => { - panic!("AddressIndex not handled, should already have errored out"); - } }; } Ok(()) diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index 5e0d1a7f9..e59cef153 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -1,13 +1,11 @@ use fallible_iterator::FallibleIterator; -use common::{DebugRngListsBase, DebugRngListsIndex, Format, RangeListsOffset}; +use common::{ + DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, Format, RangeListsOffset, +}; use constants; use endianity::Endianity; -use read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section}; - -/// An offset into the `.debug_addr` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AddressIndex(pub u64); +use read::{DebugAddr, EndianSlice, Error, Reader, ReaderOffset, Result, Section}; /// The raw contents of the `.debug_ranges` section. #[derive(Debug, Default, Clone, Copy)] @@ -186,10 +184,14 @@ impl RangeLists { unit_version: u16, address_size: u8, base_address: u64, + debug_addr: &DebugAddr, + debug_addr_base: DebugAddrBase, ) -> Result> { Ok(RngListIter::new( self.raw_ranges(offset, unit_version, address_size)?, base_address, + debug_addr.clone(), + debug_addr_base, )) } @@ -262,7 +264,7 @@ pub struct RawRngListIter { /// A raw entry in .debug_rnglists #[derive(Clone, Debug)] -pub enum RawRngListEntry { +pub enum RawRngListEntry { /// DW_RLE_base_address BaseAddress { /// base address @@ -271,19 +273,19 @@ pub enum RawRngListEntry { /// DW_RLE_base_addressx BaseAddressx { /// base address - addr: AddressIndex, + addr: DebugAddrIndex, }, /// DW_RLE_startx_endx StartxEndx { /// start of range - begin: AddressIndex, + begin: DebugAddrIndex, /// end of range - end: AddressIndex, + end: DebugAddrIndex, }, /// DW_RLE_startx_length StartxLength { /// start of range - begin: AddressIndex, + begin: DebugAddrIndex, /// length of range length: u64, }, @@ -310,9 +312,13 @@ pub enum RawRngListEntry { }, } -impl RawRngListEntry { +impl RawRngListEntry { /// Parse a range entry from `.debug_rnglists` - fn parse(input: &mut R, version: u16, address_size: u8) -> Result> { + fn parse>( + input: &mut R, + version: u16, + address_size: u8, + ) -> Result> { if version < 5 { let range = RawRange::parse(input, address_size)?; return Ok(if range.is_end() { @@ -329,14 +335,14 @@ impl RawRngListEntry { Ok(match constants::DwRle(input.read_u8()?) { constants::DW_RLE_end_of_list => None, constants::DW_RLE_base_addressx => Some(RawRngListEntry::BaseAddressx { - addr: AddressIndex(input.read_uleb128()?), + addr: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), }), constants::DW_RLE_startx_endx => Some(RawRngListEntry::StartxEndx { - begin: AddressIndex(input.read_uleb128()?), - end: AddressIndex(input.read_uleb128()?), + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), + end: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), }), constants::DW_RLE_startx_length => Some(RawRngListEntry::StartxLength { - begin: AddressIndex(input.read_uleb128()?), + begin: DebugAddrIndex(input.read_uleb128().and_then(R::Offset::from_u64)?), length: input.read_uleb128()?, }), constants::DW_RLE_offset_pair => Some(RawRngListEntry::OffsetPair { @@ -372,7 +378,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); } @@ -393,7 +399,7 @@ impl RawRngListIter { } impl FallibleIterator for RawRngListIter { - type Item = RawRngListEntry; + type Item = RawRngListEntry; type Error = Error; fn next(&mut self) -> ::std::result::Result, Self::Error> { @@ -410,12 +416,30 @@ impl FallibleIterator for RawRngListIter { pub struct RngListIter { raw: RawRngListIter, base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, } impl RngListIter { /// Construct a `RngListIter`. - fn new(raw: RawRngListIter, base_address: u64) -> RngListIter { - RngListIter { raw, base_address } + fn new( + raw: RawRngListIter, + base_address: u64, + debug_addr: DebugAddr, + debug_addr_base: DebugAddrBase, + ) -> RngListIter { + RngListIter { + raw, + base_address, + debug_addr, + debug_addr_base, + } + } + + #[inline] + fn get_address(&self, index: DebugAddrIndex) -> Result { + self.debug_addr + .get_address(self.raw.address_size, self.debug_addr_base, index) } /// Advance the iterator to the next range. @@ -431,6 +455,20 @@ impl RngListIter { self.base_address = addr; continue; } + RawRngListEntry::BaseAddressx { addr } => { + self.base_address = self.get_address(addr)?; + continue; + } + RawRngListEntry::StartxEndx { begin, end } => { + let begin = self.get_address(begin)?; + let end = self.get_address(end)?; + Range { begin, end } + } + RawRngListEntry::StartxLength { begin, length } => { + let begin = self.get_address(begin)?; + let end = begin + length; + Range { begin, end } + } RawRngListEntry::OffsetPair { begin, end } => { let mut range = Range { begin, end }; range.add_base_address(self.base_address, self.raw.address_size); @@ -441,10 +479,6 @@ impl RngListIter { begin, end: begin + length, }, - _ => { - // We don't support AddressIndex-based entries yet - return Err(Error::UnsupportedAddressIndex); - } }; if range.begin > range.end { @@ -536,6 +570,15 @@ mod tests { #[test] fn test_rnglists_32() { + let section = Section::with_endian(Endian::Little) + .L32(0x0300_0000) + .L32(0x0301_0300) + .L32(0x0301_0400) + .L32(0x0301_0500); + let buf = section.get_contents().unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let start = Label::new(); let first = Label::new(); let size = Label::new(); @@ -568,6 +611,13 @@ mod tests { // An OffsetPair that ends at -1. .L8(5).L32(0) .L8(4).uleb(0).uleb(0xffff_ffff) + // A BaseAddressx + OffsetPair + .L8(1).uleb(0) + .L8(4).uleb(0x10100).uleb(0x10200) + // A StartxEndx + .L8(2).uleb(1).uleb(2) + // A StartxLength + .L8(3).uleb(3).uleb(0x100) // A range end. .L8(0) // Some extra data. @@ -579,7 +629,9 @@ mod tests { let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); let offset = RangeListsOffset((&first - &start) as usize); - let mut ranges = rnglists.ranges(offset, 5, 0, 0x0100_0000).unwrap(); + let mut ranges = rnglists + .ranges(offset, 5, 0, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal range. assert_eq!( @@ -660,18 +712,61 @@ mod tests { })) ); + // A BaseAddressx + OffsetPair + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0301_0100, + end: 0x0301_0200, + })) + ); + + // A StartxEndx + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0301_0300, + end: 0x0301_0400, + })) + ); + + // A StartxLength + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0301_0500, + end: 0x0301_0600, + })) + ); + // A range end. assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. let mut ranges = rnglists - .ranges(RangeListsOffset(buf.len()), 5, 0, 0x0100_0000) + .ranges( + RangeListsOffset(buf.len()), + 5, + 0, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } #[test] fn test_rnglists_64() { + let section = Section::with_endian(Endian::Little) + .L64(0x0300_0000) + .L64(0x0301_0300) + .L64(0x0301_0400) + .L64(0x0301_0500); + let buf = section.get_contents().unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&buf, LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let start = Label::new(); let first = Label::new(); let size = Label::new(); @@ -705,6 +800,13 @@ mod tests { // An OffsetPair that ends at -1. .L8(5).L64(0) .L8(4).uleb(0).uleb(0xffff_ffff) + // A BaseAddressx + OffsetPair + .L8(1).uleb(0) + .L8(4).uleb(0x10100).uleb(0x10200) + // A StartxEndx + .L8(2).uleb(1).uleb(2) + // A StartxLength + .L8(3).uleb(3).uleb(0x100) // A range end. .L8(0) // Some extra data. @@ -716,7 +818,9 @@ mod tests { let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); let offset = RangeListsOffset((&first - &start) as usize); - let mut ranges = rnglists.ranges(offset, 5, 0, 0x0100_0000).unwrap(); + let mut ranges = rnglists + .ranges(offset, 5, 0, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal range. assert_eq!( @@ -797,12 +901,46 @@ mod tests { })) ); + // A BaseAddressx + OffsetPair + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0301_0100, + end: 0x0301_0200, + })) + ); + + // A StartxEndx + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0301_0300, + end: 0x0301_0400, + })) + ); + + // A StartxLength + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0301_0500, + end: 0x0301_0600, + })) + ); + // A range end. assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. let mut ranges = rnglists - .ranges(RangeListsOffset(buf.len()), 5, 0, 0x0100_0000) + .ranges( + RangeListsOffset(buf.len()), + 5, + 0, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } @@ -873,7 +1011,11 @@ mod tests { let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); let offset = RangeListsOffset((&first - &start) as usize); let version = 4; - let mut ranges = rnglists.ranges(offset, version, 4, 0x0100_0000).unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let mut ranges = rnglists + .ranges(offset, version, 4, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal range. assert_eq!( @@ -932,7 +1074,14 @@ mod tests { // An offset at the end of buf. let mut ranges = rnglists - .ranges(RangeListsOffset(buf.len()), version, 4, 0x0100_0000) + .ranges( + RangeListsOffset(buf.len()), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } @@ -971,7 +1120,11 @@ mod tests { let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); let offset = RangeListsOffset((&first - &start) as usize); let version = 4; - let mut ranges = rnglists.ranges(offset, version, 8, 0x0100_0000).unwrap(); + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let mut ranges = rnglists + .ranges(offset, version, 8, 0x0100_0000, debug_addr, debug_addr_base) + .unwrap(); // A normal range. assert_eq!( @@ -1030,7 +1183,14 @@ mod tests { // An offset at the end of buf. let mut ranges = rnglists - .ranges(RangeListsOffset(buf.len()), version, 8, 0x0100_0000) + .ranges( + RangeListsOffset(buf.len()), + version, + 8, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } @@ -1049,21 +1209,44 @@ mod tests { let debug_rnglists = DebugRngLists::new(&[], LittleEndian); let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); let version = 4; + let debug_addr = &DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); // An invalid range. let mut ranges = rnglists - .ranges(RangeListsOffset(0x0), version, 4, 0x0100_0000) + .ranges( + RangeListsOffset(0x0), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); // An invalid range after wrapping. let mut ranges = rnglists - .ranges(RangeListsOffset(0x8), version, 4, 0x0100_0000) + .ranges( + RangeListsOffset(0x8), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) .unwrap(); assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); // An invalid offset. - match rnglists.ranges(RangeListsOffset(buf.len() + 1), version, 4, 0x0100_0000) { + match rnglists.ranges( + RangeListsOffset(buf.len() + 1), + version, + 4, + 0x0100_0000, + debug_addr, + debug_addr_base, + ) { Err(Error::UnexpectedEof) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } diff --git a/tests/parse_self.rs b/tests/parse_self.rs index 2f4dd7701..968c4432c 100644 --- a/tests/parse_self.rs +++ b/tests/parse_self.rs @@ -239,6 +239,9 @@ fn test_parse_self_debug_ranges() { let debug_abbrev = read_section("debug_abbrev"); let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian); + let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian)); + let debug_addr_base = DebugAddrBase(0); + let debug_ranges = read_section("debug_ranges"); let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian); let debug_rnglists = DebugRngLists::new(&[], LittleEndian); @@ -271,7 +274,14 @@ fn test_parse_self_debug_ranges() { while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { if let AttributeValue::RangeListsRef(offset) = attr.value() { let mut ranges = rnglists - .ranges(offset, unit.version(), unit.address_size(), low_pc) + .ranges( + offset, + unit.version(), + unit.address_size(), + low_pc, + &debug_addr, + debug_addr_base, + ) .expect("Should parse ranges OK"); while let Some(range) = ranges.next().expect("Should parse next range") { assert!(range.begin <= range.end); From 725d0a2046030ffe6f5d95cb9ca8937112116680 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 14 Jan 2019 19:06:23 +1000 Subject: [PATCH 11/12] read: implement DW_OP_addrx and DW_OP_constx --- examples/dwarfdump.rs | 6 +++ src/read/op.rs | 120 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index 45a1f33b6..d71088239 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -1536,6 +1536,12 @@ fn dump_op( gimli::Operation::Address { address } => { write!(w, " 0x{:08x}", address)?; } + gimli::Operation::AddressIndex { index } => { + write!(w, " 0x{:08x}", index.0)?; + } + gimli::Operation::ConstantIndex { index } => { + write!(w, " 0x{:08x}", index.0)?; + } gimli::Operation::TypedLiteral { base_type, value } => { write!(w, " type 0x{:08x} contents 0x", base_type.0)?; for byte in value.to_slice()?.iter() { diff --git a/src/read/op.rs b/src/read/op.rs index e6e592c48..eeadca28e 100644 --- a/src/read/op.rs +++ b/src/read/op.rs @@ -3,7 +3,7 @@ use std::mem; use vec::Vec; -use common::{DebugInfoOffset, Format, Register}; +use common::{DebugAddrIndex, DebugInfoOffset, Format, Register}; use constants; use read::{Error, Reader, ReaderOffset, Result, UnitOffset, Value, ValueType}; @@ -206,9 +206,23 @@ where /// Represents `DW_OP_addr`. /// Relocate the address if needed, and push it on the stack. Address { - /// The offfset to add. + /// The offset to add. address: u64, }, + /// Represents `DW_OP_addrx`. + /// Read the address at the given index in `.debug_addr, relocate the address if needed, + /// and push it on the stack. + AddressIndex { + /// The index of the address in `.debug_addr`. + index: DebugAddrIndex, + }, + /// Represents `DW_OP_constx`. + /// Read the address at the given index in `.debug_addr, and push it on the stack. + /// Do not relocate the address. + ConstantIndex { + /// The index of the address in `.debug_addr`. + index: DebugAddrIndex, + }, /// Represents `DW_OP_const_type`. /// Interpret the value bytes as a constant of a given type, and push it on the stack. TypedLiteral { @@ -667,6 +681,18 @@ where byte_offset, }) } + constants::DW_OP_addrx => { + let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::AddressIndex { + index: DebugAddrIndex(index), + }) + } + constants::DW_OP_constx => { + let index = bytes.read_uleb128().and_then(R::Offset::from_u64)?; + Ok(Operation::ConstantIndex { + index: DebugAddrIndex(index), + }) + } constants::DW_OP_entry_value | constants::DW_OP_GNU_entry_value => { let len = bytes.read_uleb128().and_then(R::Offset::from_u64)?; let expression = bytes.split(len)?; @@ -752,6 +778,7 @@ enum EvaluationWaiting { EntryValue, ParameterRef, RelocatedAddress, + IndexedAddress, TypedLiteral { value: R }, Convert, Reinterpret, @@ -820,6 +847,17 @@ pub enum EvaluationResult { /// Once the caller determines what value to provide it should resume the /// `Evaluation` by calling `Evaluation::resume_with_relocated_address`. RequiresRelocatedAddress(u64), + /// 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 + /// `Evaluation` by calling `Evaluation::resume_with_indexed_address`. + RequiresIndexedAddress { + /// The index of the address in the `.debug_addr` section, + /// relative to the `DW_AT_addr_base` of the compilation unit. + index: DebugAddrIndex, + /// Whether the address also needs to be relocated. + relocate: bool, + }, /// The `Evaluation` needs the `ValueType` for the base type DIE at /// the give unit offset. Once the caller determines what value to provide it /// should resume the `Evaluation` by calling @@ -1307,6 +1345,26 @@ impl Evaluation { )); } + Operation::AddressIndex { index } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::IndexedAddress, + EvaluationResult::RequiresIndexedAddress { + index, + relocate: true, + }, + )); + } + + Operation::ConstantIndex { index } => { + return Ok(OperationEvaluationResult::Waiting( + EvaluationWaiting::IndexedAddress, + EvaluationResult::RequiresIndexedAddress { + index, + relocate: false, + }, + )); + } + Operation::Piece { size_in_bits, bit_offset, @@ -1590,6 +1648,28 @@ impl Evaluation { self.evaluate_internal() } + /// Resume the `Evaluation` with the provided indexed `address`. This will use the + /// provided indexed address for the operation that required it, and continue evaluating + /// opcodes until the evaluation is completed, reaches an error, or needs + /// more information again. + /// + /// # Panics + /// Panics if this `Evaluation` did not previously stop with + /// `EvaluationResult::RequiresIndexedAddress`. + pub fn resume_with_indexed_address(&mut self, address: u64) -> Result> { + match self.state { + EvaluationState::Error(err) => return Err(err), + EvaluationState::Waiting(EvaluationWaiting::IndexedAddress) => { + self.push(Value::Generic(address)); + } + _ => panic!( + "Called `Evaluation::resume_with_indexed_address` without a preceding `EvaluationResult::RequiresIndexedAddress`" + ), + }; + + self.evaluate_internal() + } + /// Resume the `Evaluation` with the provided `base_type`. This will use the /// provided base type for the operation that required it, and continue evaluating /// opcodes until the evaluation is completed, reaches an error, or needs @@ -2243,6 +2323,23 @@ mod tests { )); } + if *value <= (!0u32).into() { + inputs.extend(&[ + ( + constants::DW_OP_addrx, + Operation::AddressIndex { + index: DebugAddrIndex(*value as usize), + }, + ), + ( + constants::DW_OP_constx, + Operation::ConstantIndex { + index: DebugAddrIndex(*value as usize), + }, + ), + ]); + } + // FIXME if *value < !0u64 / 8 { inputs.push(( @@ -3165,6 +3262,18 @@ mod tests { Op(DW_OP_ne), Op(DW_OP_bra), Branch(fail), + Op(DW_OP_addrx), Uleb(0x10), + Op(DW_OP_deref), + Op(DW_OP_const4u), U32(0x4040), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + + Op(DW_OP_constx), Uleb(17), + Op(DW_OP_form_tls_address), + Op(DW_OP_constu), Uleb(!27), + Op(DW_OP_ne), + Op(DW_OP_bra), Branch(fail), + // Success. Op(DW_OP_lit0), Op(DW_OP_nop), @@ -3214,6 +3323,13 @@ mod tests { EvaluationResult::RequiresRelocatedAddress(address) => { eval.resume_with_relocated_address(address)? } + EvaluationResult::RequiresIndexedAddress { index, relocate } => { + if relocate { + eval.resume_with_indexed_address(0x1000 + index.0 as u64)? + } else { + eval.resume_with_indexed_address(10 + index.0 as u64)? + } + } _ => panic!(), }; } From 280863cc33912acc93d5cc3475df792338fbeb29 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Tue, 15 Jan 2019 11:28:35 +1000 Subject: [PATCH 12/12] Review fixes --- src/read/addr.rs | 4 ++-- src/read/loclists.rs | 2 +- src/read/reader.rs | 2 +- src/read/rnglists.rs | 2 +- src/read/str.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/read/addr.rs b/src/read/addr.rs index d4e771981..22b16ca8b 100644 --- a/src/read/addr.rs +++ b/src/read/addr.rs @@ -64,8 +64,8 @@ mod tests { #[test] fn test_get_address() { - for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { - for address_size in [4, 8].iter().cloned() { + for format in vec![Format::Dwarf32, Format::Dwarf64] { + for address_size in vec![4, 8] { let zero = Label::new(); let length = Label::new(); let start = Label::new(); diff --git a/src/read/loclists.rs b/src/read/loclists.rs index 518ec9cdb..31a2a2252 100644 --- a/src/read/loclists.rs +++ b/src/read/loclists.rs @@ -1331,7 +1331,7 @@ mod tests { #[test] fn test_get_offset() { - for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { + for format in vec![Format::Dwarf32, Format::Dwarf64] { let zero = Label::new(); let length = Label::new(); let start = Label::new(); diff --git a/src/read/reader.rs b/src/read/reader.rs index 1cb0c3a26..2a779f78f 100644 --- a/src/read/reader.rs +++ b/src/read/reader.rs @@ -261,7 +261,7 @@ pub trait Reader: Debug + Clone { /// Does not advance the reader. fn to_string_lossy(&self) -> Result>; - /// Read a u8 slice. + /// Read exactly `buf.len()` bytes into `buf`. fn read_slice(&mut self, buf: &mut [u8]) -> Result<()>; /// Read a u8 array. diff --git a/src/read/rnglists.rs b/src/read/rnglists.rs index e59cef153..293961c26 100644 --- a/src/read/rnglists.rs +++ b/src/read/rnglists.rs @@ -1254,7 +1254,7 @@ mod tests { #[test] fn test_get_offset() { - for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { + for format in vec![Format::Dwarf32, Format::Dwarf64] { let zero = Label::new(); let length = Label::new(); let start = Label::new(); diff --git a/src/read/str.rs b/src/read/str.rs index 9ac55d368..31541c62b 100644 --- a/src/read/str.rs +++ b/src/read/str.rs @@ -126,7 +126,7 @@ mod tests { #[test] fn test_get_str_offset() { - for format in [Format::Dwarf32, Format::Dwarf64].iter().cloned() { + for format in vec![Format::Dwarf32, Format::Dwarf64] { let zero = Label::new(); let length = Label::new(); let start = Label::new();