use crate::debugger::debugee::dwarf::EndianArcSlice;
use crate::debugger::error::Error;
use gimli::{
AbbreviationsCache, DebugAbbrev, DebugAddr, DebugAranges, DebugInfo, DebugLine, DebugLineStr,
DebugLoc, DebugLocLists, DebugMacinfo, DebugMacro, DebugNames, DebugRanges, DebugRngLists,
DebugStr, DebugStrOffsets, DebugTypes, Dwarf, DwarfFileType, LocationLists, RangeLists,
RunTimeEndian, Section, SectionId,
};
use object::{File, Object, ObjectSection};
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use std::borrow::Cow;
use std::sync::Arc;
use std::sync::Mutex;
#[derive(Default)]
struct Sections {
debug_abbrev: Option<DebugAbbrev<EndianArcSlice>>,
debug_addr: Option<DebugAddr<EndianArcSlice>>,
debug_aranges: Option<DebugAranges<EndianArcSlice>>,
debug_info: Option<DebugInfo<EndianArcSlice>>,
debug_line: Option<DebugLine<EndianArcSlice>>,
debug_line_str: Option<DebugLineStr<EndianArcSlice>>,
debug_macro: Option<DebugMacro<EndianArcSlice>>,
debug_macinfo: Option<DebugMacinfo<EndianArcSlice>>,
debug_names: Option<DebugNames<EndianArcSlice>>,
debug_str: Option<DebugStr<EndianArcSlice>>,
debug_str_offsets: Option<DebugStrOffsets<EndianArcSlice>>,
debug_types: Option<DebugTypes<EndianArcSlice>>,
debug_loc: Option<DebugLoc<EndianArcSlice>>,
debug_loclists: Option<DebugLocLists<EndianArcSlice>>,
debug_ranges: Option<DebugRanges<EndianArcSlice>>,
debug_rnglists: Option<DebugRngLists<EndianArcSlice>>,
}
pub fn load_section(
id: SectionId,
file: &File,
endian: RunTimeEndian,
) -> Result<EndianArcSlice, Error> {
let data = file
.section_by_name(id.name())
.and_then(|section| section.uncompressed_data().ok())
.unwrap_or(Cow::Borrowed(&[]));
Ok(gimli::EndianArcSlice::new(Arc::from(&*data), endian))
}
macro_rules! make_sect_loader {
($file: expr, $endian: expr, $field: tt) => {{
move |dest: Arc<Mutex<Option<Sections>>>| -> Result<(), Error> {
let sect = Section::load(|id| load_section(id, $file, $endian))?;
let mut lock = dest.lock().expect("unexpected: panic in another lock");
let sections = lock.as_mut().expect("unexpected: sections must exists");
sections.$field = Some(sect);
Ok(())
}
}};
}
pub fn load_par(file: &File, endian: RunTimeEndian) -> Result<Dwarf<EndianArcSlice>, Error> {
let load_debug_abbrev = make_sect_loader!(file, endian, debug_abbrev);
let load_debug_addr = make_sect_loader!(file, endian, debug_addr);
let load_debug_aranges = make_sect_loader!(file, endian, debug_aranges);
let load_debug_info = make_sect_loader!(file, endian, debug_info);
let load_debug_line = make_sect_loader!(file, endian, debug_line);
let load_debug_line_str = make_sect_loader!(file, endian, debug_line_str);
let load_debug_macro = make_sect_loader!(file, endian, debug_macro);
let load_debug_macinfo = make_sect_loader!(file, endian, debug_macinfo);
let load_debug_names = make_sect_loader!(file, endian, debug_names);
let load_debug_str = make_sect_loader!(file, endian, debug_str);
let load_debug_str_offsets = make_sect_loader!(file, endian, debug_str_offsets);
let load_debug_types = make_sect_loader!(file, endian, debug_types);
let load_debug_loc = make_sect_loader!(file, endian, debug_loc);
let load_debug_loclists = make_sect_loader!(file, endian, debug_loclists);
let load_debug_ranges = make_sect_loader!(file, endian, debug_ranges);
let load_debug_rnglists = make_sect_loader!(file, endian, debug_rnglists);
type SectLoaders<'a> =
Vec<Box<dyn FnOnce(Arc<Mutex<Option<Sections>>>) -> Result<(), Error> + Send + Sync + 'a>>;
let loaders: SectLoaders = vec![
Box::new(load_debug_abbrev),
Box::new(load_debug_addr),
Box::new(load_debug_aranges),
Box::new(load_debug_info),
Box::new(load_debug_line),
Box::new(load_debug_line_str),
Box::new(load_debug_macro),
Box::new(load_debug_macinfo),
Box::new(load_debug_names),
Box::new(load_debug_str),
Box::new(load_debug_str_offsets),
Box::new(load_debug_types),
Box::new(load_debug_loc),
Box::new(load_debug_loclists),
Box::new(load_debug_ranges),
Box::new(load_debug_rnglists),
];
let sections = Arc::new(Mutex::new(Some(Sections::default())));
loaders
.into_par_iter()
.try_for_each(|loader| loader(sections.clone()))?;
let sections = sections
.lock()
.expect("unexpected: panic in another lock")
.take()
.expect("unexpected: sections must exists");
const SECT_MUST_EXISTS: &str = "section must exists";
Ok(Dwarf {
debug_abbrev: sections.debug_abbrev.expect(SECT_MUST_EXISTS),
debug_addr: sections.debug_addr.expect(SECT_MUST_EXISTS),
debug_aranges: sections.debug_aranges.expect(SECT_MUST_EXISTS),
debug_info: sections.debug_info.expect(SECT_MUST_EXISTS),
debug_line: sections.debug_line.expect(SECT_MUST_EXISTS),
debug_line_str: sections.debug_line_str.expect(SECT_MUST_EXISTS),
debug_macro: sections.debug_macro.expect(SECT_MUST_EXISTS),
debug_macinfo: sections.debug_macinfo.expect(SECT_MUST_EXISTS),
debug_names: sections.debug_names.expect(SECT_MUST_EXISTS),
debug_str: sections.debug_str.expect(SECT_MUST_EXISTS),
debug_str_offsets: sections.debug_str_offsets.expect(SECT_MUST_EXISTS),
debug_types: sections.debug_types.expect(SECT_MUST_EXISTS),
locations: LocationLists::new(
sections.debug_loc.expect(SECT_MUST_EXISTS),
sections.debug_loclists.expect(SECT_MUST_EXISTS),
),
ranges: RangeLists::new(
sections.debug_ranges.expect(SECT_MUST_EXISTS),
sections.debug_rnglists.expect(SECT_MUST_EXISTS),
),
file_type: DwarfFileType::Main,
sup: None,
abbreviations_cache: AbbreviationsCache::new(),
})
}