summaryrefslogtreecommitdiff
path: root/plugins/dwarf/dwarf_import/src
diff options
context:
space:
mode:
authorJosh Ferrell <josh@vector35.com>2025-10-16 12:19:57 -0400
committerJosh Ferrell <josh@vector35.com>2025-10-16 20:29:43 -0400
commitb6740d03abd22441e2e79e1d6a13c474e3fcba90 (patch)
treeb4b317e182f23a0b9f2f633b25c54bed814abb4b /plugins/dwarf/dwarf_import/src
parente75d64a86a128b9a8cb3cb606e5f9560e90a4758 (diff)
Apply relocations when parsing DWARF
Diffstat (limited to 'plugins/dwarf/dwarf_import/src')
-rw-r--r--plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs4
-rw-r--r--plugins/dwarf/dwarf_import/src/lib.rs207
2 files changed, 93 insertions, 118 deletions
diff --git a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs
index 0dc6b7fb..94f370a1 100644
--- a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs
+++ b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs
@@ -125,7 +125,7 @@ pub(crate) struct DebugInfoBuilderContext<R: ReaderType> {
}
impl<R: ReaderType> DebugInfoBuilderContext<R> {
- pub(crate) fn new(view: &BinaryView, dwarf: &Dwarf<R>) -> Option<Self> {
+ pub(crate) fn new(default_address_size: usize, dwarf: &Dwarf<R>) -> Option<Self> {
let mut units = vec![];
let mut iter = dwarf.units();
while let Ok(Some(header)) = iter.next() {
@@ -154,7 +154,7 @@ impl<R: ReaderType> DebugInfoBuilderContext<R> {
units,
sup_units,
names: HashMap::new(),
- default_address_size: view.address_size(),
+ default_address_size,
total_die_count: 0,
total_unit_size_bytes: 0,
})
diff --git a/plugins/dwarf/dwarf_import/src/lib.rs b/plugins/dwarf/dwarf_import/src/lib.rs
index dcac4f0b..8ad5e442 100644
--- a/plugins/dwarf/dwarf_import/src/lib.rs
+++ b/plugins/dwarf/dwarf_import/src/lib.rs
@@ -32,9 +32,7 @@ use binaryninja::{
settings::Settings,
template_simplifier::simplify_str_to_str,
};
-use dwarfreader::{
- create_section_reader, get_endian, is_dwo_dwarf, is_non_dwo_dwarf, is_raw_dwo_dwarf,
-};
+use dwarfreader::{create_section_reader_object, get_endian, is_dwo_dwarf, is_non_dwo_dwarf};
use functions::parse_lexical_block;
use gimli::{
@@ -46,6 +44,7 @@ use binaryninja::logger::Logger;
use helpers::{get_build_id, load_debug_info_for_build_id};
use iset::IntervalMap;
use log::{debug, error, warn};
+use object::{Object, ObjectSection};
trait ReaderType: Reader<Offset = usize> {}
impl<T: Reader<Offset = usize>> ReaderType for T {}
@@ -388,7 +387,7 @@ fn parse_unit<R: ReaderType>(
}
fn parse_unwind_section<R: Reader, U: UnwindSection<R>>(
- view: &BinaryView,
+ file: &object::File,
unwind_section: U,
) -> gimli::Result<iset::IntervalMap<u64, i64>>
where
@@ -396,40 +395,22 @@ where
{
let mut bases = gimli::BaseAddresses::default();
- // DWARF info is stored relative to the original image base (0 for relocatable images), normalize entries to the original image base
- let section_adjustment = view.original_image_base().wrapping_sub(view.image_base());
-
- 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().wrapping_add(section_adjustment));
+ if let Some(section) = file.section_by_name(".eh_frame_hdr") {
+ bases = bases.set_eh_frame_hdr(section.address());
}
- if let Some(section) = view
- .section_by_name(".eh_frame")
- .or(view.section_by_name("__eh_frame"))
- {
- bases = bases.set_eh_frame(section.start().wrapping_add(section_adjustment));
- } 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().wrapping_add(section_adjustment));
+ if let Some(section) = file.section_by_name(".eh_frame") {
+ bases = bases.set_eh_frame(section.address());
+ } else if let Some(section) = file.section_by_name(".debug_frame") {
+ bases = bases.set_eh_frame(section.address());
}
- if let Some(section) = view
- .section_by_name(".text")
- .or(view.section_by_name("__text"))
- {
- bases = bases.set_text(section.start().wrapping_add(section_adjustment));
+ if let Some(section) = file.section_by_name(".text") {
+ bases = bases.set_text(section.address());
}
- if let Some(section) = view
- .section_by_name(".got")
- .or(view.section_by_name("__got"))
- {
- bases = bases.set_got(section.start().wrapping_add(section_adjustment));
+ if let Some(section) = file.section_by_name(".got") {
+ bases = bases.set_got(section.address());
}
let mut cies = HashMap::new();
@@ -535,58 +516,49 @@ 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 = match gimli::EhFrame::load(eh_frame_section_reader) {
- Ok(x) => x,
- Err(e) => {
- log::error!("Failed to load EH frame: {}", e);
- return None;
- }
- };
- if let Some(view_arch) = bv.default_arch() {
- if view_arch.name().as_str() == "aarch64" {
- eh_frame.set_vendor(gimli::Vendor::AArch64);
- }
+fn parse_range_data_offsets(bv: &BinaryView) -> Result<IntervalMap<u64, i64>, String> {
+ let raw_view = bv.raw_view().unwrap();
+ let raw_view_data = raw_view.read_vec(0, raw_view.len() as usize);
+ let file =
+ object::File::parse(&*raw_view_data).map_err(|e| format!("Failed to parse bv: {}", e))?;
+ let dwo_file = file.section_by_name(".debug_info.dwo").is_some();
+ let endian = match file.endianness() {
+ object::Endianness::Little => gimli::RunTimeEndian::Little,
+ object::Endianness::Big => gimli::RunTimeEndian::Big,
+ };
+
+ let section_reader = |section_id: SectionId| -> _ {
+ create_section_reader_object(section_id, &file, endian, dwo_file)
+ };
+
+ if file.section_by_name(".eh_frame").is_some() {
+ let mut eh_frame = gimli::EhFrame::load(section_reader)
+ .map_err(|e| format!("Failed to load EH frame: {}", e))?;
+
+ if file.architecture() == object::Architecture::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 = match gimli::DebugFrame::load(debug_frame_section_reader) {
- Ok(x) => x,
- Err(e) => {
- log::error!("Failed to load debug frame: {}", e);
- return None;
- }
- };
- if let Some(view_arch) = bv.default_arch() {
- if view_arch.name().as_str() == "aarch64" {
- debug_frame.set_vendor(gimli::Vendor::AArch64);
- }
+
+ if let Some(address_size) = file.architecture().address_size() {
+ eh_frame.set_address_size(address_size.bytes());
}
- 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)),
- )
+
+ parse_unwind_section(&file, eh_frame).map_err(|e| format!("Error parsing .eh_frame: {}", e))
+ } else if file.section_by_name(".debug_frame").is_some() {
+ let mut debug_frame = gimli::DebugFrame::load(section_reader)
+ .map_err(|e| format!("Failed to load debug frame: {}", e))?;
+
+ if file.architecture() == object::Architecture::Aarch64 {
+ debug_frame.set_vendor(gimli::Vendor::AArch64);
+ }
+
+ if let Some(address_size) = file.architecture().address_size() {
+ debug_frame.set_address_size(address_size.bytes());
+ }
+ parse_unwind_section(&file, debug_frame)
+ .map_err(|e| format!("Error parsing .debug_frame: {}", e))
} else {
- None
+ Ok(Default::default())
}
}
@@ -595,35 +567,43 @@ fn parse_dwarf(
debug_bv: &BinaryView,
supplementary_bv: Option<&BinaryView>,
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
-) -> Result<DebugInfoBuilder, ()> {
+) -> Result<DebugInfoBuilder, String> {
// 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
// Figure out if it's the given view or the raw view that has the dwarf info in it
- let raw_view = &debug_bv.raw_view().ok_or(())?;
- let view = if is_dwo_dwarf(debug_bv) || is_non_dwo_dwarf(debug_bv) {
- debug_bv
+ let raw_view = &debug_bv
+ .raw_view()
+ .ok_or("Failed to get raw view for debug binary view".to_string())?;
+
+ let address_size = if is_dwo_dwarf(debug_bv) || is_non_dwo_dwarf(debug_bv) {
+ debug_bv.address_size()
} else {
- raw_view
+ raw_view.address_size()
};
- let dwo_file = is_dwo_dwarf(view) || is_raw_dwo_dwarf(view);
+ // Parse this early to reduce peak memory usage
+ let range_data_offsets = parse_range_data_offsets(bv).unwrap_or_default();
- // gimli setup
- let endian = get_endian(view);
- let mut section_reader =
- |section_id: SectionId| -> _ { create_section_reader(section_id, view, endian, dwo_file) };
+ // Read the raw view to an object::File so relocations get handled for us
+ let raw_view_data = raw_view.read_vec(0, raw_view.len() as usize);
+ let debug_file =
+ object::File::parse(&*raw_view_data).map_err(|e| format!("Failed to parse bv: {}", e))?;
+ let dwo_file = debug_file.section_by_name(".debug_info.dwo").is_some();
+ let endian = match debug_file.endianness() {
+ object::Endianness::Little => gimli::RunTimeEndian::Little,
+ object::Endianness::Big => gimli::RunTimeEndian::Big,
+ };
- let mut dwarf = match Dwarf::load(&mut section_reader) {
- Ok(x) => x,
- Err(e) => {
- error!("Failed to load DWARF info: {}", e);
- return Err(());
- }
+ let mut section_reader = |section_id: SectionId| -> _ {
+ create_section_reader_object(section_id, &debug_file, endian, dwo_file)
};
+ let mut dwarf = Dwarf::load(&mut section_reader)
+ .map_err(|e| format!("Failed to load DWARF info: {}", e))?;
+
if dwo_file {
dwarf.file_type = DwarfFileType::Dwo;
} else {
@@ -631,31 +611,22 @@ fn parse_dwarf(
}
if let Some(sup_bv) = supplementary_bv {
+ let sup_raw_view = sup_bv
+ .raw_view()
+ .ok_or_else(|| format!("Failed to get raw view for supplementary bv"))?;
+ let sup_view_data = sup_raw_view.read_vec(0, sup_raw_view.len() as usize);
+ let sup_file = object::File::parse(&*sup_view_data)
+ .map_err(|e| format!("Failed to parse supplementary bv: {}", e))?;
let sup_endian = get_endian(sup_bv);
- let sup_dwo_file = is_dwo_dwarf(sup_bv) || is_raw_dwo_dwarf(sup_bv);
+ let sup_dwo_file = sup_file.section_by_name(".debug_info.dwo").is_some();
let sup_section_reader = |section_id: SectionId| -> _ {
- create_section_reader(section_id, sup_bv, sup_endian, sup_dwo_file)
+ create_section_reader_object(section_id, &sup_file, sup_endian, sup_dwo_file)
};
if let Err(e) = dwarf.load_sup(sup_section_reader) {
error!("Failed to load supplementary file: {}", e);
}
}
- 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()
- }
- }
- };
-
// Create debug info builder and recover name mapping first
// Since DWARF is stored as a tree with arbitrary implicit edges among leaves,
// it is not possible to correctly track namespaces while you're parsing "in order" without backtracking,
@@ -663,7 +634,8 @@ fn parse_dwarf(
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 let Some(mut debug_info_builder_context) = DebugInfoBuilderContext::new(address_size, &dwarf)
+ {
calculate_total_unit_bytes(&dwarf, &mut debug_info_builder_context);
let progress_weights = [0.5, 0.5];
@@ -770,7 +742,10 @@ impl CustomDebugInfoParser for DWARFParser {
builder.post_process(bv, debug_info).commit_info(debug_info);
true
}
- Err(_) => false,
+ Err(e) => {
+ log::error!("Failed to parse DWARF: {}", e);
+ false
+ }
};
if let (Some(ext), true) = (external_file, close_external) {