diff options
| author | Josh Ferrell <josh@vector35.com> | 2024-10-10 17:36:52 -0400 |
|---|---|---|
| committer | Josh Ferrell <josh@vector35.com> | 2024-10-10 17:37:09 -0400 |
| commit | 039033f13726b6ddcb1dd0312419f7495637283a (patch) | |
| tree | 42c5ffa9ba8643819ea236dc8aa81f5cc8778247 /rust/examples/dwarf/dwarf_import/src/functions.rs | |
| parent | 7be992787ec6b299c7aeb42f6293809bd9288c67 (diff) | |
Lots of improvements to stack variable location calculations in DWARF
Diffstat (limited to 'rust/examples/dwarf/dwarf_import/src/functions.rs')
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/functions.rs | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/rust/examples/dwarf/dwarf_import/src/functions.rs b/rust/examples/dwarf/dwarf_import/src/functions.rs index 9ca01a2c..43b69ca3 100644 --- a/rust/examples/dwarf/dwarf_import/src/functions.rs +++ b/rust/examples/dwarf/dwarf_import/src/functions.rs @@ -20,8 +20,8 @@ use crate::types::get_type; use binaryninja::templatesimplifier::simplify_str_to_str; use cpp_demangle::DemangleOptions; -use gimli::{constants, DebuggingInformationEntry, Dwarf, Unit}; -use log::debug; +use gimli::{constants, AttributeValue, DebuggingInformationEntry, Dwarf, Operation, Unit}; +use log::{debug, error}; use regex::Regex; fn get_parameters<R: ReaderType>( @@ -126,5 +126,79 @@ pub(crate) fn parse_function_entry<R: ReaderType>( return None; } - debug_info_builder.insert_function(full_name, raw_name, return_type, address, ¶meters, variable_arguments) + let use_cfa; + if let Ok(Some(AttributeValue::Exprloc(mut expression))) = entry.attr_value(constants::DW_AT_frame_base) { + use_cfa = match Operation::parse(&mut expression.0, unit.encoding()) { + Ok(Operation::Register { register: _ }) => false, // TODO: handle register-relative encodings later + Ok(Operation::CallFrameCFA) => true, + _ => false + }; + } + else { + use_cfa = false; + } + + debug_info_builder.insert_function(full_name, raw_name, return_type, address, ¶meters, variable_arguments, use_cfa) +} + + +pub(crate) fn parse_lexical_block<R: ReaderType>( + dwarf: &Dwarf<R>, + unit: &Unit<R>, + entry: &DebuggingInformationEntry<R>, +) -> Option<iset::IntervalSet<u64>> { + // Return lexical block ranges + // Must have either DW_AT_ranges or DW_AT_low_pc and DW_AT_high_pc + let mut result = iset::IntervalSet::new(); + 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) + { + while let Ok(Some(range)) = ranges.next() { + // Ranges where start == end may be ignored (DWARFv5 spec, 2.17.3 line 17) + if range.begin == range.end { + continue + } + result.insert(range.begin..range.end); + } + } + } + } + else if let Ok(Some(low_pc_value)) = entry.attr_value(constants::DW_AT_low_pc) { + let Ok(Some(low_pc)) = dwarf.attr_address(unit, low_pc_value.clone()) else { + let unit_base: usize = unit.header.offset().as_debug_info_offset().unwrap().0; + error!("Failed to read lexical block low_pc for entry {:#x}, please report this bug.", unit_base + entry.offset().0); + return None; + }; + + let Ok(Some(high_pc_value)) = entry.attr_value(constants::DW_AT_high_pc) else { + let unit_base: usize = unit.header.offset().as_debug_info_offset().unwrap().0; + error!("Failed to read lexical block high_pc attribute for entry {:#x}, please report this bug.", unit_base + entry.offset().0); + return None; + }; + + let Some(high_pc) = high_pc_value + .udata_value() + .and_then(|x| Some(low_pc + x)) + .or_else(|| dwarf.attr_address(unit, high_pc_value).unwrap_or(None)) + else { + let unit_base: usize = unit.header.offset().as_debug_info_offset().unwrap().0; + error!("Failed to read lexical block high_pc for entry {:#x}, please report this bug.", unit_base + entry.offset().0); + return None; + }; + + if low_pc < high_pc { + result.insert(low_pc..high_pc); + } + else { + error!("Invalid lexical block range: {:#x} -> {:#x}", low_pc, high_pc); + } + } + else { + // If neither case is hit the lexical block doesn't define any ranges and we should ignore it + return None; + } + + Some(result) } |
