Skip to content

Commit 0493db0

Browse files
committed
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
1 parent 8385022 commit 0493db0

File tree

4 files changed

+92
-45
lines changed

4 files changed

+92
-45
lines changed

plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ impl DebugInfoBuilder {
608608
if func.address.is_none() && func.raw_name.is_some() {
609609
// 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 )
610610
if symbol.sym_type() != SymbolType::ImportAddress {
611-
func.address = Some(symbol.address());
611+
func.address = Some(symbol.address() - bv.start());
612612
}
613613
}
614614

plugins/dwarf/dwarf_import/src/functions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub(crate) fn parse_function_entry<R: ReaderType>(
8181
debug_info_builder: &mut DebugInfoBuilder,
8282
) -> Option<usize> {
8383
// Collect function properties (if they exist in this DIE)
84-
let raw_name = get_raw_name(dwarf, unit, entry);
84+
let raw_name = get_raw_name(dwarf, unit, entry, debug_info_builder_context);
8585
let return_type = get_type(
8686
dwarf,
8787
unit,

plugins/dwarf/dwarf_import/src/helpers.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,21 +221,31 @@ pub(crate) fn get_raw_name<R: ReaderType>(
221221
dwarf: &Dwarf<R>,
222222
unit: &Unit<R>,
223223
entry: &DebuggingInformationEntry<R>,
224+
debug_info_builder_context: &DebugInfoBuilderContext<R>,
224225
) -> Option<String> {
225-
if let Ok(Some(attr_val)) = entry.attr_value(constants::DW_AT_linkage_name) {
226-
if let Ok(attr_string) = dwarf.attr_string(unit, attr_val.clone()) {
227-
if let Ok(attr_string) = attr_string.to_string() {
228-
return Some(attr_string.to_string());
229-
}
230-
} else if let Some(dwarf) = dwarf.sup() {
231-
if let Ok(attr_string) = dwarf.attr_string(unit, attr_val) {
232-
if let Ok(attr_string) = attr_string.to_string() {
233-
return Some(attr_string.to_string());
226+
match resolve_specification(dwarf, unit, entry, debug_info_builder_context) {
227+
DieReference::UnitAndOffset((dwarf, entry_unit, entry_offset)) => {
228+
if let Ok(Some(attr_val)) = entry_unit
229+
.entry(entry_offset)
230+
.unwrap()
231+
.attr_value(constants::DW_AT_linkage_name)
232+
{
233+
if let Ok(attr_string) = dwarf.attr_string(entry_unit, attr_val.clone()) {
234+
if let Ok(attr_string) = attr_string.to_string() {
235+
return Some(attr_string.to_string());
236+
}
237+
} else if let Some(dwarf) = &dwarf.sup {
238+
if let Ok(attr_string) = dwarf.attr_string(entry_unit, attr_val) {
239+
if let Ok(attr_string) = attr_string.to_string() {
240+
return Some(attr_string.to_string());
241+
}
242+
}
234243
}
235244
}
245+
None
236246
}
247+
DieReference::Err => None,
237248
}
238-
None
239249
}
240250

241251
// Get the size of an object as a usize

plugins/dwarf/dwarf_import/src/lib.rs

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ use gimli::{
4444

4545
use binaryninja::logger::Logger;
4646
use helpers::{get_build_id, load_debug_info_for_build_id};
47+
use iset::IntervalMap;
4748
use log::{debug, error, warn};
4849

4950
trait ReaderType: Reader<Offset = usize> {}
@@ -374,37 +375,39 @@ where
374375
{
375376
let mut bases = gimli::BaseAddresses::default();
376377

378+
let view_start = view.start();
379+
377380
if let Some(section) = view
378381
.section_by_name(".eh_frame_hdr")
379382
.or(view.section_by_name("__eh_frame_hdr"))
380383
{
381-
bases = bases.set_eh_frame_hdr(section.start());
384+
bases = bases.set_eh_frame_hdr(section.start() - view_start);
382385
}
383386

384387
if let Some(section) = view
385388
.section_by_name(".eh_frame")
386389
.or(view.section_by_name("__eh_frame"))
387390
{
388-
bases = bases.set_eh_frame(section.start());
391+
bases = bases.set_eh_frame(section.start() - view_start);
389392
} else if let Some(section) = view
390393
.section_by_name(".debug_frame")
391394
.or(view.section_by_name("__debug_frame"))
392395
{
393-
bases = bases.set_eh_frame(section.start());
396+
bases = bases.set_eh_frame(section.start() - view_start);
394397
}
395398

396399
if let Some(section) = view
397400
.section_by_name(".text")
398401
.or(view.section_by_name("__text"))
399402
{
400-
bases = bases.set_text(section.start());
403+
bases = bases.set_text(section.start() - view_start);
401404
}
402405

403406
if let Some(section) = view
404407
.section_by_name(".got")
405408
.or(view.section_by_name("__got"))
406409
{
407-
bases = bases.set_got(section.start());
410+
bases = bases.set_got(section.start() - view_start);
408411
}
409412

410413
let mut cies = HashMap::new();
@@ -453,6 +456,19 @@ where
453456
register: _,
454457
offset,
455458
} => {
459+
//TODO: can we normalize this to be sp-based?
460+
/*
461+
Switching to RBP from RSP in this example breaks things, and we should know that RBP = RSP - 8
462+
65 │ 0x1139: CFA=RSP+8: RIP=[CFA-8]
463+
66 │ 0x113a: CFA=RSP+16: RBP=[CFA-16], RIP=[CFA-8]
464+
67 │ 0x113d: CFA=RBP+16: RBP=[CFA-16], RIP=[CFA-8]
465+
68 │ 0x1162: CFA=RSP+8: RBP=[CFA-16], RIP=[CFA-8]
466+
467+
can we
468+
know that CFA=RSP+8 at the beginning
469+
in the next instruction (66) we know RBP=[CFA-16]=[RSP-8]
470+
and do something with that?
471+
*/
456472
// TODO: we should store offsets by register
457473
if row.start_address() < row.end_address() {
458474
cfa_offsets
@@ -497,8 +513,44 @@ fn get_supplementary_build_id(bv: &BinaryView) -> Option<String> {
497513
}
498514
}
499515

516+
fn parse_range_data_offsets(bv: &BinaryView, dwo_file: bool) -> Option<Result<IntervalMap<u64, i64>, ()>> {
517+
if bv.section_by_name(".eh_frame").is_some() || bv.section_by_name("__eh_frame").is_some() {
518+
let eh_frame_endian = get_endian(bv);
519+
let eh_frame_section_reader = |section_id: SectionId| -> _ {
520+
create_section_reader(section_id, bv, eh_frame_endian, dwo_file)
521+
};
522+
let mut eh_frame = gimli::EhFrame::load(eh_frame_section_reader).unwrap();
523+
if let Some(view_arch) = bv.default_arch() {
524+
if view_arch.name().as_str() == "aarch64" {
525+
eh_frame.set_vendor(gimli::Vendor::AArch64);
526+
}
527+
}
528+
eh_frame.set_address_size(bv.address_size() as u8);
529+
Some(parse_unwind_section(bv, eh_frame)
530+
.map_err(|e| error!("Error parsing .eh_frame: {}", e)))
531+
} else if bv.section_by_name(".debug_frame").is_some()
532+
|| bv.section_by_name("__debug_frame").is_some()
533+
{
534+
let debug_frame_endian = get_endian(bv);
535+
let debug_frame_section_reader = |section_id: SectionId| -> _ {
536+
create_section_reader(section_id, bv, debug_frame_endian, dwo_file)
537+
};
538+
let mut debug_frame = gimli::DebugFrame::load(debug_frame_section_reader).unwrap();
539+
if let Some(view_arch) = bv.default_arch() {
540+
if view_arch.name().as_str() == "aarch64" {
541+
debug_frame.set_vendor(gimli::Vendor::AArch64);
542+
}
543+
}
544+
debug_frame.set_address_size(bv.address_size() as u8);
545+
Some(parse_unwind_section(bv, debug_frame)
546+
.map_err(|e| error!("Error parsing .debug_frame: {}", e)))
547+
} else {
548+
None
549+
}
550+
}
551+
500552
fn parse_dwarf(
501-
_bv: &BinaryView,
553+
bv: &BinaryView,
502554
debug_bv: &BinaryView,
503555
supplementary_bv: Option<&BinaryView>,
504556
progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>,
@@ -548,35 +600,20 @@ fn parse_dwarf(
548600
}
549601
}
550602

551-
let range_data_offsets;
552-
if view.section_by_name(".eh_frame").is_some() || view.section_by_name("__eh_frame").is_some() {
553-
let eh_frame_endian = get_endian(view);
554-
let eh_frame_section_reader = |section_id: SectionId| -> _ {
555-
create_section_reader(section_id, view, eh_frame_endian, dwo_file)
556-
};
557-
let mut eh_frame = gimli::EhFrame::load(eh_frame_section_reader).unwrap();
558-
if let Some(view_arch) = view.default_arch() {
559-
if view_arch.name().as_str() == "aarch64" {
560-
eh_frame.set_vendor(gimli::Vendor::AArch64);
603+
let range_data_offsets = match parse_range_data_offsets(bv, dwo_file) {
604+
Some(x) => x?,
605+
None => {
606+
if let Some(raw_view) = bv.raw_view() {
607+
if let Some(offsets) = parse_range_data_offsets(&raw_view, dwo_file) {
608+
offsets?
609+
} else {
610+
Default::default()
611+
}
612+
} else {
613+
Default::default()
561614
}
562615
}
563-
eh_frame.set_address_size(view.address_size() as u8);
564-
range_data_offsets = parse_unwind_section(view, eh_frame)
565-
.map_err(|e| error!("Error parsing .eh_frame: {}", e))?;
566-
} else if view.section_by_name(".debug_frame").is_some()
567-
|| view.section_by_name("__debug_frame").is_some()
568-
{
569-
let debug_frame_endian = get_endian(view);
570-
let debug_frame_section_reader = |section_id: SectionId| -> _ {
571-
create_section_reader(section_id, view, debug_frame_endian, dwo_file)
572-
};
573-
let mut debug_frame = gimli::DebugFrame::load(debug_frame_section_reader).unwrap();
574-
debug_frame.set_address_size(view.address_size() as u8);
575-
range_data_offsets = parse_unwind_section(view, debug_frame)
576-
.map_err(|e| error!("Error parsing .debug_frame: {}", e))?;
577-
} else {
578-
range_data_offsets = Default::default();
579-
}
616+
};
580617

581618
// Create debug info builder and recover name mapping first
582619
// Since DWARF is stored as a tree with arbitrary implicit edges among leaves,

0 commit comments

Comments
 (0)