summaryrefslogtreecommitdiff
path: root/plugins/dwarf
diff options
context:
space:
mode:
authorJosh Ferrell <josh@vector35.com>2025-04-18 15:46:27 -0400
committerJosh Ferrell <josh@vector35.com>2025-04-23 15:46:37 -0400
commit0493db09dee436a9ecb9009ae7222dccefd3d5e3 (patch)
tree7a775b5b383fcd77bb9ed3bab665a6b2d8a86408 /plugins/dwarf
parent8385022779729901786510517878173596454097 (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.rs2
-rw-r--r--plugins/dwarf/dwarf_import/src/functions.rs2
-rw-r--r--plugins/dwarf/dwarf_import/src/helpers.rs30
-rw-r--r--plugins/dwarf/dwarf_import/src/lib.rs103
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,