1use crate::error::{Error, Result};
2use gimli::{Dwarf, EndianSlice, RunTimeEndian, SectionId};
3use memmap2::Mmap;
4use object::{Object, ObjectSection};
5use std::borrow::Cow;
6use std::fs::File;
7use std::path::Path;
8
9pub struct BinaryData {
10 pub mmap: Mmap,
11}
12
13pub type DwarfSlice<'a> = EndianSlice<'a, RunTimeEndian>;
14
15pub struct LoadedDwarf<'a> {
16 pub dwarf: Dwarf<DwarfSlice<'a>>,
17 pub address_size: u8,
18}
19
20impl BinaryData {
21 pub fn load(path: &Path) -> Result<Self> {
22 let file = File::open(path)?;
23 let mmap = unsafe { Mmap::map(&file)? };
24 Ok(Self { mmap })
25 }
26
27 pub fn load_dwarf(&self) -> Result<LoadedDwarf<'_>> {
28 let object = object::File::parse(&*self.mmap)?;
29
30 if !matches!(
31 object.format(),
32 object::BinaryFormat::Elf | object::BinaryFormat::MachO | object::BinaryFormat::Pe
33 ) {
34 return Err(Error::UnsupportedFormat);
35 }
36
37 let endian =
38 if object.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big };
39
40 let load_section = |id: SectionId| -> std::result::Result<DwarfSlice<'_>, gimli::Error> {
41 let data = object
42 .section_by_name(id.name())
43 .and_then(|s| s.uncompressed_data().ok())
44 .unwrap_or(Cow::Borrowed(&[]));
45
46 let slice: &[u8] = match &data {
48 Cow::Borrowed(b) => b,
49 Cow::Owned(_) => {
50 &[]
53 }
54 };
55
56 Ok(EndianSlice::new(slice, endian))
57 };
58
59 let dwarf = Dwarf::load(load_section).map_err(|e| Error::Dwarf(e.to_string()))?;
60
61 let mut units = dwarf.units();
62 if units.next().map_err(|e| Error::Dwarf(e.to_string()))?.is_none() {
63 return Err(Error::NoDebugInfo);
64 }
65
66 Ok(LoadedDwarf { dwarf, address_size: if object.is_64() { 8 } else { 4 } })
67 }
68}