Apple aarch64 fixes (#660)

* Apple aarch64 fixes

* added shmem provider testcase

* added method to not ignore cores, removed deprecated core_affinity api

* cleaned up set_affinity tests

* fixes

* fixes

* more aarch

* apple needs serial tests

* disable testcase for now
This commit is contained in:
Dominik Maier 2022-06-04 16:02:11 +02:00 committed by GitHub
parent e7e82af52c
commit 2e746bf439
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 244 additions and 93 deletions

View File

@ -16,7 +16,7 @@
//! let handles = core_ids.into_iter().map(|id| {
//! thread::spawn(move || {
//! // Pin this thread to a single CPU core.
//! core_affinity::set_for_current(id);
//! id.set_affinity();
//! // Do more work after this.
//! })
//! }).collect::<Vec<_>>();
@ -43,16 +43,6 @@ pub fn get_core_ids() -> Result<Vec<CoreId>, Error> {
get_core_ids_helper()
}
/// This function tries to pin the current
/// thread to the specified core.
///
/// # Arguments
///
/// * `core_id` - `ID` of the core to pin
pub fn set_for_current(core_id: CoreId) -> Result<(), Error> {
set_for_current_helper(core_id)
}
/// This represents a CPU core.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct CoreId {
@ -62,8 +52,21 @@ pub struct CoreId {
impl CoreId {
/// Set the affinity of the current process to this [`CoreId`]
///
/// Note: This will *_not_* fail if the target platform does not support core affinity.
/// (only on error cases for supported platforms)
/// If you really need to fail for unsupported platforms (like `aarch64` on `macOS`), use [`CoreId::set_affinity_forced`] instead.
///
pub fn set_affinity(&self) -> Result<(), Error> {
set_for_current(*self)
match set_for_current_helper(*self) {
Ok(_) | Err(Error::Unsupported(_, _)) => Ok(()),
Err(e) => Err(e),
}
}
/// Set the affinity of the current process to this [`CoreId`]
pub fn set_affinity_forced(&self) -> Result<(), Error> {
set_for_current_helper(*self)
}
}
@ -274,8 +277,6 @@ mod linux {
#[cfg(test)]
mod tests {
use num_cpus;
use super::*;
#[test]
@ -283,19 +284,13 @@ mod linux {
get_affinity_mask().unwrap();
}
#[test]
fn test_linux_get_core_ids() {
let set = get_core_ids().unwrap();
assert_eq!(set.len(), num_cpus::get());
}
#[test]
fn test_linux_set_for_current() {
let ids = get_core_ids().unwrap();
assert!(!ids.is_empty());
set_for_current(ids[0]).unwrap();
ids[0].set_affinity().unwrap();
// Ensure that the system pinned the current thread
// to the specified core.
@ -542,28 +537,6 @@ mod windows {
Some(n_logical_procs)
}
#[cfg(test)]
mod tests {
use num_cpus;
use super::*;
#[test]
fn test_apple_get_core_ids() {
let set = get_core_ids().unwrap();
assert_eq!(set.len(), num_cpus::get());
}
#[test]
fn test_apple_set_for_current() {
let ids = get_core_ids().unwrap();
assert!(!ids.is_empty());
set_for_current(ids[0]).unwrap();
}
}
}
// Apple Section
@ -590,8 +563,8 @@ mod apple {
use alloc::vec::Vec;
use libc::{
integer_t, kern_return_t, mach_msg_type_number_t, pthread_mach_thread_np, pthread_self,
thread_policy_flavor_t, thread_policy_t, thread_t, THREAD_AFFINITY_POLICY,
THREAD_AFFINITY_POLICY_COUNT,
thread_policy_flavor_t, thread_policy_t, thread_t, KERN_NOT_SUPPORTED, KERN_SUCCESS,
THREAD_AFFINITY_POLICY, THREAD_AFFINITY_POLICY_COUNT,
};
use num_cpus;
@ -632,9 +605,18 @@ mod apple {
);
// 0 == KERN_SUCCESS
if result == 0 {
if result == KERN_SUCCESS {
Ok(())
} else if result == KERN_NOT_SUPPORTED {
// 46 == KERN_NOT_SUPPORTED
// Seting a core affinity is not supported on aarch64 apple...
// We won't report this as an error to the user, a there's nothing they could do about it.
// Error codes, see <https://opensource.apple.com/source/xnu/xnu-792/osfmk/mach/kern_return.h>
//|| (cfg!(all(target_vendor = "apple", target_arch = "aarch64"))
// && result == KERN_NOT_SUPPORTED)
Err(Error::unsupported(
"Setting a core affinity is not supported on this platform (KERN_NOT_SUPPORTED)",
))
} else {
Err(Error::unknown(format!(
"Failed to set_for_current {:?}",
@ -643,28 +625,6 @@ mod apple {
}
}
}
#[cfg(test)]
mod tests {
use num_cpus;
use super::*;
#[test]
fn test_windows_get_core_ids() {
let set = get_core_ids().unwrap();
assert_eq!(set.len(), num_cpus::get());
}
#[test]
fn test_windows_set_for_current() {
let ids = get_core_ids().unwrap();
assert!(!ids.is_empty());
set_for_current(ids[0]).unwrap();
}
}
}
#[cfg(test)]
@ -684,11 +644,11 @@ mod tests {
}
#[test]
fn test_set_for_current() {
fn test_set_affinity() {
let ids = get_core_ids().unwrap();
assert!(!ids.is_empty());
set_for_current(ids[0]).unwrap();
ids[0].set_affinity().unwrap();
}
}

View File

@ -2745,7 +2745,7 @@ mod tests {
#[test]
#[serial]
pub fn llmp_connection() {
pub fn test_llmp_connection() {
#[allow(unused_variables)]
let shmem_provider = StdShMemProvider::new().unwrap();
let mut broker = match LlmpConnection::on_port(shmem_provider.clone(), 1337).unwrap() {

View File

@ -103,7 +103,7 @@ pub fn dump_registers<W: Write>(
writer: &mut BufWriter<W>,
ucontext: &ucontext_t,
) -> Result<(), std::io::Error> {
let mcontext = unsafe { *ucontext.uc_mcontext };
let mcontext = unsafe { &*ucontext.uc_mcontext };
for reg in 0..29_u8 {
writeln!(
writer,
@ -225,7 +225,7 @@ fn write_crash<W: Write>(
signal: Signal,
ucontext: &ucontext_t,
) -> Result<(), std::io::Error> {
let mcontext = unsafe { *ucontext.uc_mcontext };
let mcontext = unsafe { &*ucontext.uc_mcontext };
writeln!(
writer,
"Received signal {} at 0x{:016x}, fault address: 0x{:016x}",

View File

@ -190,6 +190,7 @@ where
res.id = id;
Ok(res)
}
fn new_shmem(&mut self, map_size: usize) -> Result<Self::ShMem, Error> {
let (server_fd, client_fd) = self.send_receive(ServedShMemRequest::NewMap(map_size))?;
@ -718,3 +719,25 @@ where
}
}
}
/*
TODO: Fix test
#[cfg(test)]
mod tests {
use serial_test::serial;
use crate::bolts::{
os::unix_shmem_server::ServedShMemProvider,
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
};
#[test]
#[serial]
fn test_shmem_server_connection() {
let mut sp = ServedShMemProvider::<UnixShMemProvider>::new().unwrap();
let map = sp.new_shmem(2 << 14).unwrap();
assert!(map.is_empty());
}
}
*/

View File

@ -67,8 +67,8 @@ pub struct mcontext_t {
pub fault_address: c_ulong,
}
/// User Context Struct
#[cfg(target_arch = "arm")]
/// User Context Struct on `arm` `linux`
#[cfg(all(target_os = "linux", target_arch = "arm"))]
#[derive(Debug)]
#[allow(non_camel_case_types)]
#[repr(C)]
@ -85,9 +85,165 @@ pub struct ucontext_t {
pub uc_sigmask: libc::sigset_t,
}
#[cfg(not(target_arch = "arm"))]
/// # Internal representation
///
/// ```c
/// _STRUCT_ARM_EXCEPTION_STATE64
/// {
/// __uint64_t far; /* Virtual Fault Address */
/// __uint32_t esr; /* Exception syndrome */
/// __uint32_t exception; /* number of arm exception taken */
/// };
/// ```
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
#[derive(Debug)]
#[repr(C)]
pub struct arm_exception_state64 {
/// Virtual Fault Address
pub __far: u64,
/// Exception syndrome
pub __esr: u32,
/// number of arm exception taken
pub __exception: u32,
}
/// ```c
/// _STRUCT_ARM_THREAD_STATE64
/// {
/// __uint64_t __x[29]; /* General purpose registers x0-x28 */
/// __uint64_t __fp; /* Frame pointer x29 */
/// __uint64_t __lr; /* Link register x30 */
/// __uint64_t __sp; /* Stack pointer x31 */
/// __uint64_t __pc; /* Program counter */
/// __uint32_t __cpsr; /* Current program status register */
/// __uint32_t __pad; /* Same size for 32-bit or 64-bit clients */
/// };
/// ```
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
#[derive(Debug)]
#[repr(C)]
pub struct arm_thread_state64 {
/// General purpose registers x0-x28
pub __x: [u64; 29],
/// Frame pointer x29
pub __fp: u64,
/// Link register x30
pub __lr: u64,
/// Stack pointer x31
pub __sp: u64,
/// Program counter
pub __pc: u64,
/// Current program status register
pub __cpsr: u32,
/// Same size for 32-bit or 64-bit clients
pub __pad: u32,
}
/// ```c
/// _STRUCT_ARM_NEON_STATE64
/// {
/// char opaque[(32 * 16) + (2 * sizeof(__uint32_t))];
/// } __attribute__((aligned(16)));
/// ````
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
#[derive(Debug)]
#[allow(non_camel_case_types)]
#[repr(C, align(16))]
//#[repr(align(16))]
pub struct arm_neon_state64 {
/// opaque
pub opaque: [u8; (32 * 16) + (2 * mem::size_of::<u32>())],
}
/// ```c
/// _STRUCT_MCONTEXT64
/// {
/// _STRUCT_ARM_EXCEPTION_STATE64 es;
/// _STRUCT_ARM_THREAD_STATE64 ss;
/// _STRUCT_ARM_NEON_STATE64 ns;
///};
/// ```
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub struct mcontext64 {
/// _STRUCT_ARM_EXCEPTION_STATE64
pub __es: arm_exception_state64,
/// _STRUCT_ARM_THREAD_STATE64
pub __ss: arm_thread_state64,
/// _STRUCT_ARM_NEON_STATE64
pub __ns: arm_neon_state64,
}
/// ```c
/// _STRUCT_SIGALTSTACK
/// {
/// void *ss_sp; /* signal stack base */
/// __darwin_size_t ss_size; /* signal stack length */
/// int ss_flags; /* SA_DISABLE and/or SA_ONSTACK */
/// };
/// ````
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
#[derive(Debug)]
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct sigaltstack {
/// signal stack base
pub ss_sp: *mut c_void,
/// signal stack length
pub ss_size: libc::size_t,
/// SA_DISABLE and/or SA_ONSTACK
pub ss_flags: c_int,
}
/// User Context Struct on apple `aarch64`
///
/// ```c
/// _STRUCT_UCONTEXT
/// {
/// int uc_onstack;
/// __darwin_sigset_t uc_sigmask; /* signal mask used by this context */
/// _STRUCT_SIGALTSTACK uc_stack; /* stack used by this context */
/// _STRUCT_UCONTEXT *uc_link; /* pointer to resuming context */
/// __darwin_size_t uc_mcsize; /* size of the machine context passed in */
/// _STRUCT_MCONTEXT *uc_mcontext; /* pointer to machine specific context */
/// #ifdef _XOPEN_SOURCE
/// _STRUCT_MCONTEXT __mcontext_data;
/// #endif /* _XOPEN_SOURCE */
/// };
/// ```
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
#[derive(Debug)]
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct ucontext_t {
/// onstack
pub uc_onstack: c_int,
/// signal mask used by this context
pub uc_sigmask: u32,
/// stack used by this context
pub uc_stack: sigaltstack,
/// pointer to resuming context
pub uc_link: *mut c_void,
/// size of the machine context passed in
pub uc_mcsize: ssize_t,
/// pointer to machine specific context
pub uc_mcontext: *mut mcontext64,
/// The mcontext data in multiple steps.
pub mcontext_data: mcontext64,
}
pub use libc::{c_void, siginfo_t};
#[cfg(not(any(
all(target_os = "linux", target_arch = "arm"),
all(target_vendor = "apple", target_arch = "aarch64")
)))]
pub use libc::ucontext_t;
#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))]
use libc::ssize_t;
use libc::{
c_int, malloc, sigaction, sigaddset, sigaltstack, sigemptyset, stack_t, SA_NODEFER, SA_ONSTACK,
SA_SIGINFO, SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, SIGPIPE,
@ -97,17 +253,10 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
use crate::Error;
pub use libc::{c_void, siginfo_t};
extern "C" {
/// The `libc` `getcontext`
/// For some reason, it's not available on MacOS.
///
/// # Notes
///
/// Somehow, `MacOS` on `aarch64` claims this type uses a 128 bit `int`
/// (@`rustc` 1.59.0)
/// Not much we can about it, for now.
#[allow(improper_ctypes)]
fn getcontext(ucp: *mut ucontext_t) -> c_int;
}

View File

@ -12,10 +12,7 @@ use crate::bolts::{
llmp::{LLMP_FLAG_COMPRESSED, LLMP_FLAG_INITIALIZED},
};
#[cfg(feature = "std")]
use crate::bolts::{
core_affinity::set_for_current, llmp::LlmpConnection, shmem::StdShMemProvider,
staterestore::StateRestorer,
};
use crate::bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer};
use crate::{
bolts::{
llmp::{self, Flags, LlmpClient, LlmpClientDescription, Tag},
@ -825,8 +822,9 @@ where
};
if let Some(core_id) = core_id {
let core_id: CoreId = core_id;
println!("Setting core affinity to {:?}", core_id);
set_for_current(core_id)?;
core_id.set_affinity()?;
}
// We are the fuzzer respawner in a llmp client
@ -894,7 +892,8 @@ where
};
if let Some(core_id) = core_id {
set_for_current(core_id)?;
let core_id: CoreId = core_id;
core_id.set_affinity()?;
}
// If we're restarting, deserialize the old state.

View File

@ -41,7 +41,7 @@ use super::HasObservers;
/// `StdIn`: The traget reads from stdin
/// `File`: The target reads from the specified [`InputFile`]
#[derive(Debug, Clone, PartialEq, Eq)]
enum InputLocation {
pub enum InputLocation {
/// Mutate a command line argument to deliver an input
Arg {
/// The offset of the argument to mutate

View File

@ -1624,6 +1624,7 @@ pub mod child_signal_handlers {
#[cfg(test)]
mod tests {
use core::marker::PhantomData;
use serial_test::serial;
#[cfg(all(feature = "std", feature = "fork", unix))]
use crate::{
@ -1653,6 +1654,7 @@ mod tests {
}
#[test]
#[serial]
#[cfg(all(feature = "std", feature = "fork", unix))]
fn test_inprocessfork_exec() {
use crate::executors::inprocess::InChildProcessHandlers;

View File

@ -161,6 +161,8 @@ pub enum Error {
IllegalState(String, ErrorBacktrace),
/// The argument passed to this method or function is not valid
IllegalArgument(String, ErrorBacktrace),
/// The performed action is not supported on the current platform
Unsupported(String, ErrorBacktrace),
/// Shutting down, not really an error.
ShuttingDown,
/// Something else happened
@ -249,6 +251,14 @@ impl Error {
pub fn shutting_down() -> Self {
Error::ShuttingDown
}
/// This operation is not supported on the current architecture or platform
#[must_use]
pub fn unsupported<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::Unsupported(arg.into(), ErrorBacktrace::new())
}
/// Something else happened
#[must_use]
pub fn unknown<S>(arg: S) -> Self
@ -304,6 +314,14 @@ impl fmt::Display for Error {
write!(f, "Illegal argument: {0}", &s)?;
display_error_backtrace(f, b)
}
Self::Unsupported(s, b) => {
write!(
f,
"The operation is not supported on the current platform: {0}",
&s
)?;
display_error_backtrace(f, b)
}
Self::ShuttingDown => write!(f, "Shutting down!"),
Self::Unknown(s, b) => {
write!(f, "Unknown error: {0}", &s)?;