summaryrefslogtreecommitdiffstats
path: root/src/tools/rustfmt/tests/source/cfg_if/detect/os/freebsd/auxvec.rs
blob: a2bac7676014d94a92f2284858e75ac4db8bd834 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! 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);
}