ghostscope-dwarf 0.1.5

DWARF parser and symbolizer used by GhostScope to resolve variables and types at runtime.
Documentation
use super::LoadedObjfile;
use crate::core::{GlobalVariableInfo, SectionType};
use object::{Object, ObjectSection};
use std::collections::HashSet;

impl LoadedObjfile {
    pub(crate) fn find_global_variables_by_name_any(&self, name: &str) -> Vec<GlobalVariableInfo> {
        let base = self.find_global_variables_by_name(name);
        if !base.is_empty() {
            return base;
        }

        let candidate_indices = self.matching_variable_candidate_indices(name);
        if candidate_indices.is_empty() {
            return Vec::new();
        }

        let obj = match object::File::parse(&self._binary_mapped_file.data[..]) {
            Ok(f) => f,
            Err(_) => return Vec::new(),
        };

        let mut out = Vec::new();
        let mut seen_offsets: HashSet<(u64, u64)> = HashSet::new();

        for idx in candidate_indices {
            if let Some(entry) = self.lightweight_index.entry(idx) {
                let key = (entry.unit_offset.0 as u64, entry.die_offset.0 as u64);
                if !seen_offsets.insert(key) {
                    continue;
                }
                let link_address = entry.representative_addr;
                let section = link_address.and_then(|addr| self.classify_section(&obj, addr));
                out.push(GlobalVariableInfo {
                    name: name.to_string(),
                    link_address,
                    section,
                    die_offset: entry.die_offset,
                    unit_offset: entry.unit_offset,
                });
            }
        }

        out
    }

    pub(crate) fn find_global_variables_by_name(&self, name: &str) -> Vec<GlobalVariableInfo> {
        let mut out = Vec::new();
        let entries = self.lightweight_index.find_variables_by_name(name);
        let mut seen_offsets: HashSet<(u64, u64)> = HashSet::new();

        let obj = match object::File::parse(&self._binary_mapped_file.data[..]) {
            Ok(f) => f,
            Err(_) => {
                for e in entries {
                    let key = (e.unit_offset.0 as u64, e.die_offset.0 as u64);
                    if !seen_offsets.insert(key) {
                        continue;
                    }
                    let link_address = e.representative_addr;
                    out.push(GlobalVariableInfo {
                        name: e.name.to_string(),
                        link_address,
                        section: None,
                        die_offset: e.die_offset,
                        unit_offset: e.unit_offset,
                    });
                }
                return out;
            }
        };

        for e in entries {
            let key = (e.unit_offset.0 as u64, e.die_offset.0 as u64);
            if !seen_offsets.insert(key) {
                continue;
            }
            let link_address = e.representative_addr;
            let section = link_address.and_then(|addr| self.classify_section(&obj, addr));

            out.push(GlobalVariableInfo {
                name: e.name.to_string(),
                link_address,
                section,
                die_offset: e.die_offset,
                unit_offset: e.unit_offset,
            });
        }

        out
    }

    fn classify_section(&self, obj: &object::File<'_>, addr: u64) -> Option<SectionType> {
        for sect in obj.sections() {
            let saddr = sect.address();
            let ssize = sect.size();
            if ssize == 0 {
                continue;
            }
            if addr >= saddr && addr < saddr + ssize {
                let name = sect.name().ok().unwrap_or("");
                let stype = if name == ".text" || name.starts_with(".text.") {
                    SectionType::Text
                } else if name == ".rodata"
                    || name.starts_with(".rodata")
                    || name.starts_with(".data.rel.ro")
                {
                    SectionType::Rodata
                } else if name == ".data" || name.starts_with(".data") {
                    SectionType::Data
                } else if name == ".bss" || name.starts_with(".bss.") {
                    SectionType::Bss
                } else {
                    SectionType::Unknown
                };
                return Some(stype);
            }
        }
        None
    }

    pub(crate) fn classify_section_for_vaddr(&self, addr: u64) -> Option<SectionType> {
        match object::File::parse(&self._binary_mapped_file.data[..]) {
            Ok(obj) => self.classify_section(&obj, addr),
            Err(_) => None,
        }
    }

    pub(crate) fn list_all_global_variables(&self) -> Vec<GlobalVariableInfo> {
        let mut out = Vec::new();
        let _obj = match object::File::parse(&self._binary_mapped_file.data[..]) {
            Ok(f) => f,
            Err(_) => {
                return out;
            }
        };

        for name in self.lightweight_index.get_variable_names() {
            for info in self.find_global_variables_by_name(name) {
                out.push(info);
            }
        }

        out
    }
}