isr-dwarf 0.5.0

DWARF parser for ISR
Documentation
use std::{fs::File, io::Read};

use gimli::RunTimeEndian;
use isr_core::schema::{Architecture, Profile};
use object::{Endianness, Object as _};

use super::{
    Error,
    symbols::SystemMapSymbols as _,
    types::{DwarfCache, DwarfTypes as _},
};

/// Parses `kernel_file` (DWARF) + `systemmap_file` and hands the resulting
/// [`Profile`] to `serialize`.
pub fn create_profile<F, E>(
    kernel_file: File,
    mut systemmap_file: File,
    serialize: F,
) -> Result<(), Error>
where
    F: FnOnce(&Profile) -> Result<(), E>,
    E: std::error::Error + Send + Sync + 'static,
{
    let kernel_mmap = unsafe { memmap2::Mmap::map(&kernel_file)? };
    let object = object::File::parse(&*kernel_mmap)?;
    let endian = match object.endianness() {
        Endianness::Little => RunTimeEndian::Little,
        Endianness::Big => RunTimeEndian::Big,
    };

    let dwarf_sections = super::_gimli::load_dwarf_sections(&object)?;
    let dwarf = super::_gimli::load_dwarf(&dwarf_sections, endian);

    let mut profile = Profile {
        architecture: Architecture::Amd64,
        ..Default::default()
    };

    tracing::debug!("collecting types");
    let mut iter = dwarf.units();
    let mut unit_len = 0;
    while iter.next()?.is_some() {
        unit_len += 1;
    }

    let mut cache = DwarfCache::new();
    let mut iter = dwarf.units();
    let mut unit_idx = 0;
    while let Some(header) = iter.next()? {
        unit_idx += 1;

        tracing::debug!("collecting types: {unit_idx}/{unit_len}");

        let unit = dwarf.unit(header)?;
        let unit_ref = unit.unit_ref(&dwarf);
        profile.add(&unit_ref, &mut cache)?;
    }

    tracing::debug!("collecting symbols");
    let mut systemmap = String::new();
    systemmap_file.read_to_string(&mut systemmap)?;
    profile.parse_symbols(&systemmap)?;

    tracing::debug!("writing profile");
    serialize(&profile).map_err(|err| Error::Serialization(err.into()))?;

    Ok(())
}