From e0a58827d5dba75438f9fa9b83ec5d593745abdf Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Sun, 31 Dec 2017 17:09:21 +1000 Subject: [PATCH 1/5] Add Format::initial_length_size --- src/abbrev.rs | 9 ++------- src/aranges.rs | 5 +---- src/parser.rs | 16 +++++++++++++--- src/unit.rs | 24 +++--------------------- 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/abbrev.rs b/src/abbrev.rs index da493a152..a9e6978a5 100644 --- a/src/abbrev.rs +++ b/src/abbrev.rs @@ -2,7 +2,7 @@ use constants; use endianity::{EndianBuf, Endianity}; -use parser::{Error, Format, Result}; +use parser::{Error, Result}; use reader::Reader; use unit::UnitHeader; use vec::Vec; @@ -324,12 +324,7 @@ impl AttributeSpecification { constants::DW_FORM_sec_offset | constants::DW_FORM_ref_addr | constants::DW_FORM_ref_sig8 | - constants::DW_FORM_strp => { - match header.format() { - Format::Dwarf32 => Some(4), - Format::Dwarf64 => Some(8), - } - } + constants::DW_FORM_strp => Some(header.format().word_size() as usize), // Variably sized forms. constants::DW_FORM_block | diff --git a/src/aranges.rs b/src/aranges.rs index 916523a35..1bbc0ab00 100644 --- a/src/aranges.rs +++ b/src/aranges.rs @@ -105,10 +105,7 @@ impl LookupParser for ArangeParser { let segment_size = rest.read_u8()?; // unit_length + version + offset + address_size + segment_size - let header_length = match format { - Format::Dwarf32 => 4 + 2 + 4 + 1 + 1, - Format::Dwarf64 => 12 + 2 + 8 + 1 + 1, - }; + let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1; // The first tuple following the header in each set begins at an offset that is // a multiple of the size of a single tuple (that is, the size of a segment selector diff --git a/src/parser.rs b/src/parser.rs index ed717bb5a..18e94db88 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -455,11 +455,21 @@ pub enum Format { } impl Format { + /// Return the serialized size of an initial length field for the format. + #[inline] + pub fn initial_length_size(self) -> u8 { + match self { + Format::Dwarf32 => 4, + Format::Dwarf64 => 12, + } + } + /// Return the natural word size for the format - pub fn word_size(&self) -> u8 { + #[inline] + pub fn word_size(self) -> u8 { match self { - &Format::Dwarf32 => 4, - &Format::Dwarf64 => 8, + Format::Dwarf32 => 4, + Format::Dwarf64 => 8, } } } diff --git a/src/unit.rs b/src/unit.rs index 616718891..55e4f5940 100644 --- a/src/unit.rs +++ b/src/unit.rs @@ -471,19 +471,10 @@ where } } - /// Return the serialized size of the `unit_length` attribute for the given - /// DWARF format. - pub fn size_of_unit_length(format: Format) -> usize { - match format { - Format::Dwarf32 => 4, - Format::Dwarf64 => 12, - } - } - /// Return the serialized size of the common unit header for the given /// DWARF format. pub fn size_of_header(format: Format) -> usize { - let unit_length_size = Self::size_of_unit_length(format); + let unit_length_size = format.initial_length_size() as usize; let version_size = 2; let debug_abbrev_offset_size = format.word_size() as usize; let address_size_size = 1; @@ -507,13 +498,7 @@ where /// Get the length of the debugging info for this compilation unit, /// including the byte length of the encoded length itself. pub fn length_including_self(&self) -> R::Offset { - match self.format { - // Length of the 32-bit header plus the unit length. - Format::Dwarf32 => R::Offset::from_u8(4) + self.unit_length, - // Length of the 4 byte 0xffffffff value to enable 64-bit mode plus - // the actual 64-bit length. - Format::Dwarf64 => R::Offset::from_u8(4 + 8) + self.unit_length, - } + R::Offset::from_u8(self.format.word_size()) + self.unit_length } /// Get the DWARF version of the debugging info for this compilation unit. @@ -2622,10 +2607,7 @@ where pub fn size_of_header(format: Format) -> usize { let unit_header_size = UnitHeader::::size_of_header(format); let type_signature_size = 8; - let type_offset_size = match format { - Format::Dwarf32 => 4, - Format::Dwarf64 => 8, - }; + let type_offset_size = format.word_size() as usize; unit_header_size + type_signature_size + type_offset_size } From f4c96add232e52ab7ef9e6eaeb7e064a9aee4231 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Sat, 27 Jan 2018 18:00:26 +1000 Subject: [PATCH 2/5] Add LocationLists and RangeLists These allow users to parse lists without caring about DWARF version details. --- benches/bench.rs | 45 +++-- examples/dwarfdump.rs | 396 +++++++++++++++++------------------------- src/lib.rs | 8 +- src/loc.rs | 2 +- src/loclists.rs | 138 ++++++++++++--- src/ranges.rs | 2 +- src/rnglists.rs | 138 +++++++++++---- src/unit.rs | 20 +-- tests/parse_self.rs | 20 ++- 9 files changed, 428 insertions(+), 341 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index d463da6dd..9dcaedafc 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -4,8 +4,9 @@ extern crate gimli; extern crate test; use gimli::{AttributeValue, DebugAbbrev, DebugAranges, DebugInfo, DebugLine, DebugLineOffset, - DebugLoc, DebugPubNames, DebugPubTypes, DebugRanges, EntriesTreeNode, Expression, - Format, LittleEndian, Operation, Reader}; + DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, + EntriesTreeNode, Expression, Format, LittleEndian, LocationLists, Operation, + RangeLists, Reader}; use std::env; use std::fs::File; use std::io::Read; @@ -201,6 +202,8 @@ fn bench_parsing_debug_loc(b: &mut test::Bencher) { 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 mut offsets = Vec::new(); @@ -228,16 +231,16 @@ fn bench_parsing_debug_loc(b: &mut test::Bencher) { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { - if let gimli::AttributeValue::DebugLocRef(offset) = attr.value() { - offsets.push((offset, unit.address_size(), low_pc)); + if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() { + offsets.push((offset, unit.version(), unit.address_size(), low_pc)); } } } } - b.iter(|| for &(offset, address_size, base_address) in &*offsets { - let mut locs = debug_loc - .locations(offset, address_size, base_address) + b.iter(|| for &(offset, version, address_size, base_address) in &*offsets { + let mut locs = loclists + .locations(offset, version, address_size, base_address) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { test::black_box(loc); @@ -255,6 +258,8 @@ fn bench_parsing_debug_ranges(b: &mut test::Bencher) { let debug_ranges = read_section("debug_ranges"); let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists).expect("Should parse rnglists"); let mut offsets = Vec::new(); @@ -282,16 +287,16 @@ fn bench_parsing_debug_ranges(b: &mut test::Bencher) { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { - if let gimli::AttributeValue::DebugRangesRef(offset) = attr.value() { - offsets.push((offset, unit.address_size(), low_pc)); + if let gimli::AttributeValue::RangeListsRef(offset) = attr.value() { + offsets.push((offset, unit.version(), unit.address_size(), low_pc)); } } } } - b.iter(|| for &(offset, address_size, base_address) in &*offsets { - let mut ranges = debug_ranges - .ranges(offset, address_size, base_address) + b.iter(|| for &(offset, version, address_size, base_address) in &*offsets { + let mut ranges = rnglists + .ranges(offset, version, address_size, base_address) .expect("Should parse ranges OK"); while let Some(range) = ranges.next().expect("Should parse next range") { test::black_box(range); @@ -368,7 +373,7 @@ fn bench_evaluating_debug_info_expressions(b: &mut test::Bencher) { fn debug_loc_expressions( debug_info: &DebugInfo, debug_abbrev: &DebugAbbrev, - debug_loc: &DebugLoc, + loclists: &LocationLists, ) -> Vec<(Expression, u8, Format)> { let mut expressions = Vec::new(); @@ -396,9 +401,9 @@ fn debug_loc_expressions( let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { - if let gimli::AttributeValue::DebugLocRef(offset) = attr.value() { - let mut locs = debug_loc - .locations(offset, unit.address_size(), low_pc) + if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() { + let mut locs = loclists + .locations(offset, unit.version(), unit.address_size(), low_pc) .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())); @@ -421,8 +426,10 @@ fn bench_parsing_debug_loc_expressions(b: &mut test::Bencher) { 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, &debug_loc); + let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &loclists); b.iter(|| { for &(expression, address_size, format) in &*expressions { @@ -445,8 +452,10 @@ fn bench_evaluating_debug_loc_expressions(b: &mut test::Bencher) { 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, &debug_loc); + let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &loclists); b.iter(|| { for &(expression, address_size, format) in &*expressions { diff --git a/examples/dwarfdump.rs b/examples/dwarfdump.rs index b8c65f3e8..6ba633c4a 100644 --- a/examples/dwarfdump.rs +++ b/examples/dwarfdump.rs @@ -229,15 +229,19 @@ where let debug_aranges = &load_section(file, endian); let debug_info = &load_section(file, endian); let debug_line = &load_section(file, endian); - let debug_loc = &load_section(file, endian); - let debug_loclists = &load_section(file, endian); let debug_pubnames = &load_section(file, endian); let debug_pubtypes = &load_section(file, endian); - let debug_ranges = &load_section(file, endian); - let debug_rnglists = &load_section(file, endian); let debug_str = &load_section(file, endian); let debug_types = &load_section(file, endian); + let debug_loc = load_section(file, endian); + let debug_loclists = load_section(file, endian); + let loclists = &gimli::LocationLists::new(debug_loc, debug_loclists)?; + + let debug_ranges = load_section(file, endian); + let debug_rnglists = load_section(file, endian); + let rnglists = &gimli::RangeLists::new(debug_ranges, debug_rnglists)?; + if flags.eh_frame { dump_eh_frame(eh_frame)?; } @@ -246,11 +250,9 @@ where debug_info, debug_abbrev, debug_line, - debug_loc, - debug_loclists, - debug_ranges, - debug_rnglists, debug_str, + loclists, + rnglists, endian, flags, )?; @@ -258,11 +260,9 @@ where debug_types, debug_abbrev, debug_line, - debug_loc, - debug_loclists, - debug_ranges, - debug_rnglists, debug_str, + loclists, + rnglists, endian, flags, )?; @@ -500,11 +500,9 @@ fn dump_info( debug_info: &gimli::DebugInfo, debug_abbrev: &gimli::DebugAbbrev, debug_line: &gimli::DebugLine, - debug_loc: &gimli::DebugLoc, - debug_loclists: &gimli::DebugLocLists, - debug_ranges: &gimli::DebugRanges, - debug_rnglists: &gimli::DebugRngLists, debug_str: &gimli::DebugStr, + loclists: &gimli::LocationLists, + rnglists: &gimli::RangeLists, endian: R::Endian, flags: &Flags, ) -> Result<()> { @@ -530,11 +528,9 @@ fn dump_info( unit.version(), unit.format(), debug_line, - debug_loc, - debug_loclists, - debug_ranges, - debug_rnglists, debug_str, + loclists, + rnglists, endian, flags, ); @@ -553,11 +549,9 @@ fn dump_types( debug_types: &gimli::DebugTypes, debug_abbrev: &gimli::DebugAbbrev, debug_line: &gimli::DebugLine, - debug_loc: &gimli::DebugLoc, - debug_loclists: &gimli::DebugLocLists, - debug_ranges: &gimli::DebugRanges, - debug_rnglists: &gimli::DebugRngLists, debug_str: &gimli::DebugStr, + loclists: &gimli::LocationLists, + rnglists: &gimli::RangeLists, endian: R::Endian, flags: &Flags, ) -> Result<()> { @@ -593,11 +587,9 @@ fn dump_types( unit.version(), unit.format(), debug_line, - debug_loc, - debug_loclists, - debug_ranges, - debug_rnglists, debug_str, + loclists, + rnglists, endian, flags, ); @@ -631,11 +623,9 @@ fn dump_entries( version: u16, format: gimli::Format, debug_line: &gimli::DebugLine, - debug_loc: &gimli::DebugLoc, - debug_loclists: &gimli::DebugLocLists, - debug_ranges: &gimli::DebugRanges, - debug_rnglists: &gimli::DebugRngLists, debug_str: &gimli::DebugStr, + loclists: &gimli::LocationLists, + rnglists: &gimli::RangeLists, endian: R::Endian, flags: &Flags, ) -> Result<()> { @@ -702,7 +692,7 @@ fn dump_entries( if flags.raw { println!("{:?}", attr.raw_value()); } else { - match dump_attr_value(&attr, &unit, debug_loc, debug_loclists, debug_ranges, debug_rnglists, debug_str) { + match dump_attr_value(&attr, &unit, debug_str, loclists, rnglists) { Ok(_) => (), Err(ref err) => println!( "Failed to dump attribute value: {}", @@ -718,11 +708,9 @@ fn dump_entries( fn dump_attr_value( attr: &gimli::Attribute, unit: &Unit, - debug_loc: &gimli::DebugLoc, - debug_loclists: &gimli::DebugLocLists, - debug_ranges: &gimli::DebugRanges, - debug_rnglists: &gimli::DebugRngLists, debug_str: &gimli::DebugStr, + loclists: &gimli::LocationLists, + rnglists: &gimli::RangeLists, ) -> Result<()> { let value = attr.value(); match value { @@ -817,15 +805,15 @@ fn dump_attr_value( gimli::AttributeValue::DebugLineRef(gimli::DebugLineOffset(offset)) => { println!("0x{:08x}", offset); } - gimli::AttributeValue::DebugLocRef(offset) => { - dump_loc_list(debug_loc, debug_loclists, offset, unit)?; + gimli::AttributeValue::LocationListsRef(offset) => { + dump_loc_list(loclists, offset, unit)?; } gimli::AttributeValue::DebugMacinfoRef(gimli::DebugMacinfoOffset(offset)) => { println!("{}", offset); } - gimli::AttributeValue::DebugRangesRef(offset) => { + gimli::AttributeValue::RangeListsRef(offset) => { println!("0x{:08x}", offset.0); - dump_range_list(debug_ranges, debug_rnglists, offset, unit)?; + dump_range_list(rnglists, offset, unit)?; } gimli::AttributeValue::DebugTypesRef(signature) => { dump_type_signature(signature, unit.endian); @@ -1085,219 +1073,145 @@ fn dump_op( } fn dump_loc_list( - debug_loc: &gimli::DebugLoc, - debug_loclists: &gimli::DebugLocLists, - offset: gimli::DebugLocOffset, + loclists: &gimli::LocationLists, + offset: gimli::LocationListsOffset, unit: &Unit, ) -> Result<()> { - if unit.version < 5 { - let locations = debug_loc.raw_locations(offset, unit.address_size)?; - let mut locations: Vec<_> = locations.collect()?; - - // libdwarf-dwarfdump doesn't include the end entry. - let has_end = if let Some(location) = locations.last() { - location.range.is_end() - } else { - false - }; - if has_end { - locations.pop(); - } - if locations.is_empty() { - println!(""); - return Ok(()); - } - - println!( - "", - offset.0, - locations.len() - ); - let mut base_address = unit.base_address; - for (i, location) in locations.iter().enumerate() { - print!("\t\t\t[{:2}]", i); - if location.range.is_end() { - println!(""); - } else if location.range.is_base_address(unit.address_size) { - println!("", location.range.end); - base_address = location.range.end; - } else { - let mut range = location.range; - range.add_base_address(base_address, unit.address_size); - // This messed up formatting matches libdwarf-dwarfdump. + let raw_locations = loclists.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)?; + + println!( + "", + offset.0, + raw_locations.len() + ); + for (i, raw) in raw_locations.iter().enumerate() { + print!("\t\t\t[{:2}]", i); + match raw { + &gimli::RawLocListEntry::BaseAddress { addr } => { + println!("", addr); + }, + &gimli::RawLocListEntry::OffsetPair { begin, end, ref data } => { + let location = locations.next()?.unwrap(); print!( - "< offset pair \ - low-off : 0x{:08x} addr 0x{:08x} \ - high-off 0x{:08x} addr 0x{:08x}>", + "", + begin, location.range.begin, - range.begin, - location.range.end, - range.end + end, + location.range.end ); - dump_exprloc(&location.data, unit)?; + dump_exprloc(data, unit)?; println!(""); - } - } - } else { - let raw_locations = debug_loclists.raw_locations(offset)?; - let raw_locations: Vec<_> = raw_locations.collect()?; - let mut locations = debug_loclists.locations(offset, unit.base_address)?; - - println!( - "", - offset.0, - raw_locations.len() - ); - for (i, raw) in raw_locations.iter().enumerate() { - print!("\t\t\t[{:2}]", i); - match raw { - &gimli::RawLocListEntry::BaseAddress { addr } => { - println!("", addr); - }, - &gimli::RawLocListEntry::OffsetPair { begin, end, ref data } => { - let location = locations.next()?.unwrap(); - // libdwarf-dwarfdump doesn't support .debug_loclists yet, - // so stop the misformatting madness - print!( - "", - begin, - location.range.begin, - end, - location.range.end - ); - dump_exprloc(data, unit)?; - println!(""); - }, - &gimli::RawLocListEntry::DefaultLocation { ref data } => { - print!(""); - dump_exprloc(data, unit)?; - println!(""); - }, - &gimli::RawLocListEntry::StartEnd { begin, end, ref data } => { - let location = locations.next()?.unwrap(); - print!( - "", - begin, - location.range.begin, - end, - location.range.end - ); - dump_exprloc(data, unit)?; - println!(""); - }, - &gimli::RawLocListEntry::StartLength { begin, length, ref data } => { - let location = locations.next()?.unwrap(); - print!( - "", - begin, - location.range.begin, - length, - location.range.end - ); - dump_exprloc(data, unit)?; - println!(""); - }, - _ => { - panic!("AddressIndex not handled, should already have errored out"); - }, - }; - } + }, + &gimli::RawLocListEntry::DefaultLocation { ref data } => { + print!(""); + dump_exprloc(data, unit)?; + println!(""); + }, + &gimli::RawLocListEntry::StartEnd { begin, end, ref data } => { + let location = locations.next()?.unwrap(); + print!( + "", + begin, + location.range.begin, + end, + location.range.end + ); + dump_exprloc(data, unit)?; + println!(""); + }, + &gimli::RawLocListEntry::StartLength { begin, length, ref data } => { + let location = locations.next()?.unwrap(); + print!( + "", + begin, + location.range.begin, + length, + location.range.end + ); + dump_exprloc(data, unit)?; + println!(""); + }, + _ => { + panic!("AddressIndex not handled, should already have errored out"); + }, + }; } Ok(()) } fn dump_range_list( - debug_ranges: &gimli::DebugRanges, - debug_rnglists: &gimli::DebugRngLists, - offset: gimli::DebugRangesOffset, + rnglists: &gimli::RangeLists, + offset: gimli::RangeListsOffset, unit: &Unit, ) -> Result<()> { - if unit.version < 5 { - let ranges = debug_ranges.raw_ranges(offset, unit.address_size)?; - let ranges: Vec<_> = ranges.collect()?; - println!( - "\t\tranges: {} at .debug_ranges offset {} (0x{:08x}) ({} bytes)", - ranges.len(), - offset.0, - offset.0, - ranges.len() * unit.address_size as usize * 2 - ); - for (i, range) in ranges.iter().enumerate() { - print!("\t\t\t[{:2}] ", i); - if range.is_end() { - print!("range end "); - } else if range.is_base_address(unit.address_size) { - print!("addr selection"); - } else { - print!("range entry "); - } - println!(" 0x{:08x} 0x{:08x}", range.begin, range.end); - } - } else { - let raw_ranges = debug_rnglists.raw_ranges(offset)?; - let raw_ranges: Vec<_> = raw_ranges.collect()?; - let mut ranges = debug_rnglists.ranges(offset, unit.base_address)?; - println!( - "\t\tranges: {} at .debug_rnglists offset {} (0x{:08x})", - raw_ranges.len(), - offset.0, - offset.0 - ); - for (i, raw) in raw_ranges.iter().enumerate() { - print!("\t\t\t[{:2}] ", i); - match raw { - &gimli::RawRngListEntry::BaseAddress { addr } => { - println!("", addr); - }, - &gimli::RawRngListEntry::OffsetPair { begin, end } => { - let range = ranges.next()?.unwrap(); - // libdwarf-dwarfdump doesn't support .debug_loclists yet, - // so stop the misformatting madness - println!( - "", - begin, - range.begin, - end, - range.end - ); - }, - &gimli::RawRngListEntry::StartEnd { begin, end } => { - let range = ranges.next()?.unwrap(); - println!( - "", - begin, - range.begin, - end, - range.end - ); - }, - &gimli::RawRngListEntry::StartLength { begin, length } => { - let range = ranges.next()?.unwrap(); - println!( - "", - begin, - range.begin, - length, - range.end - ); - }, - _ => { - panic!("AddressIndex not handled, should already have errored out"); - }, - }; - } + let raw_ranges = rnglists.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)?; + println!( + "\t\tranges: {} at {} offset {} (0x{:08x})", + raw_ranges.len(), + if unit.version < 5 { ".debug_ranges" } else { ".debug_rnglists" }, + offset.0, + offset.0 + ); + for (i, raw) in raw_ranges.iter().enumerate() { + print!("\t\t\t[{:2}] ", i); + match raw { + &gimli::RawRngListEntry::BaseAddress { addr } => { + println!("", addr); + }, + &gimli::RawRngListEntry::OffsetPair { begin, end } => { + let range = ranges.next()?.unwrap(); + println!( + "", + begin, + range.begin, + end, + range.end + ); + }, + &gimli::RawRngListEntry::StartEnd { begin, end } => { + let range = if begin == end { + gimli::Range { begin, end } + } else { + ranges.next()?.unwrap() + }; + println!( + "", + begin, + range.begin, + end, + range.end + ); + }, + &gimli::RawRngListEntry::StartLength { begin, length } => { + let range = ranges.next()?.unwrap(); + println!( + "", + begin, + range.begin, + length, + range.end + ); + }, + _ => { + panic!("AddressIndex not handled, should already have errored out"); + }, + }; } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 5233b2b86..b217e2bb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -240,10 +240,10 @@ mod line; pub use line::*; mod loc; -pub use loc::{DebugLoc, DebugLocOffset, LocationListEntry, LocationListIter, RawLocationListIter}; +pub use loc::{DebugLoc, LocationListEntry, LocationListIter, RawLocationListIter}; mod loclists; -pub use loclists::{DebugLocLists, LocListIter, RawLocListEntry, RawLocListIter}; +pub use loclists::{DebugLocLists, LocationLists, LocationListsOffset, LocListIter, RawLocListEntry, RawLocListIter}; mod lookup; @@ -257,10 +257,10 @@ mod pubtypes; pub use pubtypes::{DebugPubTypes, PubTypesEntry, PubTypesEntryIter}; mod ranges; -pub use ranges::{DebugRanges, DebugRangesOffset, Range, RangesIter, RawRangesIter}; +pub use ranges::{DebugRanges, Range, RangesIter, RawRangesIter}; mod rnglists; -pub use rnglists::{DebugRngLists, RawRngListEntry, RngListIter}; +pub use rnglists::{DebugRngLists, RangeLists, RangeListsOffset, RawRngListEntry, RngListIter}; mod str; pub use str::*; diff --git a/src/loc.rs b/src/loc.rs index 811f32689..7f91e2bb6 100644 --- a/src/loc.rs +++ b/src/loc.rs @@ -14,7 +14,7 @@ pub struct DebugLocOffset(pub T); /// found in the `.debug_loc` section. #[derive(Debug, Clone, Copy)] pub struct DebugLoc { - debug_loc_section: R, + pub(crate) debug_loc_section: R, } impl<'input, Endian> DebugLoc> diff --git a/src/loclists.rs b/src/loclists.rs index 82461a682..061b61d58 100644 --- a/src/loclists.rs +++ b/src/loclists.rs @@ -1,7 +1,7 @@ use constants; use endianity::{EndianBuf, Endianity}; use fallible_iterator::FallibleIterator; -use loc::{DebugLocOffset, LocationListEntry}; +use loc::{DebugLoc, LocationListEntry}; use op::Expression; use parser::{self, Format, Error, Result}; use reader::{Reader, ReaderOffset}; @@ -39,6 +39,19 @@ where } } +/// An offset into either the `.debug_loc` section or the `.debug_loclists` section, +/// depending on the version of the unit the offset was contained in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LocationListsOffset(pub T); + +/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections. +#[derive(Debug, Clone, Copy)] +pub struct LocationLists { + debug_loc: DebugLoc, + debug_loclists: DebugLocLists, + header: LocListsHeader, +} + #[derive(Debug, Clone, Copy)] struct LocListsHeader { format: Format, @@ -46,22 +59,30 @@ struct LocListsHeader { offset_entry_count: u32, } +impl LocListsHeader { + /// Return the serialized size of the table header. + fn size(&self) -> u8 { + // initial_length + version + address_size + segment_selector_size + offset_entry_count + self.format.initial_length_size() + 2 + 1 + 1 + 4 + } +} + fn parse_header(input: &mut R) -> Result { let (length, format) = parser::parse_initial_length(input)?; let length = R::Offset::from_u64(length)?; - let mut rest = input.split(length)?; + input.truncate(length)?; - let version = rest.read_u16()?; + let version = input.read_u16()?; if version != 5 { return Err(Error::UnknownVersion(version as u64)); } - let address_size = rest.read_u8()?; - let segment_selector_size = rest.read_u8()?; + let address_size = input.read_u8()?; + let segment_selector_size = input.read_u8()?; if segment_selector_size != 0 { return Err(Error::UnsupportedSegmentSize); } - let offset_entry_count = rest.read_u32()?; + let offset_entry_count = input.read_u32()?; Ok(LocListsHeader { format: format, address_size: address_size, @@ -69,9 +90,32 @@ fn parse_header(input: &mut R) -> Result { }) } -impl DebugLocLists { +impl LocationLists { + /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and + /// `.debug_loclists` sections. + pub fn new(debug_loc: DebugLoc, debug_loclists: DebugLocLists) -> Result> { + let mut input = debug_loclists.debug_loclists_section.clone(); + let header = if input.is_empty() { + LocListsHeader { + format: Format::Dwarf32, + address_size: 0, + offset_entry_count: 0, + } + } else { + parse_header(&mut input)? + }; + Ok(LocationLists { + debug_loc, + debug_loclists, + header, + }) + } + /// Iterate over the `LocationListEntry`s starting at the given offset. /// + /// The `unit_version` and `address_size` must match the compilation unit that the + /// offset was contained in. + /// /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the /// `DW_TAG_compile_unit` entry for the compilation unit that contains this location /// list. @@ -80,14 +124,19 @@ impl DebugLocLists { /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn locations( &self, - offset: DebugLocOffset, + offset: LocationListsOffset, + unit_version: u16, + address_size: u8, base_address: u64, ) -> Result> { - Ok(LocListIter::new(self.raw_locations(offset)?, base_address)) + Ok(LocListIter::new(self.raw_locations(offset, unit_version, address_size)?, base_address)) } /// Iterate over the raw `LocationListEntry`s starting at the given offset. /// + /// The `unit_version` and `address_size` must match the compilation unit that the + /// offset was contained in. + /// /// This iterator does not perform any processing of the location entries, /// such as handling base addresses. /// @@ -95,13 +144,22 @@ impl DebugLocLists { /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn raw_locations( &self, - offset: DebugLocOffset, + offset: LocationListsOffset, + unit_version: u16, + address_size: u8, ) -> Result> { - let mut input = self.debug_loclists_section.clone(); - let header = parse_header(&mut input)?; - input = self.debug_loclists_section.clone(); - input.skip(offset.0)?; - Ok(RawLocListIter::new(input, header.address_size)) + if unit_version < 5 { + let mut input = self.debug_loc.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(); + input.skip(offset.0)?; + Ok(RawLocListIter::new(input, unit_version, self.header.address_size)) + } } } @@ -124,6 +182,7 @@ impl From for DebugLocLists { #[derive(Debug)] pub struct RawLocListIter { input: R, + version: u16, address_size: u8, } @@ -199,7 +258,25 @@ fn parse_data(input: &mut R) -> Result> { impl RawLocListEntry { /// Parse a range entry from `.debug_rnglists` - fn parse(input: &mut R, address_size: u8) -> Result> { + fn parse(input: &mut R, version: u16, address_size: u8) -> Result> { + if version < 5 { + let range = Range::parse(input, address_size)?; + return Ok(if range.is_end() { + None + } else if range.is_base_address(address_size) { + Some(RawLocListEntry::BaseAddress { + addr: range.end, + }) + } else { + let len = R::Offset::from_u16(input.read_u16()?); + let data = Expression(input.split(len)?); + Some(RawLocListEntry::OffsetPair { + begin: range.begin, + end: range.end, + data, + }) + }); + } Ok(match constants::DwLle(input.read_u8()?) { constants::DW_LLE_end_of_list => { None @@ -263,10 +340,11 @@ impl RawLocListEntry { impl RawLocListIter { /// Construct a `RawLocListIter`. - pub fn new(input: R, address_size: u8) -> RawLocListIter { + pub fn new(input: R, version: u16, address_size: u8) -> RawLocListIter { RawLocListIter { - input: input, - address_size: address_size, + input, + version, + address_size, } } @@ -276,7 +354,7 @@ impl RawLocListIter { return Ok(None); } - match RawLocListEntry::parse(&mut self.input, self.address_size) { + match RawLocListEntry::parse(&mut self.input, self.version, self.address_size) { Ok(entry) => { if entry.is_none() { self.input.empty(); @@ -428,9 +506,11 @@ mod tests { size.set_const((§ion.here() - &start - 4) as u64); let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&[], LittleEndian); let debug_loclists = DebugLocLists::new(&buf, LittleEndian); - let offset = DebugLocOffset((&first - &start) as usize); - let mut locations = debug_loclists.locations(offset, 0x01000000).unwrap(); + let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); + let offset = LocationListsOffset((&first - &start) as usize); + let mut locations = loclists.locations(offset, 5, 0, 0x01000000).unwrap(); // A normal location. assert_eq!( @@ -532,8 +612,8 @@ mod tests { assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. - let mut locations = debug_loclists - .locations(DebugLocOffset(buf.len()), 0x01000000) + let mut locations = loclists + .locations(LocationListsOffset(buf.len()), 5, 0, 0x01000000) .unwrap(); assert_eq!(locations.next(), Ok(None)); } @@ -579,9 +659,11 @@ mod tests { size.set_const((§ion.here() - &start - 12) as u64); let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&[], LittleEndian); let debug_loclists = DebugLocLists::new(&buf, LittleEndian); - let offset = DebugLocOffset((&first - &start) as usize); - let mut locations = debug_loclists.locations(offset, 0x01000000).unwrap(); + let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); + let offset = LocationListsOffset((&first - &start) as usize); + let mut locations = loclists.locations(offset, 5, 0, 0x01000000).unwrap(); // A normal location. assert_eq!( @@ -683,8 +765,8 @@ mod tests { assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. - let mut locations = debug_loclists - .locations(DebugLocOffset(buf.len()), 0x01000000) + let mut locations = loclists + .locations(LocationListsOffset(buf.len()), 5, 0, 0x01000000) .unwrap(); assert_eq!(locations.next(), Ok(None)); } diff --git a/src/ranges.rs b/src/ranges.rs index d1e4945b2..0849559de 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -12,7 +12,7 @@ pub struct DebugRangesOffset(pub T); /// found in the `.debug_ranges` section. #[derive(Debug, Clone, Copy)] pub struct DebugRanges { - debug_ranges_section: R, + pub(crate) debug_ranges_section: R, } impl<'input, Endian> DebugRanges> diff --git a/src/rnglists.rs b/src/rnglists.rs index f70351730..ec3718465 100644 --- a/src/rnglists.rs +++ b/src/rnglists.rs @@ -2,7 +2,7 @@ use constants; use endianity::{EndianBuf, Endianity}; use fallible_iterator::FallibleIterator; use parser::{self, Error, Format, Result}; -use ranges::{Range, DebugRangesOffset}; +use ranges::{Range, DebugRanges}; use reader::{Reader, ReaderOffset}; use Section; @@ -24,22 +24,30 @@ pub struct DebugRngLists { debug_rnglists_section: R, } +impl RngListsHeader { + /// Return the serialized size of the table header. + fn size(&self) -> u8 { + // initial_length + version + address_size + segment_selector_size + offset_entry_count + self.format.initial_length_size() + 2 + 1 + 1 + 4 + } +} + fn parse_header(input: &mut R) -> Result { let (length, format) = parser::parse_initial_length(input)?; let length = R::Offset::from_u64(length)?; - let mut rest = input.split(length)?; + input.truncate(length)?; - let version = rest.read_u16()?; + let version = input.read_u16()?; if version != 5 { return Err(Error::UnknownVersion(version as u64)); } - let address_size = rest.read_u8()?; - let segment_selector_size = rest.read_u8()?; + let address_size = input.read_u8()?; + let segment_selector_size = input.read_u8()?; if segment_selector_size != 0 { return Err(Error::UnsupportedSegmentSize); } - let offset_entry_count = rest.read_u32()?; + let offset_entry_count = input.read_u32()?; Ok(RngListsHeader { format: format, address_size: address_size, @@ -63,7 +71,7 @@ where /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_rnglists_section_somehow = || &buf; - /// let debug_ranges = + /// let debug_rnglists = /// DebugRngLists::new(read_debug_rnglists_section_somehow(), LittleEndian); /// ``` pub fn new(debug_rnglists_section: &'input [u8], endian: Endian) -> Self { @@ -85,10 +93,45 @@ impl From for DebugRngLists { } } -impl DebugRngLists { +/// An offset into either the `.debug_ranges` section or the `.debug_rnglists` section, +/// depending on the version of the unit the offset was contained in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct RangeListsOffset(pub T); + +/// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections. +#[derive(Debug, Clone, Copy)] +pub struct RangeLists { + debug_ranges: DebugRanges, + debug_rnglists: DebugRngLists, + header: RngListsHeader, +} + +impl RangeLists { + /// Construct a new `RangeLists` instance from the data in the `.debug_ranges` and + /// `.debug_rnglists` sections. + pub fn new(debug_ranges: DebugRanges, debug_rnglists: DebugRngLists) -> Result> { + let mut input = debug_rnglists.debug_rnglists_section.clone(); + let header = if input.is_empty() { + RngListsHeader { + format: Format::Dwarf32, + address_size: 0, + offset_entry_count: 0, + } + } else { + parse_header(&mut input)? + }; + Ok(RangeLists { + debug_ranges, + debug_rnglists, + header, + }) + } + /// Iterate over the `Range` list entries starting at the given offset. /// - /// The `address_size` must be match the compilation unit for this range list. + /// The `unit_version` and `address_size` must match the compilation unit that the + /// offset was contained in. + /// /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the /// `DW_TAG_compile_unit` entry for the compilation unit that contains this range list. /// @@ -96,14 +139,19 @@ impl DebugRngLists { /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn ranges( &self, - offset: DebugRangesOffset, + offset: RangeListsOffset, + unit_version: u16, + address_size: u8, base_address: u64, ) -> Result> { - Ok(RngListIter::new(self.raw_ranges(offset)?, base_address)) + Ok(RngListIter::new(self.raw_ranges(offset, unit_version, address_size)?, base_address)) } /// Iterate over the `RawRngListEntry`ies starting at the given offset. /// + /// The `unit_version` and `address_size` must match the compilation unit that the + /// offset was contained in. + /// /// This iterator does not perform any processing of the range entries, /// such as handling base addresses. /// @@ -111,13 +159,22 @@ impl DebugRngLists { /// `FallibleIterator`](./index.html#using-with-fallibleiterator). pub fn raw_ranges( &self, - offset: DebugRangesOffset, + offset: RangeListsOffset, + unit_version: u16, + address_size: u8, ) -> Result> { - let mut input = self.debug_rnglists_section.clone(); - let header = parse_header(&mut input)?; - input = self.debug_rnglists_section.clone(); - input.skip(offset.0)?; - Ok(RawRngListIter::new(input, header.address_size)) + if unit_version < 5 { + let mut input = self.debug_ranges.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(); + input.skip(offset.0)?; + Ok(RawRngListIter::new(input, unit_version, self.header.address_size)) + } } } @@ -128,6 +185,7 @@ impl DebugRngLists { #[derive(Debug)] pub struct RawRngListIter { input: R, + version: u16, address_size: u8, } @@ -183,7 +241,22 @@ pub enum RawRngListEntry { impl RawRngListEntry { /// Parse a range entry from `.debug_rnglists` - fn parse(input: &mut R, address_size: u8) -> Result> { + fn parse(input: &mut R, version: u16, address_size: u8) -> Result> { + if version < 5 { + let range = Range::parse(input, address_size)?; + return Ok(if range.is_end() { + None + } else if range.is_base_address(address_size) { + Some(RawRngListEntry::BaseAddress { + addr: range.end, + }) + } else { + Some(RawRngListEntry::OffsetPair { + begin: range.begin, + end: range.end, + }) + }); + } Ok(match constants::DwRle(input.read_u8()?) { constants::DW_RLE_end_of_list => { None @@ -237,10 +310,11 @@ impl RawRngListEntry { impl RawRngListIter { /// Construct a `RawRngListIter`. - fn new(input: R, address_size: u8) -> RawRngListIter { + fn new(input: R, version: u16, address_size: u8) -> RawRngListIter { RawRngListIter { - input: input, - address_size: address_size, + input, + version, + address_size, } } @@ -250,7 +324,7 @@ impl RawRngListIter { return Ok(None); } - match RawRngListEntry::parse(&mut self.input, self.address_size) { + match RawRngListEntry::parse(&mut self.input, self.version, self.address_size) { Ok(range) => { if range.is_none() { self.input.empty(); @@ -393,9 +467,11 @@ mod tests { size.set_const((§ion.here() - &start - 4) as u64); let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&[], LittleEndian); let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); - let offset = DebugRangesOffset((&first - &start) as usize); - let mut ranges = debug_rnglists.ranges(offset, 0x01000000).unwrap(); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); + let offset = RangeListsOffset((&first - &start) as usize); + let mut ranges = rnglists.ranges(offset, 5, 0, 0x01000000).unwrap(); // A normal range. assert_eq!( @@ -464,8 +540,8 @@ mod tests { assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. - let mut ranges = debug_rnglists - .ranges(DebugRangesOffset(buf.len()), 0x01000000) + let mut ranges = rnglists + .ranges(RangeListsOffset(buf.len()), 5, 0, 0x01000000) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } @@ -509,9 +585,11 @@ mod tests { size.set_const((§ion.here() - &start - 12) as u64); let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&[], LittleEndian); let debug_rnglists = DebugRngLists::new(&buf, LittleEndian); - let offset = DebugRangesOffset((&first - &start) as usize); - let mut ranges = debug_rnglists.ranges(offset, 0x01000000).unwrap(); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); + let offset = RangeListsOffset((&first - &start) as usize); + let mut ranges = rnglists.ranges(offset, 5, 0, 0x01000000).unwrap(); // A normal range. assert_eq!( @@ -580,8 +658,8 @@ mod tests { assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. - let mut ranges = debug_rnglists - .ranges(DebugRangesOffset(buf.len()), 0x01000000) + let mut ranges = rnglists + .ranges(RangeListsOffset(buf.len()), 5, 0, 0x01000000) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } diff --git a/src/unit.rs b/src/unit.rs index 55e4f5940..7cb7b5e7a 100644 --- a/src/unit.rs +++ b/src/unit.rs @@ -5,10 +5,10 @@ use abbrev::{Abbreviation, Abbreviations, AttributeSpecification, DebugAbbrev, D use endianity::{EndianBuf, Endianity}; use fallible_iterator::FallibleIterator; use line::DebugLineOffset; -use loc::DebugLocOffset; +use loclists::LocationListsOffset; use op::Expression; use parser::{parse_initial_length, DebugMacinfoOffset, Error, Format, Result}; -use ranges::DebugRangesOffset; +use rnglists::RangeListsOffset; use reader::{Reader, ReaderOffset}; use std::cell::Cell; use std::ops::{Range, RangeFrom, RangeTo}; @@ -1000,14 +1000,14 @@ pub enum AttributeValue { /// An offset into the `.debug_line` section. DebugLineRef(DebugLineOffset), - /// An offset into the `.debug_loc` section. - DebugLocRef(DebugLocOffset), + /// An offset into either the `.debug_loc` section or the `.debug_loclists` section. + LocationListsRef(LocationListsOffset), /// An offset into the `.debug_macinfo` section. DebugMacinfoRef(DebugMacinfoOffset), /// An offset into the `.debug_ranges` section. - DebugRangesRef(DebugRangesOffset), + RangeListsRef(RangeListsOffset), /// A type signature. DebugTypesRef(DebugTypeSignature), @@ -1133,7 +1133,7 @@ impl Attribute { macro_rules! loclistptr { () => ( if let Some(offset) = self.offset_value() { - return AttributeValue::DebugLocRef(DebugLocOffset(offset)); + return AttributeValue::LocationListsRef(LocationListsOffset(offset)); }); } macro_rules! lineptr { @@ -1151,7 +1151,7 @@ impl Attribute { macro_rules! rangelistptr { () => ( if let Some(offset) = self.offset_value() { - return AttributeValue::DebugRangesRef(DebugRangesOffset(offset)); + return AttributeValue::RangeListsRef(RangeListsOffset(offset)); }); } macro_rules! reference { @@ -2803,7 +2803,7 @@ mod tests { use constants::*; use endianity::{EndianBuf, Endianity, LittleEndian}; use leb128; - use loc::DebugLocOffset; + use loclists::LocationListsOffset; use parser::{Error, Format, Result}; use self::test_assembler::{Endian, Label, LabelMaker, Section}; use str::DebugStrOffset; @@ -3324,7 +3324,7 @@ mod tests { constants::DW_FORM_data4, data4, AttributeValue::SecOffset(0x01020304), - AttributeValue::DebugLocRef(DebugLocOffset(0x01020304)), + AttributeValue::LocationListsRef(LocationListsOffset(0x01020304)), ), ( 4, @@ -3341,7 +3341,7 @@ mod tests { constants::DW_FORM_data8, data8, AttributeValue::SecOffset(0x0102030405060708), - AttributeValue::DebugLocRef(DebugLocOffset(0x0102030405060708)), + AttributeValue::LocationListsRef(LocationListsOffset(0x0102030405060708)), ), ( 4, diff --git a/tests/parse_self.rs b/tests/parse_self.rs index 0c5b8a126..b56f28ee1 100644 --- a/tests/parse_self.rs +++ b/tests/parse_self.rs @@ -1,8 +1,8 @@ extern crate gimli; use gimli::{AttributeValue, DebugAbbrev, DebugAranges, DebugInfo, DebugLine, DebugLoc, - DebugPubNames, DebugPubTypes, DebugRanges, DebugStr, Expression, Format, LittleEndian, - Operation, Reader}; + DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, DebugStr, + Expression, Format, LittleEndian, LocationLists, Operation, RangeLists, Reader}; use std::env; use std::collections::hash_map::HashMap; use std::fs::File; @@ -150,6 +150,8 @@ fn test_parse_self_debug_loc() { 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 mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { @@ -175,9 +177,9 @@ fn test_parse_self_debug_loc() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { - if let AttributeValue::DebugLocRef(offset) = attr.value() { - let mut locs = debug_loc - .locations(offset, unit.address_size(), low_pc) + if let AttributeValue::LocationListsRef(offset) = attr.value() { + let mut locs = loclists + .locations(offset, unit.version(), unit.address_size(), low_pc) .expect("Should parse locations OK"); while let Some(loc) = locs.next().expect("Should parse next location") { assert!(loc.range.begin <= loc.range.end); @@ -199,6 +201,8 @@ fn test_parse_self_debug_ranges() { let debug_ranges = read_section("debug_ranges"); let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists).expect("Should parse rnglists"); let mut iter = debug_info.units(); while let Some(unit) = iter.next().expect("Should parse compilation unit") { @@ -224,9 +228,9 @@ fn test_parse_self_debug_ranges() { let entry = cursor.current().expect("Should have a current entry"); let mut attrs = entry.attrs(); while let Some(attr) = attrs.next().expect("Should parse entry's attribute") { - if let AttributeValue::DebugRangesRef(offset) = attr.value() { - let mut ranges = debug_ranges - .ranges(offset, unit.address_size(), low_pc) + if let AttributeValue::RangeListsRef(offset) = attr.value() { + let mut ranges = rnglists + .ranges(offset, unit.version(), unit.address_size(), low_pc) .expect("Should parse ranges OK"); while let Some(range) = ranges.next().expect("Should parse next range") { assert!(range.begin <= range.end); From 41ecd07b475d5ec9fb248db8ad200147406dabd8 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Sat, 27 Jan 2018 19:18:49 +1000 Subject: [PATCH 3/5] Use LocationLists and RangeLists for loc and ranges tests --- src/loc.rs | 36 +++++++++++++++++++++++------------- src/loclists.rs | 4 +++- src/ranges.rs | 36 +++++++++++++++++++++++------------- src/rnglists.rs | 4 +++- 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/loc.rs b/src/loc.rs index 7f91e2bb6..6ec293847 100644 --- a/src/loc.rs +++ b/src/loc.rs @@ -246,6 +246,7 @@ mod tests { use super::*; use endianity::{EndianBuf, LittleEndian}; + use loclists::{DebugLocLists, LocationLists, LocationListsOffset}; use parser::Error; use ranges::Range; use self::test_assembler::{Endian, Label, LabelMaker, Section}; @@ -279,8 +280,11 @@ mod tests { let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&buf, LittleEndian); - let offset = DebugLocOffset((&first - &start) as usize); - let mut locations = debug_loc.locations(offset, 4, 0x01000000).unwrap(); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); // A normal location. assert_eq!( @@ -346,8 +350,8 @@ mod tests { assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. - let mut locations = debug_loc - .locations(DebugLocOffset(buf.len()), 4, 0x01000000) + let mut locations = loclists + .locations(LocationListsOffset(buf.len()), version, 4, 0x01000000) .unwrap(); assert_eq!(locations.next(), Ok(None)); } @@ -381,8 +385,11 @@ mod tests { let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&buf, LittleEndian); - let offset = DebugLocOffset((&first - &start) as usize); - let mut locations = debug_loc.locations(offset, 8, 0x01000000).unwrap(); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); // A normal location. assert_eq!( @@ -448,8 +455,8 @@ mod tests { assert_eq!(locations.next(), Ok(None)); // An offset at the end of buf. - let mut locations = debug_loc - .locations(DebugLocOffset(buf.len()), 8, 0x01000000) + let mut locations = loclists + .locations(LocationListsOffset(buf.len()), version, 8, 0x01000000) .unwrap(); assert_eq!(locations.next(), Ok(None)); } @@ -464,21 +471,24 @@ mod tests { let buf = section.get_contents().unwrap(); let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); + let version = 4; // An invalid location range. - let mut locations = debug_loc - .locations(DebugLocOffset(0x0), 4, 0x01000000) + let mut locations = loclists + .locations(LocationListsOffset(0x0), version, 4, 0x01000000) .unwrap(); assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); // An invalid location range after wrapping. - let mut locations = debug_loc - .locations(DebugLocOffset(0x8), 4, 0x01000000) + let mut locations = loclists + .locations(LocationListsOffset(14), version, 4, 0x01000000) .unwrap(); assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); // An invalid offset. - match debug_loc.locations(DebugLocOffset(buf.len() + 1), 4, 0x01000000) { + match loclists.locations(LocationListsOffset(buf.len() + 1), version, 4, 0x01000000) { Err(Error::UnexpectedEof) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } diff --git a/src/loclists.rs b/src/loclists.rs index 061b61d58..8df1142c9 100644 --- a/src/loclists.rs +++ b/src/loclists.rs @@ -415,7 +415,9 @@ impl LocListIter { (Range { begin: 0, end: u64::max_value() }, data) } RawLocListEntry::OffsetPair { begin, end, data } => { - (Range { begin: self.base_address + begin, end: self.base_address + end }, data) + let mut range = Range { begin, end }; + range.add_base_address(self.base_address, self.raw.address_size); + (range, data) }, RawLocListEntry::StartEnd { begin, end, data } => { (Range { begin: begin, end: end }, data) diff --git a/src/ranges.rs b/src/ranges.rs index 0849559de..571018c2c 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -264,6 +264,7 @@ mod tests { use super::*; use endianity::LittleEndian; use parser::Error; + use rnglists::{DebugRngLists, RangeLists, RangeListsOffset}; use self::test_assembler::{Endian, Label, LabelMaker, Section}; #[test] @@ -327,8 +328,11 @@ mod tests { let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let offset = DebugRangesOffset((&first - &start) as usize); - let mut ranges = debug_ranges.ranges(offset, 4, 0x01000000).unwrap(); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); // A normal range. assert_eq!( @@ -379,8 +383,8 @@ mod tests { assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. - let mut ranges = debug_ranges - .ranges(DebugRangesOffset(buf.len()), 4, 0x01000000) + let mut ranges = rnglists + .ranges(RangeListsOffset(buf.len()), version, 4, 0x01000000) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } @@ -414,8 +418,11 @@ mod tests { let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let offset = DebugRangesOffset((&first - &start) as usize); - let mut ranges = debug_ranges.ranges(offset, 8, 0x01000000).unwrap(); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); // A normal range. assert_eq!( @@ -466,8 +473,8 @@ mod tests { assert_eq!(ranges.next(), Ok(None)); // An offset at the end of buf. - let mut ranges = debug_ranges - .ranges(DebugRangesOffset(buf.len()), 8, 0x01000000) + let mut ranges = rnglists + .ranges(RangeListsOffset(buf.len()), version, 8, 0x01000000) .unwrap(); assert_eq!(ranges.next(), Ok(None)); } @@ -482,21 +489,24 @@ mod tests { let buf = section.get_contents().unwrap(); let debug_ranges = DebugRanges::new(&buf, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); + let version = 4; // An invalid range. - let mut ranges = debug_ranges - .ranges(DebugRangesOffset(0x0), 4, 0x01000000) + let mut ranges = rnglists + .ranges(RangeListsOffset(0x0), version, 4, 0x01000000) .unwrap(); assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); // An invalid range after wrapping. - let mut ranges = debug_ranges - .ranges(DebugRangesOffset(0x8), 4, 0x01000000) + let mut ranges = rnglists + .ranges(RangeListsOffset(0x8), version, 4, 0x01000000) .unwrap(); assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); // An invalid offset. - match debug_ranges.ranges(DebugRangesOffset(buf.len() + 1), 4, 0x01000000) { + match rnglists.ranges(RangeListsOffset(buf.len() + 1), version, 4, 0x01000000) { Err(Error::UnexpectedEof) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } diff --git a/src/rnglists.rs b/src/rnglists.rs index ec3718465..261b75112 100644 --- a/src/rnglists.rs +++ b/src/rnglists.rs @@ -382,7 +382,9 @@ impl RngListIter { continue; }, RawRngListEntry::OffsetPair { begin, end } => { - Range { begin: self.base_address + begin, end: self.base_address + end } + let mut range = Range { begin, end }; + range.add_base_address(self.base_address, self.raw.address_size); + range }, RawRngListEntry::StartEnd { begin, end } => { Range { begin: begin, end: end } From 85924626729202a638f7a87e48112d0e4e37b4b4 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Sat, 27 Jan 2018 19:28:55 +1000 Subject: [PATCH 4/5] Delete unused loc/ranges iterators And move the rest of loc/ranges in loclists/rnglists. --- src/lib.rs | 12 +- src/loc.rs | 496 ---------------------------------------------- src/loclists.rs | 345 +++++++++++++++++++++++++++++--- src/ranges.rs | 514 ------------------------------------------------ src/rnglists.rs | 410 ++++++++++++++++++++++++++++++++++---- 5 files changed, 699 insertions(+), 1078 deletions(-) delete mode 100644 src/loc.rs delete mode 100644 src/ranges.rs diff --git a/src/lib.rs b/src/lib.rs index b217e2bb6..f7f523a6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,11 +239,9 @@ pub use aranges::{ArangeEntry, ArangeEntryIter, DebugAranges}; mod line; pub use line::*; -mod loc; -pub use loc::{DebugLoc, LocationListEntry, LocationListIter, RawLocationListIter}; - mod loclists; -pub use loclists::{DebugLocLists, LocationLists, LocationListsOffset, LocListIter, RawLocListEntry, RawLocListIter}; +pub use loclists::{DebugLoc, DebugLocLists, LocationLists, LocationListsOffset, + LocationListEntry, LocListIter, RawLocListEntry, RawLocListIter}; mod lookup; @@ -256,11 +254,9 @@ pub use pubnames::{DebugPubNames, PubNamesEntry, PubNamesEntryIter}; mod pubtypes; pub use pubtypes::{DebugPubTypes, PubTypesEntry, PubTypesEntryIter}; -mod ranges; -pub use ranges::{DebugRanges, Range, RangesIter, RawRangesIter}; - mod rnglists; -pub use rnglists::{DebugRngLists, RangeLists, RangeListsOffset, RawRngListEntry, RngListIter}; +pub use rnglists::{DebugRanges, DebugRngLists, Range, RangeLists, RangeListsOffset, + RawRngListEntry, RngListIter}; mod str; pub use str::*; diff --git a/src/loc.rs b/src/loc.rs deleted file mode 100644 index 6ec293847..000000000 --- a/src/loc.rs +++ /dev/null @@ -1,496 +0,0 @@ -use endianity::{EndianBuf, Endianity}; -use fallible_iterator::FallibleIterator; -use parser::{Error, Result}; -use op::Expression; -use reader::{Reader, ReaderOffset}; -use ranges::Range; -use Section; - -/// An offset into the `.debug_loc` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DebugLocOffset(pub T); - -/// The `DebugLoc` struct represents the DWARF strings -/// found in the `.debug_loc` section. -#[derive(Debug, Clone, Copy)] -pub struct DebugLoc { - pub(crate) debug_loc_section: R, -} - -impl<'input, Endian> DebugLoc> -where - Endian: Endianity, -{ - /// Construct a new `DebugLoc` instance from the data in the `.debug_loc` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_loc` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. - /// - /// ``` - /// use gimli::{DebugLoc, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # 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(EndianBuf::new(debug_loc_section, endian)) - } -} - -impl DebugLoc { - /// Iterate over the `LocationListEntry`s starting at the given offset. - /// - /// The `address_size` must be match the compilation unit for this location list. - /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the - /// `DW_TAG_compile_unit` entry for the compilation unit that contains this location - /// list. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn locations( - &self, - offset: DebugLocOffset, - address_size: u8, - base_address: u64, - ) -> Result> { - let mut input = self.debug_loc_section.clone(); - input.skip(offset.0)?; - Ok(LocationListIter::new(input, address_size, base_address)) - } - - /// Iterate over the raw `LocationListEntry`s starting at the given offset. - /// - /// The `address_size` must be match the compilation unit for this location list. - /// - /// This iterator does not perform any processing of the location entries, - /// such as handling base addresses. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn raw_locations( - &self, - offset: DebugLocOffset, - address_size: u8, - ) -> Result> { - let mut input = self.debug_loc_section.clone(); - input.skip(offset.0)?; - Ok(RawLocationListIter::new(input, address_size)) - } -} - -impl Section for DebugLoc { - fn section_name() -> &'static str { - ".debug_loc" - } -} - -impl From for DebugLoc { - fn from(debug_loc_section: R) -> Self { - DebugLoc { debug_loc_section } - } -} - -/// A raw iterator over a location list. -/// -/// This iterator does not perform any processing of the location entries, -/// such as handling base addresses. -#[derive(Debug)] -pub struct RawLocationListIter { - input: R, - address_size: u8, -} - -impl RawLocationListIter { - /// Construct a `RawLocationListIter`. - pub fn new(input: R, address_size: u8) -> RawLocationListIter { - RawLocationListIter { - input: input, - address_size: address_size, - } - } - - /// Advance the iterator to the next location. - pub fn next(&mut self) -> Result>> { - if self.input.is_empty() { - return Ok(None); - } - - match LocationListEntry::parse(&mut self.input, self.address_size) { - Ok(location) => { - if location.range.is_end() { - self.input.empty(); - } - Ok(Some(location)) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -impl FallibleIterator for RawLocationListIter { - type Item = LocationListEntry; - type Error = Error; - - fn next(&mut self) -> ::std::result::Result, Self::Error> { - RawLocationListIter::next(self) - } -} - -/// An iterator over a location list. -/// -/// This iterator internally handles processing of base address selection entries -/// and list end entries. Thus, it only returns location entries that are valid -/// and already adjusted for the base address. -#[derive(Debug)] -pub struct LocationListIter { - raw: RawLocationListIter, - base_address: u64, -} - -impl LocationListIter { - /// Construct a `LocationListIter`. - fn new(input: R, address_size: u8, base_address: u64) -> LocationListIter { - LocationListIter { - raw: RawLocationListIter::new(input, address_size), - base_address: base_address, - } - } - - /// Advance the iterator to the next location. - pub fn next(&mut self) -> Result>> { - loop { - let mut location = match self.raw.next()? { - Some(location) => location, - None => return Ok(None), - }; - - if location.range.is_end() { - return Ok(None); - } - - if location.range.is_base_address(self.raw.address_size) { - self.base_address = location.range.end; - continue; - } - - if location.range.begin == location.range.end { - // An empty location list entry, skip it. - continue; - } - - location - .range - .add_base_address(self.base_address, self.raw.address_size); - if location.range.begin > location.range.end { - self.raw.input.empty(); - return Err(Error::InvalidLocationAddressRange); - } - - return Ok(Some(location)); - } - } -} - -impl FallibleIterator for LocationListIter { - type Item = LocationListEntry; - type Error = Error; - - fn next(&mut self) -> ::std::result::Result, Self::Error> { - LocationListIter::next(self) - } -} - -/// A location list entry from the `.debug_loc` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct LocationListEntry { - /// The address range that this location is valid for. - pub range: Range, - - /// The data containing a single location description. - pub data: Expression, -} - -impl LocationListEntry { - /// Parse a location list entry from `.debug_loc`. - fn parse(input: &mut R, address_size: u8) -> Result> { - let range = Range::parse(input, address_size)?; - if range.is_end() || range.is_base_address(address_size) { - let mut data = input.clone(); - data.empty(); - let location = LocationListEntry { - range: range, - data: Expression(data), - }; - Ok(location) - } else { - let len = input.read_u16().map(R::Offset::from_u16)?; - let data = input.split(len)?; - let location = LocationListEntry { - range: range, - data: Expression(data), - }; - Ok(location) - } - } -} - -#[cfg(test)] -mod tests { - extern crate test_assembler; - - use super::*; - use endianity::{EndianBuf, LittleEndian}; - use loclists::{DebugLocLists, LocationLists, LocationListsOffset}; - use parser::Error; - use ranges::Range; - use self::test_assembler::{Endian, Label, LabelMaker, Section}; - - #[test] - fn test_location_list_32() { - let start = Label::new(); - let first = Label::new(); - let section = Section::with_endian(Endian::Little) - // A location before the offset. - .mark(&start) - .L32(0x10000).L32(0x10100).L16(4).L32(1) - .mark(&first) - // A normal location. - .L32(0x10200).L32(0x10300).L16(4).L32(2) - // A base address selection followed by a normal location. - .L32(0xffffffff).L32(0x02000000) - .L32(0x10400).L32(0x10500).L16(4).L32(3) - // An empty location range followed by a normal location. - .L32(0x10600).L32(0x10600).L16(4).L32(4) - .L32(0x10800).L32(0x10900).L16(4).L32(5) - // A location range that starts at 0. - .L32(0).L32(1).L16(4).L32(6) - // A location range that ends at -1. - .L32(0xffffffff).L32(0x00000000) - .L32(0).L32(0xffffffff).L16(4).L32(7) - // A location list end. - .L32(0).L32(0) - // Some extra data. - .L32(0); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&buf, LittleEndian); - let debug_loclists = DebugLocLists::new(&[], LittleEndian); - 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, 0x01000000).unwrap(); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x01010200, - end: 0x01010300, - }, - data: Expression(EndianBuf::new(&[2, 0, 0, 0], LittleEndian)), - })) - ); - - // A base address selection followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x02010400, - end: 0x02010500, - }, - data: Expression(EndianBuf::new(&[3, 0, 0, 0], LittleEndian)), - })) - ); - - // An empty location range followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x02010800, - end: 0x02010900, - }, - data: Expression(EndianBuf::new(&[5, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that starts at 0. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x02000000, - end: 0x02000001, - }, - data: Expression(EndianBuf::new(&[6, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that ends at -1. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x00000000, - end: 0xffffffff, - }, - data: Expression(EndianBuf::new(&[7, 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()), version, 4, 0x01000000) - .unwrap(); - assert_eq!(locations.next(), Ok(None)); - } - - #[test] - fn test_location_list_64() { - let start = Label::new(); - let first = Label::new(); - let section = Section::with_endian(Endian::Little) - // A location before the offset. - .mark(&start) - .L64(0x10000).L64(0x10100).L16(4).L32(1) - .mark(&first) - // A normal location. - .L64(0x10200).L64(0x10300).L16(4).L32(2) - // A base address selection followed by a normal location. - .L64(0xffffffffffffffff).L64(0x02000000) - .L64(0x10400).L64(0x10500).L16(4).L32(3) - // An empty location range followed by a normal location. - .L64(0x10600).L64(0x10600).L16(4).L32(4) - .L64(0x10800).L64(0x10900).L16(4).L32(5) - // A location range that starts at 0. - .L64(0).L64(1).L16(4).L32(6) - // A location range that ends at -1. - .L64(0xffffffffffffffff).L64(0x00000000) - .L64(0).L64(0xffffffffffffffff).L16(4).L32(7) - // A location list end. - .L64(0).L64(0) - // Some extra data. - .L64(0); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&buf, LittleEndian); - let debug_loclists = DebugLocLists::new(&[], LittleEndian); - 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, 0x01000000).unwrap(); - - // A normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x01010200, - end: 0x01010300, - }, - data: Expression(EndianBuf::new(&[2, 0, 0, 0], LittleEndian)), - })) - ); - - // A base address selection followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x02010400, - end: 0x02010500, - }, - data: Expression(EndianBuf::new(&[3, 0, 0, 0], LittleEndian)), - })) - ); - - // An empty location range followed by a normal location. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x02010800, - end: 0x02010900, - }, - data: Expression(EndianBuf::new(&[5, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that starts at 0. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x02000000, - end: 0x02000001, - }, - data: Expression(EndianBuf::new(&[6, 0, 0, 0], LittleEndian)), - })) - ); - - // A location range that ends at -1. - assert_eq!( - locations.next(), - Ok(Some(LocationListEntry { - range: Range { - begin: 0x0, - end: 0xffffffffffffffff, - }, - data: Expression(EndianBuf::new(&[7, 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()), version, 8, 0x01000000) - .unwrap(); - assert_eq!(locations.next(), Ok(None)); - } - - #[test] - fn test_locations_invalid() { - let section = Section::with_endian(Endian::Little) - // An invalid location range. - .L32(0x20000).L32(0x10000).L16(4).L32(1) - // An invalid range after wrapping. - .L32(0x20000).L32(0xff010000).L16(4).L32(2); - - let buf = section.get_contents().unwrap(); - let debug_loc = DebugLoc::new(&buf, LittleEndian); - let debug_loclists = DebugLocLists::new(&[], LittleEndian); - let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); - let version = 4; - - // An invalid location range. - let mut locations = loclists - .locations(LocationListsOffset(0x0), version, 4, 0x01000000) - .unwrap(); - assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); - - // An invalid location range after wrapping. - let mut locations = loclists - .locations(LocationListsOffset(14), version, 4, 0x01000000) - .unwrap(); - assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); - - // An invalid offset. - match loclists.locations(LocationListsOffset(buf.len() + 1), version, 4, 0x01000000) { - Err(Error::UnexpectedEof) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } -} diff --git a/src/loclists.rs b/src/loclists.rs index 8df1142c9..c6dd49588 100644 --- a/src/loclists.rs +++ b/src/loclists.rs @@ -1,14 +1,54 @@ use constants; use endianity::{EndianBuf, Endianity}; use fallible_iterator::FallibleIterator; -use loc::{DebugLoc, LocationListEntry}; use op::Expression; use parser::{self, Format, Error, Result}; use reader::{Reader, ReaderOffset}; -use ranges::Range; -use rnglists::AddressIndex; +use rnglists::{AddressIndex, Range}; use Section; +/// The `DebugLoc` struct represents the DWARF strings +/// found in the `.debug_loc` section. +#[derive(Debug, Clone, Copy)] +pub struct DebugLoc { + pub(crate) debug_loc_section: R, +} + +impl<'input, Endian> DebugLoc> +where + Endian: Endianity, +{ + /// Construct a new `DebugLoc` instance from the data in the `.debug_loc` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_loc` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on OSX, etc. + /// + /// ``` + /// use gimli::{DebugLoc, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # 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(EndianBuf::new(debug_loc_section, endian)) + } +} + +impl Section for DebugLoc { + fn section_name() -> &'static str { + ".debug_loc" + } +} + +impl From for DebugLoc { + fn from(debug_loc_section: R) -> Self { + DebugLoc { debug_loc_section } + } +} + /// The `DebugLocLists` struct represents the DWARF data /// found in the `.debug_loclists` section. #[derive(Debug, Clone, Copy)] @@ -39,17 +79,16 @@ where } } -/// An offset into either the `.debug_loc` section or the `.debug_loclists` section, -/// depending on the version of the unit the offset was contained in. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct LocationListsOffset(pub T); +impl Section for DebugLocLists { + fn section_name() -> &'static str { + ".debug_loclists" + } +} -/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections. -#[derive(Debug, Clone, Copy)] -pub struct LocationLists { - debug_loc: DebugLoc, - debug_loclists: DebugLocLists, - header: LocListsHeader, +impl From for DebugLocLists { + fn from(debug_loclists_section: R) -> Self { + DebugLocLists { debug_loclists_section } + } } #[derive(Debug, Clone, Copy)] @@ -90,6 +129,19 @@ fn parse_header(input: &mut R) -> Result { }) } +/// An offset into either the `.debug_loc` section or the `.debug_loclists` section, +/// depending on the version of the unit the offset was contained in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LocationListsOffset(pub T); + +/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections. +#[derive(Debug, Clone, Copy)] +pub struct LocationLists { + debug_loc: DebugLoc, + debug_loclists: DebugLocLists, + header: LocListsHeader, +} + impl LocationLists { /// Construct a new `LocationLists` instance from the data in the `.debug_loc` and /// `.debug_loclists` sections. @@ -163,18 +215,6 @@ impl LocationLists { } } -impl Section for DebugLocLists { - fn section_name() -> &'static str { - ".debug_loclists" - } -} - -impl From for DebugLocLists { - fn from(debug_loclists_section: R) -> Self { - DebugLocLists { debug_loclists_section } - } -} - /// A raw iterator over a location list. /// /// This iterator does not perform any processing of the location entries, @@ -458,13 +498,23 @@ impl FallibleIterator for LocListIter { } } +/// A location list entry from the `.debug_loc` or `.debug_loclists` sections. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LocationListEntry { + /// The address range that this location is valid for. + pub range: Range, + + /// The data containing a single location description. + pub data: Expression, +} + #[cfg(test)] mod tests { extern crate test_assembler; use super::*; use endianity::{EndianBuf, LittleEndian}; - use ranges::Range; + use rnglists::Range; use self::test_assembler::{Endian, Label, LabelMaker, Section}; use test_util::GimliSectionMethods; @@ -772,4 +822,247 @@ mod tests { .unwrap(); assert_eq!(locations.next(), Ok(None)); } + + #[test] + fn test_location_list_32() { + let start = Label::new(); + let first = Label::new(); + let section = Section::with_endian(Endian::Little) + // A location before the offset. + .mark(&start) + .L32(0x10000).L32(0x10100).L16(4).L32(1) + .mark(&first) + // A normal location. + .L32(0x10200).L32(0x10300).L16(4).L32(2) + // A base address selection followed by a normal location. + .L32(0xffffffff).L32(0x02000000) + .L32(0x10400).L32(0x10500).L16(4).L32(3) + // An empty location range followed by a normal location. + .L32(0x10600).L32(0x10600).L16(4).L32(4) + .L32(0x10800).L32(0x10900).L16(4).L32(5) + // A location range that starts at 0. + .L32(0).L32(1).L16(4).L32(6) + // A location range that ends at -1. + .L32(0xffffffff).L32(0x00000000) + .L32(0).L32(0xffffffff).L16(4).L32(7) + // A location list end. + .L32(0).L32(0) + // Some extra data. + .L32(0); + + let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); + + // A normal location. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x01010200, + end: 0x01010300, + }, + data: Expression(EndianBuf::new(&[2, 0, 0, 0], LittleEndian)), + })) + ); + + // A base address selection followed by a normal location. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x02010400, + end: 0x02010500, + }, + data: Expression(EndianBuf::new(&[3, 0, 0, 0], LittleEndian)), + })) + ); + + // An empty location range followed by a normal location. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x02010800, + end: 0x02010900, + }, + data: Expression(EndianBuf::new(&[5, 0, 0, 0], LittleEndian)), + })) + ); + + // A location range that starts at 0. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x02000000, + end: 0x02000001, + }, + data: Expression(EndianBuf::new(&[6, 0, 0, 0], LittleEndian)), + })) + ); + + // A location range that ends at -1. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x00000000, + end: 0xffffffff, + }, + data: Expression(EndianBuf::new(&[7, 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()), version, 4, 0x01000000) + .unwrap(); + assert_eq!(locations.next(), Ok(None)); + } + + #[test] + fn test_location_list_64() { + let start = Label::new(); + let first = Label::new(); + let section = Section::with_endian(Endian::Little) + // A location before the offset. + .mark(&start) + .L64(0x10000).L64(0x10100).L16(4).L32(1) + .mark(&first) + // A normal location. + .L64(0x10200).L64(0x10300).L16(4).L32(2) + // A base address selection followed by a normal location. + .L64(0xffffffffffffffff).L64(0x02000000) + .L64(0x10400).L64(0x10500).L16(4).L32(3) + // An empty location range followed by a normal location. + .L64(0x10600).L64(0x10600).L16(4).L32(4) + .L64(0x10800).L64(0x10900).L16(4).L32(5) + // A location range that starts at 0. + .L64(0).L64(1).L16(4).L32(6) + // A location range that ends at -1. + .L64(0xffffffffffffffff).L64(0x00000000) + .L64(0).L64(0xffffffffffffffff).L16(4).L32(7) + // A location list end. + .L64(0).L64(0) + // Some extra data. + .L64(0); + + let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); + + // A normal location. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x01010200, + end: 0x01010300, + }, + data: Expression(EndianBuf::new(&[2, 0, 0, 0], LittleEndian)), + })) + ); + + // A base address selection followed by a normal location. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x02010400, + end: 0x02010500, + }, + data: Expression(EndianBuf::new(&[3, 0, 0, 0], LittleEndian)), + })) + ); + + // An empty location range followed by a normal location. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x02010800, + end: 0x02010900, + }, + data: Expression(EndianBuf::new(&[5, 0, 0, 0], LittleEndian)), + })) + ); + + // A location range that starts at 0. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x02000000, + end: 0x02000001, + }, + data: Expression(EndianBuf::new(&[6, 0, 0, 0], LittleEndian)), + })) + ); + + // A location range that ends at -1. + assert_eq!( + locations.next(), + Ok(Some(LocationListEntry { + range: Range { + begin: 0x0, + end: 0xffffffffffffffff, + }, + data: Expression(EndianBuf::new(&[7, 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()), version, 8, 0x01000000) + .unwrap(); + assert_eq!(locations.next(), Ok(None)); + } + + #[test] + fn test_locations_invalid() { + let section = Section::with_endian(Endian::Little) + // An invalid location range. + .L32(0x20000).L32(0x10000).L16(4).L32(1) + // An invalid range after wrapping. + .L32(0x20000).L32(0xff010000).L16(4).L32(2); + + let buf = section.get_contents().unwrap(); + let debug_loc = DebugLoc::new(&buf, LittleEndian); + let debug_loclists = DebugLocLists::new(&[], LittleEndian); + let loclists = LocationLists::new(debug_loc, debug_loclists).unwrap(); + let version = 4; + + // An invalid location range. + let mut locations = loclists + .locations(LocationListsOffset(0x0), version, 4, 0x01000000) + .unwrap(); + assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); + + // An invalid location range after wrapping. + let mut locations = loclists + .locations(LocationListsOffset(14), version, 4, 0x01000000) + .unwrap(); + assert_eq!(locations.next(), Err(Error::InvalidLocationAddressRange)); + + // An invalid offset. + match loclists.locations(LocationListsOffset(buf.len() + 1), version, 4, 0x01000000) { + Err(Error::UnexpectedEof) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } } diff --git a/src/ranges.rs b/src/ranges.rs deleted file mode 100644 index 571018c2c..000000000 --- a/src/ranges.rs +++ /dev/null @@ -1,514 +0,0 @@ -use endianity::{EndianBuf, Endianity}; -use fallible_iterator::FallibleIterator; -use parser::{Error, Result}; -use reader::Reader; -use Section; - -/// An offset into the `.debug_ranges` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DebugRangesOffset(pub T); - -/// The `DebugRanges` struct represents the DWARF strings -/// found in the `.debug_ranges` section. -#[derive(Debug, Clone, Copy)] -pub struct DebugRanges { - pub(crate) debug_ranges_section: R, -} - -impl<'input, Endian> DebugRanges> -where - Endian: Endianity, -{ - /// Construct a new `DebugRanges` instance from the data in the `.debug_ranges` - /// section. - /// - /// It is the caller's responsibility to read the `.debug_ranges` section and - /// present it as a `&[u8]` slice. That means using some ELF loader on - /// Linux, a Mach-O loader on OSX, etc. - /// - /// ``` - /// use gimli::{DebugRanges, LittleEndian}; - /// - /// # let buf = [0x00, 0x01, 0x02, 0x03]; - /// # 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(EndianBuf::new(debug_ranges_section, endian)) - } -} - -impl DebugRanges { - /// Iterate over the `Range` list entries starting at the given offset. - /// - /// The `address_size` must be match the compilation unit for this range list. - /// The `base_address` should be obtained from the `DW_AT_low_pc` attribute in the - /// `DW_TAG_compile_unit` entry for the compilation unit that contains this range list. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn ranges( - &self, - offset: DebugRangesOffset, - address_size: u8, - base_address: u64, - ) -> Result> { - let mut input = self.debug_ranges_section.clone(); - input.skip(offset.0)?; - Ok(RangesIter::new(input, address_size, base_address)) - } - - /// Iterate over the raw `Range` list entries starting at the given offset. - /// - /// The `address_size` must be match the compilation unit for this range list. - /// - /// This iterator does not perform any processing of the range entries, - /// such as handling base addresses. - /// - /// Can be [used with - /// `FallibleIterator`](./index.html#using-with-fallibleiterator). - pub fn raw_ranges( - &self, - offset: DebugRangesOffset, - address_size: u8, - ) -> Result> { - let mut input = self.debug_ranges_section.clone(); - input.skip(offset.0)?; - Ok(RawRangesIter::new(input, address_size)) - } -} - -impl Section for DebugRanges { - fn section_name() -> &'static str { - ".debug_ranges" - } -} - -impl From for DebugRanges { - fn from(debug_ranges_section: R) -> Self { - DebugRanges { - debug_ranges_section, - } - } -} - -/// A raw iterator over an address range list. -/// -/// This iterator does not perform any processing of the range entries, -/// such as handling base addresses. -#[derive(Debug)] -pub struct RawRangesIter { - input: R, - address_size: u8, -} - -impl RawRangesIter { - /// Construct a `RawRangesIter`. - fn new(input: R, address_size: u8) -> RawRangesIter { - RawRangesIter { - input: input, - address_size: address_size, - } - } - - /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result> { - if self.input.is_empty() { - return Ok(None); - } - - match Range::parse(&mut self.input, self.address_size) { - Ok(range) => { - if range.is_end() { - self.input.empty(); - } - Ok(Some(range)) - } - Err(e) => { - self.input.empty(); - Err(e) - } - } - } -} - -impl FallibleIterator for RawRangesIter { - type Item = Range; - type Error = Error; - - fn next(&mut self) -> ::std::result::Result, Self::Error> { - RawRangesIter::next(self) - } -} - -/// An iterator over an address range list. -/// -/// This iterator internally handles processing of base address selection entries -/// and range end entries. Thus, it only returns range entries that are valid -/// and already adjusted for the base address. -#[derive(Debug)] -pub struct RangesIter { - raw: RawRangesIter, - base_address: u64, -} - -impl RangesIter { - /// Construct a `RangesIter`. - fn new(input: R, address_size: u8, base_address: u64) -> RangesIter { - RangesIter { - raw: RawRangesIter::new(input, address_size), - base_address: base_address, - } - } - - /// Advance the iterator to the next range. - pub fn next(&mut self) -> Result> { - loop { - let mut range = match self.raw.next()? { - Some(range) => range, - None => return Ok(None), - }; - - if range.is_end() { - return Ok(None); - } - - if range.is_base_address(self.raw.address_size) { - self.base_address = range.end; - continue; - } - - if range.begin == range.end { - // An empty range list entry, skip it. - continue; - } - - range.add_base_address(self.base_address, self.raw.address_size); - if range.begin > range.end { - self.raw.input.empty(); - return Err(Error::InvalidAddressRange); - } - - return Ok(Some(range)); - } - } -} - -impl FallibleIterator for RangesIter { - type Item = Range; - type Error = Error; - - fn next(&mut self) -> ::std::result::Result, Self::Error> { - RangesIter::next(self) - } -} - -/// An address range from the `.debug_ranges` section. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Range { - /// The beginning address of the range. - pub begin: u64, - - /// The first address past the end of the range. - pub end: u64, -} - -impl Range { - /// Check if this is a range end entry. - /// - /// This will only occur for raw ranges. - #[inline] - pub fn is_end(&self) -> bool { - self.begin == 0 && self.end == 0 - } - - /// Check if this is a base address selection entry. - /// - /// A base address selection entry changes the base address that subsequent - /// range entries are relative to. This will only occur for raw ranges. - #[inline] - pub fn is_base_address(&self, address_size: u8) -> bool { - self.begin == !0 >> (64 - address_size * 8) - } - - /// Add a base address to this range. - /// - /// This should only be called for raw ranges. - #[inline] - pub fn add_base_address(&mut self, base_address: u64, address_size: u8) { - debug_assert!(!self.is_end()); - debug_assert!(!self.is_base_address(address_size)); - let mask = !0 >> (64 - address_size * 8); - self.begin = base_address.wrapping_add(self.begin) & mask; - self.end = base_address.wrapping_add(self.end) & mask; - } - - /// Parse an address range entry from `.debug_ranges` or `.debug_loc`. - #[doc(hidden)] - #[inline] - pub fn parse(input: &mut R, address_size: u8) -> Result { - let begin = input.read_address(address_size)?; - let end = input.read_address(address_size)?; - let range = Range { - begin: begin, - end: end, - }; - Ok(range) - } -} - -#[cfg(test)] -mod tests { - extern crate test_assembler; - - use super::*; - use endianity::LittleEndian; - use parser::Error; - use rnglists::{DebugRngLists, RangeLists, RangeListsOffset}; - use self::test_assembler::{Endian, Label, LabelMaker, Section}; - - #[test] - fn test_range() { - let range = Range { - begin: 0, - end: 0xffffffff, - }; - assert!(!range.is_end()); - assert!(!range.is_base_address(4)); - assert!(!range.is_base_address(8)); - - let range = Range { begin: 0, end: 0 }; - assert!(range.is_end()); - assert!(!range.is_base_address(4)); - assert!(!range.is_base_address(8)); - - let range = Range { - begin: 0xffffffff, - end: 0, - }; - assert!(!range.is_end()); - assert!(range.is_base_address(4)); - assert!(!range.is_base_address(8)); - - let range = Range { - begin: 0xffffffffffffffff, - end: 0, - }; - assert!(!range.is_end()); - assert!(!range.is_base_address(4)); - assert!(range.is_base_address(8)); - } - - #[test] - fn test_ranges_32() { - let start = Label::new(); - let first = Label::new(); - let section = Section::with_endian(Endian::Little) - // A range before the offset. - .mark(&start) - .L32(0x10000).L32(0x10100) - .mark(&first) - // A normal range. - .L32(0x10200).L32(0x10300) - // A base address selection followed by a normal range. - .L32(0xffffffff).L32(0x02000000) - .L32(0x10400).L32(0x10500) - // An empty range followed by a normal range. - .L32(0x10600).L32(0x10600) - .L32(0x10800).L32(0x10900) - // A range that starts at 0. - .L32(0).L32(1) - // A range that ends at -1. - .L32(0xffffffff).L32(0x00000000) - .L32(0).L32(0xffffffff) - // A range end. - .L32(0).L32(0) - // Some extra data. - .L32(0); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let debug_rnglists = DebugRngLists::new(&[], LittleEndian); - 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, 0x01000000).unwrap(); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x01010200, - end: 0x01010300, - })) - ); - - // A base address selection followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x02010400, - end: 0x02010500, - })) - ); - - // An empty range followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x02010800, - end: 0x02010900, - })) - ); - - // A range that starts at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x02000000, - end: 0x02000001, - })) - ); - - // A range that ends at -1. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x00000000, - end: 0xffffffff, - })) - ); - - // A range end. - assert_eq!(ranges.next(), Ok(None)); - - // An offset at the end of buf. - let mut ranges = rnglists - .ranges(RangeListsOffset(buf.len()), version, 4, 0x01000000) - .unwrap(); - assert_eq!(ranges.next(), Ok(None)); - } - - #[test] - fn test_ranges_64() { - let start = Label::new(); - let first = Label::new(); - let section = Section::with_endian(Endian::Little) - // A range before the offset. - .mark(&start) - .L64(0x10000).L64(0x10100) - .mark(&first) - // A normal range. - .L64(0x10200).L64(0x10300) - // A base address selection followed by a normal range. - .L64(0xffffffffffffffff).L64(0x02000000) - .L64(0x10400).L64(0x10500) - // An empty range followed by a normal range. - .L64(0x10600).L64(0x10600) - .L64(0x10800).L64(0x10900) - // A range that starts at 0. - .L64(0).L64(1) - // A range that ends at -1. - .L64(0xffffffffffffffff).L64(0x00000000) - .L64(0).L64(0xffffffffffffffff) - // A range end. - .L64(0).L64(0) - // Some extra data. - .L64(0); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let debug_rnglists = DebugRngLists::new(&[], LittleEndian); - 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, 0x01000000).unwrap(); - - // A normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x01010200, - end: 0x01010300, - })) - ); - - // A base address selection followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x02010400, - end: 0x02010500, - })) - ); - - // An empty range followed by a normal range. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x02010800, - end: 0x02010900, - })) - ); - - // A range that starts at 0. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x02000000, - end: 0x02000001, - })) - ); - - // A range that ends at -1. - assert_eq!( - ranges.next(), - Ok(Some(Range { - begin: 0x0, - end: 0xffffffffffffffff, - })) - ); - - // A range end. - assert_eq!(ranges.next(), Ok(None)); - - // An offset at the end of buf. - let mut ranges = rnglists - .ranges(RangeListsOffset(buf.len()), version, 8, 0x01000000) - .unwrap(); - assert_eq!(ranges.next(), Ok(None)); - } - - #[test] - fn test_ranges_invalid() { - let section = Section::with_endian(Endian::Little) - // An invalid range. - .L32(0x20000).L32(0x10000) - // An invalid range after wrapping. - .L32(0x20000).L32(0xff010000); - - let buf = section.get_contents().unwrap(); - let debug_ranges = DebugRanges::new(&buf, LittleEndian); - let debug_rnglists = DebugRngLists::new(&[], LittleEndian); - let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); - let version = 4; - - // An invalid range. - let mut ranges = rnglists - .ranges(RangeListsOffset(0x0), version, 4, 0x01000000) - .unwrap(); - assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); - - // An invalid range after wrapping. - let mut ranges = rnglists - .ranges(RangeListsOffset(0x8), version, 4, 0x01000000) - .unwrap(); - assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); - - // An invalid offset. - match rnglists.ranges(RangeListsOffset(buf.len() + 1), version, 4, 0x01000000) { - Err(Error::UnexpectedEof) => {} - otherwise => panic!("Unexpected result: {:?}", otherwise), - } - } -} diff --git a/src/rnglists.rs b/src/rnglists.rs index 261b75112..8e150ed34 100644 --- a/src/rnglists.rs +++ b/src/rnglists.rs @@ -2,7 +2,6 @@ use constants; use endianity::{EndianBuf, Endianity}; use fallible_iterator::FallibleIterator; use parser::{self, Error, Format, Result}; -use ranges::{Range, DebugRanges}; use reader::{Reader, ReaderOffset}; use Section; @@ -10,49 +9,55 @@ use 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. #[derive(Debug, Clone, Copy)] -struct RngListsHeader { - format: Format, - address_size: u8, - offset_entry_count: u32, +pub struct DebugRanges { + pub(crate) debug_ranges_section: R, } -/// The `DebugRngLists` struct represents the contents of the -/// `.debug_rnglists` section. -#[derive(Debug, Clone, Copy)] -pub struct DebugRngLists { - debug_rnglists_section: R, +impl<'input, Endian> DebugRanges> +where + Endian: Endianity, +{ + /// Construct a new `DebugRanges` instance from the data in the `.debug_ranges` + /// section. + /// + /// It is the caller's responsibility to read the `.debug_ranges` section and + /// present it as a `&[u8]` slice. That means using some ELF loader on + /// Linux, a Mach-O loader on OSX, etc. + /// + /// ``` + /// use gimli::{DebugRanges, LittleEndian}; + /// + /// # let buf = [0x00, 0x01, 0x02, 0x03]; + /// # 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(EndianBuf::new(debug_ranges_section, endian)) + } } -impl RngListsHeader { - /// Return the serialized size of the table header. - fn size(&self) -> u8 { - // initial_length + version + address_size + segment_selector_size + offset_entry_count - self.format.initial_length_size() + 2 + 1 + 1 + 4 +impl Section for DebugRanges { + fn section_name() -> &'static str { + ".debug_ranges" } } -fn parse_header(input: &mut R) -> Result { - let (length, format) = parser::parse_initial_length(input)?; - let length = R::Offset::from_u64(length)?; - input.truncate(length)?; - - let version = input.read_u16()?; - if version != 5 { - return Err(Error::UnknownVersion(version as u64)); +impl From for DebugRanges { + fn from(debug_ranges_section: R) -> Self { + DebugRanges { + debug_ranges_section, + } } +} - let address_size = input.read_u8()?; - let segment_selector_size = input.read_u8()?; - if segment_selector_size != 0 { - return Err(Error::UnsupportedSegmentSize); - } - let offset_entry_count = input.read_u32()?; - Ok(RngListsHeader { - format: format, - address_size: address_size, - offset_entry_count: offset_entry_count, - }) +/// The `DebugRngLists` struct represents the contents of the +/// `.debug_rnglists` section. +#[derive(Debug, Clone, Copy)] +pub struct DebugRngLists { + debug_rnglists_section: R, } impl<'input, Endian> DebugRngLists> @@ -93,6 +98,44 @@ impl From for DebugRngLists { } } +#[derive(Debug, Clone, Copy)] +struct RngListsHeader { + format: Format, + address_size: u8, + offset_entry_count: u32, +} + +impl RngListsHeader { + /// Return the serialized size of the table header. + fn size(&self) -> u8 { + // initial_length + version + address_size + segment_selector_size + offset_entry_count + self.format.initial_length_size() + 2 + 1 + 1 + 4 + } +} + +fn parse_header(input: &mut R) -> Result { + let (length, format) = parser::parse_initial_length(input)?; + let length = R::Offset::from_u64(length)?; + input.truncate(length)?; + + let version = input.read_u16()?; + if version != 5 { + return Err(Error::UnknownVersion(version as u64)); + } + + let address_size = input.read_u8()?; + let segment_selector_size = input.read_u8()?; + if segment_selector_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } + let offset_entry_count = input.read_u32()?; + Ok(RngListsHeader { + format: format, + address_size: address_size, + offset_entry_count: offset_entry_count, + }) +} + /// An offset into either the `.debug_ranges` section or the `.debug_rnglists` section, /// depending on the version of the unit the offset was contained in. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -422,6 +465,60 @@ impl FallibleIterator for RngListIter { } } +/// An address range from the `.debug_ranges` section. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Range { + /// The beginning address of the range. + pub begin: u64, + + /// The first address past the end of the range. + pub end: u64, +} + +impl Range { + /// Check if this is a range end entry. + /// + /// This will only occur for raw ranges. + #[inline] + pub fn is_end(&self) -> bool { + self.begin == 0 && self.end == 0 + } + + /// Check if this is a base address selection entry. + /// + /// A base address selection entry changes the base address that subsequent + /// range entries are relative to. This will only occur for raw ranges. + #[inline] + pub fn is_base_address(&self, address_size: u8) -> bool { + self.begin == !0 >> (64 - address_size * 8) + } + + /// Add a base address to this range. + /// + /// This should only be called for raw ranges. + #[inline] + pub fn add_base_address(&mut self, base_address: u64, address_size: u8) { + debug_assert!(!self.is_end()); + debug_assert!(!self.is_base_address(address_size)); + let mask = !0 >> (64 - address_size * 8); + self.begin = base_address.wrapping_add(self.begin) & mask; + self.end = base_address.wrapping_add(self.end) & mask; + } + + /// Parse an address range entry from `.debug_ranges` or `.debug_loc`. + #[doc(hidden)] + #[inline] + pub fn parse(input: &mut R, address_size: u8) -> Result { + let begin = input.read_address(address_size)?; + let end = input.read_address(address_size)?; + let range = Range { + begin: begin, + end: end, + }; + Ok(range) + } +} + #[cfg(test)] mod tests { extern crate test_assembler; @@ -665,4 +762,249 @@ mod tests { .unwrap(); assert_eq!(ranges.next(), Ok(None)); } + + #[test] + fn test_range() { + let range = Range { + begin: 0, + end: 0xffffffff, + }; + assert!(!range.is_end()); + assert!(!range.is_base_address(4)); + assert!(!range.is_base_address(8)); + + let range = Range { begin: 0, end: 0 }; + assert!(range.is_end()); + assert!(!range.is_base_address(4)); + assert!(!range.is_base_address(8)); + + let range = Range { + begin: 0xffffffff, + end: 0, + }; + assert!(!range.is_end()); + assert!(range.is_base_address(4)); + assert!(!range.is_base_address(8)); + + let range = Range { + begin: 0xffffffffffffffff, + end: 0, + }; + assert!(!range.is_end()); + assert!(!range.is_base_address(4)); + assert!(range.is_base_address(8)); + } + + #[test] + fn test_ranges_32() { + let start = Label::new(); + let first = Label::new(); + let section = Section::with_endian(Endian::Little) + // A range before the offset. + .mark(&start) + .L32(0x10000).L32(0x10100) + .mark(&first) + // A normal range. + .L32(0x10200).L32(0x10300) + // A base address selection followed by a normal range. + .L32(0xffffffff).L32(0x02000000) + .L32(0x10400).L32(0x10500) + // An empty range followed by a normal range. + .L32(0x10600).L32(0x10600) + .L32(0x10800).L32(0x10900) + // A range that starts at 0. + .L32(0).L32(1) + // A range that ends at -1. + .L32(0xffffffff).L32(0x00000000) + .L32(0).L32(0xffffffff) + // A range end. + .L32(0).L32(0) + // Some extra data. + .L32(0); + + let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&buf, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); + + // A normal range. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x01010200, + end: 0x01010300, + })) + ); + + // A base address selection followed by a normal range. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x02010400, + end: 0x02010500, + })) + ); + + // An empty range followed by a normal range. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x02010800, + end: 0x02010900, + })) + ); + + // A range that starts at 0. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x02000000, + end: 0x02000001, + })) + ); + + // A range that ends at -1. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x00000000, + end: 0xffffffff, + })) + ); + + // A range end. + assert_eq!(ranges.next(), Ok(None)); + + // An offset at the end of buf. + let mut ranges = rnglists + .ranges(RangeListsOffset(buf.len()), version, 4, 0x01000000) + .unwrap(); + assert_eq!(ranges.next(), Ok(None)); + } + + #[test] + fn test_ranges_64() { + let start = Label::new(); + let first = Label::new(); + let section = Section::with_endian(Endian::Little) + // A range before the offset. + .mark(&start) + .L64(0x10000).L64(0x10100) + .mark(&first) + // A normal range. + .L64(0x10200).L64(0x10300) + // A base address selection followed by a normal range. + .L64(0xffffffffffffffff).L64(0x02000000) + .L64(0x10400).L64(0x10500) + // An empty range followed by a normal range. + .L64(0x10600).L64(0x10600) + .L64(0x10800).L64(0x10900) + // A range that starts at 0. + .L64(0).L64(1) + // A range that ends at -1. + .L64(0xffffffffffffffff).L64(0x00000000) + .L64(0).L64(0xffffffffffffffff) + // A range end. + .L64(0).L64(0) + // Some extra data. + .L64(0); + + let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&buf, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + 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, 0x01000000).unwrap(); + + // A normal range. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x01010200, + end: 0x01010300, + })) + ); + + // A base address selection followed by a normal range. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x02010400, + end: 0x02010500, + })) + ); + + // An empty range followed by a normal range. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x02010800, + end: 0x02010900, + })) + ); + + // A range that starts at 0. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x02000000, + end: 0x02000001, + })) + ); + + // A range that ends at -1. + assert_eq!( + ranges.next(), + Ok(Some(Range { + begin: 0x0, + end: 0xffffffffffffffff, + })) + ); + + // A range end. + assert_eq!(ranges.next(), Ok(None)); + + // An offset at the end of buf. + let mut ranges = rnglists + .ranges(RangeListsOffset(buf.len()), version, 8, 0x01000000) + .unwrap(); + assert_eq!(ranges.next(), Ok(None)); + } + + #[test] + fn test_ranges_invalid() { + let section = Section::with_endian(Endian::Little) + // An invalid range. + .L32(0x20000).L32(0x10000) + // An invalid range after wrapping. + .L32(0x20000).L32(0xff010000); + + let buf = section.get_contents().unwrap(); + let debug_ranges = DebugRanges::new(&buf, LittleEndian); + let debug_rnglists = DebugRngLists::new(&[], LittleEndian); + let rnglists = RangeLists::new(debug_ranges, debug_rnglists).unwrap(); + let version = 4; + + // An invalid range. + let mut ranges = rnglists + .ranges(RangeListsOffset(0x0), version, 4, 0x01000000) + .unwrap(); + assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); + + // An invalid range after wrapping. + let mut ranges = rnglists + .ranges(RangeListsOffset(0x8), version, 4, 0x01000000) + .unwrap(); + assert_eq!(ranges.next(), Err(Error::InvalidAddressRange)); + + // An invalid offset. + match rnglists.ranges(RangeListsOffset(buf.len() + 1), version, 4, 0x01000000) { + Err(Error::UnexpectedEof) => {} + otherwise => panic!("Unexpected result: {:?}", otherwise), + } + } } From abc7d18369e0df1915fc0c19f61486eb50fdc38d Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Sun, 28 Jan 2018 14:11:51 +1000 Subject: [PATCH 5/5] Fix coverage Can't disable ALSR in containers. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5807fa7a8..99f930d21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,6 +43,7 @@ matrix: # Coverage should only run on Linux and stable Rust. - rust: stable os: linux + sudo: required env: GIMLI_JOB="coverage" GIMLI_PROFILE= # Building docs only needs to happen on one os and only on stable. - rust: stable