From a88bcf5cf4511a144093ab94490e4551c5adf6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20M=C3=BCller?= Date: Mon, 10 Jun 2024 15:00:40 -0700 Subject: [PATCH] Use gimli::UnitRef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch over to using gimli::UnitRef as a replacement for the various gimli::Unit & Units tuples that we pass around. We still need Units in some places, but we can now remove its dwarf() method, which exposed a gimli::Dwarf object, which may be problematic in the context of split DWARF support. Signed-off-by: Daniel Müller --- src/dwarf/function.rs | 50 +++++++++++++++++++------------------------ src/dwarf/lines.rs | 16 ++++++-------- src/dwarf/location.rs | 3 ++- src/dwarf/range.rs | 5 ++--- src/dwarf/unit.rs | 17 +++++++-------- src/dwarf/units.rs | 38 +++++++++++++++++++------------- 6 files changed, 64 insertions(+), 65 deletions(-) diff --git a/src/dwarf/function.rs b/src/dwarf/function.rs index ed1a4f93..2b1080ed 100644 --- a/src/dwarf/function.rs +++ b/src/dwarf/function.rs @@ -41,7 +41,7 @@ use super::units::Units; fn name_entry<'dwarf>( - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, offset: gimli::UnitOffset< as gimli::Reader>::Offset>, units: &Units<'dwarf>, recursion_limit: usize, @@ -59,12 +59,12 @@ fn name_entry<'dwarf>( match entries.read_attribute(*spec) { Ok(ref attr) => match attr.name() { gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => { - if let Ok(val) = units.dwarf().attr_string(unit, attr.value()) { + if let Ok(val) = unit.attr_string(attr.value()) { return Ok(Some(val)) } } gimli::DW_AT_name => { - if let Ok(val) = units.dwarf().attr_string(unit, attr.value()) { + if let Ok(val) = unit.attr_string(attr.value()) { name = Some(val); } } @@ -91,7 +91,7 @@ fn name_entry<'dwarf>( fn name_attr<'dwarf>( attr: gimli::AttributeValue, - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, recursion_limit: usize, ) -> Result>, Error> { @@ -139,7 +139,7 @@ pub(super) struct InlinedFunctions<'dwarf> { impl<'dwarf> InlinedFunctions<'dwarf> { pub(crate) fn parse( dw_die_offset: gimli::UnitOffset< as gimli::Reader>::Offset>, - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, ) -> Result { let mut entries = unit.entries_raw(Some(dw_die_offset))?; @@ -283,7 +283,7 @@ pub(crate) struct Functions<'dwarf> { impl<'dwarf> Functions<'dwarf> { pub(crate) fn parse( - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, ) -> Result { let mut functions = Vec::new(); @@ -300,16 +300,13 @@ impl<'dwarf> Functions<'dwarf> { Ok(ref attr) => { match attr.name() { gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => { - if let Ok(val) = - units.dwarf().attr_string(unit, attr.value()) - { + if let Ok(val) = unit.attr_string(attr.value()) { name = Some(val); } } gimli::DW_AT_name => { if name.is_none() { - name = - units.dwarf().attr_string(unit, attr.value()).ok(); + name = unit.attr_string(attr.value()).ok(); } } gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => { @@ -322,8 +319,7 @@ impl<'dwarf> Functions<'dwarf> { ranges.low_pc = Some(val) } gimli::AttributeValue::DebugAddrIndex(index) => { - ranges.low_pc = - Some(units.dwarf().address(unit, index)?); + ranges.low_pc = Some(unit.address(index)?); } _ => {} }, @@ -332,8 +328,7 @@ impl<'dwarf> Functions<'dwarf> { ranges.high_pc = Some(val) } gimli::AttributeValue::DebugAddrIndex(index) => { - ranges.high_pc = - Some(units.dwarf().address(unit, index)?); + ranges.high_pc = Some(unit.address(index)?); } gimli::AttributeValue::Udata(val) => { ranges.size = Some(val) @@ -342,7 +337,7 @@ impl<'dwarf> Functions<'dwarf> { }, gimli::DW_AT_ranges => { ranges.ranges_offset = - units.dwarf().attr_ranges_offset(unit, attr.value())?; + unit.attr_ranges_offset(attr.value())?; } _ => {} }; @@ -352,7 +347,7 @@ impl<'dwarf> Functions<'dwarf> { } let function_index = functions.len(); - let added = ranges.for_each_range(units.dwarf(), unit, |range| { + let added = ranges.for_each_range(unit, |range| { addresses.push(FunctionAddress { range, function: function_index, @@ -394,7 +389,7 @@ impl<'dwarf> Functions<'dwarf> { #[cfg(feature = "nightly")] pub(crate) fn parse_inlined_functions( &self, - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, ) -> Result<(), Error> { for function in &*self.functions { @@ -422,7 +417,7 @@ impl<'dwarf> Function<'dwarf> { fn parse_children( entries: &mut gimli::EntriesRaw<'_, '_, R<'dwarf>>, depth: isize, - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, inlined_functions: &mut Vec>, inlined_addresses: &mut Vec, @@ -460,7 +455,7 @@ impl<'dwarf> Function<'dwarf> { pub(super) fn parse_inlined_functions( &self, - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, ) -> Result<&InlinedFunctions<'dwarf>, Error> { self.inlined_functions @@ -490,7 +485,7 @@ impl<'dwarf> InlinedFunction<'dwarf> { entries: &mut gimli::EntriesRaw<'_, '_, R<'dwarf>>, abbrev: &gimli::Abbreviation, depth: isize, - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, inlined_functions: &mut Vec>, inlined_addresses: &mut Vec, @@ -507,30 +502,29 @@ impl<'dwarf> InlinedFunction<'dwarf> { gimli::DW_AT_low_pc => match attr.value() { gimli::AttributeValue::Addr(val) => ranges.low_pc = Some(val), gimli::AttributeValue::DebugAddrIndex(index) => { - ranges.low_pc = Some(units.dwarf().address(unit, index)?); + ranges.low_pc = Some(unit.address(index)?); } _ => {} }, gimli::DW_AT_high_pc => match attr.value() { gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val), gimli::AttributeValue::DebugAddrIndex(index) => { - ranges.high_pc = Some(units.dwarf().address(unit, index)?); + ranges.high_pc = Some(unit.address(index)?); } gimli::AttributeValue::Udata(val) => ranges.size = Some(val), _ => {} }, gimli::DW_AT_ranges => { - ranges.ranges_offset = - units.dwarf().attr_ranges_offset(unit, attr.value())?; + ranges.ranges_offset = unit.attr_ranges_offset(attr.value())?; } gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => { - if let Ok(val) = units.dwarf().attr_string(unit, attr.value()) { + if let Ok(val) = unit.attr_string(attr.value()) { name = Some(val); } } gimli::DW_AT_name => { if name.is_none() { - name = units.dwarf().attr_string(unit, attr.value()).ok(); + name = unit.attr_string(attr.value()).ok(); } } gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => { @@ -576,7 +570,7 @@ impl<'dwarf> InlinedFunction<'dwarf> { call_column, }); - ranges.for_each_range(units.dwarf(), unit, |range| { + ranges.for_each_range(unit, |range| { inlined_addresses.push(InlinedFunctionAddress { range, call_depth: inlined_depth, diff --git a/src/dwarf/lines.rs b/src/dwarf/lines.rs index f909e584..d54be448 100644 --- a/src/dwarf/lines.rs +++ b/src/dwarf/lines.rs @@ -46,12 +46,11 @@ fn path_push<'p>(path: &'p Path, p: &'p Path) -> Cow<'p, Path> { } fn render_file<'dwarf>( - dw_unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, file: &gimli::FileEntry, as gimli::Reader>::Offset>, header: &gimli::LineProgramHeader, as gimli::Reader>::Offset>, - sections: &gimli::Dwarf>, ) -> Result<(Cow<'dwarf, Path>, &'dwarf OsStr), gimli::Error> { - let dir = if let Some(ref comp_dir) = dw_unit.comp_dir { + let dir = if let Some(ref comp_dir) = unit.comp_dir { Path::new(OsStr::from_bytes(comp_dir.slice())) } else { Path::new("") @@ -61,7 +60,7 @@ fn render_file<'dwarf>( // directory. let dir = if file.directory_index() != 0 { if let Some(directory) = file.directory(header) { - let d = sections.attr_string(dw_unit, directory)?; + let d = unit.attr_string(directory)?; path_push(dir, Path::new(OsStr::from_bytes(d.slice()))) } else { Cow::default() @@ -70,7 +69,7 @@ fn render_file<'dwarf>( Cow::default() }; - let f = sections.attr_string(dw_unit, file.path_name())?; + let f = unit.attr_string(file.path_name())?; let file = OsStr::from_bytes(f.slice()); Ok((dir, file)) } @@ -96,9 +95,8 @@ pub(crate) struct Lines<'dwarf> { impl<'dwarf> Lines<'dwarf> { pub(crate) fn parse( - dw_unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, ilnp: gimli::IncompleteLineProgram, as gimli::Reader>::Offset>, - sections: &gimli::Dwarf>, ) -> Result { let mut sequences = Vec::new(); let mut sequence_rows = Vec::::new(); @@ -147,12 +145,12 @@ impl<'dwarf> Lines<'dwarf> { let mut files = Vec::new(); let header = rows.header(); match header.file(0) { - Some(file) => files.push(render_file(dw_unit, file, header, sections)?), + Some(file) => files.push(render_file(unit, file, header)?), None => files.push(Default::default()), // DWARF version <= 4 may not have 0th index } let mut index = 1; while let Some(file) = header.file(index) { - files.push(render_file(dw_unit, file, header, sections)?); + files.push(render_file(unit, file, header)?); index += 1; } diff --git a/src/dwarf/location.rs b/src/dwarf/location.rs index 8c6f7224..312590be 100644 --- a/src/dwarf/location.rs +++ b/src/dwarf/location.rs @@ -64,7 +64,8 @@ impl<'unit, 'dwarf> LocationRangeUnitIter<'unit, 'dwarf> { probe_low: u64, probe_high: u64, ) -> Result, gimli::Error> { - let lines = unit.parse_lines(units)?; + let unit_ref = units.unit_ref(unit.dw_unit()); + let lines = unit.parse_lines(unit_ref)?; if let Some(lines) = lines { // Find index for probe_low. diff --git a/src/dwarf/range.rs b/src/dwarf/range.rs index 31845bef..3fd81d34 100644 --- a/src/dwarf/range.rs +++ b/src/dwarf/range.rs @@ -47,8 +47,7 @@ impl Default for RangeAttributes { impl RangeAttributes { pub(crate) fn for_each_range( &self, - sections: &gimli::Dwarf, - unit: &gimli::Unit, + unit: gimli::UnitRef<'_, R>, mut f: F, ) -> Result { let mut added_any = false; @@ -59,7 +58,7 @@ impl RangeAttributes { } }; if let Some(ranges_offset) = self.ranges_offset { - let mut range_list = sections.ranges(unit, ranges_offset)?; + let mut range_list = unit.ranges(ranges_offset)?; while let Some(range) = range_list.next()? { add_range(range); } diff --git a/src/dwarf/unit.rs b/src/dwarf/unit.rs index 70fa1788..4f254a04 100644 --- a/src/dwarf/unit.rs +++ b/src/dwarf/unit.rs @@ -73,7 +73,7 @@ impl<'dwarf> Unit<'dwarf> { &'unit self, units: &Units<'dwarf>, ) -> Result<&'unit Functions<'dwarf>, gimli::Error> { - let unit = &self.dw_unit; + let unit = units.unit_ref(&self.dw_unit); let functions = self.parse_functions_dwarf_and_unit(unit, units)?; Ok(functions) } @@ -84,9 +84,8 @@ impl<'dwarf> Unit<'dwarf> { &'unit self, units: &Units<'dwarf>, ) -> Result<&'unit Functions<'dwarf>, gimli::Error> { - let unit = &self.dw_unit; - self.funcs.get_or_try_init(|| { + let unit = units.unit_ref(&self.dw_unit); let funcs = Functions::parse(unit, units)?; let () = funcs.parse_inlined_functions(unit, units)?; Ok(funcs) @@ -95,16 +94,16 @@ impl<'dwarf> Unit<'dwarf> { pub(super) fn parse_lines( &self, - units: &Units<'dwarf>, + unit: gimli::UnitRef<'_, R<'dwarf>>, ) -> Result>, gimli::Error> { // NB: line information is always stored in the main debug file so this does not // need to handle DWOs. - let ilnp = match self.dw_unit.line_program { + let ilnp = match unit.unit.line_program { Some(ref ilnp) => ilnp, None => return Ok(None), }; self.lines - .get_or_try_init(|| Lines::parse(&self.dw_unit, ilnp.clone(), units.dwarf())) + .get_or_try_init(|| Lines::parse(unit, ilnp.clone())) .map(Some) } @@ -125,7 +124,7 @@ impl<'dwarf> Unit<'dwarf> { fn parse_functions_dwarf_and_unit( &self, - unit: &gimli::Unit>, + unit: gimli::UnitRef<'_, R<'dwarf>>, units: &Units<'dwarf>, ) -> Result<&Functions<'dwarf>, gimli::Error> { self.funcs.get_or_try_init(|| Functions::parse(unit, units)) @@ -136,7 +135,7 @@ impl<'dwarf> Unit<'dwarf> { probe: u64, units: &Units<'dwarf>, ) -> Result>, gimli::Error> { - let unit = &self.dw_unit; + let unit = units.unit_ref(&self.dw_unit); let functions = self.parse_functions_dwarf_and_unit(unit, units)?; let function = match functions.find_address(probe) { Some(address) => { @@ -154,7 +153,7 @@ impl<'dwarf> Unit<'dwarf> { name: &str, units: &Units<'dwarf>, ) -> Result>, gimli::Error> { - let unit = &self.dw_unit; + let unit = units.unit_ref(&self.dw_unit); let functions = self.parse_functions_dwarf_and_unit(unit, units)?; for func in functions.functions.iter() { let name = Some(name.as_bytes()); diff --git a/src/dwarf/units.rs b/src/dwarf/units.rs index 3414bcda..d120e9db 100644 --- a/src/dwarf/units.rs +++ b/src/dwarf/units.rs @@ -175,7 +175,8 @@ impl<'dwarf> Units<'dwarf> { } } } else { - have_unit_range |= ranges.for_each_range(§ions, &dw_unit, |range| { + let unit = gimli::UnitRef::new(§ions, &dw_unit); + have_unit_range |= ranges.for_each_range(unit, |range| { unit_ranges.push(UnitRange { range, unit_id, @@ -190,9 +191,10 @@ impl<'dwarf> Units<'dwarf> { // The unit did not declare any ranges. // Try to get some ranges from the line program sequences. if let Some(ref ilnp) = dw_unit.line_program { - if let Ok(lines) = - lines.get_or_try_init(|| Lines::parse(&dw_unit, ilnp.clone(), §ions)) - { + if let Ok(lines) = lines.get_or_try_init(|| { + let unit = gimli::UnitRef::new(§ions, &dw_unit); + Lines::parse(unit, ilnp.clone()) + }) { for sequence in lines.sequences.iter() { unit_ranges.push(UnitRange { range: gimli::Range { @@ -236,7 +238,7 @@ impl<'dwarf> Units<'dwarf> { offset: gimli::DebugInfoOffset< as gimli::Reader>::Offset>, ) -> Result< ( - &gimli::Unit>, + gimli::UnitRef<'_, R<'dwarf>>, gimli::UnitOffset< as gimli::Reader>::Offset>, ), gimli::Error, @@ -253,6 +255,7 @@ impl<'dwarf> Units<'dwarf> { let unit_offset = offset .to_unit_offset(&unit.header) .ok_or(gimli::Error::NoEntryAtGivenOffset)?; + let unit = gimli::UnitRef::new(&self.dwarf, unit); Ok((unit, unit_offset)) } @@ -349,8 +352,9 @@ impl<'dwarf> Units<'dwarf> { >, gimli::Error, > { - let inlined_fns = function.parse_inlined_functions(unit.dw_unit(), self)?; - let iter = inlined_fns.find_inlined_functions(probe).map(|inlined_fn| { + let unit_ref = gimli::UnitRef::new(&self.dwarf, unit.dw_unit()); + let inlined_fns = function.parse_inlined_functions(unit_ref, self)?; + let iter = inlined_fns.find_inlined_functions(probe).map(move |inlined_fn| { let name = inlined_fn .name .map(|name| name.to_string()) @@ -358,7 +362,7 @@ impl<'dwarf> Units<'dwarf> { .unwrap_or(""); let code_info = if let Some(call_file) = inlined_fn.call_file { - if let Some(lines) = unit.parse_lines(self)? { + if let Some(lines) = unit.parse_lines(unit_ref)? { if let Some((dir, file)) = lines.files.get(call_file as usize) { let code_info = Location { dir, @@ -404,6 +408,15 @@ impl<'dwarf> Units<'dwarf> { .filter_map(move |unit| unit.find_name(name, self).transpose()) } + /// Retrieve a [`gimli::UnitRef`] for the provided `unit`. + #[inline] + pub(crate) fn unit_ref<'unit>( + &'unit self, + unit: &'unit gimli::Unit>, + ) -> gimli::UnitRef<'_, R<'dwarf>> { + gimli::UnitRef::new(&self.dwarf, unit) + } + /// Initialize all function data structures. This is used for benchmarks. #[cfg(test)] #[cfg(feature = "nightly")] @@ -430,16 +443,11 @@ impl<'dwarf> Units<'dwarf> { #[cfg(feature = "nightly")] fn parse_lines(&self) -> Result<(), gimli::Error> { for unit in self.units.iter() { - let _lines = unit.parse_lines(self)?; + let unit_ref = self.unit_ref(unit.dw_unit()); + let _lines = unit.parse_lines(unit_ref)?; } Ok(()) } - - /// Retrieve the underlying [`gimli::Dwarf`] object. - #[inline] - pub(super) fn dwarf(&self) -> &gimli::Dwarf> { - &self.dwarf - } }