summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Ferrell <josh@vector35.com>2024-07-18 14:05:23 -0400
committerJosh Ferrell <josh@vector35.com>2024-07-18 15:58:28 -0400
commit6a496b01b3e8a85c8231c949a306933e7ad58bfc (patch)
tree07d0a26da2a4a4648e3caafcfe9ecd0bce5e1606
parentdb0eb3ad8270c46a6938a6d0c03e316d80306357 (diff)
Support loading supplementary DWARF files
-rw-r--r--rust/Cargo.lock4
-rw-r--r--rust/examples/dwarf/dwarf_export/Cargo.toml2
-rw-r--r--rust/examples/dwarf/dwarf_import/Cargo.toml2
-rw-r--r--rust/examples/dwarf/dwarf_import/src/die_handlers.rs33
-rw-r--r--rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs43
-rw-r--r--rust/examples/dwarf/dwarf_import/src/functions.rs23
-rw-r--r--rust/examples/dwarf/dwarf_import/src/helpers.rs183
-rw-r--r--rust/examples/dwarf/dwarf_import/src/lib.rs178
-rw-r--r--rust/examples/dwarf/dwarf_import/src/types.rs77
-rw-r--r--rust/examples/dwarf/dwarfdump/Cargo.toml2
-rw-r--r--rust/examples/dwarf/shared/Cargo.toml2
11 files changed, 362 insertions, 187 deletions
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index 23078ec8..2b1afe26 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -415,9 +415,9 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.28.1"
+version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
+checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
dependencies = [
"fallible-iterator 0.3.0",
"indexmap",
diff --git a/rust/examples/dwarf/dwarf_export/Cargo.toml b/rust/examples/dwarf/dwarf_export/Cargo.toml
index 5f537c69..715686f2 100644
--- a/rust/examples/dwarf/dwarf_export/Cargo.toml
+++ b/rust/examples/dwarf/dwarf_export/Cargo.toml
@@ -8,6 +8,6 @@ crate-type = ["cdylib"]
[dependencies]
binaryninja = {path="../../../"}
-gimli = "^0.28"
+gimli = "^0.31"
log = "^0.4"
object = { version = "0.32.1", features = ["write"] }
diff --git a/rust/examples/dwarf/dwarf_import/Cargo.toml b/rust/examples/dwarf/dwarf_import/Cargo.toml
index 1dfae181..838e435e 100644
--- a/rust/examples/dwarf/dwarf_import/Cargo.toml
+++ b/rust/examples/dwarf/dwarf_import/Cargo.toml
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
[dependencies]
dwarfreader = { path = "../shared/" }
binaryninja = { path = "../../../" }
-gimli = "0.28"
+gimli = "0.31"
log = "0.4.20"
iset = "0.2.2"
cpp_demangle = "0.4.3"
diff --git a/rust/examples/dwarf/dwarf_import/src/die_handlers.rs b/rust/examples/dwarf/dwarf_import/src/die_handlers.rs
index be77a414..51d52d5b 100644
--- a/rust/examples/dwarf/dwarf_import/src/die_handlers.rs
+++ b/rust/examples/dwarf/dwarf_import/src/die_handlers.rs
@@ -13,7 +13,7 @@
// limitations under the License.
use crate::dwarfdebuginfo::{DebugInfoBuilder, DebugInfoBuilderContext, TypeUID};
-use crate::helpers::*;
+use crate::{helpers::*, ReaderType};
use crate::types::get_type;
use binaryninja::{
@@ -21,9 +21,11 @@ use binaryninja::{
types::{EnumerationBuilder, FunctionParameter, ReferenceType, Type, TypeBuilder},
};
-use gimli::{constants, AttributeValue::Encoding, DebuggingInformationEntry, Reader, Unit};
+use gimli::Dwarf;
+use gimli::{constants, AttributeValue::Encoding, DebuggingInformationEntry, Unit};
-pub(crate) fn handle_base_type<R: Reader<Offset = usize>>(
+pub(crate) fn handle_base_type<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
@@ -37,7 +39,7 @@ pub(crate) fn handle_base_type<R: Reader<Offset = usize>>(
// *Some indication of signedness?
// * = Optional
- let name = debug_info_builder_context.get_name(unit, entry)?;
+ let name = debug_info_builder_context.get_name(dwarf, unit, entry)?;
let size = get_size_as_usize(entry)?;
match entry.attr_value(constants::DW_AT_encoding) {
Ok(Some(Encoding(encoding))) => {
@@ -69,7 +71,8 @@ pub(crate) fn handle_base_type<R: Reader<Offset = usize>>(
}
}
-pub(crate) fn handle_enum<R: Reader<Offset = usize>>(
+pub(crate) fn handle_enum<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
@@ -107,7 +110,7 @@ pub(crate) fn handle_enum<R: Reader<Offset = usize>>(
let mut children = tree.root().unwrap().children();
while let Ok(Some(child)) = children.next() {
if child.entry().tag() == constants::DW_TAG_enumerator {
- let name = debug_info_builder_context.get_name(unit, child.entry())?;
+ let name = debug_info_builder_context.get_name(dwarf, unit, child.entry())?;
let attr = &child
.entry()
.attr(constants::DW_AT_const_value)
@@ -150,7 +153,7 @@ pub(crate) fn handle_typedef(
(None, false)
}
-pub(crate) fn handle_pointer<R: Reader<Offset = usize>>(
+pub(crate) fn handle_pointer<R: ReaderType>(
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
debug_info_builder: &mut DebugInfoBuilder,
@@ -206,7 +209,7 @@ pub(crate) fn handle_pointer<R: Reader<Offset = usize>>(
}
}
-pub(crate) fn handle_array<R: Reader<Offset = usize>>(
+pub(crate) fn handle_array<R: ReaderType>(
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder: &mut DebugInfoBuilder,
@@ -252,7 +255,8 @@ pub(crate) fn handle_array<R: Reader<Offset = usize>>(
}
}
-pub(crate) fn handle_function<R: Reader<Offset = usize>>(
+pub(crate) fn handle_function<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
@@ -292,9 +296,9 @@ pub(crate) fn handle_function<R: Reader<Offset = usize>>(
};
// Alias function type in the case that it contains itself
- if let Some(name) = debug_info_builder_context.get_name(unit, entry) {
+ if let Some(name) = debug_info_builder_context.get_name(dwarf, unit, entry) {
debug_info_builder.add_type(
- get_uid(unit, entry),
+ get_uid(dwarf, unit, entry),
&name,
Type::named_type_from_type(
&name,
@@ -315,12 +319,13 @@ pub(crate) fn handle_function<R: Reader<Offset = usize>>(
if let (Some(child_uid), Some(name)) = {
(
get_type(
+ dwarf,
unit,
child.entry(),
debug_info_builder_context,
debug_info_builder,
),
- debug_info_builder_context.get_name(unit, child.entry()),
+ debug_info_builder_context.get_name(dwarf, unit, child.entry()),
)
} {
let child_type = debug_info_builder.get_type(child_uid).unwrap().get_type();
@@ -331,8 +336,8 @@ pub(crate) fn handle_function<R: Reader<Offset = usize>>(
}
}
- if debug_info_builder_context.get_name(unit, entry).is_some() {
- debug_info_builder.remove_type(get_uid(unit, entry));
+ if debug_info_builder_context.get_name(dwarf, unit, entry).is_some() {
+ debug_info_builder.remove_type(get_uid(dwarf, unit, entry));
}
Some(Type::function(
diff --git a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
index 0e0e8f53..4cb64138 100644
--- a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
+++ b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use crate::helpers::{get_uid, resolve_specification, DieReference};
+use crate::{helpers::{get_uid, resolve_specification, DieReference}, ReaderType};
use binaryninja::{
binaryview::{BinaryView, BinaryViewBase, BinaryViewExt},
@@ -25,7 +25,7 @@ use binaryninja::{
binaryninjacore_sys::BNVariableSourceType,
};
-use gimli::{DebuggingInformationEntry, Dwarf, Reader, Unit};
+use gimli::{DebuggingInformationEntry, Dwarf, Unit};
use log::{debug, error, warn};
use std::{
@@ -111,16 +111,17 @@ impl DebugType {
}
}
-pub(crate) struct DebugInfoBuilderContext<R: Reader<Offset = usize>> {
- dwarf: Dwarf<R>,
+pub(crate) struct DebugInfoBuilderContext<R: ReaderType> {
units: Vec<Unit<R>>,
+ sup_units: Vec<Unit<R>>,
names: HashMap<TypeUID, String>,
default_address_size: usize,
pub(crate) total_die_count: usize,
}
-impl<R: Reader<Offset = usize>> DebugInfoBuilderContext<R> {
- pub(crate) fn new(view: &BinaryView, dwarf: Dwarf<R>) -> Option<Self> {
+impl<R: ReaderType> DebugInfoBuilderContext<R> {
+ pub(crate) fn new(view: &BinaryView, dwarf: &Dwarf<R>) -> Option<Self> {
+
let mut units = vec![];
let mut iter = dwarf.units();
while let Ok(Some(header)) = iter.next() {
@@ -132,40 +133,56 @@ impl<R: Reader<Offset = usize>> DebugInfoBuilderContext<R> {
}
}
+ let mut sup_units = vec![];
+ if let Some(sup_dwarf) = dwarf.sup() {
+ let mut sup_iter = sup_dwarf.units();
+ while let Ok(Some(header)) = sup_iter.next() {
+ if let Ok(unit) = sup_dwarf.unit(header) {
+ sup_units.push(unit);
+ } else {
+ error!("Unable to read supplementary DWARF information. File may be malformed or corrupted. Not applying debug info.");
+ return None;
+ }
+ }
+ }
+
Some(Self {
- dwarf,
units,
+ sup_units,
names: HashMap::new(),
default_address_size: view.address_size(),
total_die_count: 0,
})
}
- pub(crate) fn dwarf(&self) -> &Dwarf<R> {
- &self.dwarf
- }
-
pub(crate) fn units(&self) -> &[Unit<R>] {
&self.units
}
+ pub(crate) fn sup_units(&self) -> &[Unit<R>] {
+ &self.sup_units
+ }
+
pub(crate) fn default_address_size(&self) -> usize {
self.default_address_size
}
pub(crate) fn set_name(&mut self, die_uid: TypeUID, name: String) {
+ // die_uids need to be unique here
assert!(self.names.insert(die_uid, name).is_none());
}
pub(crate) fn get_name(
&self,
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
) -> Option<String> {
- match resolve_specification(unit, entry, self) {
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => self
+ match resolve_specification(dwarf, unit, entry, self) {
+ DieReference::UnitAndOffset((dwarf, entry_unit, entry_offset)) => self
.names
.get(&get_uid(
+ dwarf,
entry_unit,
&entry_unit.entry(entry_offset).unwrap(),
))
diff --git a/rust/examples/dwarf/dwarf_import/src/functions.rs b/rust/examples/dwarf/dwarf_import/src/functions.rs
index f418a47f..ea6aba4d 100644
--- a/rust/examples/dwarf/dwarf_import/src/functions.rs
+++ b/rust/examples/dwarf/dwarf_import/src/functions.rs
@@ -15,15 +15,16 @@
use std::sync::OnceLock;
use crate::dwarfdebuginfo::{DebugInfoBuilder, DebugInfoBuilderContext, TypeUID};
-use crate::helpers::*;
+use crate::{helpers::*, ReaderType};
use crate::types::get_type;
use binaryninja::templatesimplifier::simplify_str_to_str;
use cpp_demangle::DemangleOptions;
-use gimli::{constants, DebuggingInformationEntry, Reader, Unit};
+use gimli::{constants, DebuggingInformationEntry, Dwarf, Unit};
use regex::Regex;
-fn get_parameters<R: Reader<Offset = usize>>(
+fn get_parameters<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
@@ -45,9 +46,10 @@ fn get_parameters<R: Reader<Offset = usize>>(
constants::DW_TAG_formal_parameter => {
//TODO: if the param type is a typedef to an anonymous struct (typedef struct {...} foo) then this is reoslved to an anonymous struct instead of foo
// We should still recurse to make sure we load all types this param type depends on, but
- let name = debug_info_builder_context.get_name(unit, child.entry());
+ let name = debug_info_builder_context.get_name(dwarf, unit, child.entry());
let type_ = get_type(
+ dwarf,
unit,
child.entry(),
debug_info_builder_context,
@@ -70,17 +72,18 @@ fn get_parameters<R: Reader<Offset = usize>>(
(result, variable_arguments)
}
-pub(crate) fn parse_function_entry<R: Reader<Offset = usize>>(
+pub(crate) fn parse_function_entry<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
debug_info_builder: &mut DebugInfoBuilder,
) -> Option<usize> {
// Collect function properties (if they exist in this DIE)
- let raw_name = get_raw_name(unit, entry, debug_info_builder_context);
- let return_type = get_type(unit, entry, debug_info_builder_context, debug_info_builder);
- let address = get_start_address(unit, entry, debug_info_builder_context);
- let (parameters, variable_arguments) = get_parameters(unit, entry, debug_info_builder_context, debug_info_builder);
+ let raw_name = get_raw_name(dwarf, unit, entry);
+ let return_type = get_type(dwarf, unit, entry, debug_info_builder_context, debug_info_builder);
+ let address = get_start_address(dwarf, unit, entry);
+ let (parameters, variable_arguments) = get_parameters(dwarf, unit, entry, debug_info_builder_context, debug_info_builder);
// If we have a raw name, it might be mangled, see if we can demangle it into full_name
// raw_name should contain a superset of the info we have in full_name
@@ -111,7 +114,7 @@ pub(crate) fn parse_function_entry<R: Reader<Offset = usize>>(
// If we didn't demangle the raw name, fetch the name given
if full_name.is_none() {
- full_name = debug_info_builder_context.get_name(unit, entry)
+ full_name = debug_info_builder_context.get_name(dwarf, unit, entry)
}
debug_info_builder.insert_function(full_name, raw_name, return_type, address, &parameters, variable_arguments)
diff --git a/rust/examples/dwarf/dwarf_import/src/helpers.rs b/rust/examples/dwarf/dwarf_import/src/helpers.rs
index 92b08bce..7127b2b8 100644
--- a/rust/examples/dwarf/dwarf_import/src/helpers.rs
+++ b/rust/examples/dwarf/dwarf_import/src/helpers.rs
@@ -20,127 +20,171 @@ use std::{
str::FromStr
};
-use crate::DebugInfoBuilderContext;
+use crate::{DebugInfoBuilderContext, ReaderType};
use binaryninja::binaryview::BinaryViewBase;
use binaryninja::filemetadata::FileMetadata;
use binaryninja::Endianness;
use binaryninja::{binaryview::{BinaryView, BinaryViewExt}, downloadprovider::{DownloadInstanceInputOutputCallbacks, DownloadProvider}, rc::Ref, settings::Settings};
+use gimli::Dwarf;
use gimli::{
constants, Attribute, AttributeValue,
- AttributeValue::{DebugInfoRef, UnitRef},
- DebuggingInformationEntry, Operation, Reader, Unit, UnitOffset, UnitSectionOffset,
+ AttributeValue::{DebugInfoRef, DebugInfoRefSup, UnitRef},
+ DebuggingInformationEntry, Operation, Unit, UnitOffset, UnitSectionOffset,
};
use log::warn;
-pub(crate) fn get_uid<R: Reader<Offset = usize>>(
+pub(crate) fn get_uid<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
) -> usize {
- match entry.offset().to_unit_section_offset(unit) {
+ // We set a large gap between supplementary and main entries
+ let adj = dwarf.sup().map_or(0, |_| 0x1000000000000000);
+ let entry_offset = match entry.offset().to_unit_section_offset(unit) {
UnitSectionOffset::DebugInfoOffset(o) => o.0,
UnitSectionOffset::DebugTypesOffset(o) => o.0,
- }
+ };
+ entry_offset + adj
}
////////////////////////////////////
// DIE attr convenience functions
-pub(crate) enum DieReference<'a, R: Reader<Offset = usize>> {
- UnitAndOffset((&'a Unit<R>, UnitOffset)),
+pub(crate) enum DieReference<'a, R: ReaderType> {
+ UnitAndOffset((&'a Dwarf<R>, &'a Unit<R>, UnitOffset)),
Err,
}
-pub(crate) fn get_attr_die<'a, R: Reader<Offset = usize>>(
+pub(crate) fn get_attr_die<'a, R: ReaderType>(
+ dwarf: &'a Dwarf<R>,
unit: &'a Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &'a DebugInfoBuilderContext<R>,
attr: constants::DwAt,
) -> Option<DieReference<'a, R>> {
match entry.attr_value(attr) {
- Ok(Some(UnitRef(offset))) => Some(DieReference::UnitAndOffset((unit, offset))),
+ Ok(Some(UnitRef(offset))) => Some(DieReference::UnitAndOffset((dwarf, unit, offset))),
Ok(Some(DebugInfoRef(offset))) => {
- for source_unit in debug_info_builder_context.units() {
+ if dwarf.sup().is_some() {
+ 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((dwarf, source_unit, new_offset)));
+ }
+ }
+ }
+ else {
+ // This could either have no supplementary file because it is one or because it just doesn't have one
+ // operate on supplementary file if dwarf is a supplementary file, else self
+
+ // It's possible this is a reference in the supplementary file to itself
+ for source_unit in debug_info_builder_context.sup_units() {
+ if let Some(new_offset) = offset.to_unit_offset(&source_unit.header) {
+ return Some(DieReference::UnitAndOffset((dwarf, source_unit, new_offset)));
+ }
+ }
+
+ // ... or it just doesn't have a supplementary file
+ 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((dwarf, source_unit, new_offset)));
+ }
+ }
+ }
+
+ None
+ },
+ Ok(Some(DebugInfoRefSup(offset))) => {
+ for source_unit in debug_info_builder_context.sup_units() {
if let Some(new_offset) = offset.to_unit_offset(&source_unit.header) {
- return Some(DieReference::UnitAndOffset((source_unit, new_offset)));
+ return Some(DieReference::UnitAndOffset((dwarf.sup().unwrap(), source_unit, new_offset)));
}
}
- warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ warn!("Failed to fetch DIE. Supplementary debug information may be incomplete.");
None
- }
- // Ok(Some(DebugInfoRefSup(offset))) TODO - dwarf 5 stuff
+ },
_ => None,
}
}
-pub(crate) fn resolve_specification<'a, R: Reader<Offset = usize>>(
+pub(crate) fn resolve_specification<'a, R: ReaderType>(
+ dwarf: &'a Dwarf<R>,
unit: &'a Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &'a DebugInfoBuilderContext<R>,
) -> DieReference<'a, R> {
if let Some(die_reference) = get_attr_die(
+ dwarf,
unit,
entry,
debug_info_builder_context,
constants::DW_AT_specification,
) {
match die_reference {
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
+ DieReference::UnitAndOffset((dwarf, entry_unit, entry_offset)) => {
if let Ok(entry) = entry_unit.entry(entry_offset) {
- resolve_specification(entry_unit, &entry, debug_info_builder_context)
+ resolve_specification(dwarf, entry_unit, &entry, debug_info_builder_context)
} else {
- warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ warn!("Failed to fetch DIE for attr DW_AT_specification. Debug information may be incomplete.");
DieReference::Err
}
}
DieReference::Err => DieReference::Err,
}
} else if let Some(die_reference) = get_attr_die(
+ dwarf,
unit,
entry,
debug_info_builder_context,
constants::DW_AT_abstract_origin,
) {
match die_reference {
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
- if entry_offset == entry.offset() {
+ DieReference::UnitAndOffset((dwarf, entry_unit, entry_offset)) => {
+ if entry_offset == entry.offset() && unit.header.offset() == entry_unit.header.offset() {
warn!("DWARF information is invalid (infinite abstract origin reference cycle). Debug information may be incomplete.");
DieReference::Err
} else if let Ok(new_entry) = entry_unit.entry(entry_offset) {
- resolve_specification(entry_unit, &new_entry, debug_info_builder_context)
+ resolve_specification(dwarf, entry_unit, &new_entry, debug_info_builder_context)
} else {
- warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ warn!("Failed to fetch DIE for attr DW_AT_abstract_origin. Debug information may be incomplete.");
DieReference::Err
}
}
DieReference::Err => DieReference::Err,
}
} else {
- DieReference::UnitAndOffset((unit, entry.offset()))
+ DieReference::UnitAndOffset((dwarf, unit, entry.offset()))
}
}
// Get name from DIE, or referenced dependencies
-pub(crate) fn get_name<R: Reader<Offset = usize>>(
+pub(crate) fn get_name<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
) -> Option<String> {
- match resolve_specification(unit, entry, debug_info_builder_context) {
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
+ match resolve_specification(dwarf, unit, entry, debug_info_builder_context) {
+ DieReference::UnitAndOffset((dwarf, 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) = debug_info_builder_context
- .dwarf()
- .attr_string(entry_unit, attr_val)
+ if let Ok(attr_string) = dwarf.attr_string(entry_unit, attr_val.clone())
{
if let Ok(attr_string) = attr_string.to_string() {
return Some(attr_string.to_string());
}
}
+ else if let Some(dwarf) = &dwarf.sup {
+ if let Ok(attr_string) = dwarf.attr_string(entry_unit, attr_val)
+ {
+ if let Ok(attr_string) = attr_string.to_string() {
+ return Some(attr_string.to_string());
+ }
+ }
+ }
}
// if let Some(raw_name) = get_raw_name(unit, entry, debug_info_builder_context) {
@@ -157,26 +201,32 @@ pub(crate) fn get_name<R: Reader<Offset = usize>>(
}
// Get raw name from DIE, or referenced dependencies
-pub(crate) fn get_raw_name<R: Reader<Offset = usize>>(
+pub(crate) fn get_raw_name<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
- debug_info_builder_context: &DebugInfoBuilderContext<R>,
) -> Option<String> {
if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_linkage_name) {
- if let Ok(attr_string) = debug_info_builder_context
- .dwarf()
- .attr_string(unit, attr_val)
+ if let Ok(attr_string) = dwarf.attr_string(unit, attr_val.clone())
{
if let Ok(attr_string) = attr_string.to_string() {
return Some(attr_string.to_string());
}
}
+ else if let Some(dwarf) = dwarf.sup() {
+ if let Ok(attr_string) = dwarf.attr_string(unit, attr_val)
+ {
+ if let Ok(attr_string) = attr_string.to_string() {
+ return Some(attr_string.to_string());
+ }
+ }
+ }
}
None
}
// Get the size of an object as a usize
-pub(crate) fn get_size_as_usize<R: Reader<Offset = usize>>(
+pub(crate) fn get_size_as_usize<R: ReaderType>(
entry: &DebuggingInformationEntry<R>,
) -> Option<usize> {
if let Ok(Some(attr)) = entry.attr(constants::DW_AT_byte_size) {
@@ -189,7 +239,7 @@ pub(crate) fn get_size_as_usize<R: Reader<Offset = usize>>(
}
// Get the size of an object as a u64
-pub(crate) fn get_size_as_u64<R: Reader<Offset = usize>>(
+pub(crate) fn get_size_as_u64<R: ReaderType>(
entry: &DebuggingInformationEntry<R>,
) -> Option<u64> {
if let Ok(Some(attr)) = entry.attr(constants::DW_AT_byte_size) {
@@ -202,7 +252,7 @@ pub(crate) fn get_size_as_u64<R: Reader<Offset = usize>>(
}
// Get the size of a subrange as a u64
-pub(crate) fn get_subrange_size<R: Reader<Offset = usize>>(
+pub(crate) fn get_subrange_size<R: ReaderType>(
entry: &DebuggingInformationEntry<R>,
) -> u64 {
if let Ok(Some(attr)) = entry.attr(constants::DW_AT_upper_bound) {
@@ -217,35 +267,27 @@ pub(crate) fn get_subrange_size<R: Reader<Offset = usize>>(
}
// Get the start address of a function
-pub(crate) fn get_start_address<R: Reader<Offset = usize>>(
+pub(crate) fn get_start_address<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
- debug_info_builder_context: &DebugInfoBuilderContext<R>,
) -> Option<u64> {
if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_low_pc) {
- match debug_info_builder_context
- .dwarf()
- .attr_address(unit, attr_val)
+ match 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 debug_info_builder_context
- .dwarf()
- .attr_address(unit, attr_val)
+ match 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)) = debug_info_builder_context
- .dwarf()
- .attr_ranges_offset(unit, attr_value)
+ if let Ok(Some(ranges_offset)) = dwarf.attr_ranges_offset(unit, attr_value)
{
- if let Ok(mut ranges) = debug_info_builder_context
- .dwarf()
- .ranges(unit, ranges_offset)
+ if let Ok(mut ranges) = dwarf.ranges(unit, ranges_offset)
{
if let Ok(Some(range)) = ranges.next() {
return Some(range.begin);
@@ -259,7 +301,7 @@ pub(crate) fn get_start_address<R: Reader<Offset = usize>>(
}
// Get an attribute value as a u64 if it can be coerced
-pub(crate) fn get_attr_as_u64<R: Reader<Offset = usize>>(attr: &Attribute<R>) -> Option<u64> {
+pub(crate) fn get_attr_as_u64<R: ReaderType>(attr: &Attribute<R>) -> Option<u64> {
if let Some(value) = attr.udata_value() {
Some(value)
} else if let Some(value) = attr.sdata_value() {
@@ -278,7 +320,7 @@ pub(crate) fn get_attr_as_u64<R: Reader<Offset = usize>>(attr: &Attribute<R>) ->
}
// Get an attribute value as a usize if it can be coerced
-pub(crate) fn get_attr_as_usize<R: Reader<Offset = usize>>(attr: Attribute<R>) -> Option<usize> {
+pub(crate) fn get_attr_as_usize<R: ReaderType>(attr: Attribute<R>) -> Option<usize> {
if let Some(value) = attr.u8_value() {
Some(value.into())
} else if let Some(value) = attr.u16_value() {
@@ -292,7 +334,7 @@ pub(crate) fn get_attr_as_usize<R: Reader<Offset = usize>>(attr: Attribute<R>) -
// 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<R: Reader<Offset = usize>>(
+pub(crate) fn get_expr_value<R: ReaderType>(
unit: &Unit<R>,
attr: Attribute<R>,
) -> Option<u64> {
@@ -365,11 +407,9 @@ pub(crate) fn get_build_id(view: &BinaryView) -> Result<String, String> {
}
-pub(crate) fn download_debug_info(view: &BinaryView) -> Result<Ref<BinaryView>, String> {
+pub(crate) fn download_debug_info(build_id: &String, view: &BinaryView) -> Result<Ref<BinaryView>, String> {
let settings = Settings::new("");
- let build_id = get_build_id(view)?;
-
let debug_server_urls = settings.get_string_list("network.debuginfodServers", Some(view), None);
for debug_server_url in debug_server_urls.iter() {
@@ -438,7 +478,7 @@ pub(crate) fn download_debug_info(view: &BinaryView) -> Result<Ref<BinaryView>,
}
-pub(crate) fn find_local_debug_file(view: &BinaryView) -> Option<String> {
+pub(crate) fn find_local_debug_file(build_id: &String, view: &BinaryView) -> Option<String> {
let settings = Settings::new("");
let debug_info_paths = settings.get_string_list("analysis.debugInfo.debugDirectories", Some(view), None);
@@ -446,11 +486,6 @@ pub(crate) fn find_local_debug_file(view: &BinaryView) -> Option<String> {
return None
}
- let build_id = match get_build_id(view) {
- Ok(x) => x,
- Err(_) => return None,
- };
-
for debug_info_path in debug_info_paths.into_iter() {
if let Ok(path) = PathBuf::from_str(&debug_info_path.to_string())
{
@@ -482,17 +517,23 @@ pub(crate) fn find_local_debug_file(view: &BinaryView) -> Option<String> {
}
-pub(crate) fn load_debug_info_for_build_id(view: &BinaryView) -> Result<Option<Ref<BinaryView>>, String> {
- if let Some(debug_file_path) = find_local_debug_file(view) {
- Ok(
+pub(crate) fn load_debug_info_for_build_id(build_id: &String, view: &BinaryView) -> (Option<Ref<BinaryView>>, bool) {
+ if let Some(debug_file_path) = find_local_debug_file(build_id, view) {
+ return
+ (
binaryninja::load_with_options(
debug_file_path,
false,
Some("{\"analysis.debugInfo.internal\": false}")
- )
- )
+ ),
+ false
+ );
}
- else {
- Ok(None)
+ else if Settings::new("").get_bool("network.enableDebuginfod", Some(view), None) {
+ return (
+ download_debug_info(build_id, view).ok(),
+ true
+ );
}
+ (None, false)
}
diff --git a/rust/examples/dwarf/dwarf_import/src/lib.rs b/rust/examples/dwarf/dwarf_import/src/lib.rs
index 374baa37..78c99123 100644
--- a/rust/examples/dwarf/dwarf_import/src/lib.rs
+++ b/rust/examples/dwarf/dwarf_import/src/lib.rs
@@ -39,15 +39,39 @@ use dwarfreader::{
use gimli::{constants, DebuggingInformationEntry, Dwarf, DwarfFileType, Reader, Section, SectionId, Unit, UnwindSection};
+use helpers::{get_build_id, load_debug_info_for_build_id};
use log::{error, warn, LevelFilter};
-fn recover_names<R: Reader<Offset = usize>>(
+
+trait ReaderType: Reader<Offset = usize> {}
+impl<T: Reader<Offset = usize>> ReaderType for T {}
+
+
+fn recover_names<R: ReaderType>(
+ dwarf: &Dwarf<R>,
debug_info_builder_context: &mut DebugInfoBuilderContext<R>,
progress: &dyn Fn(usize, usize) -> Result<(), ()>,
) -> bool {
- let mut iter = debug_info_builder_context.dwarf().units();
+
+ let mut res = true;
+ if let Some(sup_dwarf) = dwarf.sup() {
+ res = recover_names_internal(sup_dwarf, debug_info_builder_context, progress);
+ }
+
+ if res {
+ res = recover_names_internal(dwarf, debug_info_builder_context, progress);
+ }
+ res
+}
+
+fn recover_names_internal<R: ReaderType>(
+ dwarf: &Dwarf<R>,
+ debug_info_builder_context: &mut DebugInfoBuilderContext<R>,
+ progress: &dyn Fn(usize, usize) -> Result<(), ()>,
+) -> bool {
+ let mut iter = dwarf.units();
while let Ok(Some(header)) = iter.next() {
- let unit = debug_info_builder_context.dwarf().unit(header).unwrap();
+ let unit = dwarf.unit(header).unwrap();
let mut namespace_qualifiers: Vec<(isize, String)> = vec![];
let mut entries = unit.entries();
let mut depth = 0;
@@ -76,7 +100,8 @@ fn recover_names<R: Reader<Offset = usize>>(
match entry.tag() {
constants::DW_TAG_namespace => {
- fn resolve_namespace_name<R: Reader<Offset = usize>>(
+ fn resolve_namespace_name<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
@@ -84,18 +109,20 @@ fn recover_names<R: Reader<Offset = usize>>(
depth: isize,
) {
if let Some(namespace_qualifier) =
- get_name(unit, entry, debug_info_builder_context)
+ get_name(dwarf, unit, entry, debug_info_builder_context)
{
namespace_qualifiers.push((depth, namespace_qualifier));
} else if let Some(die_reference) = get_attr_die(
+ dwarf,
unit,
entry,
debug_info_builder_context,
constants::DW_AT_extension,
) {
match die_reference {
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => {
+ DieReference::UnitAndOffset((dwarf, entry_unit, entry_offset)) => {
resolve_namespace_name(
+ dwarf,
entry_unit,
&entry_unit.entry(entry_offset).unwrap(),
debug_info_builder_context,
@@ -105,7 +132,7 @@ fn recover_names<R: Reader<Offset = usize>>(
}
DieReference::Err => {
warn!(
- "Failed to fetch DIE. Debug information may be incomplete."
+ "Failed to fetch DIE when resolving namespace. Debug information may be incomplete."
);
}
}
@@ -115,6 +142,7 @@ fn recover_names<R: Reader<Offset = usize>>(
}
resolve_namespace_name(
+ dwarf,
&unit,
entry,
debug_info_builder_context,
@@ -125,7 +153,7 @@ fn recover_names<R: Reader<Offset = usize>>(
constants::DW_TAG_class_type
| constants::DW_TAG_structure_type
| constants::DW_TAG_union_type => {
- if let Some(name) = get_name(&unit, entry, debug_info_builder_context) {
+ if let Some(name) = get_name(dwarf, &unit, entry, debug_info_builder_context) {
namespace_qualifiers.push((depth, name))
} else {
namespace_qualifiers.push((
@@ -141,7 +169,7 @@ fn recover_names<R: Reader<Offset = usize>>(
))
}
debug_info_builder_context.set_name(
- get_uid(&unit, entry),
+ get_uid(dwarf, &unit, entry),
simplify_str_to_str(
namespace_qualifiers
.iter()
@@ -155,9 +183,9 @@ fn recover_names<R: Reader<Offset = usize>>(
constants::DW_TAG_typedef
| constants::DW_TAG_subprogram
| constants::DW_TAG_enumeration_type => {
- if let Some(name) = get_name(&unit, entry, debug_info_builder_context) {
+ if let Some(name) = get_name(dwarf, &unit, entry, debug_info_builder_context) {
debug_info_builder_context.set_name(
- get_uid(&unit, entry),
+ get_uid(dwarf, &unit, entry),
simplify_str_to_str(
namespace_qualifiers
.iter()
@@ -171,8 +199,8 @@ fn recover_names<R: Reader<Offset = usize>>(
}
}
_ => {
- if let Some(name) = get_name(&unit, entry, debug_info_builder_context) {
- debug_info_builder_context.set_name(get_uid(&unit, entry), name);
+ if let Some(name) = get_name(dwarf, &unit, entry, debug_info_builder_context) {
+ debug_info_builder_context.set_name(get_uid(dwarf, &unit, entry), name);
}
}
}
@@ -182,7 +210,8 @@ fn recover_names<R: Reader<Offset = usize>>(
true
}
-fn parse_unit<R: Reader<Offset = usize>>(
+fn parse_unit<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
debug_info_builder: &mut DebugInfoBuilder,
@@ -225,12 +254,12 @@ fn parse_unit<R: Reader<Offset = usize>>(
match entry.tag() {
constants::DW_TAG_subprogram => {
- let fn_idx = parse_function_entry(unit, entry, debug_info_builder_context, debug_info_builder);
+ let fn_idx = parse_function_entry(dwarf, unit, entry, debug_info_builder_context, debug_info_builder);
functions_by_depth.push((fn_idx, current_depth));
},
constants::DW_TAG_variable => {
let current_fn_idx = functions_by_depth.last().and_then(|x| x.0);
- parse_variable(unit, entry, debug_info_builder_context, debug_info_builder, current_fn_idx)
+ parse_variable(dwarf, unit, entry, debug_info_builder_context, debug_info_builder, current_fn_idx)
},
constants::DW_TAG_class_type |
constants::DW_TAG_enumeration_type |
@@ -238,7 +267,7 @@ fn parse_unit<R: Reader<Offset = usize>>(
constants::DW_TAG_union_type |
constants::DW_TAG_typedef => {
// Ensure types are loaded even if they're unused
- types::get_type(unit, entry, debug_info_builder_context, debug_info_builder);
+ types::get_type(dwarf, unit, entry, debug_info_builder_context, debug_info_builder);
},
_ => (),
}
@@ -303,11 +332,38 @@ fn parse_eh_frame<R: Reader>(
}
}
+fn get_supplementary_build_id(bv: &BinaryView) -> Option<String> {
+ let raw_view = bv.raw_view().ok()?;
+ if let Ok(section) = raw_view.section_by_name(".gnu_debugaltlink") {
+ let start = section.start();
+ let len = section.len();
+
+ if len < 20 {
+ // Not large enough to hold a build id
+ return None;
+ }
+
+ raw_view
+ .read_vec(start, len)
+ .splitn(2, |x| *x == 0)
+ .last()
+ .map(|a| {
+ a.iter().map(|b| format!("{:02x}", b)).collect()
+ })
+ }
+ else {
+ None
+ }
+}
+
fn parse_dwarf(
bv: &BinaryView,
debug_bv: &BinaryView,
+ supplementary_bv: Option<&BinaryView>,
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
) -> Result<DebugInfoBuilder, ()> {
+ // TODO: warn if no supplementary file and .gnu_debugaltlink section present
+
// Determine if this is a DWO
// TODO : Make this more robust...some DWOs follow non-DWO conventions
@@ -329,6 +385,19 @@ fn parse_dwarf(
if dwo_file {
dwarf.file_type = DwarfFileType::Dwo;
}
+ else {
+ dwarf.file_type = DwarfFileType::Main;
+ }
+
+ if let Some(sup_bv) = supplementary_bv {
+ let sup_endian = get_endian(sup_bv);
+ let sup_dwo_file = is_dwo_dwarf(sup_bv) || is_raw_dwo_dwarf(sup_bv);
+ let sup_section_reader =
+ |section_id: SectionId| -> _ { create_section_reader(section_id, sup_bv, sup_endian, sup_dwo_file) };
+ if let Err(e) = dwarf.load_sup(sup_section_reader) {
+ error!("Failed to load supplementary file: {}", e);
+ }
+ }
let eh_frame_endian = get_endian(bv);
let mut eh_frame_section_reader =
@@ -336,7 +405,7 @@ fn parse_dwarf(
let eh_frame = gimli::EhFrame::load(&mut eh_frame_section_reader).unwrap();
let range_data_offsets = parse_eh_frame(bv, eh_frame)
- .map_err(|e| println!("Error parsing .eh_frame: {}", e))?;
+ .map_err(|e| error!("Error parsing .eh_frame: {}", e))?;
// Create debug info builder and recover name mapping first
// Since DWARF is stored as a tree with arbitrary implicit edges among leaves,
@@ -344,8 +413,9 @@ fn parse_dwarf(
// so we just do it up front
let mut debug_info_builder = DebugInfoBuilder::new();
debug_info_builder.set_range_data_offsets(range_data_offsets);
- if let Some(mut debug_info_builder_context) = DebugInfoBuilderContext::new(view, dwarf) {
- if !recover_names(&mut debug_info_builder_context, &progress)
+
+ if let Some(mut debug_info_builder_context) = DebugInfoBuilderContext::new(view, &dwarf) {
+ if !recover_names(&dwarf, &mut debug_info_builder_context, &progress)
|| debug_info_builder_context.total_die_count == 0
{
return Ok(debug_info_builder);
@@ -353,9 +423,22 @@ fn parse_dwarf(
// Parse all the compilation units
let mut current_die_number = 0;
+
+ for unit in debug_info_builder_context.sup_units() {
+ parse_unit(
+ dwarf.sup().unwrap(),
+ &unit,
+ &debug_info_builder_context,
+ &mut debug_info_builder,
+ &progress,
+ &mut current_die_number,
+ );
+ }
+
for unit in debug_info_builder_context.units() {
parse_unit(
- unit,
+ &dwarf,
+ &unit,
&debug_info_builder_context,
&mut debug_info_builder,
&progress,
@@ -363,6 +446,7 @@ fn parse_dwarf(
);
}
}
+
Ok(debug_info_builder)
}
@@ -370,9 +454,15 @@ struct DWARFParser;
impl CustomDebugInfoParser for DWARFParser {
fn is_valid(&self, view: &BinaryView) -> bool {
- dwarfreader::is_valid(view) ||
- dwarfreader::can_use_debuginfod(view) ||
- (dwarfreader::has_build_id_section(view) && helpers::find_local_debug_file(view).is_some())
+ if dwarfreader::is_valid(view) || dwarfreader::can_use_debuginfod(view) {
+ return true;
+ }
+ if dwarfreader::has_build_id_section(view) {
+ if let Ok(build_id) = get_build_id(view) {
+ return helpers::find_local_debug_file(&build_id, view).is_some();
+ }
+ }
+ false
}
fn parse_info(
@@ -383,28 +473,34 @@ impl CustomDebugInfoParser for DWARFParser {
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
) -> bool {
let (external_file, close_external) = if !dwarfreader::is_valid(bv) {
- if dwarfreader::has_build_id_section(bv) {
- if let Ok(Some(debug_view)) = helpers::load_debug_info_for_build_id(bv) {
- (Some(debug_view), false)
- } else {
- if dwarfreader::can_use_debuginfod(bv) {
- if let Ok(debug_view) = helpers::download_debug_info(bv) {
- (Some(debug_view), true)
- } else {
- (None, false)
- }
- } else {
- (None, false)
- }
- }
- } else {
+ if let Ok(build_id) = get_build_id(bv) {
+ helpers::load_debug_info_for_build_id(&build_id, bv)
+ }
+ else {
(None, false)
}
- } else {
+ }
+ else {
(None, false)
};
- let result = match parse_dwarf(bv, external_file.as_deref().unwrap_or(debug_file), progress)
+ let sup_bv = get_supplementary_build_id(
+ external_file
+ .as_deref()
+ .unwrap_or(debug_file)
+ )
+ .and_then(|build_id| {
+ load_debug_info_for_build_id(&build_id, bv)
+ .0
+ .map(|x| x.raw_view().unwrap())
+ });
+
+ let result = match parse_dwarf(
+ bv,
+ external_file.as_deref().unwrap_or(debug_file),
+ sup_bv.as_deref(),
+ progress
+ )
{
Ok(mut builder) => {
builder.post_process(bv, debug_info).commit_info(debug_info);
diff --git a/rust/examples/dwarf/dwarf_import/src/types.rs b/rust/examples/dwarf/dwarf_import/src/types.rs
index e3b53d99..35794e36 100644
--- a/rust/examples/dwarf/dwarf_import/src/types.rs
+++ b/rust/examples/dwarf/dwarf_import/src/types.rs
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use crate::die_handlers::*;
+use crate::{die_handlers::*, ReaderType};
use crate::dwarfdebuginfo::{DebugInfoBuilder, DebugInfoBuilderContext, TypeUID};
use crate::helpers::*;
@@ -23,19 +23,20 @@ use binaryninja::{
},
};
-use gimli::{constants, AttributeValue, DebuggingInformationEntry, Operation, Reader, Unit};
+use gimli::{constants, AttributeValue, DebuggingInformationEntry, Dwarf, Operation, Unit};
use log::{debug, error, warn};
-pub(crate) fn parse_variable<R: Reader<Offset = usize>>(
+pub(crate) fn parse_variable<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
debug_info_builder: &mut DebugInfoBuilder,
function_index: Option<usize>,
) {
- let full_name = debug_info_builder_context.get_name(unit, entry);
- let type_uid = get_type(unit, entry, debug_info_builder_context, debug_info_builder);
+ let full_name = debug_info_builder_context.get_name(dwarf, unit, entry);
+ let type_uid = get_type(dwarf, unit, entry, debug_info_builder_context, debug_info_builder);
let Ok(Some(attr)) = entry.attr(constants::DW_AT_location) else {
return
@@ -66,7 +67,8 @@ pub(crate) fn parse_variable<R: Reader<Offset = usize>>(
}
}
-fn do_structure_parse<R: Reader<Offset = usize>>(
+fn do_structure_parse<R: ReaderType>(
+ dwarf: &Dwarf<R>,
structure_type: StructureType,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
@@ -110,8 +112,8 @@ fn do_structure_parse<R: Reader<Offset = usize>>(
return None;
}
- let full_name = if get_name(unit, entry, debug_info_builder_context).is_some() {
- debug_info_builder_context.get_name(unit, entry)
+ let full_name = if get_name(dwarf, unit, entry, debug_info_builder_context).is_some() {
+ debug_info_builder_context.get_name(dwarf, unit, entry)
} else {
None
};
@@ -128,7 +130,7 @@ fn do_structure_parse<R: Reader<Offset = usize>>(
// it will also be how any other types refer to this struct
if let Some(full_name) = &full_name {
debug_info_builder.add_type(
- get_uid(unit, entry),
+ get_uid(dwarf, unit, entry),
&full_name,
Type::named_type_from_type(
full_name.clone(),
@@ -140,9 +142,9 @@ fn do_structure_parse<R: Reader<Offset = usize>>(
// We _need_ to have initial typedefs or else we can enter infinite parsing loops
// These get overwritten in the last step with the actual type, however, so this
// is either perfectly fine or breaking a bunch of NTRs
- let full_name = format!("anonymous_structure_{:x}", get_uid(unit, entry));
+ let full_name = format!("anonymous_structure_{:x}", get_uid(dwarf, unit, entry));
debug_info_builder.add_type(
- get_uid(unit, entry),
+ get_uid(dwarf, unit, entry),
&full_name,
Type::named_type_from_type(&full_name, &Type::structure(&structure_builder.finalize())),
false,
@@ -155,6 +157,7 @@ fn do_structure_parse<R: Reader<Offset = usize>>(
while let Ok(Some(child)) = children.next() {
if child.entry().tag() == constants::DW_TAG_member {
if let Some(child_type_id) = get_type(
+ dwarf,
unit,
child.entry(),
debug_info_builder_context,
@@ -163,7 +166,7 @@ fn do_structure_parse<R: Reader<Offset = usize>>(
if let Some(t) = debug_info_builder.get_type(child_type_id) {
let child_type = t.get_type();
if let Some(child_name) = debug_info_builder_context
- .get_name(unit, child.entry())
+ .get_name(dwarf, unit, child.entry())
.map_or(
if child_type.type_class() == TypeClass::StructureTypeClass {
Some("".to_string())
@@ -208,31 +211,32 @@ fn do_structure_parse<R: Reader<Offset = usize>>(
let finalized_structure = Type::structure(&structure_builder.finalize());
if let Some(full_name) = full_name {
debug_info_builder.add_type(
- get_uid(unit, entry) + 1, // TODO : This is super broke (uid + 1 is not guaranteed to be unique)
+ get_uid(dwarf, unit, entry) + 1, // TODO : This is super broke (uid + 1 is not guaranteed to be unique)
&full_name,
finalized_structure,
true,
);
} else {
debug_info_builder.add_type(
- get_uid(unit, entry),
+ get_uid(dwarf, unit, entry),
&format!("{}", finalized_structure),
finalized_structure,
false, // Don't commit anonymous unions (because I think it'll break things)
);
}
- Some(get_uid(unit, entry))
+ Some(get_uid(dwarf, unit, entry))
}
// This function iterates up through the dependency references, adding all the types along the way until there are no more or stopping at the first one already tracked, then returns the UID of the type of the given DIE
-pub(crate) fn get_type<R: Reader<Offset = usize>>(
+pub(crate) fn get_type<R: ReaderType>(
+ dwarf: &Dwarf<R>,
unit: &Unit<R>,
entry: &DebuggingInformationEntry<R>,
debug_info_builder_context: &DebugInfoBuilderContext<R>,
debug_info_builder: &mut DebugInfoBuilder,
) -> Option<TypeUID> {
// If this node (and thus all its referenced nodes) has already been processed, just return the offset
- let entry_uid = get_uid(unit, entry);
+ let entry_uid = get_uid(dwarf, unit, entry);
if debug_info_builder.contains_type(entry_uid) {
return Some(entry_uid);
}
@@ -243,6 +247,7 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
}
let entry_type = if let Some(die_reference) = get_attr_die(
+ dwarf,
unit,
entry,
debug_info_builder_context,
@@ -250,25 +255,29 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
) {
// This needs to recurse first (before the early return below) to ensure all sub-types have been parsed
match die_reference {
- DieReference::UnitAndOffset((entry_unit, entry_offset)) => get_type(
- entry_unit,
- &entry_unit.entry(entry_offset).unwrap(),
- debug_info_builder_context,
- debug_info_builder,
- ),
+ DieReference::UnitAndOffset((dwarf, entry_unit, entry_offset)) => {
+ get_type(
+ dwarf,
+ entry_unit,
+ &entry_unit.entry(entry_offset).unwrap(),
+ debug_info_builder_context,
+ debug_info_builder,
+ )
+ }
DieReference::Err => {
- warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ warn!("Failed to fetch DIE when getting type through DW_AT_type. Debug information may be incomplete.");
None
}
}
} else {
// This needs to recurse first (before the early return below) to ensure all sub-types have been parsed
- match resolve_specification(unit, entry, debug_info_builder_context) {
- DieReference::UnitAndOffset((entry_unit, entry_offset))
+ match resolve_specification(dwarf, unit, entry, debug_info_builder_context) {
+ DieReference::UnitAndOffset((dwarf, entry_unit, entry_offset))
if entry_unit.header.offset() != unit.header.offset()
&& entry_offset != entry.offset() =>
{
get_type(
+ dwarf,
entry_unit,
&entry_unit.entry(entry_offset).unwrap(),
debug_info_builder_context,
@@ -277,7 +286,7 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
}
DieReference::UnitAndOffset(_) => None,
DieReference::Err => {
- warn!("Failed to fetch DIE. Debug information may be incomplete.");
+ warn!("Failed to fetch DIE when getting type. Debug information may be incomplete.");
None
}
}
@@ -293,12 +302,13 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
// Create the type, make a TypeInfo for it, and add it to the debug info
let (type_def, mut commit): (Option<Ref<Type>>, bool) = match entry.tag() {
constants::DW_TAG_base_type => (
- handle_base_type(unit, entry, debug_info_builder_context),
+ handle_base_type(dwarf, unit, entry, debug_info_builder_context),
false,
),
constants::DW_TAG_structure_type => {
return do_structure_parse(
+ dwarf,
StructureType::StructStructureType,
unit,
entry,
@@ -308,6 +318,7 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
}
constants::DW_TAG_class_type => {
return do_structure_parse(
+ dwarf,
StructureType::ClassStructureType,
unit,
entry,
@@ -317,6 +328,7 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
}
constants::DW_TAG_union_type => {
return do_structure_parse(
+ dwarf,
StructureType::UnionStructureType,
unit,
entry,
@@ -327,12 +339,12 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
// Enum
constants::DW_TAG_enumeration_type => {
- (handle_enum(unit, entry, debug_info_builder_context), true)
+ (handle_enum(dwarf, unit, entry, debug_info_builder_context), true)
}
// Basic types
constants::DW_TAG_typedef => {
- if let Some(name) = debug_info_builder_context.get_name(unit, entry) {
+ if let Some(name) = debug_info_builder_context.get_name(dwarf, unit, entry) {
handle_typedef(debug_info_builder, entry_type, &name)
} else {
(None, false)
@@ -377,6 +389,7 @@ pub(crate) fn get_type<R: Reader<Offset = usize>>(
constants::DW_TAG_unspecified_type => (Some(Type::void()), false),
constants::DW_TAG_subroutine_type => (
handle_function(
+ dwarf,
unit,
entry,
debug_info_builder_context,
@@ -396,8 +409,8 @@ 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(unit, entry, debug_info_builder_context).is_some() {
- debug_info_builder_context.get_name(unit, entry)
+ let name = if get_name(dwarf, unit, entry, debug_info_builder_context).is_some() {
+ debug_info_builder_context.get_name(dwarf, unit, entry)
} else {
None
}
diff --git a/rust/examples/dwarf/dwarfdump/Cargo.toml b/rust/examples/dwarf/dwarfdump/Cargo.toml
index 0ede6afb..3f1e25f6 100644
--- a/rust/examples/dwarf/dwarfdump/Cargo.toml
+++ b/rust/examples/dwarf/dwarfdump/Cargo.toml
@@ -10,4 +10,4 @@ crate-type = ["cdylib"]
[dependencies]
dwarfreader = { path = "../shared/" }
binaryninja = {path="../../../"}
-gimli = "0.28"
+gimli = "0.31"
diff --git a/rust/examples/dwarf/shared/Cargo.toml b/rust/examples/dwarf/shared/Cargo.toml
index 521a705e..c5b9a978 100644
--- a/rust/examples/dwarf/shared/Cargo.toml
+++ b/rust/examples/dwarf/shared/Cargo.toml
@@ -6,4 +6,4 @@ edition = "2021"
[dependencies]
binaryninja = {path="../../../"}
-gimli = "0.28"
+gimli = "0.31"