struct_audit/
loader.rs

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            // Convert Cow to slice - we know this is safe because we keep mmap alive
47            let slice: &[u8] = match &data {
48                Cow::Borrowed(b) => b,
49                Cow::Owned(_) => {
50                    // For compressed sections, we'd need different handling
51                    // For now, skip them
52                    &[]
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}