summaryrefslogtreecommitdiff
path: root/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
diff options
context:
space:
mode:
authorJosh Ferrell <josh@vector35.com>2024-06-13 14:13:11 -0400
committerJosh Ferrell <josh@vector35.com>2024-06-13 14:13:11 -0400
commitd75066545afdc9b5d0a52bd2518e43f683c671a5 (patch)
treebed26d348a726fc02c1d44cbdc36a8056b44baaf /rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
parentf3a440248cda4d0c850cd32e3aa127ab29e0bb3e (diff)
Apply stack variables from DWARF
Diffstat (limited to 'rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs')
-rw-r--r--rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs88
1 files changed, 82 insertions, 6 deletions
diff --git a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
index 0d4fda98..f3cc7b08 100644
--- a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
+++ b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs
@@ -21,12 +21,13 @@ use binaryninja::{
rc::*,
symbol::SymbolType,
templatesimplifier::simplify_str_to_fqn,
- types::{Conf, FunctionParameter, Type},
+ types::{Conf, FunctionParameter, NamedTypedVariable, Type, Variable},
+ binaryninjacore_sys::BNVariableSourceType,
};
use gimli::{DebuggingInformationEntry, Dwarf, Reader, Unit};
-use log::{error, warn};
+use log::{debug, error, warn};
use std::{
cmp::Ordering,
collections::{hash_map::Values, HashMap},
@@ -48,6 +49,7 @@ pub(crate) struct FunctionInfoBuilder {
pub(crate) parameters: Vec<Option<(String, TypeUID)>>,
pub(crate) platform: Option<Ref<Platform>>,
pub(crate) variable_arguments: bool,
+ pub(crate) stack_variables: Vec<NamedTypedVariable>,
}
impl FunctionInfoBuilder {
@@ -172,6 +174,7 @@ pub(crate) struct DebugInfoBuilder {
full_function_name_indices: HashMap<String, usize>,
types: HashMap<TypeUID, DebugType>,
data_variables: HashMap<u64, (Option<String>, TypeUID)>,
+ range_data_offsets: iset::IntervalMap<u64, i64>
}
impl DebugInfoBuilder {
@@ -182,9 +185,14 @@ impl DebugInfoBuilder {
full_function_name_indices: HashMap::new(),
types: HashMap::new(),
data_variables: HashMap::new(),
+ range_data_offsets: iset::IntervalMap::new(),
}
}
+ pub(crate) fn set_range_data_offsets(&mut self, offsets: iset::IntervalMap<u64, i64>) {
+ self.range_data_offsets = offsets
+ }
+
#[allow(clippy::too_many_arguments)]
pub(crate) fn insert_function(
&mut self,
@@ -194,7 +202,8 @@ impl DebugInfoBuilder {
address: Option<u64>,
parameters: &Vec<Option<(String, TypeUID)>>,
variable_arguments: bool,
- ) {
+ ) -> Option<usize> {
+ // Returns the index of the function
// Raw names should be the primary key, but if they don't exist, use the full name
// TODO : Consider further falling back on address/architecture
@@ -222,7 +231,7 @@ impl DebugInfoBuilder {
self.full_function_name_indices.insert(function.full_name.clone().unwrap(), *idx);
}
- return;
+ return Some(*idx);
}
}
@@ -244,13 +253,13 @@ impl DebugInfoBuilder {
self.raw_function_name_indices.insert(function.raw_name.clone().unwrap(), *idx);
}
- return;
+ return Some(*idx);
}
}
if raw_name.is_none() && full_name.is_none() {
error!("Function entry in DWARF without full or raw name. Please report this issue.");
- return;
+ return None;
}
let function = FunctionInfoBuilder {
@@ -261,6 +270,7 @@ impl DebugInfoBuilder {
parameters: parameters.clone(),
platform: None,
variable_arguments,
+ stack_variables: vec![],
};
if let Some(n) = &function.full_name {
@@ -272,6 +282,7 @@ impl DebugInfoBuilder {
}
self.functions.push(function);
+ Some(self.functions.len()-1)
}
pub(crate) fn functions(&self) -> &[FunctionInfoBuilder] {
@@ -321,6 +332,70 @@ impl DebugInfoBuilder {
self.types.get(&type_uid).is_some()
}
+
+ pub(crate) fn add_stack_variable(
+ &mut self,
+ fn_idx: Option<usize>,
+ offset: i64,
+ name: Option<String>,
+ type_uid: Option<TypeUID>,
+ ) {
+ let name = match name {
+ Some(x) => {
+ if x.len() == 1 && x.chars().next() == Some('\x00') {
+ // Anonymous variable, generate name
+ format!("debug_var_{}", offset)
+ }
+ else {
+ x
+ }
+ },
+ None => {
+ // Anonymous variable, generate name
+ format!("debug_var_{}", offset)
+ }
+ };
+
+ let Some(function_index) = fn_idx else {
+ // If we somehow lost track of what subprogram we're in or we're not actually in a subprogram
+ error!("Trying to add a local variable outside of a subprogram. Please report this issue.");
+ return;
+ };
+
+ // Either get the known type or use a 0 confidence void type so we at least get the name applied
+ let t = match type_uid {
+ Some(uid) => Conf::new(self.get_type(uid).unwrap().1, 128),
+ None => Conf::new(Type::void(), 0)
+ };
+ let function = &mut self.functions[function_index];
+
+ // TODO: If we can't find a known offset can we try to guess somehow?
+
+ let Some(func_addr) = function.address else {
+ // If we somehow are processing a function's variables before the function is created
+ error!("Trying to add a local variable without a known function start. Please report this issue.");
+ return;
+ };
+
+ let Some(offset_adjustment) = self.range_data_offsets.values_overlap(func_addr).next() else {
+ // Unknown why, but this is happening with MachO + external dSYM
+ debug!("Refusing to add a local variable ({}@{}) to function at {} without a known CIE offset.", name, offset, func_addr);
+ return;
+ };
+
+ let adjusted_offset = offset - offset_adjustment;
+
+ if adjusted_offset > 0 {
+ // If we somehow end up with a positive sp offset
+ error!("Trying to add a local variable at positive storage offset {}. Please report this issue.", adjusted_offset);
+ return;
+ }
+
+ let var = Variable::new(BNVariableSourceType::StackVariableSourceType, 0, adjusted_offset);
+ function.stack_variables.push(NamedTypedVariable::new(var, name, t, false));
+
+ }
+
pub(crate) fn add_data_variable(
&mut self,
address: u64,
@@ -399,6 +474,7 @@ impl DebugInfoBuilder {
function.address,
function.platform.clone(),
vec![], // TODO : Components
+ function.stack_variables.clone(), // TODO: local non-stack variables
));
}
}