Organised modules in folders

This commit is contained in:
Elnath 2025-05-18 15:36:47 +02:00
parent 88072597a1
commit 1fb5e8c0f8
7 changed files with 120 additions and 110 deletions

View File

@ -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,
}

32
src/debug_target/mod.rs Normal file
View File

@ -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,
}

View File

@ -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))
}
}
}

View File

@ -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())?)
}
}

View File

@ -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;

View File

@ -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 }),
}
}