Compare commits
No commits in common. "custom_clib_wrap" and "dev" have entirely different histories.
custom_cli
...
dev
|
|
@ -36,7 +36,6 @@ dependencies = [
|
||||||
name = "bdb"
|
name = "bdb"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"either",
|
"either",
|
||||||
|
|
@ -47,9 +46,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.9.1"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ color-eyre = "0.6.3"
|
||||||
either = "1.15.0"
|
either = "1.15.0"
|
||||||
libc = "0.2.172"
|
libc = "0.2.172"
|
||||||
derive_more = { version = "2.0.1", features = ["debug"] }
|
derive_more = { version = "2.0.1", features = ["debug"] }
|
||||||
bitflags = "2.9.1"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
use crate::clibwrap::{ErrnoError, Pid};
|
|
||||||
|
|
||||||
mod external {
|
|
||||||
use crate::clibwrap::Pid;
|
|
||||||
|
|
||||||
unsafe extern "C" {
|
|
||||||
pub fn fork() -> Pid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ForkResult {
|
|
||||||
Parent { child_pid: Pid },
|
|
||||||
Child,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn fork() -> Result<ForkResult, ErrnoError> {
|
|
||||||
let return_value = unsafe { external::fork() };
|
|
||||||
if return_value == -1 {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
} else if return_value == 0 {
|
|
||||||
Ok(ForkResult::Child)
|
|
||||||
} else {
|
|
||||||
Ok(ForkResult::Parent { child_pid: return_value })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
use std::ffi::{c_char, c_int, CStr};
|
|
||||||
pub mod ptrace;
|
|
||||||
pub mod fork;
|
|
||||||
|
|
||||||
pub type Pid = i32;
|
|
||||||
|
|
||||||
unsafe extern "C" {
|
|
||||||
fn __errno_location() -> *mut c_int;
|
|
||||||
fn strerror(errnum: c_int) -> *const c_char;
|
|
||||||
fn strerrorname_np(errnum: c_int) -> *const c_char;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn errno() -> c_int {
|
|
||||||
unsafe { *__errno_location() }
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn set_errno(errno: c_int) {
|
|
||||||
unsafe { *__errno_location() = errno; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
#[error("{}", self.error_message())]
|
|
||||||
pub struct ErrnoError {
|
|
||||||
errno: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ErrnoError {
|
|
||||||
pub unsafe fn from_current_errno() -> Self {
|
|
||||||
unsafe { Self { errno: errno() } }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_message(&self) -> String {
|
|
||||||
unsafe {
|
|
||||||
let error_name = {
|
|
||||||
let c_error_name = strerrorname_np(self.errno);
|
|
||||||
if c_error_name.is_null() {
|
|
||||||
"???"
|
|
||||||
} else {
|
|
||||||
&CStr::from_ptr(c_error_name).to_string_lossy().into_owned()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let error_message = {
|
|
||||||
let c_str = strerror(self.errno);
|
|
||||||
CStr::from_ptr(c_str).to_string_lossy().into_owned()
|
|
||||||
};
|
|
||||||
format!("{}: {}", error_name, error_message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
use crate::clibwrap::{errno, set_errno, ErrnoError, Pid};
|
|
||||||
use bitflags::bitflags;
|
|
||||||
use std::ffi::{c_long, c_ulonglong, c_void};
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(u32)]
|
|
||||||
enum PTraceRequest {
|
|
||||||
PTRACE_PEEKDATA = 2,
|
|
||||||
PTRACE_POKEDATA = 5,
|
|
||||||
PTRACE_CONT = 7,
|
|
||||||
PTRACE_SINGLESTEP = 9,
|
|
||||||
PTRACE_GETREGS = 12,
|
|
||||||
PTRACE_SETREGS = 13,
|
|
||||||
PTRACE_SYSCALL = 24,
|
|
||||||
PTRACE_SETOPTIONS = 0x4200,
|
|
||||||
}
|
|
||||||
unsafe extern "C" {
|
|
||||||
fn ptrace(request: PTraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> c_long;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cont(pid: Pid) -> Result<(), ErrnoError> {
|
|
||||||
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_CONT, pid, 0 as _, 0 as _) };
|
|
||||||
if return_code == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn single_step(pid: Pid) -> Result<(), ErrnoError> {
|
|
||||||
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_SINGLESTEP, pid, 0 as _, 0 as _) };
|
|
||||||
if return_code == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn syscall(pid: Pid) -> Result<(), ErrnoError> {
|
|
||||||
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_SYSCALL, pid, 0 as _, 0 as _) };
|
|
||||||
if return_code == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PTraceOptions: u32 {
|
|
||||||
const PTRACE_O_TRACESYSGOOD = 1;
|
|
||||||
// Other variants not implemented
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_options(pid: Pid, options: PTraceOptions) -> Result<(), ErrnoError> {
|
|
||||||
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_SETOPTIONS, pid, 0 as _, options.bits() as _) };
|
|
||||||
if return_code == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(derive_more::Debug)]
|
|
||||||
pub struct registers {
|
|
||||||
#[debug("{r15:#x} ({r15})")]
|
|
||||||
pub r15: c_ulonglong,
|
|
||||||
#[debug("{r14:#x} ({r14})")]
|
|
||||||
pub r14: c_ulonglong,
|
|
||||||
#[debug("{r13:#x} ({r13})")]
|
|
||||||
pub r13: c_ulonglong,
|
|
||||||
#[debug("{r12:#x} ({r12})")]
|
|
||||||
pub r12: c_ulonglong,
|
|
||||||
#[debug("{rbp:#x} ({rbp})")]
|
|
||||||
pub rbp: c_ulonglong,
|
|
||||||
#[debug("{rbx:#x} ({rbx})")]
|
|
||||||
pub rbx: c_ulonglong,
|
|
||||||
#[debug("{r11:#x} ({r11})")]
|
|
||||||
pub r11: c_ulonglong,
|
|
||||||
#[debug("{r10:#x} ({r10})")]
|
|
||||||
pub r10: c_ulonglong,
|
|
||||||
#[debug("{r9:#x} ({r9})")]
|
|
||||||
pub r9: c_ulonglong,
|
|
||||||
#[debug("{r8:#x} ({r8})")]
|
|
||||||
pub r8: c_ulonglong,
|
|
||||||
#[debug("{rax:#x} ({rax})")]
|
|
||||||
pub rax: c_ulonglong,
|
|
||||||
#[debug("{rcx:#x} ({rcx})")]
|
|
||||||
pub rcx: c_ulonglong,
|
|
||||||
#[debug("{rdx:#x} ({rdx})")]
|
|
||||||
pub rdx: c_ulonglong,
|
|
||||||
#[debug("{rsi:#x} ({rsi})")]
|
|
||||||
pub rsi: c_ulonglong,
|
|
||||||
#[debug("{rdi:#x} ({rdi})")]
|
|
||||||
pub rdi: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub orig_rax: c_ulonglong,
|
|
||||||
#[debug("{rip:#x} ({rip})")]
|
|
||||||
pub rip: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub cs: c_ulonglong,
|
|
||||||
#[debug("{eflags:#x} ({eflags:#b})")]
|
|
||||||
pub eflags: c_ulonglong,
|
|
||||||
#[debug("{rsp:#x} ({rsp})")]
|
|
||||||
pub rsp: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub ss: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub fs_base: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub gs_base: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub ds: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub es: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub fs: c_ulonglong,
|
|
||||||
#[debug(skip)]
|
|
||||||
pub gs: c_ulonglong,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_regs(pid: Pid) -> Result<registers, ErrnoError> {
|
|
||||||
let mut registers = MaybeUninit::<registers>::uninit();
|
|
||||||
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_GETREGS, pid, 0 as _, registers.as_mut_ptr() as _) };
|
|
||||||
if return_code == 0 {
|
|
||||||
unsafe { Ok(registers.assume_init()) }
|
|
||||||
} else {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_regs(pid: Pid, registers: registers) -> Result<(), ErrnoError> {
|
|
||||||
let register_address: *const registers = ®isters;
|
|
||||||
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_SETREGS, pid, 0 as _, register_address as _) };
|
|
||||||
if return_code == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn peek_data(pid: Pid, address: u64) -> Result<c_long, ErrnoError> {
|
|
||||||
unsafe {
|
|
||||||
set_errno(0);
|
|
||||||
let data = ptrace(PTraceRequest::PTRACE_PEEKDATA, pid, address as _, 0 as _);
|
|
||||||
let errno = errno();
|
|
||||||
if errno != 0 {
|
|
||||||
Err(ErrnoError::from_current_errno())
|
|
||||||
} else {
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poke_data(pid: Pid, address: u64, data: c_long) -> Result<(), ErrnoError> {
|
|
||||||
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_POKEDATA, pid, address as _, data as _) };
|
|
||||||
if return_code == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
unsafe { Err(ErrnoError::from_current_errno()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
mod stopped_target;
|
mod stopped_target;
|
||||||
mod running_target;
|
mod running_target;
|
||||||
|
|
||||||
use crate::clibwrap;
|
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
pub use running_target::*;
|
pub use running_target::*;
|
||||||
pub use stopped_target::*;
|
pub use stopped_target::*;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
#[error("Error when calling ptrace: {0}")]
|
#[error("Error when calling ptrace: {0}")]
|
||||||
pub struct PTraceError(#[from] clibwrap::ErrnoError);
|
pub struct PTraceError(#[from] nix::errno::Errno);
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
#[error("Error when waiting on child process: {0}")]
|
#[error("Error when waiting on child process: {0}")]
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::clibwrap;
|
|
||||||
use crate::debug_target::{DebugError, PTraceError, RunningTarget, WaitError};
|
use crate::debug_target::{DebugError, PTraceError, RunningTarget, WaitError};
|
||||||
use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError};
|
use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError};
|
||||||
use libc::c_long;
|
use libc::{c_long, user_regs_struct};
|
||||||
use nix::sys::wait::{waitid, Id, WaitPidFlag};
|
use nix::sys::wait::{waitid, Id, WaitPidFlag};
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
|
||||||
pub struct StoppedTarget {
|
pub struct StoppedTarget {
|
||||||
pub pid: Pid,
|
pub pid: Pid,
|
||||||
|
|
@ -21,7 +21,7 @@ impl StoppedTarget {
|
||||||
pub fn new(pid: Pid) -> Result<Self, DebugError> {
|
pub fn new(pid: Pid) -> Result<Self, DebugError> {
|
||||||
waitid(Id::Pid(pid), WaitPidFlag::WSTOPPED).map_err(WaitError)?;
|
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)
|
// Needed for waiting on syscalls and apparently also for getting syscall info (can not get it to work without this)
|
||||||
clibwrap::ptrace::set_options(pid.as_raw(), clibwrap::ptrace::PTraceOptions::PTRACE_O_TRACESYSGOOD).map_err(PTraceError)?;
|
nix::sys::ptrace::setoptions(pid, nix::sys::ptrace::Options::PTRACE_O_TRACESYSGOOD).map_err(PTraceError)?;
|
||||||
Ok(Self { pid, breakpoints: HashMap::new() })
|
Ok(Self { pid, breakpoints: HashMap::new() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@ impl StoppedTarget {
|
||||||
let mut registers = self.get_registers()?;
|
let mut registers = self.get_registers()?;
|
||||||
self.remove_breakpoint(registers.rip - 1)?;
|
self.remove_breakpoint(registers.rip - 1)?;
|
||||||
registers.rip -= 1;
|
registers.rip -= 1;
|
||||||
clibwrap::ptrace::set_regs(self.pid.as_raw(), registers).map_err(PTraceError)?;
|
nix::sys::ptrace::setregs(self.pid, registers).map_err(PTraceError)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ impl StoppedTarget {
|
||||||
if self.on_breakpoint()? {
|
if self.on_breakpoint()? {
|
||||||
self.breakpoint_remove_and_rewind()?;
|
self.breakpoint_remove_and_rewind()?;
|
||||||
}
|
}
|
||||||
clibwrap::ptrace::cont(self.pid.as_raw()).map_err(PTraceError)?;
|
nix::sys::ptrace::cont(self.pid, None).map_err(PTraceError)?;
|
||||||
Ok(self.to_running())
|
Ok(self.to_running())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ impl StoppedTarget {
|
||||||
if self.on_breakpoint()? {
|
if self.on_breakpoint()? {
|
||||||
self.breakpoint_remove_and_rewind()?;
|
self.breakpoint_remove_and_rewind()?;
|
||||||
}
|
}
|
||||||
clibwrap::ptrace::single_step(self.pid.as_raw()).map_err(PTraceError)?;
|
nix::sys::ptrace::step(self.pid, None).map_err(PTraceError)?;
|
||||||
Ok(self.to_running())
|
Ok(self.to_running())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,12 +58,12 @@ impl StoppedTarget {
|
||||||
if self.on_breakpoint()? {
|
if self.on_breakpoint()? {
|
||||||
self.breakpoint_remove_and_rewind()?;
|
self.breakpoint_remove_and_rewind()?;
|
||||||
}
|
}
|
||||||
clibwrap::ptrace::syscall(self.pid.as_raw()).map_err(PTraceError)?;
|
nix::sys::ptrace::syscall(self.pid, None).map_err(PTraceError)?;
|
||||||
Ok(self.to_running())
|
Ok(self.to_running())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_registers(&self) -> Result<clibwrap::ptrace::registers, PTraceError> {
|
pub fn get_registers(&self) -> Result<user_regs_struct, PTraceError> {
|
||||||
clibwrap::ptrace::get_regs(self.pid.as_raw()).map_err(PTraceError)
|
Ok(nix::sys::ptrace::getregs(self.pid)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_syscall_info(&self) -> Result<SyscallInfo, SyscallInfoError> {
|
pub fn get_syscall_info(&self) -> Result<SyscallInfo, SyscallInfoError> {
|
||||||
|
|
@ -75,10 +75,10 @@ impl StoppedTarget {
|
||||||
if self.breakpoints.contains_key(&address) {
|
if self.breakpoints.contains_key(&address) {
|
||||||
return Err(DebugError::DuplicateBreakpoint { address });
|
return Err(DebugError::DuplicateBreakpoint { address });
|
||||||
}
|
}
|
||||||
let orig_bytes = clibwrap::ptrace::peek_data(self.pid.as_raw(), address).map_err(PTraceError)?;
|
let orig_bytes = nix::sys::ptrace::read(self.pid, address as *mut c_void).map_err(PTraceError)?;
|
||||||
let target_byte: u8 = (orig_bytes & 0xFF as c_long) as u8;
|
let target_byte: u8 = (orig_bytes & 0xFF as c_long) as u8;
|
||||||
let new_content = (orig_bytes & (!0xff as c_long)) | (0xCC as c_long);
|
let new_content = (orig_bytes & (!0xff as c_long)) | (0xCC as c_long);
|
||||||
clibwrap::ptrace::poke_data(self.pid.as_raw(), address, new_content).map_err(PTraceError)?;
|
nix::sys::ptrace::write(self.pid, address as *mut c_void, new_content).map_err(PTraceError)?;
|
||||||
|
|
||||||
self.breakpoints.insert(address, target_byte);
|
self.breakpoints.insert(address, target_byte);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -89,9 +89,9 @@ impl StoppedTarget {
|
||||||
match self.breakpoints.remove(&address) {
|
match self.breakpoints.remove(&address) {
|
||||||
None => Err(DebugError::NonExistingBreakpoint { address }),
|
None => Err(DebugError::NonExistingBreakpoint { address }),
|
||||||
Some(original_byte) => {
|
Some(original_byte) => {
|
||||||
let content = clibwrap::ptrace::peek_data(self.pid.as_raw(), address).map_err(PTraceError)?;
|
let content = nix::sys::ptrace::read(self.pid, address as *mut c_void).map_err(PTraceError)?;
|
||||||
let new_content = (content & (!0xff as c_long)) | (original_byte as c_long);
|
let new_content = (content & (!0xff as c_long)) | (original_byte as c_long);
|
||||||
clibwrap::ptrace::poke_data(self.pid.as_raw(), address, new_content).map_err(PTraceError)?;
|
nix::sys::ptrace::write(self.pid, address as *mut c_void, new_content).map_err(PTraceError)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/main.rs
14
src/main.rs
|
|
@ -1,12 +1,10 @@
|
||||||
mod debug_target;
|
mod debug_target;
|
||||||
mod syscall_info;
|
mod syscall_info;
|
||||||
mod clibwrap;
|
|
||||||
|
|
||||||
use crate::debug_target::{ExitedTarget, StoppedTarget};
|
use crate::debug_target::{ExitedTarget, StoppedTarget};
|
||||||
use clibwrap::fork::{fork, ForkResult};
|
|
||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::{fork, ForkResult};
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -15,7 +13,7 @@ fn single_step_all(mut target: StoppedTarget) -> color_eyre::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
instruction_number += 1;
|
instruction_number += 1;
|
||||||
let regs = target.get_registers()?;
|
let regs = target.get_registers()?;
|
||||||
println!("🔎 [==> {instruction_number} {regs:?}");
|
println!("🔎 [==> {}] rip= {:#016x}, rax = 0x{rax:x} ({rax})", instruction_number, regs.rip, rax = regs.rax);
|
||||||
match target.stepi()?.wait_for_something()? {
|
match target.stepi()?.wait_for_something()? {
|
||||||
Either::Left(t) => target = t,
|
Either::Left(t) => target = t,
|
||||||
Either::Right(ExitedTarget { exit_code, was_pid: _was_pid }) => {
|
Either::Right(ExitedTarget { exit_code, was_pid: _was_pid }) => {
|
||||||
|
|
@ -53,10 +51,10 @@ fn main() -> color_eyre::Result<()> {
|
||||||
nix::unistd::execv(&child_exec_path, &[&child_exec_path])?;
|
nix::unistd::execv(&child_exec_path, &[&child_exec_path])?;
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
Ok(ForkResult::Parent { child_pid }) => {
|
Ok(ForkResult::Parent { child: child_pid }) => {
|
||||||
println!("✔️ Created child {child_pid}");
|
println!("✔️ Created child {child_pid}");
|
||||||
|
|
||||||
let mut target = StoppedTarget::new(Pid::from_raw(child_pid))?;
|
let mut target = StoppedTarget::new(child_pid)?;
|
||||||
println!("✔️ Child ready!");
|
println!("✔️ Child ready!");
|
||||||
|
|
||||||
let breakpoint1 = 0x40101b;
|
let breakpoint1 = 0x40101b;
|
||||||
|
|
@ -69,8 +67,8 @@ fn main() -> color_eyre::Result<()> {
|
||||||
println!("🚧 We are on a breakpoint!")
|
println!("🚧 We are on a breakpoint!")
|
||||||
}
|
}
|
||||||
println!("🔎 rip: {:#x}", t.get_registers()?.rip);
|
println!("🔎 rip: {:#x}", t.get_registers()?.rip);
|
||||||
single_step_all(t)?;
|
// single_step_all(t)?;
|
||||||
// strace(t)?;
|
strace(t)?;
|
||||||
}
|
}
|
||||||
Either::Right(ExitedTarget { exit_code, .. }) => {
|
Either::Right(ExitedTarget { exit_code, .. }) => {
|
||||||
println!("👋 Child exited with code {exit_code}");
|
println!("👋 Child exited with code {exit_code}");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue