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
13 changes: 7 additions & 6 deletions examples/synthetic.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! Emits default minidump with no streams to specified path

use std::fs::File;

use minidump_writer::{
dir_section::DirSection,
mem_writer::{Buffer, MemoryWriter},
minidump_format::{MDRawHeader, MD_HEADER_SIGNATURE, MD_HEADER_VERSION},
use {
minidump_writer::{
dir_section::DirSection,
mem_writer::{Buffer, MemoryWriter},
minidump_format::{MDRawHeader, MD_HEADER_SIGNATURE, MD_HEADER_VERSION},
},
std::fs::File,
};

// usage: `cargo run --example synthetic /tmp/micro-minidump.dmp`
Expand Down
91 changes: 24 additions & 67 deletions src/bin/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ mod linux {
super::*,
error_graph::ErrorList,
minidump_writer::{
minidump_writer::STOP_TIMEOUT, module_reader, ptrace_dumper::PtraceDumper,
LINUX_GATE_LIBRARY_NAME,
minidump_writer::{MinidumpWriter, MinidumpWriterConfig},
module_reader, LINUX_GATE_LIBRARY_NAME,
},
nix::{
sys::mman::{mmap_anonymous, MapFlags, ProtFlags},
Expand Down Expand Up @@ -40,12 +40,8 @@ mod linux {
let ppid = getppid();
fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
ppid.as_raw(),
STOP_TIMEOUT,
Default::default(),
&mut soft_errors,
)?
MinidumpWriterConfig::new(ppid.as_raw(), ppid.as_raw())
.build_for_testing(&mut soft_errors)?
);
Ok(())
}
Expand All @@ -54,12 +50,8 @@ mod linux {
let ppid = getppid();
let dumper = fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
ppid.as_raw(),
STOP_TIMEOUT,
Default::default(),
&mut soft_errors,
)?
MinidumpWriterConfig::new(ppid.as_raw(), ppid.as_raw())
.build_for_testing(&mut soft_errors)?
);
test!(!dumper.threads.is_empty(), "No threads");
test!(
Expand Down Expand Up @@ -87,18 +79,11 @@ mod linux {
use minidump_writer::mem_reader::MemReader;

let ppid = getppid().as_raw();
let mut dumper = fail_on_soft_error!(
let dumper = fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
ppid,
STOP_TIMEOUT,
Default::default(),
&mut soft_errors
)?
MinidumpWriterConfig::new(ppid, ppid).build_for_testing(&mut soft_errors)?
);

fail_on_soft_error!(soft_errors, dumper.suspend_threads(&mut soft_errors));

// We support 3 different methods of reading memory from another
// process, ensure they all function and give the same results

Expand Down Expand Up @@ -141,30 +126,27 @@ mod linux {
}

let stack_res =
PtraceDumper::copy_from_process(ppid, stack_var, std::mem::size_of::<usize>())?;
MinidumpWriter::copy_from_process(ppid, stack_var, std::mem::size_of::<usize>())?;

test!(stack_res == expected_stack, "stack var not correct");

let heap_res =
PtraceDumper::copy_from_process(ppid, heap_var, std::mem::size_of::<usize>())?;
MinidumpWriter::copy_from_process(ppid, heap_var, std::mem::size_of::<usize>())?;

test!(heap_res == expected_heap, "heap var not correct");

fail_on_soft_error!(soft_errors, dumper.resume_threads(&mut soft_errors));
drop(dumper);

Ok(())
}

fn test_find_mappings(addr1: usize, addr2: usize) -> Result<()> {
let ppid = getppid();

let dumper = fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
ppid.as_raw(),
STOP_TIMEOUT,
Default::default(),
&mut soft_errors,
)?
MinidumpWriterConfig::new(ppid.as_raw(), ppid.as_raw())
.build_for_testing(&mut soft_errors)?
);
dumper
.find_mapping(addr1)
Expand All @@ -185,16 +167,9 @@ mod linux {

let mut dumper = fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
ppid,
STOP_TIMEOUT,
Default::default(),
&mut soft_errors
)?
MinidumpWriterConfig::new(ppid, ppid).build_for_testing(&mut soft_errors)?
);

fail_on_soft_error!(soft_errors, dumper.suspend_threads(&mut soft_errors));

