use core::{
error::Error as StdError,
ffi::c_int,
fmt::{Display, Formatter, Result as FmtResult},
};
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ReadError(pub(crate) ReadErrorInner);
impl ReadError {
pub fn virtual_mem_error(&self) -> Option<&(dyn StdError + 'static)> {
match &self.0 {
ReadErrorInner::AllStrategies { vmem_err, .. } => Some(vmem_err),
ReadErrorInner::VirtualMemStrategy(e) => Some(e),
_ => None,
}
}
pub fn file_error(&self) -> Option<&(dyn StdError + 'static)> {
match &self.0 {
ReadErrorInner::AllStrategies { file_err, .. } => Some(file_err),
ReadErrorInner::FileStrategy(e) => Some(e),
_ => None,
}
}
pub fn ptrace_error(&self) -> Option<&(dyn StdError + 'static)> {
match &self.0 {
ReadErrorInner::AllStrategies { ptrace_err, .. } => Some(ptrace_err),
ReadErrorInner::PtraceStrategy(e) => Some(e),
_ => None,
}
}
}
impl Display for ReadError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
use ReadErrorInner as E;
match &self.0 {
E::AllStrategies { .. } => write!(f, "all process reading strategies failed"),
E::VirtualMemStrategy(_) => write!(f, "virtual memory strategy failed"),
E::FileStrategy(_) => write!(f, "file strategy failed"),
E::PtraceStrategy(_) => write!(f, "ptrace strategy failed"),
}
}
}
impl StdError for ReadError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
use ReadErrorInner as E;
match &self.0 {
E::AllStrategies { .. } => None,
E::VirtualMemStrategy(e) => Some(e),
E::FileStrategy(e) => Some(e),
E::PtraceStrategy(e) => Some(e),
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub(crate) enum ReadErrorInner {
AllStrategies {
vmem_err: ProcessVmReadvFailed,
file_err: FileStrategyError,
ptrace_err: PtraceError,
},
VirtualMemStrategy(ProcessVmReadvFailed),
FileStrategy(FileStrategyError),
PtraceStrategy(PtraceError),
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum ReadExactError {
Read(ReadError),
UnexpectedEof,
}
impl Display for ReadExactError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::Read(_) => write!(f, "an error occurred before filling entire buffer"),
Self::UnexpectedEof => write!(f, "unexpected end-of-file before filling entire buffer"),
}
}
}
impl StdError for ReadExactError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Read(e) => Some(e),
Self::UnexpectedEof => None,
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub(crate) struct ProcessVmReadvFailed(pub(crate) c_int);
impl Display for ProcessVmReadvFailed {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "process_vm_readv() returned an error code: {}", self.0)
}
}
impl StdError for ProcessVmReadvFailed {}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub(crate) enum FileStrategyError {
Open(OpenFailed),
Read(ReadExactAtError),
}
impl Display for FileStrategyError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::Open(_) => write!(f, "failed to open /proc/<pid>/mem file"),
Self::Read(_) => write!(f, "failed to read /proc/<pid>/mem file"),
}
}
}
impl StdError for FileStrategyError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Open(e) => Some(e),
Self::Read(e) => Some(e),
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub(crate) struct OpenFailed(pub(crate) c_int);
impl Display for OpenFailed {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "open64() returned an error code: {}", self.0)
}
}
impl StdError for OpenFailed {}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub(crate) enum ReadExactAtError {
ReadAt(ReadAtFailed),
AddressOverflow,
UnexpectedEof { position: usize },
}
impl Display for ReadExactAtError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::ReadAt(_) => write!(f, "I/O error reading file"),
Self::AddressOverflow => write!(
f,
"the given address/length pair overflowed the machine's memory range"
),
Self::UnexpectedEof { position } => write!(
f,
"unexpected end-of-file encountered at position: {position}"
),
}
}
}
impl StdError for ReadExactAtError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::ReadAt(e) => Some(e),
Self::AddressOverflow => None,
Self::UnexpectedEof { .. } => None,
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub(crate) enum ReadAtFailed {
Syscall(c_int),
AddressOutOfBounds,
}
impl Display for ReadAtFailed {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::Syscall(errno) => write!(f, "pread64() returned an error code: {errno}"),
Self::AddressOutOfBounds => {
write!(f, "requested address was out-of-bounds for pread64()")
}
}
}
}
impl StdError for ReadAtFailed {}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub(crate) enum PtraceError {
Syscall { errno: c_int, position: usize },
AddressOverflow,
}
impl Display for PtraceError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::Syscall { errno, position } => write!(
f,
"ptrace(PTRACE_PEEKDATA) returned an error code at position {position}: {errno}",
),
Self::AddressOverflow => write!(
f,
"the given address/length pair overflowed the machine's memory range"
),
}
}
}
impl StdError for PtraceError {}