diff options
| author | Josh Ferrell <josh@vector35.com> | 2025-04-18 15:46:27 -0400 |
|---|---|---|
| committer | Josh Ferrell <josh@vector35.com> | 2025-04-23 15:46:37 -0400 |
| commit | 0493db09dee436a9ecb9009ae7222dccefd3d5e3 (patch) | |
| tree | 7a775b5b383fcd77bb9ed3bab665a6b2d8a86408 /plugins/dwarf | |
| parent | 8385022779729901786510517878173596454097 (diff) | |
Various DWARF fixes
- Do not add binary base to function address twice when a symbol with that function's raw name already exists
- Load eh_frame/debug_frame from base bv instead of debug bv and make calculated cie offset ranges relative to bv start
- Fix dwarf raw name resolution not resolving specification
- Try to load eh_frame/debug_frame from both raw and normal views in dwarf import
Diffstat (limited to 'plugins/dwarf')
| -rw-r--r-- | plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs | 2 | ||||
| -rw-r--r-- | plugins/dwarf/dwarf_import/src/functions.rs | 2 | ||||
| -rw-r--r-- | plugins/dwarf/dwarf_import/src/helpers.rs | 30 | ||||
| -rw-r--r-- | plugins/dwarf/dwarf_import/src/lib.rs | 103 |
4 files changed, 92 insertions, 45 deletions
diff --git a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs index 604867f5..136a7a8b 100644 --- a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs +++ b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs @@ -608,7 +608,7 @@ impl DebugInfoBuilder { if func.address.is_none() && func.raw_name.is_some() { // DWARF doesn't contain GOT info, so remove any entries there...they will be wrong (relying on Binja's mechanisms for the GOT is good ) if symbol.sym_type() != SymbolType::ImportAddress { - func.address = Some(symbol.address()); + func.address = Some(symbol.address() - bv.start()); } } diff --git a/plugins/dwarf/dwarf_import/src/functions.rs b/plugins/dwarf/dwarf_import/src/functions.rs index 5b228713..6400ea84 100644 --- a/plugins/dwarf/dwarf_import/src/functions.rs +++ b/plugins/dwarf/dwarf_import/src/functions.rs @@ -81,7 +81,7 @@ pub(crate) fn parse_function_entry<R: ReaderType>( debug_info_builder: &mut DebugInfoBuilder, ) -> Option<usize> { // Collect function properties (if they exist in this DIE) - let raw_name = get_raw_name(dwarf, unit, entry); + let raw_name = get_raw_name(dwarf, unit, entry, debug_info_builder_context); let return_type = get_type( dwarf, unit, diff --git a/plugins/dwarf/dwarf_import/src/helpers.rs b/plugins/dwarf/dwarf_import/src/helpers.rs index e6f30a3b..e23eb498 100644 --- a/plugins/dwarf/dwarf_import/src/helpers.rs +++ b/plugins/dwarf/dwarf_import/src/helpers.rs @@ -221,21 +221,31 @@ 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) = 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()); + 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_linkage_name) + { + 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()); + } + } } } + None } + DieReference::Err => None, } - None } // Get the size of an object as a usize diff --git a/plugins/dwarf/dwarf_import/src/lib.rs b/plugins/dwarf/dwarf_import/src/lib.rs index d401f36f..a35bef60 100644 --- a/plugins/dwarf/dwarf_import/src/lib.rs +++ b/plugins/dwarf/dwarf_import/src/lib.rs @@ -44,6 +44,7 @@ use gimli::{ use binaryninja::logger::Logger; use helpers::{get_build_id, load_debug_info_for_build_id}; +use iset::IntervalMap; use log::{debug, error, warn}; trait ReaderType: Reader<Offset = usize> {} @@ -374,37 +375,39 @@ where { let mut bases = gimli::BaseAddresses::default(); + let view_start = view.start(); + if let Some(section) = view .section_by_name(".eh_frame_hdr") .or(view.section_by_name("__eh_frame_hdr")) { - bases = bases.set_eh_frame_hdr(section.start()); + bases = bases.set_eh_frame_hdr(section.start() - view_start); } if let Some(section) = view .section_by_name(".eh_frame") .or(view.section_by_name("__eh_frame")) { - bases = bases.set_eh_frame(section.start()); + bases = bases.set_eh_frame(section.start() - view_start); } else if let Some(section) = view .section_by_name(".debug_frame") .or(view.section_by_name("__debug_frame")) { - bases = bases.set_eh_frame(section.start()); + bases = bases.set_eh_frame(section.start() - view_start); } if let Some(section) = view .section_by_name(".text") .or(view.section_by_name("__text")) { - bases = bases.set_text(section.start()); + bases = bases.set_text(section.start() - view_start); } if let Some(section) = view .section_by_name(".got") .or(view.section_by_name("__got")) { - bases = bases.set_got(section.start()); + bases = bases.set_got(section.start() - view_start); } let mut cies = HashMap::new(); @@ -453,6 +456,19 @@ where register: _, offset, } => { + //TODO: can we normalize this to be sp-based? + /* + Switching to RBP from RSP in this example breaks things, and we should know that RBP = RSP - 8 + 65 │ 0x1139: CFA=RSP+8: RIP=[CFA-8] + 66 │ 0x113a: CFA=RSP+16: RBP=[CFA-16], RIP=[CFA-8] + 67 │ 0x113d: CFA=RBP+16: RBP=[CFA-16], RIP=[CFA-8] + 68 │ 0x1162: CFA=RSP+8: RBP=[CFA-16], RIP=[CFA-8] + + can we + know that CFA=RSP+8 at the beginning + in the next instruction (66) we know RBP=[CFA-16]=[RSP-8] + and do something with that? + */ // TODO: we should store offsets by register if row.start_address() < row.end_address() { cfa_offsets @@ -497,8 +513,44 @@ fn get_supplementary_build_id(bv: &BinaryView) -> Option<String> { } } +fn parse_range_data_offsets(bv: &BinaryView, dwo_file: bool) -> Option<Result<IntervalMap<u64, i64>, ()>> { + if bv.section_by_name(".eh_frame").is_some() || bv.section_by_name("__eh_frame").is_some() { + let eh_frame_endian = get_endian(bv); + let eh_frame_section_reader = |section_id: SectionId| -> _ { + create_section_reader(section_id, bv, eh_frame_endian, dwo_file) + }; + let mut eh_frame = gimli::EhFrame::load(eh_frame_section_reader).unwrap(); + if let Some(view_arch) = bv.default_arch() { + if view_arch.name().as_str() == "aarch64" { + eh_frame.set_vendor(gimli::Vendor::AArch64); + } + } + eh_frame.set_address_size(bv.address_size() as u8); + Some(parse_unwind_section(bv, eh_frame) + .map_err(|e| error!("Error parsing .eh_frame: {}", e))) + } else if bv.section_by_name(".debug_frame").is_some() + || bv.section_by_name("__debug_frame").is_some() + { + let debug_frame_endian = get_endian(bv); + let debug_frame_section_reader = |section_id: SectionId| -> _ { + create_section_reader(section_id, bv, debug_frame_endian, dwo_file) + }; + let mut debug_frame = gimli::DebugFrame::load(debug_frame_section_reader).unwrap(); + if let Some(view_arch) = bv.default_arch() { + if view_arch.name().as_str() == "aarch64" { + debug_frame.set_vendor(gimli::Vendor::AArch64); + } + } + debug_frame.set_address_size(bv.address_size() as u8); + Some(parse_unwind_section(bv, debug_frame) + .map_err(|e| error!("Error parsing .debug_frame: {}", e))) + } else { + None + } +} + fn parse_dwarf( - _bv: &BinaryView, + bv: &BinaryView, debug_bv: &BinaryView, supplementary_bv: Option<&BinaryView>, progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>, @@ -548,35 +600,20 @@ fn parse_dwarf( } } - let range_data_offsets; - if view.section_by_name(".eh_frame").is_some() || view.section_by_name("__eh_frame").is_some() { - let eh_frame_endian = get_endian(view); - let eh_frame_section_reader = |section_id: SectionId| -> _ { - create_section_reader(section_id, view, eh_frame_endian, dwo_file) - }; - let mut eh_frame = gimli::EhFrame::load(eh_frame_section_reader).unwrap(); - if let Some(view_arch) = view.default_arch() { - if view_arch.name().as_str() == "aarch64" { - eh_frame.set_vendor(gimli::Vendor::AArch64); + let range_data_offsets = match parse_range_data_offsets(bv, dwo_file) { + Some(x) => x?, + None => { + if let Some(raw_view) = bv.raw_view() { + if let Some(offsets) = parse_range_data_offsets(&raw_view, dwo_file) { + offsets? + } else { + Default::default() + } + } else { + Default::default() } } - eh_frame.set_address_size(view.address_size() as u8); - range_data_offsets = parse_unwind_section(view, eh_frame) - .map_err(|e| error!("Error parsing .eh_frame: {}", e))?; - } else if view.section_by_name(".debug_frame").is_some() - || view.section_by_name("__debug_frame").is_some() - { - let debug_frame_endian = get_endian(view); - let debug_frame_section_reader = |section_id: SectionId| -> _ { - create_section_reader(section_id, view, debug_frame_endian, dwo_file) - }; - let mut debug_frame = gimli::DebugFrame::load(debug_frame_section_reader).unwrap(); - debug_frame.set_address_size(view.address_size() as u8); - range_data_offsets = parse_unwind_section(view, debug_frame) - .map_err(|e| error!("Error parsing .debug_frame: {}", e))?; - } else { - range_data_offsets = Default::default(); - } + }; // Create debug info builder and recover name mapping first // Since DWARF is stored as a tree with arbitrary implicit edges among leaves, |
