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