@@ -17,8 +17,10 @@ pub type AddressType = *mut ::libc::c_void;
1717 target_arch = "x86_64" ,
1818 any( target_env = "gnu" , target_env = "musl" )
1919 ) ,
20- all( target_arch = "x86" , target_env = "gnu" )
21- )
20+ all( target_arch = "x86" , target_env = "gnu" ) ,
21+ all( target_arch = "aarch64" , target_env = "gnu" ) ,
22+ all( target_arch = "riscv64" , target_env = "gnu" ) ,
23+ ) ,
2224) ) ]
2325use libc:: user_regs_struct;
2426
@@ -170,6 +172,29 @@ libc_enum! {
170172 }
171173}
172174
175+ libc_enum ! {
176+ #[ cfg( all(
177+ target_os = "linux" ,
178+ target_env = "gnu" ,
179+ any(
180+ target_arch = "x86_64" ,
181+ target_arch = "x86" ,
182+ target_arch = "aarch64" ,
183+ target_arch = "riscv64" ,
184+ )
185+ ) ) ]
186+ #[ repr( i32 ) ]
187+ /// Defining a specific register set, as used in [`getregset`] and [`setregset`].
188+ #[ non_exhaustive]
189+ pub enum RegisterSet {
190+ NT_PRSTATUS ,
191+ NT_PRFPREG ,
192+ NT_PRPSINFO ,
193+ NT_TASKSTRUCT ,
194+ NT_AUXV ,
195+ }
196+ }
197+
173198libc_bitflags ! {
174199 /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
175200 /// See `man ptrace` for more details.
@@ -217,6 +242,12 @@ fn ptrace_peek(
217242}
218243
219244/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
245+ ///
246+ /// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]),
247+ /// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
248+ /// on aarch64 and riscv64.
249+ ///
250+ /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
220251#[ cfg( all(
221252 target_os = "linux" ,
222253 any(
@@ -231,7 +262,58 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
231262 ptrace_get_data :: < user_regs_struct > ( Request :: PTRACE_GETREGS , pid)
232263}
233264
265+ /// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
266+ ///
267+ /// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]),
268+ /// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
269+ /// on aarch64 and riscv64.
270+ ///
271+ /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
272+ #[ cfg( all(
273+ target_os = "linux" ,
274+ target_env = "gnu" ,
275+ any( target_arch = "aarch64" , target_arch = "riscv64" )
276+ ) ) ]
277+ pub fn getregs ( pid : Pid ) -> Result < user_regs_struct > {
278+ getregset ( pid, RegisterSet :: NT_PRSTATUS )
279+ }
280+
281+ /// Get a particular set of user registers, as with `ptrace(PTRACE_GETREGSET, ...)`
282+ #[ cfg( all(
283+ target_os = "linux" ,
284+ target_env = "gnu" ,
285+ any(
286+ target_arch = "x86_64" ,
287+ target_arch = "x86" ,
288+ target_arch = "aarch64" ,
289+ target_arch = "riscv64" ,
290+ )
291+ ) ) ]
292+ pub fn getregset ( pid : Pid , set : RegisterSet ) -> Result < user_regs_struct > {
293+ let request = Request :: PTRACE_GETREGSET ;
294+ let mut data = mem:: MaybeUninit :: < user_regs_struct > :: uninit ( ) ;
295+ let mut iov = libc:: iovec {
296+ iov_base : data. as_mut_ptr ( ) . cast ( ) ,
297+ iov_len : mem:: size_of :: < user_regs_struct > ( ) ,
298+ } ;
299+ unsafe {
300+ ptrace_other (
301+ request,
302+ pid,
303+ set as i32 as AddressType ,
304+ ( & mut iov as * mut libc:: iovec ) . cast ( ) ,
305+ ) ?;
306+ } ;
307+ Ok ( unsafe { data. assume_init ( ) } )
308+ }
309+
234310/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
311+ ///
312+ /// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]),
313+ /// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
314+ /// on aarch64 and riscv64.
315+ ///
316+ /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
235317#[ cfg( all(
236318 target_os = "linux" ,
237319 any(
@@ -248,12 +330,59 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
248330 Request :: PTRACE_SETREGS as RequestType ,
249331 libc:: pid_t:: from ( pid) ,
250332 ptr:: null_mut :: < c_void > ( ) ,
251- & regs as * const _ as * const c_void ,
333+ & regs as * const user_regs_struct as * const c_void ,
252334 )
253335 } ;
254336 Errno :: result ( res) . map ( drop)
255337}
256338
339+ /// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
340+ ///
341+ /// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]),
342+ /// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect
343+ /// on aarch64 and riscv64.
344+ ///
345+ /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html
346+ #[ cfg( all(
347+ target_os = "linux" ,
348+ target_env = "gnu" ,
349+ any( target_arch = "aarch64" , target_arch = "riscv64" )
350+ ) ) ]
351+ pub fn setregs ( pid : Pid , regs : user_regs_struct ) -> Result < ( ) > {
352+ setregset ( pid, RegisterSet :: NT_PRSTATUS , regs)
353+ }
354+
355+ /// Set a particular set of user registers, as with `ptrace(PTRACE_SETREGSET, ...)`
356+ #[ cfg( all(
357+ target_os = "linux" ,
358+ target_env = "gnu" ,
359+ any(
360+ target_arch = "x86_64" ,
361+ target_arch = "x86" ,
362+ target_arch = "aarch64" ,
363+ target_arch = "riscv64" ,
364+ )
365+ ) ) ]
366+ pub fn setregset (
367+ pid : Pid ,
368+ set : RegisterSet ,
369+ mut regs : user_regs_struct ,
370+ ) -> Result < ( ) > {
371+ let mut iov = libc:: iovec {
372+ iov_base : ( & mut regs as * mut user_regs_struct ) . cast ( ) ,
373+ iov_len : mem:: size_of :: < user_regs_struct > ( ) ,
374+ } ;
375+ unsafe {
376+ ptrace_other (
377+ Request :: PTRACE_SETREGSET ,
378+ pid,
379+ set as i32 as AddressType ,
380+ ( & mut iov as * mut libc:: iovec ) . cast ( ) ,
381+ ) ?;
382+ }
383+ Ok ( ( ) )
384+ }
385+
257386/// Function for ptrace requests that return values from the data field.
258387/// Some ptrace get requests populate structs or larger elements than `c_long`
259388/// and therefore use the data field to return values. This function handles these
0 commit comments