Finish collecting dwarf dependencies

This commit is contained in:
Audrey 2024-04-16 22:04:15 -07:00
parent 68aa47a94e
commit 6926711e83
2 changed files with 46 additions and 7 deletions

View File

@ -4,6 +4,7 @@ use std::{
path::PathBuf, borrow::Cow,
};
use gimli::{constants, AttributeValue, DW_TAG_compile_unit};
use serde::{Deserialize, Serialize};
use sha2::{digest::generic_array::{GenericArray, typenum::U32}, Digest, Sha256};
use object::{Object, ReadCache, ObjectSection};
@ -129,14 +130,15 @@ impl FileStore {
}
let fp = fs::File::open(&filename)?;
self.ingest_output(filename, fp)
self.ingest_output(filename, fp);
Ok(())
}
pub fn ingest_output(
&mut self,
filename: PathBuf,
mut content: (impl io::Read + io::Seek),
) -> anyhow::Result<()> {
) -> anyhow::Result<usize> {
let mut h = Sha256::new();
io::copy(&mut content, &mut h)?;
let hash = h.finalize().into();
@ -167,7 +169,7 @@ impl FileStore {
self.filenames.insert(filename, index);
Ok(())
Ok(index)
}
fn parse_format(&mut self, fp: &mut (impl io::Read + io::Seek)) -> anyhow::Result<FileFormat> {
@ -189,22 +191,57 @@ impl FileStore {
let mut load_section = |id: gimli::SectionId| -> Result<_, _> {
load_file_section(id, &elf, endian, &arena_data)
};
let mut dwarf = gimli::Dwarf::load(&mut load_section).unwrap();
let dwarf = gimli::Dwarf::load(&mut load_section).unwrap();
let mut units = dwarf.units();
let mut inputs = vec![];
while let Ok(Some(unit)) = units.next() {
let abbrev = dwarf.abbreviations(&unit)?;
let mut entries = unit.entries(&abbrev);
while let Ok(Some(entry)) = entries.next_sibling() {
while let Some((_, entry)) = entries.next_dfs()? {
if entry.tag() == DW_TAG_compile_unit {
let mut basename = None;
let mut dirname = None;
if let Some(name) = entry.attr(constants::DW_AT_name)?.map(|a| a.value()) {
if let Ok(name) = dwarf.attr_string(&dwarf.unit(unit)?, name) {
basename = Some(PathBuf::from(name.to_string()?));
}
}
if let Some(name) = entry.attr(constants::DW_AT_comp_dir)?.map(|a| a.value()) {
if let Ok(name) = dwarf.attr_string(&dwarf.unit(unit)?, name) {
dirname = Some(PathBuf::from(name.to_string()?));
}
}
if let (Some(dirname), Some(basename)) = (dirname, basename) {
inputs.push(dirname.join(basename));
}
}
}
}
assert!(elf.is_little_endian());
let references = inputs.into_iter().map(|input| self.ingest_dependency_local(input)).collect::<Result<Vec<_>, _>>()?.into_iter().filter_map(|x| x).collect();
FileFormat::ELF {
references: vec![],
references,
}
},
_ => FileFormat::Other,
})
}
fn ingest_dependency_local(&mut self, filename: PathBuf) -> anyhow::Result<Option<usize>> {
// TODO: this needs to try suffixes of the filename against the filepath table to see if it
// was moved between compilation and ingestion
let metadata = match fs::metadata(&filename) {
Ok(m) => m,
Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(None),
Err(e) => return Err(e)?,
};
if !metadata.is_file() {
return Ok(None);
}
let fp = fs::File::open(&filename)?;
Ok(Some(self.ingest_output(filename, fp)?))
}
}
fn load_file_section<'input, 'arena, Endian: gimli::Endianity, R: object::ReadRef<'input>>(

View File

@ -585,6 +585,8 @@ impl Tracer {
// So we need to determine whether exec is successful here.
// PTRACE_EVENT_EXEC only happens for successful exec.
p.is_exec_successful = true;
let path = p.pending_syscall_event.iter().find_map(|e| match e { Event::Exec { prog, .. } => Some(prog.clone()), _ => None }).unwrap();
self.report.files.ingest_output_local(path)?;
self.drain_syscall_events(pid.into(), Box::new(|_| {}));
// Don't use seccomp_aware_cont here because that will skip the next syscall exit stop
self.syscall_enter_cont(pid.into())?;