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