8000 Isolated Processes 15.5: Treat non-essential getreg errors as soft by marti4d · Pull Request #238 · 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
11 changes: 7 additions & 4 deletions crates/linux/process-backend/src/local/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ pub enum Error {
BufferTooSmall,
#[error("not supported")]
NotSupported,
#[error("failed to get registers: {0}")]
GetRegistersFailed(c_int),
#[error("unexpected size for register set. Expected: {0}, actual: {0}")]
UnexpectedRegisterSetSize(usize, usize),
#[error(
"failed to get registers. getregset_error: `{getregset_error}`, legacy_error: `{legacy_error}`"
)]
GetRegistersFailed {
getregset_error: super::PtraceGetRegSetError,
legacy_error: super::PtraceGetRegsLegacyError,
},
#[error("failed to map memory: {0}")]
MMapfailed(c_int),
#[error("the start position of a mapping is past its end position")]
Expand Down
56 changes: 44 additions & 12 deletions crates/linux/process-backend/src/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,28 @@ impl Backend {
}

fn get_regs<T: PtraceRegisterSet>(&self, tid: libc::pid_t) -> Result<T::Output> {
self.ptrace_getregset::<T>(tid).or_else(|e| {
if T::LEGACY_REQUEST.is_some() {
self.ptrace_getregs_legacy::<T>(tid)
} else {
Err(e)
}
let getregset_error = match self.ptrace_getregset::<T>(tid) {
Ok(output) => return Ok(output),
Err(e) => e,
};

let legacy_error = match self.ptrace_getregs_legacy::<T>(tid) {
Ok(output) => return Ok(output),
Err(e) => e,
};

Err(Error::GetRegistersFailed {
getregset_error,
legacy_error,
})
}

fn ptrace_getregs_legacy<T: PtraceRegisterSet>(&self, tid: libc::pid_t) -> Result<T::Output> {
fn ptrace_getregs_legacy<T: PtraceRegisterSet>(
&self,
tid: libc::pid_t,
) -> core::result::Result<T::Output, PtraceGetRegsLegacyError> {
let Some(request) = T::LEGACY_REQUEST else {
return Err(Error::NotSupported);
return Err(PtraceGetRegsLegacyError::NotSupported);
};

let mut output = T::Output::default();
Expand All @@ -222,11 +232,14 @@ impl Backend {
(&raw mut output).cast(),
)
})
.map_err(Error::GetRegistersFailed)?;
.map_err(PtraceGetRegsLegacyError::PtraceFailed)?;
Ok(output)
}

fn ptrace_getregset<T: PtraceRegisterSet>(&self, tid: libc::pid_t) -> Result<T::Output> {
fn ptrace_getregset<T: PtraceRegisterSet>(
&self,
tid: libc::pid_t,
) -> core::result::Result<T::Output, PtraceGetRegSetError> {
let output_size = size_of::<T::Output>();
assert!(T::KERNEL_SIZE <= output_size);

Expand All @@ -244,10 +257,13 @@ impl Backend {
(&raw mut io).cast(),
)
})
.map_err(Error::GetRegistersFailed)?;
.map_err(PtraceGetRegSetError::PtraceFailed)?;

if T::KERNEL_SIZE != io.iov_len {
return Err(Error::UnexpectedRegisterSetSize(T::KERNEL_SIZE, io.iov_len));
return Err(PtraceGetRegSetError::UnexpectedRegisterSetSize(
T::KERNEL_SIZE,
io.iov_len,
));
}

Ok(output)
Expand Down Expand Up @@ -489,3 +505,19 @@ unsafe fn ptrace(
) -> c_long {
unsafe { libc::ptrace(request, pid, addr, data) }
}

#[derive(Debug, thiserror::Error, serde::Deserialize, serde::Serialize)]
pub enum PtraceGetRegSetError {
#[error("ptrace returned error code: {0}")]
PtraceFailed(c_int),
#[error("unexpected size for register set. Expected: {0}, actual: {0}")]
UnexpectedRegisterSetSize(usize, usize),
}

#[derive(Debug, thiserror::Error, serde::Deserialize, serde::Serialize)]
pub enum PtraceGetRegsLegacyError {
#[error("ptrace returned error code: {0}")]
PtraceFailed(c_int),
#[error("legacy API not supported on this architecture")]
NotSupported,
}
12 changes: 10 additions & 2 deletions src/linux/minidump_writer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,12 +752,20 @@ impl MinidumpWriter {
/// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
/// these members are set to -1. Returns true if all three members are
/// available.
pub fn get_thread_info_by_index(&self, index: usize) -> Result<ThreadInfo, ThreadInfoError> {
pub fn get_thread_info_by_index(
&self,
index: usize,
soft_errors: impl WriteErrorList<ThreadInfoError>,
) -> Result<ThreadInfo, ThreadInfoError> {
if index > self.threads.len() {
return Err(ThreadInfoError::IndexOutOfBounds(index, self.threads.len()));
}

ThreadInfo::create(self.process_inspector.as_ref(), self.threads[index].tid)
ThreadInfo::create(
self.process_inspector.as_ref(),
self.threads[index].tid,
soft_errors,
)
}

// Returns a valid stack pointer and the mapping that contains the stack.
Expand Down
12 changes: 10 additions & 2 deletions src/linux/minidump_writer/thread_list_stream.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use {
super::*, crate::minidump_cpu::RawContextCPU, error_graph::WriteErrorList, failspot::failspot,
super::*,
crate::minidump_cpu::RawContextCPU,
error_graph::{ErrorList, WriteErrorList},
failspot::failspot,
std::cmp::min,
};

Expand Down Expand Up @@ -41,6 +44,8 @@ pub enum SectionThreadListError {
GetStackInfoFailed(#[source] Box<WriterError>),
#[error("Failed to get thread info")]
ThreadInfoError(#[from] ThreadInfoError),
#[error("Soft errors occurred getting thread info")]
ThreadInfoSoftErrors(#[source] ErrorList<ThreadInfoError>),
#[error("Failed to write to memory buffer")]
IOError(
#[from]
Expand Down Expand Up @@ -180,7 +185,10 @@ impl MinidumpWriter {
self.crashing_thread_context =
CrashingThreadContext::CrashContext(cpu_section.location());
} else {
let info = self.get_thread_info_by_index(idx)?;
let info = self.get_thread_info_by_index(
idx,
soft_errors.subwriter(SectionThreadListError::ThreadInfoSoftErrors),
)?;
let max_stack_len =
if self.minidump_size_limit.is_some() && idx >= LIMIT_BASE_THREAD_COUNT {
extra_thread_stack_len
Expand Down
26 changes: 19 additions & 7 deletions src/linux/thread_info/aarch64.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use {
super::{Pid, ProcessInspector, ThreadInfoError, regs::*},
crate::minidump_cpu::{FP_REG_COUNT, GP_REG_COUNT, RawContextCPU},
error_graph::WriteErrorList,
};

#[derive(Debug)]
Expand All @@ -9,7 +10,7 @@ pub struct ThreadInfoAarch64 {
pub tgid: Pid, // thread group id
pub ppid: Pid, // parent process
pub regs: GenRegs,
pub fpregs: FpRegs,
pub fpregs: Option<FpRegs>,
}

impl ThreadInfoAarch64 {
Expand All @@ -29,22 +30,33 @@ impl ThreadInfoAarch64 {
// field instead
out.pc = self.regs.pc;

out.fpsr = self.fpregs.fpsr;
out.fpcr = self.fpregs.fpcr;
out.float_regs[..FP_REG_COUNT].copy_from_slice(&self.fpregs.vregs[..FP_REG_COUNT]);
let fpregs = self.fpregs.unwrap_or_default();
out.fpsr = fpregs.fpsr;
out.fpcr = fpregs.fpcr;
out.float_regs[..FP_REG_COUNT].copy_from_slice(&fpregs.vregs[..FP_REG_COUNT]);
}

pub fn create(
process_inspector: &dyn ProcessInspector,
tid: Pid,
mut soft_errors: impl WriteErrorList<ThreadInfoError>,
) -> Result<Self, ThreadInfoError> {
let (ppid, tgid) = super::get_ppid_and_tgid(process_inspector, tid)?;

let regs = process_inspector
.get_gen_regs(tid)
.map_err(ThreadInfoError::PtraceError)?;
let fpregs = process_inspector
.map_err(ThreadInfoError::GetGenRegsFailed)?;

let fpregs = match process_inspector
.get_fp_regs(tid)
.map_err(ThreadInfoError::PtraceError)?;
.map_err(ThreadInfoError::GetFpRegsFailed)
{
Ok(regs) => Some(regs),
Err(e) => {
soft_errors.push(e);
None
}
};

let stack_pointer = regs.sp as usize;

Expand Down
26 changes: 20 additions & 6 deletions src/linux/thread_info/arm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use {
super::{Pid, ProcessInspector, ThreadInfoError, regs::*},
crate::minidump_cpu::RawContextCPU,
error_graph::WriteErrorList,
};

#[derive(Debug)]
Expand All @@ -9,7 +10,7 @@ pub struct ThreadInfoArm {
pub tgid: Pid, // thread group id
pub ppid: Pid, // parent process
pub regs: GenRegs,
pub fpregs: FpRegs,
pub fpregs: Option<FpRegs>,
}

impl ThreadInfoArm {
Expand All @@ -23,21 +24,34 @@ impl ThreadInfoArm {

out.iregs.copy_from_slice(&self.regs.uregs[..16]);
out.cpsr = self.regs.uregs[16];
out.float_save.fpscr = self.fpregs.fpscr as u64;
out.float_save.regs = self.fpregs.fpregs;

let fpregs = self.fpregs.unwrap_or_default();

out.float_save.fpscr = fpregs.fpscr as u64;
out.float_save.regs = fpregs.fpregs;
}

pub fn create(
process_inspector: &dyn ProcessInspector,
tid: Pid,
mut soft_errors: impl WriteErrorList<ThreadInfoError>,
) -> Result<Self, ThreadInfoError> {
let (ppid, tgid) = super::get_ppid_and_tgid(process_inspector, tid)?;

let regs = process_inspector
.get_gen_regs(tid)
.map_err(ThreadInfoError::PtraceError)?;
let fpregs = process_inspector
.map_err(ThreadInfoError::GetGenRegsFailed)?;

let fpregs = match process_inspector
.get_fp_regs(tid)
.map_err(ThreadInfoError::PtraceError)?;
.map_err(ThreadInfoError::GetFpRegsFailed)
{
Ok(regs) => Some(regs),
Err(e) => {
soft_errors.push(e);
None
}
};

let stack_pointer = regs.uregs[13] as usize;

Expand Down
10 changes: 8 additions & 2 deletions src/linux/thread_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@ pub enum ThreadInfoError {
#[serde(skip)]
std::num::ParseIntError,
),
#[error("ptrace error")]
PtraceError(#[source] process_inspection::Error),
#[error("failed to get general-purpose registers")]
GetGenRegsFailed(#[source] process_inspection::Error),
#[error("failed to get floating-point registers")]
GetFpRegsFailed(#[source] process_inspection::Error),
#[error("failed to get floating-point register extended info")]
GetFpxRegsFailed(#[source] process_inspection::Error),
#[error("failed to get debug registers")]
GetDebugRegsFailed(#[source] process_inspection::Error),
#[error("Invalid line in /proc/{0}/status: {1}")]
InvalidProcStatusFile(Pid, String),
}
Expand Down
Loading
Loading
0