let mut found_exe = None;
for (idx, mapping) in dumper.mappings.iter().enumerate() {
if mapping.name.as_ref().map(|x| x.into()).as_ref() == Some(&exe_name) {
Expand All @@ -205,7 +180,7 @@ mod linux {
let idx = found_exe.unwrap();
let module_reader::BuildId(id) = dumper.from_process_memory_for_index(idx)?;

fail_on_soft_error!(soft_errors, dumper.resume_threads(&mut soft_errors));
drop(dumper);

assert!(!id.is_empty());
assert!(id.iter().any(|&x| x > 0));
Expand All @@ -216,12 +191,8 @@ mod linux {
// Now check that PtraceDumper interpreted the mappings properly.
let dumper = fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
getppid().as_raw(),
STOP_TIMEOUT,
Default::default(),
&mut soft_errors,
)?
MinidumpWriterConfig::new(getppid().as_raw(), getppid().as_raw())
.build_for_testing(&mut soft_errors)?
);
let mut mapping_count = 0;
for map in &dumper.mappings {
Expand All @@ -244,29 +215,20 @@ mod linux {

fn test_linux_gate_mapping_id() -> Result<()> {
let ppid = getppid().as_raw();
let mut dumper = fail_on_soft_error!(
let dumper = fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
ppid,
STOP_TIMEOUT,
Default::default(),
&mut soft_errors
)?
MinidumpWriterConfig::new(ppid, ppid).build_for_testing(&mut soft_errors)?
);
let mut found_linux_gate = false;
for mapping in dumper.mappings.clone() {
if mapping.name == Some(LINUX_GATE_LIBRARY_NAME.into()) {
found_linux_gate = true;

fail_on_soft_error!(soft_errors, dumper.suspend_threads(&mut soft_errors));

let module_reader::BuildId(id) =
PtraceDumper::from_process_memory_for_mapping(&mapping, ppid)?;
MinidumpWriter::from_process_memory_for_mapping(&mapping, ppid)?;
test!(!id.is_empty(), "id-vec is empty");
test!(id.iter().any(|&x| x > 0), "all id elements are 0");

fail_on_soft_error!(soft_errors, dumper.resume_threads(&mut soft_errors));

drop(dumper);
break;
}
}
Expand All @@ -278,12 +240,7 @@ mod linux {
let ppid = getppid().as_raw();
let dumper = fail_on_soft_error!(
soft_errors,
PtraceDumper::new_report_soft_errors(
ppid,
STOP_TIMEOUT,
Default::default(),
&mut soft_errors
)?
MinidumpWriterConfig::new(ppid, ppid).build_for_testing(&mut soft_errors)?
);
let linux_gate_loc = dumper.auxv.get_linux_gate_address().unwrap();
test!(linux_gate_loc != 0, "linux_gate_loc == 0");
Expand Down Expand Up @@ -332,7 +289,7 @@ mod linux {
// One less than the requested amount, as the main thread counts as well
for id in 1..num {
std::thread::Builder::new()
.name(format!("thread_{}", id))
.name(format!("thread_{id}"))
.spawn(|| {
println!("1");
loop {
Expand Down
32 changes: 24 additions & 8 deletions src/linux/android.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::errors::AndroidError;
use crate::maps_reader::MappingInfo;
use crate::ptrace_dumper::PtraceDumper;
use crate::Pid;
use goblin::elf;
use {
super::{
maps_reader::MappingInfo, mem_reader::CopyFromProcessError,
minidump_writer::MinidumpWriter, Pid,
},
goblin::elf,
};

cfg_if::cfg_if! {
if #[cfg(target_pointer_width = "32")] {
Expand All @@ -26,6 +28,20 @@ cfg_if::cfg_if! {

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

#[derive(Debug, thiserror::Error, serde::Serialize)]
pub enum AndroidError {
#[error("Failed to copy memory from process")]
CopyFromProcessError(#[from] CopyFromProcessError),
#[error("Failed slice conversion")]
TryFromSliceError(
#[from]
#[serde(skip)]
std::array::TryFromSliceError,
),
#[error("No Android rel found")]
NoRelFound,
}

struct DynVaddresses {
min_vaddr: usize,
dyn_vaddr: usize,
Expand All @@ -36,7 +52,7 @@ fn has_android_packed_relocations(pid: Pid, load_bias: usize, vaddrs: DynVaddres
let dyn_addr = load_bias + vaddrs.dyn_vaddr;
for idx in 0..vaddrs.dyn_count {
let addr = dyn_addr + SIZEOF_DYN * idx;
let dyn_data = PtraceDumper::copy_from_process(pid, addr, SIZEOF_DYN)?;
let dyn_data = MinidumpWriter::copy_from_process(pid, addr, SIZEOF_DYN)?;
// TODO: Couldn't find a nice way to use goblin for that, to avoid the unsafe-block
let dyn_obj: Dyn;
unsafe {
Expand Down Expand Up @@ -76,7 +92,7 @@ fn parse_loaded_elf_program_headers(
let mut dyn_vaddr = 0;
let mut dyn_count = 0;

let phdr_opt = PtraceDumper::copy_from_process(
let phdr_opt = MinidumpWriter::copy_from_process(
pid,
phdr_addr,
elf_header::SIZEOF_EHDR * ehdr.e_phnum as usize,
Expand Down Expand Up @@ -114,7 +130,7 @@ pub fn late_process_mappings(pid: Pid, mappings: &mut [MappingInfo]) -> Result<(
.filter(|m| m.is_executable() && m.name_is_path())
{
let ehdr_opt =
PtraceDumper::copy_from_process(pid, map.start_address, elf_header::SIZEOF_EHDR)
MinidumpWriter::copy_from_process(pid, map.start_address, elf_header::SIZEOF_EHDR)
.ok()
.and_then(|x| elf_header::Header::parse(&x).ok());

Expand Down
3 changes: 2 additions & 1 deletion src/linux/auxv/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use {
self::reader::ProcfsAuxvIter,
crate::{serializers::*, Pid},
super::Pid,
crate::serializers::*,
error_graph::WriteErrorList,
failspot::failspot,
std::{fs::File, io::BufReader},
Expand Down
2 changes: 1 addition & 1 deletion src/linux/auxv/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@ fn read_long(reader: &mut dyn Read) -> 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),
x => panic!("Unexpected type width: {}", x),
x => panic!("Unexpected type width: {x}"),
}
}
10 changes: 6 additions & 4 deletions src/linux/crash_context/aarch64.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::CrashContext;
use crate::{
minidump_cpu::{RawContextCPU, FP_REG_COUNT, GP_REG_COUNT},
minidump_format::format,
use {
super::CrashContext,
crate::{
minidump_cpu::{RawContextCPU, FP_REG_COUNT, GP_REG_COUNT},
minidump_format::format,
},
};

impl CrashContext {
Expand Down
3 changes: 1 addition & 2 deletions src/linux/crash_context/arm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use super::CrashContext;
use crate::minidump_cpu::RawContextCPU;
use {super::CrashContext, crate::minidump_cpu::RawContextCPU};

impl CrashContext {
pub fn get_instruction_pointer(&self) -> usize {
Expand Down
10 changes: 10 additions & 0 deletions src/linux/crash_context.rs → src/linux/crash_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ pub struct CrashContext {
pub inner: crash_context::CrashContext,
}

impl std::fmt::Debug for CrashContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CrashContext")
.field("siginfo", &self.inner.siginfo)
.field("pid", &self.inner.pid)
.field("tid", &self.inner.tid)
.finish_non_exhaustive()
}
}

cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
mod x86_64;
Expand Down
12 changes: 7 additions & 5 deletions src/linux/crash_context/x86.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use super::CrashContext;
use crate::{minidump_cpu::RawContextCPU, minidump_format::format::ContextFlagsX86};
use libc::{
REG_CS, REG_DS, REG_EAX, REG_EBP, REG_EBX, REG_ECX, REG_EDI, REG_EDX, REG_EFL, REG_EIP, REG_ES,
REG_ESI, REG_ESP, REG_FS, REG_GS, REG_SS, REG_UESP,
use {
super::CrashContext,
crate::{minidump_cpu::RawContextCPU, minidump_format::format::ContextFlagsX86},
libc::{
REG_CS, REG_DS, REG_EAX, REG_EBP, REG_EBX, REG_ECX, REG_EDI, REG_EDX, REG_EFL, REG_EIP,
REG_ES, REG_ESI, REG_ESP, REG_FS, REG_GS, REG_SS, REG_UESP,
},
};
impl CrashContext {
pub fn get_instruction_pointer(&self) -> usize {
Expand Down
16 changes: 8 additions & 8 deletions src/linux/crash_context/x86_64.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::CrashContext;
use crate::{
minidump_cpu::RawContextCPU, minidump_format::format, thread_info::copy_u32_registers,
use {
super::{super::thread_info::copy_u32_registers, CrashContext},
crate::{minidump_cpu::RawContextCPU, minidump_format::format},
libc::{
REG_CSGSFS, REG_EFL, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8, REG_R9,
REG_RAX, REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP,
},
scroll::Pwrite,
};
use libc::{
REG_CSGSFS, REG_EFL, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8, REG_R9,
REG_RAX, REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP,
};
use scroll::Pwrite;

impl CrashContext {
pub fn get_instruction_pointer(&self) -> usize {
Expand Down
Loading
Loading