Skip to content

Commit

Permalink
Add ability for auxv info to be passed from caller
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Martin committed Jul 16, 2024
1 parent 0d900ce commit db206b1
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 30 deletions.
16 changes: 8 additions & 8 deletions src/bin/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ mod linux {

fn test_setup() -> Result<()> {
let ppid = getppid();
PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT)?;
PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT, Default::default())?;
Ok(())
}

fn test_thread_list() -> Result<()> {
let ppid = getppid();
let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT)?;
let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT, Default::default())?;
test!(!dumper.threads.is_empty(), "No threads")?;
test!(
dumper
Expand All @@ -50,7 +50,7 @@ mod linux {

fn test_copy_from_process(stack_var: usize, heap_var: usize) -> Result<()> {
let ppid = getppid().as_raw();
let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT)?;
let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?;
dumper.suspend_threads()?;
let stack_res = PtraceDumper::copy_from_process(ppid, stack_var as *mut libc::c_void, 1)?;

Expand All @@ -72,7 +72,7 @@ mod linux {

fn test_find_mappings(addr1: usize, addr2: usize) -> Result<()> {
let ppid = getppid();
let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT)?;
let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT, Default::default())?;
dumper
.find_mapping(addr1)
.ok_or("No mapping for addr1 found")?;
Expand All @@ -89,7 +89,7 @@ mod linux {
let ppid = getppid().as_raw();
let exe_link = format!("/proc/{}/exe", ppid);
let exe_name = std::fs::read_link(exe_link)?.into_os_string();
let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT)?;
let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?;
dumper.suspend_threads()?;
let mut found_exe = None;
for (idx, mapping) in dumper.mappings.iter().enumerate() {
Expand All @@ -108,7 +108,7 @@ mod linux {

fn test_merged_mappings(path: String, mapped_mem: usize, mem_size: usize) -> Result<()> {
// Now check that PtraceDumper interpreted the mappings properly.
let dumper = PtraceDumper::new(getppid().as_raw(), STOP_TIMEOUT)?;
let dumper = PtraceDumper::new(getppid().as_raw(), STOP_TIMEOUT, Default::default())?;
let mut mapping_count = 0;
for map in &dumper.mappings {
if map
Expand All @@ -130,7 +130,7 @@ mod linux {

fn test_linux_gate_mapping_id() -> Result<()> {
let ppid = getppid().as_raw();
let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT)?;
let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?;
let mut found_linux_gate = false;
for mapping in dumper.mappings.clone() {
if mapping.name == Some(LINUX_GATE_LIBRARY_NAME.into()) {
Expand All @@ -150,7 +150,7 @@ mod linux {

fn test_mappings_include_linux_gate() -> Result<()> {
let ppid = getppid().as_raw();
let dumper = PtraceDumper::new(ppid, STOP_TIMEOUT)?;
let dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?;
let linux_gate_loc = dumper.auxv.get_linux_gate_address().unwrap();
test!(linux_gate_loc != 0, "linux_gate_loc == 0")?;
let mut found_linux_gate = false;
Expand Down
86 changes: 68 additions & 18 deletions src/linux/auxv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,37 +38,87 @@ pub struct AuxvPair {
pub value: AuxvType,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct DirectAuxvDumpInfo {
program_header_count: AuxvType,
program_header_address: AuxvType,
linux_gate_address: AuxvType,
entry_address: AuxvType,
}

impl From<DirectAuxvDumpInfo> for AuxvDumpInfo {
fn from(f: DirectAuxvDumpInfo) -> AuxvDumpInfo {
AuxvDumpInfo {
program_header_count: (f.program_header_count > 0).then_some(f.program_header_count),
program_header_address: (f.program_header_address > 0)
.then_some(f.program_header_address),
linux_gate_address: (f.linux_gate_address > 0).then_some(f.linux_gate_address),
entry_address: (f.entry_address > 0).then_some(f.entry_address),
}
}
}

#[derive(Debug, Default)]
pub struct AuxvDumpInfo {
map: HashMap<AuxvType, AuxvType>,
program_header_count: Option<AuxvType>,
program_header_address: Option<AuxvType>,
linux_gate_address: Option<AuxvType>,
entry_address: Option<AuxvType>,
}

impl AuxvDumpInfo {
pub fn try_filling_missing_info(&mut self, pid: Pid) -> Result<(), AuxvError> {
if self.is_complete() {
return Ok(());
}

let auxv_path = format!("/proc/{pid}/auxv");
let auxv_file = File::open(&auxv_path).map_err(|e| AuxvError::OpenError(auxv_path, e))?;
let auxv: HashMap<AuxvType, AuxvType> = ProcfsAuxvIter::new(BufReader::new(auxv_file))
.filter_map(Result::ok)
.map(|x| (x.key, x.value))
.collect();

if auxv.is_empty() {
return Err(AuxvError::NoAuxvEntryFound(pid));
}

if self.program_header_count.is_none() {
self.program_header_count = auxv.get(&consts::AT_PHNUM).copied();
}

if self.program_header_address.is_none() {
self.program_header_address = auxv.get(&consts::AT_PHDR).copied();
}

if self.linux_gate_address.is_none() {
self.linux_gate_address = auxv.get(&consts::AT_SYSINFO_EHDR).copied();
}

if self.entry_address.is_none() {
self.entry_address = auxv.get(&consts::AT_ENTRY).copied();
}

Ok(())
}
pub fn get_program_header_count(&self) -> Option<AuxvType> {
self.map.get(&consts::AT_PHNUM).copied()
self.program_header_count
}
pub fn get_program_header_address(&self) -> Option<AuxvType> {
self.map.get(&consts::AT_PHDR).copied()
self.program_header_address
}
pub fn get_linux_gate_address(&self) -> Option<AuxvType> {
self.map.get(&consts::AT_SYSINFO_EHDR).copied()
self.linux_gate_address
}
pub fn get_entry_address(&self) -> Option<AuxvType> {
self.map.get(&consts::AT_ENTRY).copied()
self.entry_address
}
}

pub fn read_auxv(pid: Pid) -> Result<AuxvDumpInfo, AuxvError> {
let auxv_path = format!("/proc/{pid}/auxv");
let auxv_file = File::open(&auxv_path).map_err(|e| AuxvError::OpenError(auxv_path, e))?;
let auxv: HashMap<AuxvType, AuxvType> = ProcfsAuxvIter::new(BufReader::new(auxv_file))
.filter_map(Result::ok)
.map(|x| (x.key, x.value))
.collect();
if auxv.is_empty() {
Err(AuxvError::NoAuxvEntryFound(pid))
} else {
Ok(AuxvDumpInfo { map: auxv })
pub fn is_complete(&self) -> bool {
self.program_header_count.is_some()
&& self.program_header_address.is_some()
&& self.linux_gate_address.is_some()
&& self.entry_address.is_some()
}
}

Expand Down
19 changes: 18 additions & 1 deletion src/linux/minidump_writer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::{
auxv::AuxvDumpInfo,
dir_section::{DirSection, DumpBuf},
linux::{
app_memory::AppMemoryList,
auxv::DirectAuxvDumpInfo,
crash_context::CrashContext,
dso_debug,
errors::{InitError, WriterError},
Expand Down Expand Up @@ -42,6 +44,7 @@ pub struct MinidumpWriter {
pub crash_context: Option<CrashContext>,
pub crashing_thread_context: CrashingThreadContext,
pub stop_timeout: Duration,
pub direct_auxv_dump_info: Option<DirectAuxvDumpInfo>,
}

// This doesn't work yet:
Expand Down Expand Up @@ -71,6 +74,7 @@ impl MinidumpWriter {
crash_context: None,
crashing_thread_context: CrashingThreadContext::None,
stop_timeout: STOP_TIMEOUT,
direct_auxv_dump_info: None,
}
}

Expand Down Expand Up @@ -117,10 +121,23 @@ impl MinidumpWriter {
self
}

pub fn set_direct_auxv_dump_info(
&mut self,
direct_auxv_dump_info: DirectAuxvDumpInfo,
) -> &mut Self {
self.direct_auxv_dump_info = Some(direct_auxv_dump_info);
self
}

/// Generates a minidump and writes to the destination provided. Returns the in-memory
/// version of the minidump as well.
pub fn dump(&mut self, destination: &mut (impl Write + Seek)) -> Result<Vec<u8>> {
let mut dumper = PtraceDumper::new(self.process_id, self.stop_timeout)?;
let auxv = self
.direct_auxv_dump_info
.clone()
.map(AuxvDumpInfo::from)
.unwrap_or_default();
let mut dumper = PtraceDumper::new(self.process_id, self.stop_timeout, auxv)?;
dumper.suspend_threads()?;
dumper.late_init()?;

Expand Down
10 changes: 7 additions & 3 deletions src/linux/ptrace_dumper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ fn ptrace_detach(child: Pid) -> Result<(), DumperError> {
impl PtraceDumper {
/// Constructs a dumper for extracting information of a given process
/// with a process ID of |pid|.
pub fn new(pid: Pid, stop_timeout: Duration) -> Result<Self, InitError> {
pub fn new(pid: Pid, stop_timeout: Duration, auxv: AuxvDumpInfo) -> Result<Self, InitError> {
let mut dumper = PtraceDumper {
pid,
threads_suspended: false,
threads: Vec::new(),
auxv: AuxvDumpInfo::default(),
auxv,
mappings: Vec::new(),
page_size: 0,
};
Expand All @@ -108,7 +108,11 @@ impl PtraceDumper {
if let Err(e) = self.stop_process(stop_timeout) {
log::warn!("failed to stop process {}: {e}", self.pid);
}
self.auxv = super::auxv::read_auxv(self.pid).map_err(InitError::ReadAuxvFailed)?;

if let Err(e) = self.auxv.try_filling_missing_info(self.pid) {
log::warn!("failed trying to fill in missing auxv info: {e}");
}

self.enumerate_threads()?;
self.enumerate_mappings()?;
self.page_size = nix::unistd::sysconf(nix::unistd::SysconfVar::PAGE_SIZE)?
Expand Down

0 comments on commit db206b1

Please sign in to comment.