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 child;
|
||||||
mod debug_target;
|
mod debug_target;
|
||||||
mod syscall_info;
|
mod syscall_info;
|
||||||
mod syscall_names;
|
|
||||||
|
|
||||||
use crate::debug_target::{ExitedTarget, StoppedTarget};
|
use crate::debug_target::{ExitedTarget, StoppedTarget};
|
||||||
use color_eyre::eyre::eyre;
|
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.
|
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.
|
This is an alternative implementation that relies on libc and unsafe.
|
||||||
*/
|
*/
|
||||||
|
mod syscall_names;
|
||||||
use crate::syscall_info::SyscallInfoError::UnsupportedType;
|
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
use crate::syscall_names::syscall_name;
|
pub use syscall_names::syscall_name;
|
||||||
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum SyscallInfoError {
|
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,
|
is_error: syscall_info_raw.u.exit.is_error,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
op => Err(UnsupportedType { op }),
|
op => Err(SyscallInfoError::UnsupportedType { op }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue