Finish collecting dwarf dependencies
This commit is contained in:
parent
68aa47a94e
commit
6926711e83
|
@ -4,6 +4,7 @@ use std::{
|
||||||
path::PathBuf, borrow::Cow,
|
path::PathBuf, borrow::Cow,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use gimli::{constants, AttributeValue, DW_TAG_compile_unit};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{digest::generic_array::{GenericArray, typenum::U32}, Digest, Sha256};
|
use sha2::{digest::generic_array::{GenericArray, typenum::U32}, Digest, Sha256};
|
||||||
use object::{Object, ReadCache, ObjectSection};
|
use object::{Object, ReadCache, ObjectSection};
|
||||||
|
@ -129,14 +130,15 @@ impl FileStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
let fp = fs::File::open(&filename)?;
|
let fp = fs::File::open(&filename)?;
|
||||||
self.ingest_output(filename, fp)
|
self.ingest_output(filename, fp);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ingest_output(
|
pub fn ingest_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
mut content: (impl io::Read + io::Seek),
|
mut content: (impl io::Read + io::Seek),
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<usize> {
|
||||||
let mut h = Sha256::new();
|
let mut h = Sha256::new();
|
||||||
io::copy(&mut content, &mut h)?;
|
io::copy(&mut content, &mut h)?;
|
||||||
let hash = h.finalize().into();
|
let hash = h.finalize().into();
|
||||||
|
@ -167,7 +169,7 @@ impl FileStore {
|
||||||
|
|
||||||
self.filenames.insert(filename, index);
|
self.filenames.insert(filename, index);
|
||||||
|
|
||||||
Ok(())
|
Ok(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_format(&mut self, fp: &mut (impl io::Read + io::Seek)) -> anyhow::Result<FileFormat> {
|
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<_, _> {
|
let mut load_section = |id: gimli::SectionId| -> Result<_, _> {
|
||||||
load_file_section(id, &elf, endian, &arena_data)
|
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 units = dwarf.units();
|
||||||
|
let mut inputs = vec![];
|
||||||
while let Ok(Some(unit)) = units.next() {
|
while let Ok(Some(unit)) = units.next() {
|
||||||
let abbrev = dwarf.abbreviations(&unit)?;
|
let abbrev = dwarf.abbreviations(&unit)?;
|
||||||
let mut entries = unit.entries(&abbrev);
|
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()?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(elf.is_little_endian());
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let references = inputs.into_iter().map(|input| self.ingest_dependency_local(input)).collect::<Result<Vec<_>, _>>()?.into_iter().filter_map(|x| x).collect();
|
||||||
FileFormat::ELF {
|
FileFormat::ELF {
|
||||||
references: vec![],
|
references,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => FileFormat::Other,
|
_ => 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>>(
|
fn load_file_section<'input, 'arena, Endian: gimli::Endianity, R: object::ReadRef<'input>>(
|
||||||
|
|
|
@ -585,6 +585,8 @@ impl Tracer {
|
||||||
// So we need to determine whether exec is successful here.
|
// So we need to determine whether exec is successful here.
|
||||||
// PTRACE_EVENT_EXEC only happens for successful exec.
|
// PTRACE_EVENT_EXEC only happens for successful exec.
|
||||||
p.is_exec_successful = true;
|
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(|_| {}));
|
self.drain_syscall_events(pid.into(), Box::new(|_| {}));
|
||||||
// Don't use seccomp_aware_cont here because that will skip the next syscall exit stop
|
// Don't use seccomp_aware_cont here because that will skip the next syscall exit stop
|
||||||
self.syscall_enter_cont(pid.into())?;
|
self.syscall_enter_cont(pid.into())?;
|
||||||
|
|
Loading…
Reference in New Issue