summaryrefslogtreecommitdiff
path: root/rust/examples
diff options
context:
space:
mode:
authorKyleMiles <krm504@nyu.edu>2023-08-22 13:01:09 -0400
committerKyleMiles <krm504@nyu.edu>2023-08-22 13:01:09 -0400
commit5b73fb82d272aa32ff124a69e96579679e7d3580 (patch)
tree182844e264b4c9ae5727a9a1c86aa7bf0fd462aa /rust/examples
parent02ea8d7309a0c0777ac8a07bfc1e0fd497e9f5f5 (diff)
DWARF Import : Improved Cross-Compilation-Unit Handling
Diffstat (limited to 'rust/examples')
-rw-r--r--rust/examples/dwarf/dwarf_import/src/die_handlers.rs38
-rw-r--r--rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs12
-rw-r--r--rust/examples/dwarf/dwarf_import/src/functions.rs2
-rw-r--r--rust/examples/dwarf/dwarf_import/src/helpers.rs64
-rw-r--r--rust/examples/dwarf/dwarf_import/src/lib.rs18
-rw-r--r--rust/examples/dwarf/dwarf_import/src/types.rs79
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
}