From 20e79d4e43a8734cdc5c4f9ca5b204a2c44aca8e Mon Sep 17 00:00:00 2001 From: KyleMiles Date: Fri, 25 Aug 2023 14:08:25 -0400 Subject: DWARF Import : Misc code cleanup, improvements, and enabling by default changes This includes: Gracefully handle missing DIE references Partially revert 7849cda Misc DWARFv5 Fixes Speed Improvements Fix crash on unexpected EOF Partially revert 0d5fe9ec8963a26361b8bf1af17e029afc87f952 and Correctly initialize DWARF Import plugin --- rust/examples/dwarf/dwarf_import/src/helpers.rs | 236 +++++++++++------------- 1 file changed, 106 insertions(+), 130 deletions(-) (limited to 'rust/examples/dwarf/dwarf_import/src/helpers.rs') diff --git a/rust/examples/dwarf/dwarf_import/src/helpers.rs b/rust/examples/dwarf/dwarf_import/src/helpers.rs index f3b7dd81..05cf6f82 100644 --- a/rust/examples/dwarf/dwarf_import/src/helpers.rs +++ b/rust/examples/dwarf/dwarf_import/src/helpers.rs @@ -12,12 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::DebugInfoBuilderContext; + use gimli::{ constants, Attribute, AttributeValue, - AttributeValue::{DebugInfoRef, DebugInfoRefSup, UnitRef}, - DebuggingInformationEntry, Dwarf, Operation, Reader, Unit, UnitOffset, UnitSectionOffset, + AttributeValue::{DebugInfoRef, UnitRef}, + DebuggingInformationEntry, Operation, Reader, Unit, UnitOffset, UnitSectionOffset, }; +use log::warn; use std::ffi::CString; pub(crate) fn get_uid>( @@ -33,182 +36,136 @@ pub(crate) fn get_uid>( //////////////////////////////////// // DIE attr convenience functions -pub(crate) enum DieReference> { - Offset(UnitOffset), - UnitAndOffset((Unit, UnitOffset)), -} - -fn get_unit_copy<'a, R: Reader>(dwarf: &'a Dwarf, unit: &'a Unit) -> Unit { - let mut iter = dwarf.units(); - while let Ok(Some(header)) = iter.next() { - if header.offset() == unit.header.offset() { - return dwarf.unit(header).unwrap(); - } - } - unreachable!() +pub(crate) enum DieReference<'a, R: Reader> { + UnitAndOffset((&'a Unit, UnitOffset)), + Err, } pub(crate) fn get_attr_die<'a, R: Reader>( - dwarf: &'a Dwarf, - _unit: &'a Unit, - entry: &'a DebuggingInformationEntry, + unit: &'a Unit, + entry: &DebuggingInformationEntry, + debug_info_builder_context: &'a DebugInfoBuilderContext, attr: constants::DwAt, -) -> Option> { +) -> Option> { match entry.attr_value(attr) { - Ok(Some(UnitRef(offset))) => Some(DieReference::Offset(offset)), - Ok(Some(DebugInfoRef(offset))) | Ok(Some(DebugInfoRefSup(offset))) => { - let mut iter = dwarf.units(); - while let Ok(Some(header)) = iter.next() { - if let Some(new_offset) = offset.to_unit_offset(&header) { - return Some(DieReference::UnitAndOffset(( - dwarf.unit(header).unwrap(), - new_offset, - ))); + Ok(Some(UnitRef(offset))) => Some(DieReference::UnitAndOffset((unit, offset))), + Ok(Some(DebugInfoRef(offset))) => { + for source_unit in debug_info_builder_context.units() { + if let Some(new_offset) = offset.to_unit_offset(&source_unit.header) { + return Some(DieReference::UnitAndOffset((source_unit, new_offset))); } } - unreachable!() //None + warn!("Failed to fetch DIE. Debug information may be incomplete."); + None } + // Ok(Some(DebugInfoRefSup(offset))) TODO - dwarf 5 stuff _ => None, } } pub(crate) fn resolve_specification<'a, R: Reader>( - dwarf: &'a Dwarf, unit: &'a Unit, - entry: &'a DebuggingInformationEntry, -) -> DieReference { - if let Some(die_reference) = get_attr_die(dwarf, unit, entry, constants::DW_AT_specification) { - match die_reference { - DieReference::Offset(entry_offset) => { - resolve_specification(dwarf, unit, &unit.entry(entry_offset).unwrap()) - } - DieReference::UnitAndOffset((entry_unit, entry_offset)) => { - resolve_specification_slowpath( - dwarf, - &entry_unit, - &entry_unit.entry(entry_offset).unwrap(), - ) - } - } - } else if let Some(die_reference) = - get_attr_die(dwarf, unit, entry, constants::DW_AT_abstract_origin) - { - match die_reference { - DieReference::Offset(entry_offset) => { - resolve_specification(dwarf, unit, &unit.entry(entry_offset).unwrap()) - } - DieReference::UnitAndOffset((entry_unit, entry_offset)) => { - resolve_specification_slowpath( - dwarf, - &entry_unit, - &entry_unit.entry(entry_offset).unwrap(), - ) - } - } - } else { - DieReference::Offset(entry.offset()) - } -} - -fn resolve_specification_slowpath<'a, R: Reader>( - dwarf: &'a Dwarf, - unit: &'a Unit, - entry: &'a DebuggingInformationEntry, -) -> DieReference { - if let Some(die_reference) = get_attr_die(dwarf, unit, entry, constants::DW_AT_specification) { + entry: &DebuggingInformationEntry, + debug_info_builder_context: &'a DebugInfoBuilderContext, +) -> DieReference<'a, R> { + if let Some(die_reference) = get_attr_die( + unit, + entry, + debug_info_builder_context, + constants::DW_AT_specification, + ) { match die_reference { - DieReference::Offset(entry_offset) => { - resolve_specification_slowpath(dwarf, unit, &unit.entry(entry_offset).unwrap()) - } DieReference::UnitAndOffset((entry_unit, entry_offset)) => { - resolve_specification_slowpath( - dwarf, - &entry_unit, - &entry_unit.entry(entry_offset).unwrap(), - ) + if let Ok(entry) = entry_unit.entry(entry_offset) { + resolve_specification(entry_unit, &entry, debug_info_builder_context) + } else { + warn!("Failed to fetch DIE. Debug information may be incomplete."); + DieReference::Err + } } + DieReference::Err => DieReference::Err, } - } else if let Some(die_reference) = - get_attr_die(dwarf, unit, entry, constants::DW_AT_abstract_origin) - { + } else if let Some(die_reference) = get_attr_die( + unit, + entry, + debug_info_builder_context, + constants::DW_AT_abstract_origin, + ) { match die_reference { - DieReference::Offset(entry_offset) => { - resolve_specification_slowpath(dwarf, unit, &unit.entry(entry_offset).unwrap()) - } DieReference::UnitAndOffset((entry_unit, entry_offset)) => { - resolve_specification_slowpath( - dwarf, - &entry_unit, - &entry_unit.entry(entry_offset).unwrap(), - ) + if let Ok(entry) = entry_unit.entry(entry_offset) { + resolve_specification(entry_unit, &entry, debug_info_builder_context) + } else { + warn!("Failed to fetch DIE. Debug information may be incomplete."); + DieReference::Err + } } + DieReference::Err => DieReference::Err, } } else { - DieReference::UnitAndOffset((get_unit_copy(dwarf, unit), entry.offset())) + DieReference::UnitAndOffset((unit, entry.offset())) } } // Get name from DIE, or referenced dependencies pub(crate) fn get_name>( - dwarf: &Dwarf, unit: &Unit, entry: &DebuggingInformationEntry, + debug_info_builder_context: &DebugInfoBuilderContext, ) -> Option { - match resolve_specification(dwarf, unit, entry) { - DieReference::Offset(entry_offset) => { - if let Ok(Some(attr_val)) = unit - .entry(entry_offset) - .unwrap() - .attr_value(constants::DW_AT_name) - { - if let Ok(attr_string) = dwarf.attr_string(unit, attr_val) { - if let Ok(attr_string) = attr_string.to_string() { - return Some(CString::new(attr_string.to_string()).unwrap()); - } - } - } - None - } + match resolve_specification(unit, entry, debug_info_builder_context) { DieReference::UnitAndOffset((entry_unit, entry_offset)) => { if let Ok(Some(attr_val)) = entry_unit .entry(entry_offset) .unwrap() .attr_value(constants::DW_AT_name) { - if let Ok(attr_string) = dwarf.attr_string(&entry_unit, attr_val) { + if let Ok(attr_string) = debug_info_builder_context + .dwarf() + .attr_string(entry_unit, attr_val) + { if let Ok(attr_string) = attr_string.to_string() { return Some(CString::new(attr_string.to_string()).unwrap()); } } } + + // if let Some(raw_name) = get_raw_name(unit, entry, debug_info_builder_context) { + // if let Some(arch) = debug_info_builder_context.default_architecture() { + // if let Ok((_, names)) = demangle_gnu3(&arch, raw_name, true) { + // return Some(CString::new(names.join("::")).unwrap()); + // } + // } + // } None } + DieReference::Err => None, } } // Get raw name from DIE, or referenced dependencies -pub(crate) fn get_raw_name( - dwarf: &Dwarf, +pub(crate) fn get_raw_name>( unit: &Unit, entry: &DebuggingInformationEntry, + debug_info_builder_context: &DebugInfoBuilderContext, ) -> Option { if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_linkage_name) { - if let Ok(attr_string) = dwarf.attr_string(unit, attr_val) { + if let Ok(attr_string) = debug_info_builder_context + .dwarf() + .attr_string(unit, attr_val) + { if let Ok(attr_string) = attr_string.to_string() { - Some(CString::new(attr_string.to_string()).unwrap()) - } else { - None + return Some(CString::new(attr_string.to_string()).unwrap()); } - } else { - None } - } else { - None } + None } // Get the size of an object as a usize -pub(crate) fn get_size_as_usize(entry: &DebuggingInformationEntry) -> Option { +pub(crate) fn get_size_as_usize>( + entry: &DebuggingInformationEntry, +) -> Option { if let Ok(Some(attr)) = entry.attr(constants::DW_AT_byte_size) { get_attr_as_usize(attr) } else if let Ok(Some(attr)) = entry.attr(constants::DW_AT_bit_size) { @@ -219,7 +176,9 @@ pub(crate) fn get_size_as_usize(entry: &DebuggingInformationEntry) } // Get the size of an object as a u64 -pub(crate) fn get_size_as_u64(entry: &DebuggingInformationEntry) -> Option { +pub(crate) fn get_size_as_u64>( + entry: &DebuggingInformationEntry, +) -> Option { if let Ok(Some(attr)) = entry.attr(constants::DW_AT_byte_size) { get_attr_as_u64(&attr) } else if let Ok(Some(attr)) = entry.attr(constants::DW_AT_bit_size) { @@ -230,7 +189,9 @@ pub(crate) fn get_size_as_u64(entry: &DebuggingInformationEntry) - } // Get the size of a subrange as a u64 -pub(crate) fn get_subrange_size(entry: &DebuggingInformationEntry) -> u64 { +pub(crate) fn get_subrange_size>( + entry: &DebuggingInformationEntry, +) -> u64 { if let Ok(Some(attr)) = entry.attr(constants::DW_AT_upper_bound) { get_attr_as_u64(&attr).map_or(0, |v| v + 1) } else if let Ok(Some(attr)) = entry.attr(constants::DW_AT_count) { @@ -243,24 +204,36 @@ pub(crate) fn get_subrange_size(entry: &DebuggingInformationEntry) } // Get the start address of a function -pub(crate) fn get_start_address( - dwarf: &Dwarf, +pub(crate) fn get_start_address>( unit: &Unit, entry: &DebuggingInformationEntry, + debug_info_builder_context: &DebugInfoBuilderContext, ) -> Option { if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_low_pc) { - match dwarf.attr_address(unit, attr_val) { + match debug_info_builder_context + .dwarf() + .attr_address(unit, attr_val) + { Ok(Some(val)) => Some(val), _ => None, } } else if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_entry_pc) { - match dwarf.attr_address(unit, attr_val) { + match debug_info_builder_context + .dwarf() + .attr_address(unit, attr_val) + { Ok(Some(val)) => Some(val), _ => None, } } else if let Ok(Some(attr_value)) = entry.attr_value(constants::DW_AT_ranges) { - if let Ok(Some(ranges_offset)) = dwarf.attr_ranges_offset(unit, attr_value) { - if let Ok(mut ranges) = dwarf.ranges(unit, ranges_offset) { + if let Ok(Some(ranges_offset)) = debug_info_builder_context + .dwarf() + .attr_ranges_offset(unit, attr_value) + { + if let Ok(mut ranges) = debug_info_builder_context + .dwarf() + .ranges(unit, ranges_offset) + { if let Ok(Some(range)) = ranges.next() { return Some(range.begin); } @@ -273,7 +246,7 @@ pub(crate) fn get_start_address( } // Get an attribute value as a u64 if it can be coerced -pub(crate) fn get_attr_as_u64(attr: &Attribute) -> Option { +pub(crate) fn get_attr_as_u64>(attr: &Attribute) -> Option { if let Some(value) = attr.u8_value() { Some(value.into()) } else if let Some(value) = attr.u16_value() { @@ -286,7 +259,7 @@ pub(crate) fn get_attr_as_u64(attr: &Attribute) -> Option { } // Get an attribute value as a usize if it can be coerced -pub(crate) fn get_attr_as_usize(attr: Attribute) -> Option { +pub(crate) fn get_attr_as_usize>(attr: Attribute) -> Option { if let Some(value) = attr.u8_value() { Some(value.into()) } else if let Some(value) = attr.u16_value() { @@ -300,7 +273,10 @@ pub(crate) fn get_attr_as_usize(attr: Attribute) -> Option // Get an attribute value as a usize if it can be coerced // Parses DW_OP_address, DW_OP_const -pub(crate) fn get_expr_value(unit: &Unit, attr: Attribute) -> Option { +pub(crate) fn get_expr_value>( + unit: &Unit, + attr: Attribute, +) -> Option { if let AttributeValue::Exprloc(mut expression) = attr.value() { match Operation::parse(&mut expression.0, unit.encoding()) { Ok(Operation::PlusConstant { value }) => Some(value), -- cgit v1.3.1