Organised modules in folders
This commit is contained in:
parent
88072597a1
commit
1fb5e8c0f8
|
|
@ -1,105 +0,0 @@
|
|||
use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError};
|
||||
use either::{Either, Left, Right};
|
||||
use nix::libc::user_regs_struct;
|
||||
use nix::sys::wait::{waitid, Id, WaitPidFlag, WaitStatus};
|
||||
use nix::unistd::Pid;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("Error when calling ptrace: {0}")]
|
||||
pub struct PTraceError(#[from] nix::errno::Errno);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("Error when waiting on child process: {0}")]
|
||||
pub struct WaitError(#[from] nix::errno::Errno);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum DebugError {
|
||||
#[error(transparent)]
|
||||
PTraceError(#[from] PTraceError),
|
||||
|
||||
#[error(transparent)]
|
||||
WaitError(#[from] WaitError),
|
||||
|
||||
#[error("Child stopped with status {0:?}, but was not expecting to catch this one")]
|
||||
UnexpectedWaitStatus(nix::sys::wait::WaitStatus),
|
||||
}
|
||||
|
||||
pub struct StoppedTarget {
|
||||
pub pid: Pid,
|
||||
}
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl StoppedTarget {
|
||||
fn to_running(self) -> RunningTarget {
|
||||
RunningTarget { pid: self.pid }
|
||||
}
|
||||
|
||||
pub fn new(pid: Pid) -> Result<Self, DebugError> {
|
||||
waitid(Id::Pid(pid), WaitPidFlag::WSTOPPED).map_err(WaitError)?;
|
||||
// Needed for waiting on syscalls and apparently also for getting syscall info (can not get it to work without this)
|
||||
nix::sys::ptrace::setoptions(pid, nix::sys::ptrace::Options::PTRACE_O_TRACESYSGOOD).map_err(PTraceError)?;
|
||||
Ok(Self { pid })
|
||||
}
|
||||
|
||||
pub fn cont(self) -> Result<RunningTarget, PTraceError> {
|
||||
nix::sys::ptrace::cont(self.pid, None).map_err(PTraceError)?;
|
||||
Ok(self.to_running())
|
||||
}
|
||||
|
||||
pub fn stepi(self) -> Result<RunningTarget, PTraceError> {
|
||||
nix::sys::ptrace::step(self.pid, None).map_err(PTraceError)?;
|
||||
Ok(self.to_running())
|
||||
}
|
||||
|
||||
pub fn cont_syscall(self) -> Result<RunningTarget, PTraceError> {
|
||||
nix::sys::ptrace::syscall(self.pid, None).map_err(PTraceError)?;
|
||||
Ok(self.to_running())
|
||||
}
|
||||
|
||||
pub fn get_registers(&self) -> Result<user_regs_struct, PTraceError> {
|
||||
Ok(nix::sys::ptrace::getregs(self.pid)?)
|
||||
}
|
||||
|
||||
pub fn get_syscall_info(&self) -> Result<SyscallInfo, SyscallInfoError> {
|
||||
Ok(syscall_info(self.pid.as_raw())?)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunningTarget {
|
||||
pub pid: Pid,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl RunningTarget {
|
||||
fn to_stopped(self) -> StoppedTarget {
|
||||
StoppedTarget { pid: self.pid }
|
||||
}
|
||||
|
||||
pub fn wait_for_something(self) -> Result<Either<StoppedTarget, ExitedTarget>, DebugError> {
|
||||
match waitid(Id::Pid(self.pid), WaitPidFlag::WSTOPPED | WaitPidFlag::WEXITED).map_err(WaitError)? {
|
||||
WaitStatus::Exited(_pid, exit_code) => Ok(Right(ExitedTarget { exit_code, was_pid: self.pid })),
|
||||
WaitStatus::PtraceEvent(..) | WaitStatus::PtraceSyscall(..) => Ok(Left(self.to_stopped())),
|
||||
status => Err(DebugError::UnexpectedWaitStatus(status)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_for_syscall(self) -> Result<StoppedTarget, DebugError> {
|
||||
match waitid(Id::Pid(self.pid), WaitPidFlag::WSTOPPED).map_err(WaitError)? {
|
||||
WaitStatus::PtraceSyscall(..) => Ok(self.to_stopped()),
|
||||
status => Err(DebugError::UnexpectedWaitStatus(status)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_for_exit(self) -> Result<ExitedTarget, DebugError> {
|
||||
match waitid(Id::Pid(self.pid), WaitPidFlag::WEXITED).map_err(WaitError)? {
|
||||
WaitStatus::Exited(_pid, exit_code) => Ok(ExitedTarget { exit_code, was_pid: self.pid }),
|
||||
status => Err(DebugError::UnexpectedWaitStatus(status))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExitedTarget {
|
||||
pub exit_code: i32,
|
||||
pub was_pid: Pid,
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
mod stopped_target;
|
||||
mod running_target;
|
||||
|
||||
use nix::unistd::Pid;
|
||||
pub use running_target::*;
|
||||
pub use stopped_target::*;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("Error when calling ptrace: {0}")]
|
||||
pub struct PTraceError(#[from] nix::errno::Errno);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("Error when waiting on child process: {0}")]
|
||||
pub struct WaitError(#[from] nix::errno::Errno);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum DebugError {
|
||||
#[error(transparent)]
|
||||
PTraceError(#[from] PTraceError),
|
||||
|
||||
#[error(transparent)]
|
||||
WaitError(#[from] WaitError),
|
||||
|
||||
#[error("Child stopped with status {0:?}, but was not expecting to catch this one")]
|
||||
UnexpectedWaitStatus(nix::sys::wait::WaitStatus),
|
||||
}
|
||||
|
||||
|
||||
pub struct ExitedTarget {
|
||||
pub exit_code: i32,
|
||||
pub was_pid: Pid,
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
use crate::debug_target::{DebugError, ExitedTarget, StoppedTarget, WaitError};
|
||||
use either::{Either, Left, Right};
|
||||
use nix::sys::wait::{waitid, Id, WaitPidFlag, WaitStatus};
|
||||
use nix::unistd::Pid;
|
||||
|
||||
pub struct RunningTarget {
|
||||
pub pid: Pid,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl RunningTarget {
|
||||
fn to_stopped(self) -> StoppedTarget {
|
||||
StoppedTarget { pid: self.pid }
|
||||
}
|
||||
|
||||
pub fn wait_for_something(self) -> Result<Either<StoppedTarget, ExitedTarget>, DebugError> {
|
||||
match waitid(Id::Pid(self.pid), WaitPidFlag::WSTOPPED | WaitPidFlag::WEXITED).map_err(WaitError)? {
|
||||
WaitStatus::Exited(_pid, exit_code) => Ok(Right(ExitedTarget { exit_code, was_pid: self.pid })),
|
||||
WaitStatus::PtraceEvent(..) | WaitStatus::PtraceSyscall(..) => Ok(Left(self.to_stopped())),
|
||||
status => Err(DebugError::UnexpectedWaitStatus(status)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_for_syscall(self) -> Result<StoppedTarget, DebugError> {
|
||||
match waitid(Id::Pid(self.pid), WaitPidFlag::WSTOPPED).map_err(WaitError)? {
|
||||
WaitStatus::PtraceSyscall(..) => Ok(self.to_stopped()),
|
||||
status => Err(DebugError::UnexpectedWaitStatus(status)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_for_exit(self) -> Result<ExitedTarget, DebugError> {
|
||||
match waitid(Id::Pid(self.pid), WaitPidFlag::WEXITED).map_err(WaitError)? {
|
||||
WaitStatus::Exited(_pid, exit_code) => Ok(ExitedTarget { exit_code, was_pid: self.pid }),
|
||||
status => Err(DebugError::UnexpectedWaitStatus(status))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
use crate::debug_target::{DebugError, PTraceError, RunningTarget, WaitError};
|
||||
use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError};
|
||||
use libc::user_regs_struct;
|
||||
use nix::sys::wait::{waitid, Id, WaitPidFlag};
|
||||
use nix::unistd::Pid;
|
||||
|
||||
pub struct StoppedTarget {
|
||||
pub pid: Pid,
|
||||
}
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl StoppedTarget {
|
||||
fn to_running(self) -> RunningTarget {
|
||||
RunningTarget { pid: self.pid }
|
||||
}
|
||||
|
||||
pub fn new(pid: Pid) -> Result<Self, DebugError> {
|
||||
waitid(Id::Pid(pid), WaitPidFlag::WSTOPPED).map_err(WaitError)?;
|
||||
// Needed for waiting on syscalls and apparently also for getting syscall info (can not get it to work without this)
|
||||
nix::sys::ptrace::setoptions(pid, nix::sys::ptrace::Options::PTRACE_O_TRACESYSGOOD).map_err(PTraceError)?;
|
||||
Ok(Self { pid })
|
||||
}
|
||||
|
||||
pub fn cont(self) -> Result<RunningTarget, PTraceError> {
|
||||
nix::sys::ptrace::cont(self.pid, None).map_err(PTraceError)?;
|
||||
Ok(self.to_running())
|
||||
}
|
||||
|
||||
pub fn stepi(self) -> Result<RunningTarget, PTraceError> {
|
||||
nix::sys::ptrace::step(self.pid, None).map_err(PTraceError)?;
|
||||
Ok(self.to_running())
|
||||
}
|
||||
|
||||
pub fn cont_syscall(self) -> Result<RunningTarget, PTraceError> {
|
||||
nix::sys::ptrace::syscall(self.pid, None).map_err(PTraceError)?;
|
||||
Ok(self.to_running())
|
||||
}
|
||||
|
||||
pub fn get_registers(&self) -> Result<user_regs_struct, PTraceError> {
|
||||
Ok(nix::sys::ptrace::getregs(self.pid)?)
|
||||
}
|
||||
|
||||
pub fn get_syscall_info(&self) -> Result<SyscallInfo, SyscallInfoError> {
|
||||
Ok(syscall_info(self.pid.as_raw())?)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
mod child;
|
||||
mod debug_target;
|
||||
mod syscall_info;
|
||||
mod syscall_names;
|
||||
|
||||
use crate::debug_target::{ExitedTarget, StoppedTarget};
|
||||
use color_eyre::eyre::eyre;
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ Currently nix's (v0.30.1) implementation for PTRACE_GET_SYSCALL_INFO does not se
|
|||
It also returns the raw libc struct containing a union, while this parses it in a custom union-free type.
|
||||
This is an alternative implementation that relies on libc and unsafe.
|
||||
*/
|
||||
|
||||
use crate::syscall_info::SyscallInfoError::UnsupportedType;
|
||||
mod syscall_names;
|
||||
use std::mem::MaybeUninit;
|
||||
use crate::syscall_names::syscall_name;
|
||||
pub use syscall_names::syscall_name;
|
||||
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum SyscallInfoError {
|
||||
|
|
@ -76,6 +76,6 @@ pub fn syscall_info(pid: libc::pid_t) -> Result<SyscallInfo, SyscallInfoError> {
|
|||
is_error: syscall_info_raw.u.exit.is_error,
|
||||
}
|
||||
}),
|
||||
op => Err(UnsupportedType { op }),
|
||||
op => Err(SyscallInfoError::UnsupportedType { op }),
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue