|
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