|
1 |
| -//! For detailed description of the ptrace requests, consult `man ptrace`. |
| 1 | +//! Interface for `ptrace` |
| 2 | +//! |
| 3 | +//! For detailed description of the ptrace requests, consult [`ptrace`(2)]. |
| 4 | +//! [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html |
2 | 5 |
|
3 | 6 | use std::{mem, ptr};
|
4 | 7 | use {Errno, Error, Result};
|
@@ -134,11 +137,20 @@ pub unsafe fn ptrace(request: Request, pid: Pid, addr: *mut c_void, data: *mut c
|
134 | 137 | }
|
135 | 138 | }
|
136 | 139 |
|
137 |
| -unsafe fn ptrace_peek(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { |
138 |
| - let ret = { |
139 |
| - Errno::clear(); |
140 |
| - libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) |
141 |
| - }; |
| 140 | +unsafe fn ptrace_peek( |
| 141 | + request: Request, |
| 142 | + pid: Pid, |
| 143 | + addr: *mut c_void, |
| 144 | + data: *mut c_void |
| 145 | +) -> Result<c_long> { |
| 146 | + |
| 147 | + Errno::clear(); |
| 148 | + let ret = libc::ptrace( |
| 149 | + request as RequestType, |
| 150 | + libc::pid_t::from(pid), |
| 151 | + addr, |
| 152 | + data |
| 153 | + ); |
142 | 154 | match Errno::result(ret) {
|
143 | 155 | Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
|
144 | 156 | err @ Err(..) => err,
|
@@ -168,8 +180,6 @@ unsafe fn ptrace_other(request: Request, pid: Pid, addr: *mut c_void, data: *mut
|
168 | 180 |
|
169 | 181 | /// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
|
170 | 182 | pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
|
171 |
| - use std::ptr; |
172 |
| - |
173 | 183 | let res = unsafe {
|
174 | 184 | libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
|
175 | 185 | libc::pid_t::from(pid),
|
@@ -238,12 +248,7 @@ pub fn syscall(pid: Pid) -> Result<()> {
|
238 | 248 | /// Attaches to the process specified in pid, making it a tracee of the calling process.
|
239 | 249 | pub fn attach(pid: Pid) -> Result<()> {
|
240 | 250 | unsafe {
|
241 |
| - ptrace_other( |
242 |
| - Request::PTRACE_ATTACH, |
243 |
| - pid, |
244 |
| - ptr::null_mut(), |
245 |
| - ptr::null_mut(), |
246 |
| - ).map(|_| ()) // ignore the useless return value |
| 251 | + ptrace_other(Request::PTRACE_ATTACH, pid, ptr::null_mut(), ptr::null_mut()).map(|_| ()) |
247 | 252 | }
|
248 | 253 | }
|
249 | 254 |
|
@@ -275,3 +280,209 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
|
275 | 280 | }
|
276 | 281 | }
|
277 | 282 |
|
| 283 | +/// Represents all possible ptrace-accessible registers on x86_64 |
| 284 | +#[cfg(target_arch = "x86_64")] |
| 285 | +#[allow(non_camel_case_types)] |
| 286 | +#[derive(Debug, PartialEq)] |
| 287 | +pub enum Register { |
| 288 | + R15 = 8 * ::libc::R15 as isize, |
| 289 | + R14 = 8 * ::libc::R14 as isize, |
| 290 | + R13 = 8 * ::libc::R13 as isize, |
| 291 | + R12 = 8 * ::libc::R12 as isize, |
| 292 | + RBP = 8 * ::libc::RBP as isize, |
| 293 | + RBX = 8 * ::libc::RBX as isize, |
| 294 | + R11 = 8 * ::libc::R11 as isize, |
| 295 | + R10 = 8 * ::libc::R10 as isize, |
| 296 | + R9 = 8 * ::libc::R9 as isize, |
| 297 | + R8 = 8 * ::libc::R8 as isize, |
| 298 | + RAX = 8 * ::libc::RAX as isize, |
| 299 | + RCX = 8 * ::libc::RCX as isize, |
| 300 | + RDX = 8 * ::libc::RDX as isize, |
| 301 | + RSI = 8 * ::libc::RSI as isize, |
| 302 | + RDI = 8 * ::libc::RDI as isize, |
| 303 | + ORIG_RAX = 8 * ::libc::ORIG_RAX as isize, |
| 304 | + RIP = 8 * ::libc::RIP as isize, |
| 305 | + CS = 8 * ::libc::CS as isize, |
| 306 | + EFLAGS = 8 * ::libc::EFLAGS as isize, |
| 307 | + RSP = 8 * ::libc::RSP as isize, |
| 308 | + SS = 8 * ::libc::SS as isize, |
| 309 | + FS_BASE = 8 * ::libc::FS_BASE as isize, |
| 310 | + GS_BASE = 8 * ::libc::GS_BASE as isize, |
| 311 | + DS = 8 * ::libc::DS as isize, |
| 312 | + ES = 8 * ::libc::ES as isize, |
| 313 | + FS = 8 * ::libc::FS as isize, |
| 314 | + GS = 8 * ::libc::GS as isize, |
| 315 | +} |
| 316 | + |
| 317 | +/// Represents all possible ptrace-accessible registers on x86 |
| 318 | +#[cfg(target_arch = "x86")] |
| 319 | +#[allow(non_camel_case_types)] |
| 320 | +#[derive(Debug, PartialEq)] |
| 321 | +pub enum Register { |
| 322 | + EBX = 4 * ::libc::EBX as isize, |
| 323 | + ECX = 4 * ::libc::ECX as isize, |
| 324 | + EDX = 4 * ::libc::EDX as isize, |
| 325 | + ESI = 4 * ::libc::ESI as isize, |
| 326 | + EDI = 4 * ::libc::EDI as isize, |
| 327 | + EBP = 4 * ::libc::EBP as isize, |
| 328 | + EAX = 4 * ::libc::EAX as isize, |
| 329 | + DS = 4 * ::libc::DS as isize, |
| 330 | + ES = 4 * ::libc::ES as isize, |
| 331 | + FS = 4 * ::libc::FS as isize, |
| 332 | + GS = 4 * ::libc::GS as isize, |
| 333 | + ORIG_EAX = 4 * ::libc::ORIG_EAX as isize, |
| 334 | + EIP = 4 * ::libc::EIP as isize, |
| 335 | + CS = 4 * ::libc::CS as isize, |
| 336 | + EFL = 4 * ::libc::EFL as isize, |
| 337 | + UESP = 4 * ::libc::UESP as isize, |
| 338 | + SS = 4 * ::libc::SS as isize, |
| 339 | +} |
| 340 | + |
| 341 | +/// Returns the register containing nth register argument. |
| 342 | +/// |
| 343 | +/// 0th argument is considered to be the syscall number. |
| 344 | +/// Please note that these mappings are only valid for 64-bit programs. |
| 345 | +/// Use [`syscall_arg32`] for tracing 32-bit programs instead. |
| 346 | +/// |
| 347 | +/// [`syscall_arg32`]: macro.syscall_arg32.html |
| 348 | +/// # Examples |
| 349 | +/// |
| 350 | +/// ``` |
| 351 | +/// # #[macro_use] extern crate nix; |
| 352 | +/// # fn main() { |
| 353 | +/// assert_eq!(syscall_arg!(1), nix::sys::ptrace::Register::RDI); |
| 354 | +/// # } |
| 355 | +#[cfg(target_arch = "x86_64")] |
| 356 | +#[macro_export] |
| 357 | +macro_rules! syscall_arg { |
| 358 | + (0) => ($crate::sys::ptrace::Register::ORIG_RAX); |
| 359 | + (1) => ($crate::sys::ptrace::Register::RDI); |
| 360 | + (2) => ($crate::sys::ptrace::Register::RSI); |
| 361 | + (3) => ($crate::sys::ptrace::Register::RDX); |
| 362 | + (4) => ($crate::sys::ptrace::Register::R10); |
| 363 | + (5) => ($crate::sys::ptrace::Register::R8); |
| 364 | + (6) => ($crate::sys::ptrace::Register::R9); |
| 365 | +} |
| 366 | + |
| 367 | +/// Returns the register containing nth register argument for 32-bit programs |
| 368 | +/// |
| 369 | +/// 0th argument is considered to be the syscall number. |
| 370 | +/// Please note that these mappings are only valid for 32-bit programs. |
| 371 | +/// Use [`syscall_arg`] for tracing 64-bit programs instead. |
| 372 | +/// |
| 373 | +/// [`syscall_arg`]: macro.syscall_arg.html |
| 374 | +/// # Examples |
| 375 | +/// |
| 376 | +/// ``` |
| 377 | +/// # #[macro_use] extern crate nix; |
| 378 | +/// # fn main() { |
| 379 | +/// assert_eq!(syscall_arg32!(1), nix::sys::ptrace::Register::RBX); |
| 380 | +/// # } |
| 381 | +#[cfg(target_arch = "x86_64")] |
| 382 | +#[macro_export] |
| 383 | +macro_rules! syscall_arg32 { |
| 384 | + (0) => ($crate::sys::ptrace::Register::ORIG_RAX); |
| 385 | + (1) => ($crate::sys::ptrace::Register::RBX); |
| 386 | + (2) => ($crate::sys::ptrace::Register::RCX); |
| 387 | + (3) => ($crate::sys::ptrace::Register::RDX); |
| 388 | + (4) => ($crate::sys::ptrace::Register::RSI); |
| 389 | + (5) => ($crate::sys::ptrace::Register::RDI); |
| 390 | + (6) => ($crate::sys::ptrace::Register::RBP); |
| 391 | +} |
| 392 | + |
| 393 | +/// Returns the register containing nth register argument. |
| 394 | +/// |
| 395 | +/// 0th argument is considered to be the syscall number. |
| 396 | +/// |
| 397 | +/// # Examples |
| 398 | +/// |
| 399 | +/// ``` |
| 400 | +/// # #[macro_use] extern crate nix; |
| 401 | +/// # fn main() { |
| 402 | +/// assert_eq!(syscall_arg!(1), nix::sys::ptrace::Register::RDI); |
| 403 | +/// # } |
| 404 | +#[cfg(target_arch = "x86")] |
| 405 | +#[macro_export] |
| 406 | +macro_rules! syscall_arg { |
| 407 | + (0) => ($crate::sys::ptrace::Register::ORIG_EAX); |
| 408 | + (1) => ($crate::sys::ptrace::Register::EBX); |
| 409 | + (2) => ($crate::sys::ptrace::Register::ECX); |
| 410 | + (3) => ($crate::sys::ptrace::Register::EDX); |
| 411 | + (4) => ($crate::sys::ptrace::Register::ESI); |
| 412 | + (5) => ($crate::sys::ptrace::Register::EDI); |
| 413 | + (6) => ($crate::sys::ptrace::Register::EBP); |
| 414 | +} |
| 415 | + |
| 416 | +/// An integer type, whose size equals a machine word |
| 417 | +/// |
| 418 | +/// `ptrace` always returns a machine word. This type provides an abstraction |
| 419 | +/// of the fact that on *nix systems, `c_long` is always a machine word, |
| 420 | +/// so as to prevent the library from leaking C implementation-dependent types. |
| 421 | +type Word = usize; |
| 422 | + |
| 423 | +/// Peeks a user-accessible register, as with `ptrace(PTRACE_PEEKUSER, ...)` |
| 424 | +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] |
| 425 | +pub fn peekuser(pid: Pid, reg: Register) -> Result<Word> { |
| 426 | + let reg_arg = (reg as i32) as *mut c_void; |
| 427 | + unsafe { |
| 428 | + ptrace_peek(Request::PTRACE_PEEKUSER, pid, reg_arg, ptr::null_mut()).map(|r| r as Word) |
| 429 | + } |
| 430 | +} |
| 431 | + |
| 432 | +/// Sets the value of a user-accessible register, as with `ptrace(PTRACE_POKEUSER, ...)` |
| 433 | +/// |
| 434 | +/// # Safety |
| 435 | +/// When incorrectly used, may change the registers to bad values, |
| 436 | +/// causing e.g. memory being corrupted by a syscall, thus is marked unsafe |
| 437 | +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] |
| 438 | +pub unsafe fn pokeuser(pid: Pid, reg: Register, val: Word) -> Result<()> { |
| 439 | + let reg_arg = (reg as u64) as *mut c_void; |
| 440 | + ptrace_other(Request::PTRACE_POKEUSER, pid, reg_arg, val as *mut c_void).map(|_| ()) // ignore the useless return value |
| 441 | +} |
| 442 | + |
| 443 | +/// Peeks the memory of a process, as with `ptrace(PTRACE_PEEKDATA, ...)` |
| 444 | +/// |
| 445 | +/// A memory chunk of a size of a machine word is returned. |
| 446 | +/// # Safety |
| 447 | +/// This function allows for accessing arbitrary data in the traced process |
| 448 | +/// and may crash the inferior if used incorrectly and is thus marked `unsafe`. |
| 449 | +pub unsafe fn peekdata(pid: Pid, addr: usize) -> Result<Word> { |
| 450 | + ptrace_peek( |
| 451 | + Request::PTRACE_PEEKDATA, |
| 452 | + pid, |
| 453 | + addr as *mut c_void, |
| 454 | + ptr::null_mut(), |
| 455 | + ).map(|r| r as Word) |
| 456 | +} |
| 457 | + |
| 458 | +/// Modifies the memory of a process, as with `ptrace(PTRACE_POKEUSER, ...)` |
| 459 | +/// |
| 460 | +/// A memory chunk of a size of a machine word is overwriten in the requested |
| 461 | +/// place in the memory of a process. |
| 462 | +/// |
| 463 | +/// # Safety |
| 464 | +/// This function allows for accessing arbitrary data in the traced process |
| 465 | +/// and may crash the inferior or introduce race conditions if used |
| 466 | +/// incorrectly and is thus marked `unsafe`. |
| 467 | +pub unsafe fn pokedata(pid: Pid, addr: usize, val: Word) -> Result<()> { |
| 468 | + ptrace_other( |
| 469 | + Request::PTRACE_POKEDATA, |
| 470 | + pid, |
| 471 | + addr as *mut c_void, |
| 472 | + val as *mut c_void, |
| 473 | + ).map(|_| ()) // ignore the useless return value |
| 474 | +} |
| 475 | + |
| 476 | +#[cfg(test)] |
| 477 | +mod tests { |
| 478 | + use super::Word; |
| 479 | + use std::mem::size_of; |
| 480 | + use libc::c_long; |
| 481 | + |
| 482 | + #[test] |
| 483 | + fn test_types() { |
| 484 | + // c_long is implementation defined, so make sure |
| 485 | + // its width matches |
| 486 | + assert_eq!(size_of::<Word>(), size_of::<c_long>()); |
| 487 | + } |
| 488 | +} |
0 commit comments