95 lines
2.7 KiB
Rust
95 lines
2.7 KiB
Rust
|
//! Parses ELF auxiliary vectors.
|
||
|
#![cfg_attr(any(target_arch = "arm", target_arch = "powerpc64"), 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 crate::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);
|
||
|
}
|