~taiite/protodump

47a321af432790ee7c58799b40013440300e137f — Hubert Hirtz 1 year, 5 months ago 12246fc
Match DWARF info address with symbol address

so that if there are multiple dwarf entries with the same name, the
correct one is selected.
2 files changed, 51 insertions(+), 24 deletions(-)

M src/dwarf.rs
M src/main.rs
M src/dwarf.rs => src/dwarf.rs +33 -13
@@ 19,10 19,20 @@ where
    }
}

#[derive(Clone, PartialEq)]
#[derive(Clone)]
pub struct Subprogram<R> {
    pub return_type: Option<types::InstancePtr<R>>,
    pub parameters: Option<Vec<Parameter<R>>>,
    pub address: u64,
}

impl<R> PartialEq for Subprogram<R>
where
    R: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        self.return_type == other.return_type && self.parameters == other.parameters
    }
}

impl types::Comparator {


@@ 126,6 136,23 @@ where
    }
}

pub fn entry_address_attr<R>(
    entry: &gimli::DebuggingInformationEntry<R>,
    attr: gimli::DwAt,
) -> Result<Option<u64>>
where
    R: gimli::Reader,
{
    let av = match entry.attr_value(attr)? {
        Some(av) => av,
        None => return Ok(None),
    };
    Ok(Some(match av {
        gimli::AttributeValue::Addr(n) => n,
        av => anyhow::bail!("unexpected attribute value for {}: {:?}", attr, av),
    }))
}

pub fn entry_int_attr<R>(
    entry: &gimli::DebuggingInformationEntry<R>,
    attr: gimli::DwAt,


@@ 231,24 258,16 @@ where
                    // This debug entry is not a function.
                    continue;
                }
                if let Some(gimli::AttributeValue::Flag(true)) =
                    entry.attr_value(gimli::DW_AT_declaration)?
                {
                    // This debug entry does not define the function.
                    continue;
                }

                let name = entry_name(dwarf, &unit, entry)?;
                let Some(name) = entry_name(dwarf, &unit, entry)? else { continue };
                let Some(address) = entry_address_attr(entry, gimli::DW_AT_low_pc)?
                    else { continue };
                let typ = entry_type(&mut type_cache, &unit, entry)?;
                if name.is_none() {
                    continue;
                }
                let name = name.unwrap();
                let mut parameters = Vec::new();

                let prototyped = matches!(
                    entry.attr_value(gimli::DW_AT_prototyped)?,
                    Some(gimli::AttributeValue::Flag(true))
                    Some(gimli::AttributeValue::Flag(true)),
                );

                if entry.has_children() {


@@ 283,6 302,7 @@ where
                    Subprogram {
                        return_type: typ,
                        parameters,
                        address,
                    },
                );
            }

M src/main.rs => src/main.rs +18 -11
@@ 4,7 4,7 @@ use object::read::Object as _;
use object::read::ObjectSection as _;
use object::read::ObjectSymbol as _;
use std::borrow::Cow;
use std::collections::HashSet;
use std::collections::HashMap;
use std::env;
use std::fmt;
use std::fs;


@@ 58,7 58,7 @@ struct SymbolFilter {
struct ObjectInfo<'a> {
    container_type: ContainerType,
    is_little_endian: bool,
    symbol_whitelist: HashSet<&'a str>,
    symbol_whitelist: HashMap<&'a str, u64>,
}

impl PartialEq for ObjectInfo<'_> {


@@ 304,11 304,14 @@ fn read_object_info<'a>(obj: &object::File<'a>, filter: SymbolFilter) -> Result<
        format => anyhow::bail!("unsupported object format: {:?}", format),
    };

    let mut symbol_whitelist: HashSet<_> = obj
    let mut symbol_whitelist: HashMap<_, _> = obj
        .dynamic_symbols()
        .filter(|symbol| symbol.kind() == object::SymbolKind::Text)
        .filter(|symbol| filter.imports || !symbol.is_undefined())
        .filter_map(|symbol| symbol.name().ok())
        .filter_map(|symbol| {
            let name = symbol.name().ok()?;
            Some((name, symbol.address()))
        })
        .collect();

    if filter.globals || filter.locals {


@@ 325,7 328,7 @@ fn read_object_info<'a>(obj: &object::File<'a>, filter: SymbolFilter) -> Result<
                continue;
            }
            if let Ok(name) = symbol.name() {
                symbol_whitelist.insert(name);
                symbol_whitelist.insert(name, symbol.address());
            }
        }
    }


@@ 455,10 458,12 @@ fn main() -> Result<()> {
    let mut sources = Sources::parse(&dwarf)?;
    let object_info = read_object_info(&obj, symbol_filter)?;

    sources.subprograms.retain(|func, _| {
        object_info
    sources.subprograms.retain(|func, subprogram| {
        let Some(symbol_address) = object_info
            .symbol_whitelist
            .contains(func.to_string_lossy().as_ref())
            .get(func.to_string_lossy().as_ref())
            else { return false };
        *symbol_address == subprogram.address
    });

    if let Some(baseline_path) = matches.opt_str("d") {


@@ 480,10 485,12 @@ fn main() -> Result<()> {
        let mut baseline_sources = Sources::parse(&baseline_dwarf)?;
        let baseline_object_info = read_object_info(&baseline_obj, symbol_filter)?;

        baseline_sources.subprograms.retain(|func, _| {
            baseline_object_info
        baseline_sources.subprograms.retain(|func, subprogram| {
            let Some(symbol_address) = baseline_object_info
                .symbol_whitelist
                .contains(func.to_string_lossy().as_ref())
                .get(func.to_string_lossy().as_ref())
                else { return false };
            *symbol_address == subprogram.address
        });

        let mut is_match = true;