diff options
| author | Josh Ferrell <josh@vector35.com> | 2024-10-08 22:55:09 -0400 |
|---|---|---|
| committer | Josh Ferrell <josh@vector35.com> | 2024-10-10 17:37:09 -0400 |
| commit | 7be992787ec6b299c7aeb42f6293809bd9288c67 (patch) | |
| tree | d8f8f35f26e384c9d6c229be2dfa72986c04a998 /rust/examples | |
| parent | 4539ae74c9ea3ea39efd3314fb34de757a4b1c5a (diff) | |
Parse .debug_frame if present and fix stack variable offset calculation
Diffstat (limited to 'rust/examples')
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs | 1 | ||||
| -rw-r--r-- | rust/examples/dwarf/dwarf_import/src/lib.rs | 76 |
2 files changed, 56 insertions, 21 deletions
diff --git a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs index d1208cc0..2a71b38a 100644 --- a/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs +++ b/rust/examples/dwarf/dwarf_import/src/dwarfdebuginfo.rs @@ -406,6 +406,7 @@ impl DebugInfoBuilder { return; }; + // TODO: offset should be calculated based off reference address and not function start let adjusted_offset = offset - offset_adjustment; if adjusted_offset > 0 { diff --git a/rust/examples/dwarf/dwarf_import/src/lib.rs b/rust/examples/dwarf/dwarf_import/src/lib.rs index 13c18a8c..94503856 100644 --- a/rust/examples/dwarf/dwarf_import/src/lib.rs +++ b/rust/examples/dwarf/dwarf_import/src/lib.rs @@ -37,10 +37,10 @@ use dwarfreader::{ create_section_reader, get_endian, is_dwo_dwarf, is_non_dwo_dwarf, is_raw_dwo_dwarf, }; -use gimli::{constants, DebuggingInformationEntry, Dwarf, DwarfFileType, Reader, Section, SectionId, Unit, UnwindSection}; +use gimli::{constants, CfaRule, DebuggingInformationEntry, Dwarf, DwarfFileType, Reader, Section, SectionId, Unit, UnwindContext, UnwindSection}; use helpers::{get_build_id, load_debug_info_for_build_id}; -use log::{error, warn, LevelFilter}; +use log::{debug, error, warn, LevelFilter}; trait ReaderType: Reader<Offset = usize> {} @@ -274,22 +274,27 @@ fn parse_unit<R: ReaderType>( } } -fn parse_eh_frame<R: Reader>( +fn parse_unwind_section<R: Reader, U: UnwindSection<R>>( view: &BinaryView, - mut eh_frame: gimli::EhFrame<R>, -) -> gimli::Result<iset::IntervalMap<u64, i64>> { - eh_frame.set_address_size(view.address_size() as u8); - + unwind_section: U, +) -> gimli::Result<iset::IntervalMap<u64, i64>> +where <U as UnwindSection<R>>::Offset: std::hash::Hash { let mut bases = gimli::BaseAddresses::default(); + if let Ok(section) = view.section_by_name(".eh_frame_hdr").or(view.section_by_name("__eh_frame_hdr")) { bases = bases.set_eh_frame_hdr(section.start()); } + if let Ok(section) = view.section_by_name(".eh_frame").or(view.section_by_name("__eh_frame")) { bases = bases.set_eh_frame(section.start()); + } else if let Ok(section) = view.section_by_name(".debug_frame").or(view.section_by_name("__debug_frame")) { + bases = bases.set_eh_frame(section.start()); } + if let Ok(section) = view.section_by_name(".text").or(view.section_by_name("__text")) { bases = bases.set_text(section.start()); } + if let Ok(section) = view.section_by_name(".got").or(view.section_by_name("__got")) { bases = bases.set_got(section.start()); } @@ -297,7 +302,8 @@ fn parse_eh_frame<R: Reader>( let mut cies = HashMap::new(); let mut cie_data_offsets = iset::IntervalMap::new(); - let mut entries = eh_frame.entries(&bases); + let mut entries = unwind_section.entries(&bases); + let mut unwind_context = UnwindContext::new(); loop { match entries.next()? { None => return Ok(cie_data_offsets), @@ -307,7 +313,7 @@ fn parse_eh_frame<R: Reader>( Some(gimli::CieOrFde::Fde(partial)) => { let fde = match partial.parse(|_, bases, o| { cies.entry(o) - .or_insert_with(|| eh_frame.cie_from_offset(bases, o)) + .or_insert_with(|| unwind_section.cie_from_offset(bases, o)) .clone() }) { Ok(fde) => fde, @@ -325,11 +331,23 @@ fn parse_eh_frame<R: Reader>( if fde.initial_address().overflowing_add(fde.len()).1 { warn!("FDE at offset {:?} exceeds bounds of memory space! {:#x} + length {:#x}", fde.offset(), fde.initial_address(), fde.len()); } else { - // Store CIE offset for FDE range - cie_data_offsets.insert( - fde.initial_address()..fde.initial_address() + fde.len(), - fde.cie().data_alignment_factor(), - ); + // Walk the FDE table rows and store their CFA + let mut fde_table = fde.rows(&unwind_section, &bases, &mut unwind_context)?; + while let Some(row) = fde_table.next_row()? { + match row.cfa() { + CfaRule::RegisterAndOffset {register: _, offset} => { + // TODO: this offset could be wrong because register might be something wacky + cie_data_offsets.insert( + row.start_address()..row.end_address(), + *offset, + ); + }, + CfaRule::Expression(_) => { + debug!("Unhandled CFA expression when determining offset"); + } + }; + + } } } } @@ -361,7 +379,7 @@ fn get_supplementary_build_id(bv: &BinaryView) -> Option<String> { } fn parse_dwarf( - bv: &BinaryView, + _bv: &BinaryView, debug_bv: &BinaryView, supplementary_bv: Option<&BinaryView>, progress: Box<dyn Fn(usize, usize) -> Result<(), ()>>, @@ -411,13 +429,29 @@ fn parse_dwarf( } } - let eh_frame_endian = get_endian(bv); - let mut eh_frame_section_reader = - |section_id: SectionId| -> _ { create_section_reader(section_id, bv, eh_frame_endian, dwo_file) }; - let eh_frame = gimli::EhFrame::load(&mut eh_frame_section_reader).unwrap(); + let range_data_offsets; + if view.section_by_name(".eh_frame").is_ok() || view.section_by_name("__eh_frame").is_ok() { + let eh_frame_endian = get_endian(view); + let mut 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(&mut eh_frame_section_reader).unwrap(); + 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_ok() || view.section_by_name("__debug_frame").is_ok() { + let debug_frame_endian = get_endian(view); + let mut 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(&mut 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(); + } - let range_data_offsets = parse_eh_frame(bv, eh_frame) - .map_err(|e| error!("Error parsing .eh_frame: {}", e))?; // Create debug info builder and recover name mapping first // Since DWARF is stored as a tree with arbitrary implicit edges among leaves, |
