|
| 1 | +//! Parses ELF auxiliary vectors. |
| 2 | +#![cfg_attr(any(target_arch = "arm", target_arch = "powerpc64"), allow(dead_code))] |
| 3 | + |
| 4 | +/// Key to access the CPU Hardware capabilities bitfield. |
| 5 | +pub(crate) const AT_HWCAP: usize = 25; |
| 6 | +/// Key to access the CPU Hardware capabilities 2 bitfield. |
| 7 | +pub(crate) const AT_HWCAP2: usize = 26; |
| 8 | + |
| 9 | +/// Cache HWCAP bitfields of the ELF Auxiliary Vector. |
| 10 | +/// |
| 11 | +/// If an entry cannot be read all the bits in the bitfield are set to zero. |
| 12 | +/// This should be interpreted as all the features being disabled. |
| 13 | +#[derive(Debug, Copy, Clone)] |
| 14 | +pub(crate) struct AuxVec { |
| 15 | + pub hwcap: usize, |
| 16 | + pub hwcap2: usize, |
| 17 | +} |
| 18 | + |
| 19 | +/// ELF Auxiliary Vector |
| 20 | +/// |
| 21 | +/// The auxiliary vector is a memory region in a running ELF program's stack |
| 22 | +/// composed of (key: usize, value: usize) pairs. |
| 23 | +/// |
| 24 | +/// The keys used in the aux vector are platform dependent. For FreeBSD, they are |
| 25 | +/// defined in [sys/elf_common.h][elf_common_h]. The hardware capabilities of a given |
| 26 | +/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys. |
| 27 | +/// |
| 28 | +/// Note that run-time feature detection is not invoked for features that can |
| 29 | +/// be detected at compile-time. |
| 30 | +/// |
| 31 | +/// [elf_common.h]: https://svnweb.freebsd.org/base/release/12.0.0/sys/sys/elf_common.h?revision=341707 |
| 32 | +pub(crate) fn auxv() -> Result<AuxVec, ()> { |
| 33 | + if let Ok(hwcap) = archauxv(AT_HWCAP) { |
| 34 | + if let Ok(hwcap2) = archauxv(AT_HWCAP2) { |
| 35 | + if hwcap != 0 && hwcap2 != 0 { |
| 36 | + return Ok(AuxVec { hwcap, hwcap2 }); |
| 37 | + } |
| 38 | + } |
| 39 | + } |
| 40 | + Err(()) |
| 41 | +} |
| 42 | + |
| 43 | +/// Tries to read the `key` from the auxiliary vector. |
| 44 | +fn archauxv(key: usize) -> Result<usize, ()> { |
| 45 | + use mem; |
| 46 | + |
| 47 | + #[derive (Copy, Clone)] |
| 48 | + #[repr(C)] |
| 49 | + pub struct Elf_Auxinfo { |
| 50 | + pub a_type: usize, |
| 51 | + pub a_un: unnamed, |
| 52 | + } |
| 53 | + #[derive (Copy, Clone)] |
| 54 | + #[repr(C)] |
| 55 | + pub union unnamed { |
| 56 | + pub a_val: libc::c_long, |
| 57 | + pub a_ptr: *mut libc::c_void, |
| 58 | + pub a_fcn: Option<unsafe extern "C" fn() -> ()>, |
| 59 | + } |
| 60 | + |
| 61 | + let mut auxv: [Elf_Auxinfo; 27] = |
| 62 | + [Elf_Auxinfo{a_type: 0, a_un: unnamed{a_val: 0,},}; 27]; |
| 63 | + |
| 64 | + let mut len: libc::c_uint = mem::size_of_val(&auxv) as libc::c_uint; |
| 65 | + |
| 66 | + unsafe { |
| 67 | + let mut mib = [libc::CTL_KERN, libc::KERN_PROC, libc::KERN_PROC_AUXV, libc::getpid()]; |
| 68 | + |
| 69 | + let ret = libc::sysctl(mib.as_mut_ptr(), |
| 70 | + mib.len() as u32, |
| 71 | + &mut auxv as *mut _ as *mut _, |
| 72 | + &mut len as *mut _ as *mut _, |
| 73 | + 0 as *mut libc::c_void, |
| 74 | + 0, |
| 75 | + ); |
| 76 | + |
| 77 | + if ret != -1 { |
| 78 | + for i in 0..auxv.len() { |
| 79 | + if auxv[i].a_type == key { |
| 80 | + return Ok(auxv[i].a_un.a_val as usize); |
| 81 | + } |
| 82 | + } |
| 83 | + } |
| 84 | + } |
| 85 | + return Ok(0); |
| 86 | +} |
0 commit comments