diff options
| author | KyleMiles <krm504@nyu.edu> | 2023-08-22 13:01:09 -0400 |
|---|---|---|
| committer | KyleMiles <krm504@nyu.edu> | 2023-08-22 13:01:09 -0400 |
| commit | 5b73fb82d272aa32ff124a69e96579679e7d3580 (patch) | |
| tree | 182844e264b4c9ae5727a9a1c86aa7bf0fd462aa /rust | |
| parent | 02ea8d7309a0c0777ac8a07bfc1e0fd497e9f5f5 (diff) | |
DWARF Import : Improved Cross-Compilation-Unit Handling
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/die_handlers.rs | 38 | ||||
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs | 12 | ||||
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/functions.rs | 2 | ||||
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/helpers.rs | 64 | ||||
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/lib.rs | 18 | ||||
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/types.rs | 79 |
6 files changed, 107 insertions, 106 deletions
diff --git a/rust/examples/dwarf/dwarf_import/src/die_handlers.rs b/rust/examples/dwarf/dwarf_import/src/die_handlers.rs index 5563b2a5..39e25669 100644 --- a/rust/examples/dwarf/dwarf_import/src/die_handlers.rs +++ b/rust/examples/dwarf/dwarf_import/src/die_handlers.rs @@ -41,12 +41,8 @@ pub fn handle_base_type<R: Reader<Offset = usize>>( // TODO : By spec base types need to have a name, what if it's spec non-conforming? let name = get_name(dwarf, unit, entry).expect("DW_TAG_base does not have name attribute"); - - // TODO : Handle other size specifiers (bits, offset, high_pc?, etc) let size = get_size_as_usize(entry).expect("DW_TAG_base does not have size attribute"); - match entry.attr_value(constants::DW_AT_encoding) { - // TODO : Need more binaries to see what's going on Ok(Some(Encoding(encoding))) => { match encoding { constants::DW_ATE_address => None, @@ -199,25 +195,23 @@ pub fn handle_pointer<R: Reader<Offset = usize>>( Some(reference_type), )) } + } else if let Some(entry_type_offset) = entry_type { + let parent_type = debug_info_builder.get_type(entry_type_offset).unwrap().1; + Some(Type::pointer_of_width( + parent_type.as_ref(), + debug_info_builder.default_address_size(), + false, + false, + Some(reference_type), + )) } else { - if let Some(entry_type_offset) = entry_type { - let parent_type = debug_info_builder.get_type(entry_type_offset).unwrap().1; - Some(Type::pointer_of_width( - parent_type.as_ref(), - debug_info_builder.default_address_size(), - false, - false, - Some(reference_type), - )) - } else { - Some(Type::pointer_of_width( - Type::void().as_ref(), - debug_info_builder.default_address_size(), - false, - false, - Some(reference_type), - )) - } + Some(Type::pointer_of_width( + Type::void().as_ref(), + debug_info_builder.default_address_size(), + false, + false, + Some(reference_type), + )) } } diff --git a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs index fad45f98..7872d8e2 100644 --- a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs +++ b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs @@ -22,7 +22,7 @@ use binaryninja::{ types::{Conf, FunctionParameter, Type}, }; -use gimli::{DebuggingInformationEntry, Reader, Unit}; +use gimli::{DebuggingInformationEntry, Dwarf, Reader, Unit}; use log::error; use std::{ @@ -210,15 +210,13 @@ impl DebugInfoBuilder { pub fn get_name<R: Reader<Offset = usize>>( &self, + dwarf: &Dwarf<R>, unit: &Unit<R>, entry: &DebuggingInformationEntry<R>, ) -> Option<CString> { - self.names - .get(&get_uid( - unit, - &unit.entry(resolve_specification(unit, entry)).unwrap(), - )) - .cloned() + let (entry_unit, entry_offset) = resolve_specification(dwarf, unit, entry); + let entry = entry_unit.entry(entry_offset).unwrap(); + self.names.get(&get_uid(&entry_unit, &entry)).cloned() } fn commit_types(&self, debug_info: &mut DebugInfo) { diff --git a/rust/examples/dwarf/dwarf_import/src/functions.rs b/rust/examples/dwarf/dwarf_import/src/functions.rs index 069f4ba3..652bb8a5 100644 --- a/rust/examples/dwarf/dwarf_import/src/functions.rs +++ b/rust/examples/dwarf/dwarf_import/src/functions.rs @@ -68,7 +68,7 @@ pub fn parse_function_entry<R: Reader<Offset = usize>>( // TODO : Handle OOT, stubs/trampolines // Collect function properties (if they exist in this DIE) - let full_name = debug_info_builder.get_name(unit, entry); + let full_name = debug_info_builder.get_name(dwarf, unit, entry); let raw_name = get_raw_name(dwarf, unit, entry); let return_type = get_type(dwarf, unit, entry, debug_info_builder); let address = get_start_address(dwarf, unit, entry); diff --git a/rust/examples/dwarf/dwarf_import/src/helpers.rs b/rust/examples/dwarf/dwarf_import/src/helpers.rs index 5ea35017..8670e6f4 100644 --- a/rust/examples/dwarf/dwarf_import/src/helpers.rs +++ b/rust/examples/dwarf/dwarf_import/src/helpers.rs @@ -13,8 +13,9 @@ // limitations under the License. use gimli::{ - constants, Attribute, AttributeValue, AttributeValue::UnitRef, DebuggingInformationEntry, - Dwarf, Operation, Reader, Unit, UnitOffset, UnitSectionOffset, + constants, Attribute, AttributeValue, + AttributeValue::{DebugInfoRef, DebugInfoRefSup, UnitRef}, + DebuggingInformationEntry, Dwarf, Operation, Reader, Unit, UnitOffset, UnitSectionOffset, }; use std::ffi::CString; @@ -32,16 +33,52 @@ pub(crate) fn get_uid<R: Reader<Offset = usize>>( //////////////////////////////////// // DIE attr convenience functions -pub fn resolve_specification<R: Reader<Offset = usize>>( - unit: &Unit<R>, - entry: &DebuggingInformationEntry<R>, -) -> UnitOffset { - if let Ok(Some(UnitRef(offset))) = entry.attr_value(constants::DW_AT_specification) { - resolve_specification(unit, &unit.entry(offset).unwrap()) - } else if let Ok(Some(UnitRef(offset))) = entry.attr_value(constants::DW_AT_abstract_origin) { - resolve_specification(unit, &unit.entry(offset).unwrap()) +fn get_unit_copy<'a, R: Reader<Offset = usize>>(dwarf: &'a Dwarf<R>, unit: &'a Unit<R>) -> Unit<R> { + 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) fn get_attr_die<'a, R: Reader<Offset = usize>>( + dwarf: &'a Dwarf<R>, + unit: &'a Unit<R>, + entry: &'a DebuggingInformationEntry<R>, + attr: constants::DwAt, +) -> Option<(Unit<R>, UnitOffset)> { + match entry.attr_value(attr) { + Ok(Some(UnitRef(offset))) => Some((get_unit_copy(dwarf, unit), 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((dwarf.unit(header).unwrap(), new_offset)); + } + } + unreachable!() //None + } + _ => None, + } +} + +pub(crate) fn resolve_specification<'a, R: Reader<Offset = usize>>( + dwarf: &'a Dwarf<R>, + unit: &'a Unit<R>, + entry: &'a DebuggingInformationEntry<R>, +) -> (Unit<R>, UnitOffset) { + if let Some((entry_unit, entry_offset)) = + get_attr_die(dwarf, unit, entry, constants::DW_AT_specification) + { + resolve_specification(dwarf, &entry_unit, &entry_unit.entry(entry_offset).unwrap()) + } else if let Some((entry_unit, entry_offset)) = + get_attr_die(dwarf, unit, entry, constants::DW_AT_abstract_origin) + { + resolve_specification(dwarf, &entry_unit, &entry_unit.entry(entry_offset).unwrap()) } else { - entry.offset() + (get_unit_copy(dwarf, unit), entry.offset()) } } @@ -51,10 +88,11 @@ pub(crate) fn get_name<R: Reader<Offset = usize>>( unit: &Unit<R>, entry: &DebuggingInformationEntry<R>, ) -> Option<CString> { - let entry = unit.entry(resolve_specification(unit, entry)).unwrap(); + let (entry_unit, entry_offset) = resolve_specification(dwarf, unit, entry); + let entry = entry_unit.entry(entry_offset).unwrap(); if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_name) { - if let Ok(attr_string) = dwarf.attr_string(unit, attr_val) { + if let Ok(attr_string) = 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()); } diff --git a/rust/examples/dwarf/dwarf_import/src/lib.rs b/rust/examples/dwarf/dwarf_import/src/lib.rs index 69fe42aa..4a0d5a97 100644 --- a/rust/examples/dwarf/dwarf_import/src/lib.rs +++ b/rust/examples/dwarf/dwarf_import/src/lib.rs @@ -20,7 +20,7 @@ mod types; use crate::dwarfdebuginfo::DebugInfoBuilder; use crate::functions::parse_function_entry; -use crate::helpers::{get_name, get_uid}; +use crate::helpers::{get_attr_die, get_name, get_uid}; use crate::types::parse_data_variable; use binaryninja::{ @@ -33,10 +33,7 @@ use dwarfreader::{ create_section_reader, get_endian, is_dwo_dwarf, is_non_dwo_dwarf, is_raw_dwo_dwarf, }; -use gimli::{ - constants, AttributeValue::UnitRef, DebuggingInformationEntry, Dwarf, DwarfFileType, Reader, - Unit, -}; +use gimli::{constants, DebuggingInformationEntry, Dwarf, DwarfFileType, Reader, SectionId, Unit}; use log::LevelFilter; use std::ffi::CString; @@ -78,13 +75,14 @@ fn recover_names<R: Reader<Offset = usize>>( ) { if let Some(namespace_qualifier) = get_name(dwarf, unit, entry) { namespace_qualifiers.push((depth, namespace_qualifier)); - } else if let Ok(Some(UnitRef(offset))) = - entry.attr_value(constants::DW_AT_extension) + } else if let Some((entry_unit, entry_offset)) = + get_attr_die(dwarf, unit, entry, constants::DW_AT_extension) { + let entry = entry_unit.entry(entry_offset).unwrap(); resolve_namespace_name( dwarf, - unit, - &unit.entry(offset).unwrap(), + &entry_unit, + &entry, namespace_qualifiers, depth, ); @@ -172,7 +170,7 @@ fn parse_unit<R: Reader<Offset = usize>>( dwarf: &Dwarf<R>, unit: &Unit<R>, debug_info_builder: &mut DebugInfoBuilder, - progress: &Box<dyn Fn(usize, usize) -> Result<(), ()>>, + progress: &dyn Fn(usize, usize) -> Result<(), ()>, total_die_count: usize, ) { let mut entries = unit.entries(); diff --git a/rust/examples/dwarf/dwarf_import/src/types.rs b/rust/examples/dwarf/dwarf_import/src/types.rs index 1c7201dc..ca750e19 100644 --- a/rust/examples/dwarf/dwarf_import/src/types.rs +++ b/rust/examples/dwarf/dwarf_import/src/types.rs @@ -23,7 +23,7 @@ use binaryninja::{ }, }; -use gimli::{constants, AttributeValue::UnitRef, DebuggingInformationEntry, Dwarf, Reader, Unit}; +use gimli::{constants, DebuggingInformationEntry, Dwarf, Reader, Unit}; use std::ffi::CString; @@ -33,7 +33,7 @@ pub(crate) fn parse_data_variable<R: Reader<Offset = usize>>( entry: &DebuggingInformationEntry<R>, debug_info_builder: &mut DebugInfoBuilder, ) { - let full_name = debug_info_builder.get_name(unit, entry); + let full_name = debug_info_builder.get_name(dwarf, unit, entry); let type_uid = get_type(dwarf, unit, entry, debug_info_builder); let address = if let Ok(Some(attr)) = entry.attr(constants::DW_AT_location) { @@ -92,7 +92,7 @@ fn do_structure_parse<R: Reader<Offset = usize>>( } let full_name = if get_name(dwarf, unit, entry).is_some() { - debug_info_builder.get_name(unit, entry) + debug_info_builder.get_name(dwarf, unit, entry) } else { None }; @@ -203,54 +203,27 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>( return None; } - // Passing through typedef was necessary at one point, but it seems that parsing has gotten robust enough not to explode on this....leaving it here just in case though - // // Do not trust typedefs; typedefs should be transparent; typedefs mask the base type they refer to, not other typedefs - // // This is the DIE that contains the type of the current DIE - // let entry_type = if entry.tag() == constants::DW_TAG_typedef { - // let mut typedef_type = entry.clone(); - // while typedef_type.tag() == constants::DW_TAG_typedef { - // if let Ok(Some(UnitRef(typedef_type_offset))) = - // typedef_type.attr_value(constants::DW_AT_type) - // { - // typedef_type = unit.entry(typedef_type_offset).unwrap(); - // } else { - // return None; - // } - // } - // get_type(dwarf, unit, &typedef_type, debug_info_builder) - // } else - let entry_type = - if let Ok(Some(UnitRef(entry_type_offset))) = entry.attr_value(constants::DW_AT_type) { - // This needs to recurse first (before the early return below) to ensure all sub-types have been parsed - get_type( - dwarf, - unit, - &unit.entry(entry_type_offset).unwrap(), - debug_info_builder, - ) - } else if let Ok(Some(UnitRef(entry_type_offset))) = - entry.attr_value(constants::DW_AT_specification) - { - // This needs to recurse first (before the early return below) to ensure all sub-types have been parsed - get_type( - dwarf, - unit, - &unit.entry(entry_type_offset).unwrap(), - debug_info_builder, - ) - } else if let Ok(Some(UnitRef(entry_type_offset))) = - entry.attr_value(constants::DW_AT_abstract_origin) - { - // This needs to recurse first (before the early return below) to ensure all sub-types have been parsed - get_type( - dwarf, - unit, - &unit.entry(entry_type_offset).unwrap(), - debug_info_builder, - ) - } else { - None - }; + let entry_type = if let Some((entry_unit, entry_offset)) = + get_attr_die(dwarf, unit, entry, constants::DW_AT_type) + { + // This needs to recurse first (before the early return below) to ensure all sub-types have been parsed + let entry = entry_unit.entry(entry_offset).unwrap(); + get_type(dwarf, &entry_unit, &entry, debug_info_builder) + } else if let Some((entry_unit, entry_offset)) = + get_attr_die(dwarf, unit, entry, constants::DW_AT_specification) + { + // This needs to recurse first (before the early return below) to ensure all sub-types have been parsed + let entry = entry_unit.entry(entry_offset).unwrap(); + get_type(dwarf, &entry_unit, &entry, debug_info_builder) + } else if let Some((entry_unit, entry_offset)) = + get_attr_die(dwarf, unit, entry, constants::DW_AT_abstract_origin) + { + // This needs to recurse first (before the early return below) to ensure all sub-types have been parsed + let entry = entry_unit.entry(entry_offset).unwrap(); + get_type(dwarf, &entry_unit, &entry, debug_info_builder) + } else { + None + }; // If this node (and thus all its referenced nodes) has already been processed, just return the offset // This check is not redundant because this type might have been processes in the recursive calls above @@ -298,7 +271,7 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>( constants::DW_TAG_typedef => handle_typedef( debug_info_builder, entry_type, - debug_info_builder.get_name(unit, entry).unwrap(), + debug_info_builder.get_name(dwarf, unit, entry).unwrap(), ), constants::DW_TAG_pointer_type => ( handle_pointer( @@ -350,7 +323,7 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>( // Wrap our resultant type in a TypeInfo so that the internal DebugInfo class can manage it if let Some(type_def) = type_def { let name = if get_name(dwarf, unit, entry).is_some() { - debug_info_builder.get_name(unit, entry) + debug_info_builder.get_name(dwarf, unit, entry) } else { None } |
