mirror of
https://github.com/facebookexperimental/reverie.git
synced 2025-01-22 21:04:53 +00:00
Get tests building under aarch64
Reviewed By: VladimirMakaev Differential Revision: D40701839 fbshipit-source-id: e60053c7d21696e7f7dd120420b896dee3d65ba7
This commit is contained in:
parent
21f7f9a8a6
commit
ada1e3c542
14 changed files with 186 additions and 234 deletions
|
@ -196,13 +196,22 @@ impl Tool for ChunkyPrintLocal {
|
|||
let _ = guest.send_rpc(Msg::Tick).await;
|
||||
match call {
|
||||
// Here we make some attempt to catch redirections:
|
||||
// FIXME: De-dup the dup
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
Syscall::Dup2(d) => {
|
||||
let newfd = d.newfd();
|
||||
if newfd == 1 {
|
||||
self.stdout_disconnected.store(true, Ordering::SeqCst);
|
||||
match d.newfd() {
|
||||
1 => self.stdout_disconnected.store(true, Ordering::SeqCst),
|
||||
2 => self.stderr_disconnected.store(true, Ordering::SeqCst),
|
||||
_ => {}
|
||||
}
|
||||
if newfd == 2 {
|
||||
self.stderr_disconnected.store(true, Ordering::SeqCst);
|
||||
|
||||
guest.tail_inject(call).await
|
||||
}
|
||||
Syscall::Dup3(d) => {
|
||||
match d.newfd() {
|
||||
1 => self.stdout_disconnected.store(true, Ordering::SeqCst),
|
||||
2 => self.stderr_disconnected.store(true, Ordering::SeqCst),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
guest.tail_inject(call).await
|
||||
|
|
|
@ -56,21 +56,10 @@ impl Tool for PedigreeLocal {
|
|||
syscall: Syscall,
|
||||
) -> Result<i64, Error> {
|
||||
match syscall {
|
||||
Syscall::Fork(_) | Syscall::Vfork(_) | Syscall::Clone(_) => {
|
||||
let retval = guest.inject(syscall).await?;
|
||||
let pedigree = guest.thread_state_mut().0.fork_mut();
|
||||
trace!(
|
||||
"got new pedigree: {:?} => {:x?}",
|
||||
pedigree,
|
||||
nix::unistd::Pid::try_from(&pedigree)
|
||||
);
|
||||
Ok(retval)
|
||||
}
|
||||
Syscall::Getpid(_)
|
||||
| Syscall::Getppid(_)
|
||||
| Syscall::Gettid(_)
|
||||
| Syscall::Getpgid(_)
|
||||
| Syscall::Getpgrp(_) => {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
Syscall::Fork(_) | Syscall::Vfork(_) => self.handle_fork(syscall, guest).await,
|
||||
Syscall::Clone(_) => self.handle_fork(syscall, guest).await,
|
||||
Syscall::Getpid(_) | Syscall::Getppid(_) | Syscall::Gettid(_) | Syscall::Getpgid(_) => {
|
||||
let pid = guest.inject(syscall).await?;
|
||||
let vpid = nix::unistd::Pid::try_from(&self.0).unwrap();
|
||||
trace!("getpid returned {:?} vpid: {:?}", pid, vpid);
|
||||
|
@ -84,6 +73,23 @@ impl Tool for PedigreeLocal {
|
|||
}
|
||||
}
|
||||
|
||||
impl PedigreeLocal {
|
||||
async fn handle_fork(
|
||||
&self,
|
||||
syscall: Syscall,
|
||||
guest: &mut impl Guest<Self>,
|
||||
) -> Result<i64, Error> {
|
||||
let retval = guest.inject(syscall).await?;
|
||||
let pedigree = guest.thread_state_mut().0.fork_mut();
|
||||
trace!(
|
||||
"got new pedigree: {:?} => {:x?}",
|
||||
pedigree,
|
||||
nix::unistd::Pid::try_from(&pedigree)
|
||||
);
|
||||
Ok(retval)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
let args = CommonToolArguments::from_args();
|
||||
|
|
|
@ -61,39 +61,43 @@ impl From<WriteFamily> for Syscall {
|
|||
/// Represents the stat family of syscalls. All of these have an associated stat
|
||||
/// buffer.
|
||||
// Stat not available in aarch64
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
#[derive(From, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum StatFamily {
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
Stat(super::Stat),
|
||||
Fstat(super::Fstat),
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
Lstat(super::Lstat),
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
Newfstatat(super::Newfstatat),
|
||||
}
|
||||
|
||||
// Stat not available in aarch64
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
impl StatFamily {
|
||||
/// Get address of the stat buffer. Returns `None` if a NULL pointer was
|
||||
/// specified.
|
||||
pub fn stat(&self) -> Option<StatPtr> {
|
||||
match self {
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
Self::Stat(s) => s.stat(),
|
||||
Self::Fstat(s) => s.stat(),
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
Self::Lstat(s) => s.stat(),
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
Self::Newfstatat(s) => s.stat(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stat not available in aarch64
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
impl From<StatFamily> for Syscall {
|
||||
fn from(family: StatFamily) -> Syscall {
|
||||
match family {
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
StatFamily::Stat(syscall) => Syscall::Stat(syscall),
|
||||
StatFamily::Fstat(syscall) => Syscall::Fstat(syscall),
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
StatFamily::Lstat(syscall) => Syscall::Lstat(syscall),
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
StatFamily::Newfstatat(syscall) => Syscall::Newfstatat(syscall),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,6 @@ syscall_list! {
|
|||
close => Close,
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
stat => Stat,
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
fstat => Fstat,
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
lstat => Lstat,
|
||||
|
@ -392,6 +391,7 @@ syscall_list! {
|
|||
fchownat => Fchownat,
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
futimesat => Futimesat,
|
||||
// TODO: Rename this to Fstatat.
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
newfstatat => Newfstatat,
|
||||
unlinkat => Unlinkat,
|
||||
|
@ -573,8 +573,6 @@ typed_syscall! {
|
|||
}
|
||||
}
|
||||
|
||||
// Fstat not available in aarch64
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
typed_syscall! {
|
||||
pub struct Fstat {
|
||||
fd: i32,
|
||||
|
@ -2671,7 +2669,8 @@ typed_syscall! {
|
|||
flags: AtFlags,
|
||||
}
|
||||
}
|
||||
// Stat not available in aarch64
|
||||
|
||||
// Newfstatat not available in aarch64
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
impl From<Stat> for Newfstatat {
|
||||
fn from(stat: Stat) -> Self {
|
||||
|
@ -2704,6 +2703,7 @@ typed_syscall! {
|
|||
flags: AtFlags,
|
||||
}
|
||||
}
|
||||
|
||||
// Unlink not available in aarch64
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
impl From<Unlink> for Unlinkat {
|
||||
|
|
|
@ -226,8 +226,8 @@ fn i_should_segfault() {
|
|||
use reverie_ptrace::testing::test_fn;
|
||||
let (output, _) = test_fn::<NoopTool, _>(|| {
|
||||
unsafe {
|
||||
let invalid_pointer = 0x5u64 as *mut u64;
|
||||
std::ptr::write(invalid_pointer, 0xdeadbeefu64);
|
||||
let invalid_ptr = 0x5u64 as *mut u64;
|
||||
invalid_ptr.write(0xdeadbeefu64);
|
||||
};
|
||||
})
|
||||
.unwrap();
|
||||
|
@ -240,26 +240,15 @@ fn i_should_segfault_2() {
|
|||
use nix::sys::signal::Signal::SIGSEGV;
|
||||
use reverie_ptrace::testing::test_fn;
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(feature = "llvm_asm"))]
|
||||
unsafe fn do_segfault() {
|
||||
let null_ptr: *const usize = core::ptr::null();
|
||||
core::arch::asm!(
|
||||
"jmp {0}",
|
||||
in(reg) null_ptr,
|
||||
)
|
||||
pub fn do_segfault() {
|
||||
let invalid_ptr = 0x1234 as *const usize;
|
||||
let result = unsafe { invalid_ptr.read() };
|
||||
// Print so the above doesn't get optimized out. We will never get here
|
||||
// because the above segfaults.
|
||||
println!("{}", result);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "llvm_asm")]
|
||||
#[allow(deprecated)]
|
||||
unsafe fn do_segfault() {
|
||||
llvm_asm!(r#"mov $$0, %rax
|
||||
jmpq *%rax
|
||||
"#:::"rax")
|
||||
}
|
||||
|
||||
let (output, _) = test_fn::<NoopTool, _>(|| unsafe { do_segfault() }).unwrap();
|
||||
let (output, _) = test_fn::<NoopTool, _>(|| do_segfault()).unwrap();
|
||||
assert_eq!(output.status, ExitStatus::Signaled(SIGSEGV, true),);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ use std::sync::atomic::AtomicBool;
|
|||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use raw_cpuid::cpuid;
|
||||
use reverie::syscalls::Syscall;
|
||||
use reverie::CpuIdResult;
|
||||
use reverie::Errno;
|
||||
|
@ -27,8 +26,6 @@ use reverie::GlobalRPC;
|
|||
use reverie::GlobalTool;
|
||||
use reverie::Guest;
|
||||
use reverie::Pid;
|
||||
use reverie::Rdtsc;
|
||||
use reverie::RdtscResult;
|
||||
use reverie::Signal;
|
||||
use reverie::Tid;
|
||||
use reverie::TimerSchedule;
|
||||
|
@ -124,6 +121,7 @@ impl Tool for LocalState {
|
|||
guest.tail_inject(syscall).await
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
async fn handle_cpuid_event<T: Guest<Self>>(
|
||||
&self,
|
||||
guest: &mut T,
|
||||
|
@ -131,16 +129,17 @@ impl Tool for LocalState {
|
|||
ecx: u32,
|
||||
) -> Result<CpuIdResult, Errno> {
|
||||
guest.send_rpc(IncrMsg::Increment).await;
|
||||
Ok(cpuid!(eax, ecx))
|
||||
Ok(raw_cpuid::cpuid!(eax, ecx))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
async fn handle_rdtsc_event<T: Guest<Self>>(
|
||||
&self,
|
||||
guest: &mut T,
|
||||
request: Rdtsc,
|
||||
) -> Result<RdtscResult, Errno> {
|
||||
request: reverie::Rdtsc,
|
||||
) -> Result<reverie::RdtscResult, Errno> {
|
||||
guest.send_rpc(IncrMsg::Increment).await;
|
||||
Ok(RdtscResult::new(request))
|
||||
Ok(reverie::RdtscResult::new(request))
|
||||
}
|
||||
|
||||
async fn handle_signal_event<T: Guest<Self>>(
|
||||
|
@ -179,13 +178,6 @@ impl Tool for LocalState {
|
|||
}
|
||||
}
|
||||
|
||||
/// Inform the Tool to begin counting events via a specific syscall
|
||||
fn do_marker_syscall() {
|
||||
unsafe {
|
||||
libc::clock_getres(libc::CLOCK_MONOTONIC, std::ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(sanitized), test))]
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
@ -196,6 +188,13 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
|
||||
/// Inform the Tool to begin counting events via a specific syscall
|
||||
fn do_marker_syscall() {
|
||||
unsafe {
|
||||
libc::clock_getres(libc::CLOCK_MONOTONIC, std::ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guest_busywait_no_timer() {
|
||||
let start = Instant::now();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* 748: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
|
||||
* 74f: 00
|
||||
*/
|
||||
#if defined(__x86_64__)
|
||||
__attribute__((noinline)) static int sys_getpid(void) {
|
||||
int ret;
|
||||
asm volatile(
|
||||
|
@ -29,6 +30,14 @@ __attribute__((noinline)) static int sys_getpid(void) {
|
|||
: "=r"(ret));
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
__attribute__((noinline)) static int sys_getpid(void) {
|
||||
register long x8 __asm__("x8") = 172;
|
||||
register long x0 __asm__("x0");
|
||||
asm volatile("svc 0" : "=r"(x0) : "r"(x8) : "memory", "cc");
|
||||
return (int)x0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int pid0 = getpid();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
*/
|
||||
|
||||
#![cfg_attr(feature = "llvm_asm", feature(llvm_asm))]
|
||||
// FIXME: This test does some very x86_64-specific things.
|
||||
#![cfg(target_arch = "x86_64")]
|
||||
|
||||
// when we convert syscall, such as open -> openat, the old syscall
|
||||
// args should not be clobbered, even with the conversion.
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
//! Tests cpuid interception
|
||||
|
||||
// cpuid interception is only available on x86_64
|
||||
#![cfg(target_arch = "x86_64")]
|
||||
|
||||
use raw_cpuid::CpuIdResult;
|
||||
use reverie::Errno;
|
||||
use reverie::GlobalTool;
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// rdtsc interception is only available on x86_64
|
||||
#![cfg(target_arch = "x86_64")]
|
||||
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ impl Tool for LocalState {
|
|||
let exit_failure = ExitGroup::new().with_status(1);
|
||||
match syscall {
|
||||
// glibc should wrap signalfd -> signalfd4(2).
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
Syscall::Signalfd(_) => guest.tail_inject(exit_failure).await,
|
||||
Syscall::Signalfd4(_) => {
|
||||
let (_, args) = syscall.into_parts();
|
||||
|
|
|
@ -8,11 +8,6 @@
|
|||
|
||||
// reinject stat* as fstatat unittest
|
||||
|
||||
use reverie::syscalls;
|
||||
use reverie::syscalls::Displayable;
|
||||
use reverie::syscalls::Syscall;
|
||||
use reverie::Error;
|
||||
use reverie::Guest;
|
||||
use reverie::Tool;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
@ -20,31 +15,8 @@ use serde::Serialize;
|
|||
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
|
||||
struct LocalState;
|
||||
|
||||
async fn handle_newfstatat<T: Guest<LocalState>>(
|
||||
guest: &mut T,
|
||||
call: syscalls::Newfstatat,
|
||||
) -> Result<i64, Error> {
|
||||
let res = guest.inject(call).await;
|
||||
|
||||
println!("{} = {:?}", call.display(&guest.memory()), res);
|
||||
|
||||
Ok(res?)
|
||||
}
|
||||
|
||||
#[reverie::tool]
|
||||
impl Tool for LocalState {
|
||||
async fn handle_syscall_event<T: Guest<Self>>(
|
||||
&self,
|
||||
guest: &mut T,
|
||||
syscall: Syscall,
|
||||
) -> Result<i64, Error> {
|
||||
match syscall {
|
||||
Syscall::Stat(stat) => handle_newfstatat(guest, stat.into()).await,
|
||||
Syscall::Lstat(lstat) => handle_newfstatat(guest, lstat.into()).await,
|
||||
_ => guest.tail_inject(syscall).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Tool for LocalState {}
|
||||
|
||||
#[cfg(all(not(sanitized), test))]
|
||||
mod tests {
|
||||
|
@ -79,7 +51,7 @@ mod tests {
|
|||
// glibc doesn't provide wrapper for statx
|
||||
unsafe fn statx(
|
||||
dirfd: i32,
|
||||
path: *const i8,
|
||||
path: *const libc::c_char,
|
||||
flags: i32,
|
||||
mask: u32,
|
||||
statxbuf: *mut libc::statx,
|
||||
|
|
|
@ -11,10 +11,6 @@
|
|||
//! Syscalls are abused to communicate from the guest to the tool instructions
|
||||
//! necessary to carry out the test, such as setting timers or reading clocks.
|
||||
|
||||
#![cfg_attr(feature = "llvm_asm", feature(llvm_asm))]
|
||||
use core::arch::x86_64::__cpuid;
|
||||
use core::arch::x86_64::__rdtscp;
|
||||
use core::arch::x86_64::_rdtsc;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
@ -202,126 +198,8 @@ async fn raise_sigwinch<T: Guest<LocalState>>(guest: &mut T) -> Tgkill {
|
|||
.with_sig(libc::SIGWINCH)
|
||||
}
|
||||
|
||||
// FIXME: Use the syscalls crate for doing this when it switches to using the
|
||||
// `asm!()` macro instead of asm inside of a C file.
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
#[cfg(not(feature = "llvm_asm"))]
|
||||
unsafe fn syscall_no_branches(no: libc::c_long, arg1: libc::c_long) {
|
||||
let mut _ret: u64;
|
||||
core::arch::asm!(
|
||||
"syscall",
|
||||
lateout("rax") _ret,
|
||||
in("rax") no,
|
||||
in("rdi") arg1,
|
||||
out("rcx") _, // rcx is used to store old rip
|
||||
out("r11") _, // r11 is used to store old rflags
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
#[cfg(feature = "llvm_asm")]
|
||||
#[allow(deprecated)]
|
||||
unsafe fn syscall_no_branches(no: libc::c_long, arg1: libc::c_long) {
|
||||
llvm_asm!("
|
||||
mov $0, %rax
|
||||
mov $1, %rdi
|
||||
xor %rsi, %rsi
|
||||
xor %rdx, %rdx
|
||||
xor %r10, %r10
|
||||
xor %r8, %r8
|
||||
xor %r9, %r9
|
||||
syscall
|
||||
"
|
||||
: /* no output */
|
||||
: "r"(no), "r"(arg1)
|
||||
: "cc", "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9", /* from syscall: */ "rcx", "r11"
|
||||
);
|
||||
}
|
||||
|
||||
fn sched_precise() {
|
||||
unsafe { syscall_no_branches(libc::SYS_clock_getres, 0) }
|
||||
}
|
||||
|
||||
fn sched_precise_alternate_rcb_count() {
|
||||
unsafe { syscall_no_branches(libc::SYS_msgrcv, 0) }
|
||||
}
|
||||
|
||||
fn sched_imprecise() {
|
||||
unsafe { syscall_no_branches(libc::SYS_timer_getoverrun, 0) }
|
||||
}
|
||||
|
||||
fn mark_clock() {
|
||||
unsafe { syscall_no_branches(libc::SYS_clock_settime, 0) }
|
||||
}
|
||||
|
||||
fn assert_clock(delta: u64) {
|
||||
unsafe { syscall_no_branches(libc::SYS_clock_adjtime, delta as i64) }
|
||||
}
|
||||
|
||||
fn assert_clock_at_next_timer(value: u64) {
|
||||
unsafe { syscall_no_branches(libc::SYS_timer_gettime, value as i64) }
|
||||
}
|
||||
|
||||
fn do_syscall() {
|
||||
unsafe { syscall_no_branches(libc::SYS_clock_gettime, 0) }
|
||||
}
|
||||
|
||||
fn immediate_exit() {
|
||||
unsafe { syscall_no_branches(libc::SYS_exit, 0) }
|
||||
}
|
||||
|
||||
fn sched_precise_and_raise() {
|
||||
unsafe { syscall_no_branches(libc::SYS_fanotify_init, 0) }
|
||||
}
|
||||
|
||||
fn sched_imprecise_and_raise() {
|
||||
unsafe { syscall_no_branches(libc::SYS_fanotify_mark, 0) }
|
||||
}
|
||||
|
||||
fn sched_precise_and_inject() {
|
||||
unsafe { syscall_no_branches(libc::SYS_msgctl, 0) }
|
||||
}
|
||||
|
||||
fn sched_imprecise_and_inject() {
|
||||
unsafe { syscall_no_branches(libc::SYS_msgget, 0) }
|
||||
}
|
||||
|
||||
fn cpuid() {
|
||||
unsafe {
|
||||
__cpuid(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn rdtsc() {
|
||||
unsafe {
|
||||
_rdtsc();
|
||||
}
|
||||
}
|
||||
|
||||
fn rdtscp() {
|
||||
unsafe {
|
||||
let mut x = 0u32;
|
||||
__rdtscp(&mut x as *mut _);
|
||||
}
|
||||
}
|
||||
|
||||
fn ts_check_fn(rcbs: u64, f: impl FnOnce()) -> GlobalState {
|
||||
use reverie_ptrace::testing::check_fn_with_config;
|
||||
check_fn_with_config::<LocalState, _>(
|
||||
f,
|
||||
Config {
|
||||
timeout_rcbs: rcbs,
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
const MANY_RCBS: u64 = 10000; // Normal perf signaling
|
||||
const LESS_RCBS: u64 = 15; // Low enough to use artificial signaling
|
||||
|
||||
#[cfg(all(not(sanitized), test))]
|
||||
mod timer_tests {
|
||||
mod tests {
|
||||
//! These tests are highly sensitive to the number of branches executed
|
||||
//! in the guest, and this must remain consistent between opt and debug
|
||||
//! mode. If you pass non-constant values into do_branches and need them to
|
||||
|
@ -330,12 +208,103 @@ mod timer_tests {
|
|||
//! tests.
|
||||
|
||||
use reverie_ptrace::ret_without_perf;
|
||||
use reverie_ptrace::testing::check_fn;
|
||||
use reverie_ptrace::testing::check_fn_with_config;
|
||||
use reverie_ptrace::testing::do_branches;
|
||||
use test_case::test_case;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn syscall_no_branches(no: Sysno, arg1: libc::c_long) {
|
||||
syscalls::syscall!(no, arg1, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
fn sched_precise() {
|
||||
unsafe { syscall_no_branches(Sysno::clock_getres, 0) }
|
||||
}
|
||||
|
||||
fn sched_precise_alternate_rcb_count() {
|
||||
unsafe { syscall_no_branches(Sysno::msgrcv, 0) }
|
||||
}
|
||||
|
||||
fn sched_imprecise() {
|
||||
unsafe { syscall_no_branches(Sysno::timer_getoverrun, 0) }
|
||||
}
|
||||
|
||||
fn mark_clock() {
|
||||
unsafe { syscall_no_branches(Sysno::clock_settime, 0) }
|
||||
}
|
||||
|
||||
fn assert_clock(delta: u64) {
|
||||
unsafe { syscall_no_branches(Sysno::clock_adjtime, delta as i64) }
|
||||
}
|
||||
|
||||
fn assert_clock_at_next_timer(value: u64) {
|
||||
unsafe { syscall_no_branches(Sysno::timer_gettime, value as i64) }
|
||||
}
|
||||
|
||||
fn do_syscall() {
|
||||
unsafe { syscall_no_branches(Sysno::clock_gettime, 0) }
|
||||
}
|
||||
|
||||
fn immediate_exit() {
|
||||
unsafe { syscall_no_branches(Sysno::exit, 0) }
|
||||
}
|
||||
|
||||
fn sched_precise_and_raise() {
|
||||
unsafe { syscall_no_branches(Sysno::fanotify_init, 0) }
|
||||
}
|
||||
|
||||
fn sched_imprecise_and_raise() {
|
||||
unsafe { syscall_no_branches(Sysno::fanotify_mark, 0) }
|
||||
}
|
||||
|
||||
fn sched_precise_and_inject() {
|
||||
unsafe { syscall_no_branches(Sysno::msgctl, 0) }
|
||||
}
|
||||
|
||||
fn sched_imprecise_and_inject() {
|
||||
unsafe { syscall_no_branches(Sysno::msgget, 0) }
|
||||
}
|
||||
|
||||
fn cpuid() {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe {
|
||||
core::arch::x86_64::__cpuid(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn rdtsc() {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe {
|
||||
core::arch::x86_64::_rdtsc();
|
||||
}
|
||||
}
|
||||
|
||||
fn rdtscp() {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe {
|
||||
let mut x = 0u32;
|
||||
core::arch::x86_64::__rdtscp(&mut x as *mut _);
|
||||
}
|
||||
}
|
||||
|
||||
fn ts_check_fn(rcbs: u64, f: impl FnOnce()) -> GlobalState {
|
||||
use reverie_ptrace::testing::check_fn_with_config;
|
||||
check_fn_with_config::<LocalState, _>(
|
||||
f,
|
||||
Config {
|
||||
timeout_rcbs: rcbs,
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
const MANY_RCBS: u64 = 10000; // Normal perf signaling
|
||||
const LESS_RCBS: u64 = 15; // Low enough to use artificial signaling
|
||||
|
||||
#[test_case(MANY_RCBS, sched_precise)]
|
||||
#[test_case(MANY_RCBS, sched_imprecise)]
|
||||
#[test_case(LESS_RCBS, sched_precise)]
|
||||
|
@ -641,16 +610,6 @@ mod timer_tests {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(sanitized), test))]
|
||||
mod clock_tests {
|
||||
use reverie_ptrace::ret_without_perf;
|
||||
use reverie_ptrace::testing::check_fn;
|
||||
use reverie_ptrace::testing::do_branches;
|
||||
use test_case::test_case;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn clock_accuracy() {
|
||||
|
@ -722,14 +681,6 @@ mod clock_tests {
|
|||
});
|
||||
assert_eq!(gs.num_timer_evts.into_inner(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(sanitized), test))]
|
||||
mod general {
|
||||
use reverie_ptrace::ret_without_perf;
|
||||
use reverie_ptrace::testing::check_fn_with_config;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// FIXME: aarch64 doesn't have a `vfork` syscall. Instead, it uses the `clone`
|
||||
// syscall. This test should work with both methods of doing a `vfork`.
|
||||
#![cfg(target_arch = "x86_64")]
|
||||
|
||||
// signal handling related tests.
|
||||
|
||||
use reverie::syscalls::Syscall;
|
||||
|
|
Loading…
Reference in a new issue