blob: 9f8d7f397035a8d85b46d3ac306a060e4fdd23ae [file] [log] [blame]
//! Reads /proc/self/auxv on Linux systems
use std::prelude::v1::*;
use std::slice;
use std::mem;
/// Simple abstraction for the ELF Auxiliary Vector
///
/// the elf.h provide the layout of the single entry as auxv_t.
/// The desugared version is a usize tag followed by a union with
/// the same storage size.
///
/// Cache only the HWCAP and HWCAP2 entries.
#[derive(Debug)]
pub struct AuxVec {
hwcap: Option<usize>,
hwcap2: Option<usize>,
}
#[derive(Clone, Debug, PartialEq)]
#[allow(dead_code)]
/// ELF Auxiliary vector entry types
///
/// The entry types are specified in [linux/auxvec.h][auxvec_h].
///
/// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h
pub enum AT {
/// CPU Hardware capabilities, it is a bitfield.
HWCAP = 16,
/// CPU Hardware capabilities, additional bitfield.
HWCAP2 = 26,
}
impl AuxVec {
/// Reads the ELF Auxiliary Vector
///
/// Try to read `/proc/self/auxv`.
// TODO: Make use of getauxval once it is available in a
// reliable way.
pub fn new() -> Result<Self, ::std::io::Error> {
use std::io::Read;
let mut file = ::std::fs::File::open("/proc/self/auxv")?;
let mut buf = [0usize; 64];
let mut raw = unsafe {
slice::from_raw_parts_mut(
buf.as_mut_ptr() as *mut u8,
buf.len() * mem::size_of::<usize>(),
)
};
let _ = file.read(&mut raw)?;
mem::forget(raw);
let mut auxv = AuxVec {
hwcap: None,
hwcap2: None,
};
for el in buf.chunks(2) {
if el[0] == AT::HWCAP as usize {
auxv.hwcap = Some(el[1]);
}
if el[0] == AT::HWCAP2 as usize {
auxv.hwcap2 = Some(el[1]);
}
}
Ok(auxv)
}
/// Returns the value for the AT key
pub fn lookup(&self, key: AT) -> Option<usize> {
match key {
AT::HWCAP => self.hwcap,
AT::HWCAP2 => self.hwcap2,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_os = "linux")]
#[test]
fn test_auxvec_linux() {
let auxvec = AuxVec::new().unwrap();
println!("{:?}", auxvec.lookup(AT::HWCAP));
println!("{:?}", auxvec);
}
}