blob: 29fcc8cb0c7f543f9d48bfd599a693215e0ea7f1 [file] [log] [blame]
//! Parses ELF auxiliary vectors.
#![cfg_attr(
any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc64",
target_arch = "riscv64"
),
allow(dead_code)
)]
/// Key to access the CPU Hardware capabilities bitfield.
pub(crate) const AT_HWCAP: usize = 25;
/// Key to access the CPU Hardware capabilities 2 bitfield.
pub(crate) const AT_HWCAP2: usize = 26;
/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
///
/// If an entry cannot be read all the bits in the bitfield are set to zero.
/// This should be interpreted as all the features being disabled.
#[derive(Debug, Copy, Clone)]
pub(crate) struct AuxVec {
pub hwcap: usize,
pub hwcap2: usize,
}
/// ELF Auxiliary Vector
///
/// The auxiliary vector is a memory region in a running ELF program's stack
/// composed of (key: usize, value: usize) pairs.
///
/// The keys used in the aux vector are platform dependent. For FreeBSD, they are
/// defined in [sys/elf_common.h][elf_common_h]. The hardware capabilities of a given
/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys.
///
/// Note that run-time feature detection is not invoked for features that can
/// be detected at compile-time.
///
/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707
pub(crate) fn auxv() -> Result<AuxVec, ()> {
if let Ok(hwcap) = archauxv(AT_HWCAP) {
if let Ok(hwcap2) = archauxv(AT_HWCAP2) {
if hwcap != 0 && hwcap2 != 0 {
return Ok(AuxVec { hwcap, hwcap2 });
}
}
}
Err(())
}
/// Tries to read the `key` from the auxiliary vector.
fn archauxv(key: usize) -> Result<usize, ()> {
use core::mem;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Elf_Auxinfo {
pub a_type: usize,
pub a_un: unnamed,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub union unnamed {
pub a_val: libc::c_long,
pub a_ptr: *mut libc::c_void,
pub a_fcn: Option<unsafe extern "C" fn() -> ()>,
}
let mut auxv: [Elf_Auxinfo; 27] = [Elf_Auxinfo {
a_type: 0,
a_un: unnamed { a_val: 0 },
}; 27];
let mut len: libc::c_uint = mem::size_of_val(&auxv) as libc::c_uint;
unsafe {
let mut mib = [
libc::CTL_KERN,
libc::KERN_PROC,
libc::KERN_PROC_AUXV,
libc::getpid(),
];
let ret = libc::sysctl(
mib.as_mut_ptr(),
mib.len() as u32,
&mut auxv as *mut _ as *mut _,
&mut len as *mut _ as *mut _,
0 as *mut libc::c_void,
0,
);
if ret != -1 {
for i in 0..auxv.len() {
if auxv[i].a_type == key {
return Ok(auxv[i].a_un.a_val as usize);
}
}
}
}
return Ok(0);
}