8000 Isolated Processes 5: Redirect remaining process inspection usage by marti4d · Pull Request #182 · rust-minidump/minidump-writer · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/linux/auxv/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use {
self::reader::ProcfsAuxvIter,
super::Pid,
super::{Pid, process_inspection::ProcessInspector},
crate::serializers::*,
error_graph::WriteErrorList,
failspot::failspot,
std::{fs::File, io::BufReader},
std::io::BufReader,
thiserror::Error,
};

Expand Down Expand Up @@ -84,6 +84,7 @@ pub struct AuxvDumpInfo {
impl AuxvDumpInfo {
pub fn try_filling_missing_info(
&mut self,
process_inspector: &ProcessInspector,
pid: Pid,
mut soft_errors: impl WriteErrorList<AuxvError>,
) -> Result<(), AuxvError> {
Expand All @@ -92,7 +93,9 @@ impl AuxvDumpInfo {
}

let auxv_path = format!("/proc/{pid}/auxv");
let auxv_file = File::open(&auxv_path).map_err(|e| AuxvError::OpenError(auxv_path, e))?;
let auxv_file = process_inspector
.read_file(&auxv_path)
.map_err(|e| AuxvError::OpenError(auxv_path, e))?;

for pair_result in ProcfsAuxvIter::new(BufReader::new(auxv_file)) {
let AuxvPair { key, value } = match pair_result {
Expand Down
17 changes: 7 additions & 10 deletions src/linux/auxv/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,19 @@
use {
super::{AuxvError, AuxvPair, AuxvType},
byteorder::{NativeEndian, ReadBytesExt},
std::{
fs::File,
io::{BufReader, Read},
},
std::io::Read,
};

/// An iterator across auxv pairs from procfs.
pub struct ProcfsAuxvIter {
pub struct ProcfsAuxvIter<R> {
pair_size: usize,
buf: Vec<u8>,
input: BufReader<File>,
input: R,
keep_going: bool,
}

impl ProcfsAuxvIter {
pub fn new(input: BufReader<File>) -> Self {
impl<R> ProcfsAuxvIter<R> {
pub fn new(input: R) -> Self {
let pair_size = 2 * std::mem::size_of::<AuxvType>();
let buf: Vec<u8> = Vec::with_capacity(pair_size);

Expand All @@ -36,7 +33,7 @@ impl ProcfsAuxvIter {
}
}

impl Iterator for ProcfsAuxvIter {
impl<R: Read> Iterator for ProcfsAuxvIter<R> {
type Item = Result<AuxvPair, AuxvError>;
fn next(&mut self) -> Option<Self::Item> {
if !self.keep_going {
Expand Down Expand Up @@ -95,7 +92,7 @@ impl Iterator for ProcfsAuxvIter {
}
}

fn read_long(reader: &mut dyn Read) -> std::io::Result<AuxvType> {
fn read_long<R: Read>(mut reader: R) -> std::io::Result<AuxvType> {
match std::mem::size_of::<AuxvType>() {
4 => reader.read_u32::<NativeEndian>().map(|u| u as AuxvType),
8 => reader.read_u64::<NativeEndian>().map(|u| u as AuxvType),
Expand Down
21 changes: 12 additions & 9 deletions src/linux/dumper_cpu_info/arm.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
use {
super::CpuInfoError,
super::{CpuInfoError, ProcessInspector},
crate::minidump_format::*,
scroll::Pwrite,
std::{
collections::HashSet,
fs::File,
io::{BufRead, BufReader, Read},
path,
},< 8000 /td>
};

type Result<T> = std::result::Result<T, CpuInfoError>;

pub fn parse_cpus_from_sysfile(file: &mut File) -> Result<HashSet<u32>> {
fn parse_cpus_from_sysfile<R: Read>(mut file: R) -> Result<HashSet<u32>> {
let mut res = HashSet::new();
let mut content = String::new();
file.read_to_string(&mut content)?;
Expand Down Expand Up @@ -135,7 +133,10 @@ fn parse_features(_val: &str) -> u32 {
0
}

pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> {
pub fn write_cpu_information(
process_inspector: &ProcessInspector,
sys_info: &mut MDRawSystemInfo,
) -> Result<()> {
// The CPUID value is broken up in several entries in /proc/cpuinfo.
// This table is used to rebuild it from the entries.
let cpu_id_entries = [
Expand Down Expand Up @@ -168,11 +169,13 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> {
// because the content of /proc/cpuinfo will only mirror the number
// of 'online' cores, and thus will vary with time.
// See http://www.kernel.org/doc/Documentation/cputopology.txt
if let Ok(mut present_file) = File::open("/sys/devices/system/cpu/present") {
if let Ok(mut present_file) = process_inspector.read_file("/sys/devices/system/cpu/present") {
// Ignore unparsable content
let cpus_present = parse_cpus_from_sysfile(&mut present_file).unwrap_or_default();

if let Ok(mut possible_file) = File::open("/sys/devices/system/cpu/possible") {
if let Ok(mut possible_file) =
process_inspector.read_file("/sys/devices/system/cpu/possible")
{
// Ignore unparsable content
let cpus_possible = parse_cpus_from_sysfile(&mut possible_file).unwrap_or_default();
let intersection = cpus_present.intersection(&cpus_possible).count();
Expand All @@ -187,7 +190,7 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> {
// readable from regular Android applications on later versions
// (>= 4.1) of the Android platform.

let cpuinfo_file = match File::open(path::PathBuf::from("/proc/cpuinfo")) {
let cpuinfo_file = match process_inspector.read_file("/proc/cpuinfo") {
Ok(x) => x,
Err(_) => {
// Do not return Error here to allow the minidump generation
Expand Down Expand Up @@ -307,7 +310,7 @@ mod tests {
extern crate std;
use std::io::Write;

fn new_file(content: &str) -> File {
fn new_file(content: &str) -> std::fs::File {
let mut file = tempfile::Builder::new()
.prefix("cpu_sets")
.tempfile()
Expand Down
1 change: 1 addition & 0 deletions src/linux/dumper_cpu_info/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use {
super::process_inspection::ProcessInspector,
crate::{minidump_format::PlatformId, serializers::*},
nix::sys::utsname::uname,
};
Expand Down
14 changes: 7 additions & 7 deletions src/linux/dumper_cpu_info/x86.rs
10000
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
use {
super::CpuInfoError,
super::{CpuInfoError, ProcessInspector},
crate::minidump_format::*,
failspot::failspot,
std::{
io::{BufRead, BufReader},
path,
},
std::io::{BufRead, BufReader},
};

type Result<T> = std::result::Result<T, CpuInfoError>;
Expand All @@ -26,7 +23,10 @@ impl CpuInfoEntry {
}
}

pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> {
pub fn write_cpu_information(
process_inspector: &ProcessInspector,
sys_info: &mut MDRawSystemInfo,
) -> Result<()> {
let vendor_id_name = "vendor_id";
let mut cpu_info_table = [
CpuInfoEntry::new("processor", -1, false),
Expand All @@ -50,7 +50,7 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> {
bail(std::io::Error::other("test requested cpuinfo file failure"))
);

let cpuinfo_file = std::fs::File::open(path::PathBuf::from("/proc/cpuinfo"))?;
let cpuinfo_file = process_inspector.read_file("/proc/cpuinfo")?;

let mut vendor_id = String::new();
for line in BufReader::new(cpuinfo_file).lines() {
Expand Down
22 changes: 15 additions & 7 deletions src/linux/minidump_writer/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use {
thread_names_stream::SectionThreadNamesError,
},
module_reader::ModuleReaderError,
process_inspection,
serializers::*,
},
crate::{dir_section::FileWriterError, mem_writer::MemoryWriterError, serializers::*},
Expand Down Expand Up @@ -150,15 +151,18 @@ pub enum WriterError {
#[serde(skip)]
std::num::TryFromIntError,
),
#[error("failed to suspend thread")]
SuspendThreadFailed(#[source] process_inspection::SuspendResumeThreadError),
#[error("failed to resume thread")]
ResumeThreadFailed(#[source] process_inspection::SuspendResumeThreadError),
}

#[derive(Debug, Error, serde::Serialize)]
pub enum InitError {
#[error("failed to read auxv")]
ReadAuxvFailed(#[source] super::super::auxv::AuxvError),
#[error("IO error for file {0}")]
IOError(
String,
#[error("IO error reading /proc/<pid>/task")]
ReadProcTaskFailed(
#[source]
#[serde(serialize_with = "serialize_io_error")]
std::io::Error,
Expand Down Expand Up @@ -220,6 +224,12 @@ pub enum StopProcessError {
#[serde(serialize_with = "serialize_nix_error")]
nix::Error,
),
#[error("failed to open process file")]
ReadFileFailed(
#[source]
#[serde(serialize_with = "serialize_io_error")]
std::io::Error,
),
#[error("Failed to get the process state")]
State(
#[from]
Expand All @@ -231,7 +241,5 @@ pub enum StopProcessError {
}

#[derive(Debug, thiserror::Error)]
pub enum ContinueProcessError {
#[error("Failed to continue the process")]
Continue(#[from] Errno),
}
#[error("Failed to continue the process")]
pub struct ContinueProcessError(#[source] pub Errno);
10BC8
37 changes: 17 additions & 20 deletions src/linux/minidump_writer/handle_data_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,21 @@ use {
super::*,
crate::mem_writer::MemoryWriter,
std::{
ffi::{CString, OsString},
fs::{self, DirEntry},
mem::{self},
os::unix::prelude::OsStrExt,
ffi::OsStr,
mem,
path::{Path, PathBuf},
},
};

fn file_stat(path: &Path) -> Option<libc::stat> {
let c_path = CString::new(path.as_os_str().as_bytes()).ok()?;
let mut stat = unsafe { std::mem::zeroed::<libc::stat>() };
let result = unsafe { libc::stat(c_path.as_ptr(), &mut stat) };

if result == 0 { Some(stat) } else { None }
}

fn direntry_to_descriptor(buffer: &mut DumpBuf, entry: &DirEntry) -> Option<MDRawHandleDescriptor> {
let handle = filename_to_fd(&entry.file_name())?;
let realpath = fs::read_link(entry.path()).ok()?;
fn descriptor_from_path(
process_inspector: &ProcessInspector,
buffer: &mut DumpBuf,
path: &Path,
) -> Option<MDRawHandleDescriptor> {
let handle = filename_to_fd(path.file_name().unwrap())?;
let realpath = process_inspector.read_link(path).ok()?;
let path_rva = write_string_to_location(buffer, realpath.to_string_lossy().as_ref()).ok()?;
let stat = file_stat(&entry.path())?;
let stat = process_inspector.stat_file(path).ok()?;

// TODO: We store the contents of `st_mode` into the `attributes` field, but
// we could also store a human-readable string of the file type inside
Expand All @@ -40,7 +34,7 @@ fn direntry_to_descriptor(buffer: &mut DumpBuf, entry: &DirEntry) -> Option<MDRa
})
}

fn filename_to_fd(filename: &OsString) -> Option<u64> {
fn filename_to_fd(filename: &OsStr) -> Option<u64> {
let filename = filename.to_string_lossy();
filename.parse::<u64>().ok()
}
Expand Down Expand Up @@ -69,10 +63,13 @@ impl MinidumpWriter {
buffer: &mut DumpBuf,
) -> Result<MDRawDirectory, SectionHandleDataStreamError> {
let proc_fd_path = PathBuf::from(format!("/proc/{}/fd", self.process_id));
let proc_fd_iter = fs::read_dir(proc_fd_path)?;
let proc_fd_iter = self.process_inspector.read_dir(&proc_fd_path)?;
let descriptors: Vec<_> = proc_fd_iter
.filter_map(|entry| entry.ok())
.filter_map(|entry| direntry_to_descriptor(buffer, &entry))
.filter_map(|filename| filename.ok())
.filter_map(|filename| {
let path = proc_fd_path.join(filename);
descriptor_from_path(&self.process_inspector, buffer, &path)
})
.collect();
let number_of_descriptors = descriptors.len() as u32;

Expand Down
20 changes: 7 additions & 13 deletions src/linux/minidump_writer/mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,13 @@ impl MinidumpWriter {
// from the file. If there is no note segment with the build id in
// the program headers, we can't get to the note section if the section header
// table isn't loaded.
if let Some(path) = &self.mappings[map_idx].name {
let path = std::path::Path::new(&path);
if path.exists() {
log::debug!("failed to get build id from process memory ({e}), attempting to retrieve from {}", path.display());
return module_reader::read_build_id_from_file(&self.process_inspector, path)
.map_err(errors::WriterError::ModuleReaderError);
}
log::debug!(
"not attempting to get build id from {}: path does not exist",
path.display()
);
}
Err(e)
let Some(path) = &self.mappings[map_idx].name else {
return Err(e);
};

log::debug!("failed to get build id from process memory ({e}), attempting to retrieve from {}", path.display());

module_reader::read_build_id_from_file(&self.process_inspector, path.as_ref()).map_err(errors::WriterError::ModuleReaderError)
})
.unwrap_or_else(|e| {
log::warn!("failed to get build id for mapping: {e}");
Expand Down
16 changes: 12 additions & 4 deletions src/linux/minidump_writer/memory_info_list_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ use {
pub enum SectionMemInfoListError {
#[error("Failed to write to memory")]
MemoryWriterError(#[from] MemoryWriterError),
#[error("failed to open /proc/<pid>/maps file")]
ReadFileFailed(
#[source]
#[serde(serialize_with = "serialize_io_error")]
std::io::Error,
),
#[error("Failed to read from procfs")]
ProcfsError(
#[from]
Expand All @@ -22,10 +28,12 @@ impl MinidumpWriter {
&mut self,
buffer: &mut DumpBuf,
) -> Result<MDRawDirectory, SectionMemInfoListError> {
let maps = procfs_core::process::MemoryMaps::from_file(std::path::PathBuf::from(format!(
"/proc/{}/maps",
self.blamed_thread
)))?;
let path = format!("/proc/{}/maps", self.blamed_thread);
let reader = self
.process_inspector
.read_file(&path)
.map_err(SectionMemInfoListError::ReadFileFailed)?;
let maps = procfs_core::process::MemoryMaps::from_read(reader)?;

let list_header = MemoryWriter::alloc_with_val(
buffer,
Expand Down
Loading
Loading
0