|
1 | 1 | #[cfg(all( |
2 | 2 | target_os = "linux", |
3 | | - any(target_arch = "x86_64", target_arch = "x86"), |
4 | | - target_env = "gnu" |
| 3 | + target_env = "gnu", |
| 4 | + any( |
| 5 | + target_arch = "x86_64", |
| 6 | + target_arch = "x86", |
| 7 | + target_arch = "aarch64", |
| 8 | + target_arch = "riscv64", |
| 9 | + ) |
5 | 10 | ))] |
6 | 11 | use memoffset::offset_of; |
7 | 12 | use nix::errno::Errno; |
@@ -179,8 +184,13 @@ fn test_ptrace_interrupt() { |
179 | 184 | // ptrace::{setoptions, getregs} are only available in these platforms |
180 | 185 | #[cfg(all( |
181 | 186 | target_os = "linux", |
182 | | - any(target_arch = "x86_64", target_arch = "x86"), |
183 | | - target_env = "gnu" |
| 187 | + target_env = "gnu", |
| 188 | + any( |
| 189 | + target_arch = "x86_64", |
| 190 | + target_arch = "x86", |
| 191 | + target_arch = "aarch64", |
| 192 | + target_arch = "riscv64", |
| 193 | + ) |
184 | 194 | ))] |
185 | 195 | #[test] |
186 | 196 | fn test_ptrace_syscall() { |
@@ -226,14 +236,28 @@ fn test_ptrace_syscall() { |
226 | 236 | let get_syscall_id = |
227 | 237 | || ptrace::getregs(child).unwrap().orig_eax as libc::c_long; |
228 | 238 |
|
| 239 | + #[cfg(target_arch = "aarch64")] |
| 240 | + let get_syscall_id = |
| 241 | + || ptrace::getregs(child).unwrap().regs[8] as libc::c_long; |
| 242 | + |
| 243 | + #[cfg(target_arch = "riscv64")] |
| 244 | + let get_syscall_id = |
| 245 | + || ptrace::getregs(child).unwrap().a7 as libc::c_long; |
| 246 | + |
229 | 247 | // this duplicates `get_syscall_id` for the purpose of testing `ptrace::read_user`. |
230 | 248 | #[cfg(target_arch = "x86_64")] |
231 | 249 | let rax_offset = offset_of!(libc::user_regs_struct, orig_rax); |
232 | 250 | #[cfg(target_arch = "x86")] |
233 | 251 | let rax_offset = offset_of!(libc::user_regs_struct, orig_eax); |
| 252 | + #[cfg(target_arch = "aarch64")] |
| 253 | + let rax_offset = offset_of!(libc::user_regs_struct, regs) |
| 254 | + + 8 * mem::size_of::<libc::c_ulonglong>(); |
| 255 | + #[cfg(target_arch = "riscv64")] |
| 256 | + let rax_offset = offset_of!(libc::user_regs_struct, a7); |
234 | 257 |
|
235 | 258 | let get_syscall_from_user_area = || { |
236 | 259 | // Find the offset of `user.regs.rax` (or `user.regs.eax` for x86) |
| 260 | + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] |
237 | 261 | let rax_offset = offset_of!(libc::user, regs) + rax_offset; |
238 | 262 | ptrace::read_user(child, rax_offset as _).unwrap() |
239 | 263 | as libc::c_long |
@@ -273,3 +297,76 @@ fn test_ptrace_syscall() { |
273 | 297 | } |
274 | 298 | } |
275 | 299 | } |
| 300 | + |
| 301 | +#[cfg(all( |
| 302 | + target_os = "linux", |
| 303 | + target_env = "gnu", |
| 304 | + any( |
| 305 | + target_arch = "x86_64", |
| 306 | + target_arch = "x86", |
| 307 | + target_arch = "aarch64", |
| 308 | + target_arch = "riscv64", |
| 309 | + ) |
| 310 | +))] |
| 311 | +#[test] |
| 312 | +fn test_ptrace_regsets() { |
| 313 | + use nix::sys::ptrace::{self, getregset, setregset, RegisterSet}; |
| 314 | + use nix::sys::signal::*; |
| 315 | + use nix::sys::wait::{waitpid, WaitStatus}; |
| 316 | + use nix::unistd::fork; |
| 317 | + use nix::unistd::ForkResult::*; |
| 318 | + |
| 319 | + require_capability!("test_ptrace_regsets", CAP_SYS_PTRACE); |
| 320 | + |
| 321 | + let _m = crate::FORK_MTX.lock(); |
| 322 | + |
| 323 | + match unsafe { fork() }.expect("Error: Fork Failed") { |
| 324 | + Child => { |
| 325 | + ptrace::traceme().unwrap(); |
| 326 | + // As recommended by ptrace(2), raise SIGTRAP to pause the child |
| 327 | + // until the parent is ready to continue |
| 328 | + loop { |
| 329 | + raise(Signal::SIGTRAP).unwrap(); |
| 330 | + } |
| 331 | + } |
| 332 | + |
| 333 | + Parent { child } => { |
| 334 | + assert_eq!( |
| 335 | + waitpid(child, None), |
| 336 | + Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)) |
| 337 | + ); |
| 338 | + let mut regstruct = |
| 339 | + getregset(child, RegisterSet::NT_PRSTATUS).unwrap(); |
| 340 | + |
| 341 | + #[cfg(target_arch = "x86_64")] |
| 342 | + let reg = &mut regstruct.r15; |
| 343 | + #[cfg(target_arch = "x86")] |
| 344 | + let reg = &mut regstruct.edx; |
| 345 | + #[cfg(target_arch = "aarch64")] |
| 346 | + let reg = &mut regstruct.regs[16]; |
| 347 | + #[cfg(target_arch = "riscv64")] |
| 348 | + let reg = &mut regstruct.regs[16]; |
| 349 | + |
| 350 | + *reg = 0xdeadbeef; |
| 351 | + let _ = setregset(child, RegisterSet::NT_PRSTATUS, regstruct); |
| 352 | + regstruct = getregset(child, RegisterSet::NT_PRSTATUS).unwrap(); |
| 353 | + |
| 354 | + #[cfg(target_arch = "x86_64")] |
| 355 | + let reg = regstruct.r15; |
| 356 | + #[cfg(target_arch = "x86")] |
| 357 | + let reg = regstruct.edx; |
| 358 | + #[cfg(target_arch = "aarch64")] |
| 359 | + let reg = regstruct.regs[16]; |
| 360 | + #[cfg(target_arch = "riscv64")] |
| 361 | + let reg = regstruct.regs[16]; |
| 362 | + assert_eq!(0xdeadbeef, reg); |
| 363 | + |
| 364 | + ptrace::cont(child, Some(Signal::SIGKILL)).unwrap(); |
| 365 | + match waitpid(child, None) { |
| 366 | + Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) |
| 367 | + if pid == child => {} |
| 368 | + _ => panic!("The process should have been killed"), |
| 369 | + } |
| 370 | + } |
| 371 | + } |
| 372 | +} |
0 commit comments