linux_libc_auxv/aux_var/typ.rs
1/*
2MIT License
3
4Copyright (c) 2021 Philipp Schuster
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24use core::cmp::Ordering;
25use enum_iterator::IntoEnumIterator;
26
27/// All types of auxiliary variables that Linux supports for the initial stack.
28/// Also called "AT"-variables in Linux source code.
29///
30/// According to some Linux code comments, `0-17` are architecture independent
31/// The ones above and including `32` are for `x86_64`. Values above 40 are for power PC.
32///
33/// More info:
34/// * <https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/auxvec.h>
35/// * <https://elixir.bootlin.com/linux/latest/source/fs/binfmt_elf.c#L259>
36/// * <https://man7.org/linux/man-pages/man3/getauxval.3.html>
37#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoEnumIterator)]
38#[repr(usize)]
39pub enum AuxVarType {
40 // ### architecture neutral
41 /// end of vector
42 Null = 0,
43 /// entry should be ignored
44 Ignore = 1,
45 /// file descriptor of program
46 ExecFd = 2,
47 /// program headers for program
48 Phdr = 3,
49 /// size of program header entry
50 Phent = 4,
51 /// number of program headers
52 Phnum = 5,
53 /// system page size
54 Pagesz = 6,
55 /// The base address of the program interpreter (usually, the
56 /// dynamic linker).
57 Base = 7,
58 /// Flags that apply on the whole auxiliary vector. See [`crate::AuxVarFlags`].
59 Flags = 8,
60 /// entry point of program
61 Entry = 9,
62 /// program is not ELF
63 NotElf = 10,
64 /// real uid
65 Uid = 11,
66 /// effective uid
67 EUid = 12,
68 /// real gid
69 Gid = 13,
70 /// effective gid
71 EGid = 14,
72 /// string identifying CPU for optimizations
73 Platform = 15,
74 /// Arch dependent hints at CPU capabilities.
75 /// On x86_64 these are the CPUID features.
76 HwCap = 16,
77 /// frequency at which times() increments
78 Clktck = 17,
79 /// secure mode boolean
80 Secure = 23,
81 /// string identifying real platform, may differ from AtPlatform.
82 BasePlatform = 24,
83 /// address of 16 random bytes
84 Random = 25,
85 /// extension of AtHwcap
86 HwCap2 = 26,
87 /// filename of program, for example "./my_executable\0"
88 ExecFn = 31,
89
90 // ### according to Linux code: from here: x86_64
91 /// The entry point to the system call function in the vDSO.
92 /// Not present/needed on all architectures (e.g., absent on
93 /// x86-64).
94 Sysinfo = 32,
95 /// The address of a page containing the virtual Dynamic
96 /// Shared Object (vDSO) that the kernel creates in order to
97 /// provide fast implementations of certain system calls.
98 SysinfoEhdr = 33,
99
100 // ### according to Linux code: from here: PowerPC
101 L1iCacheSize = 40,
102 L1iCacheGeometry = 41,
103 L1dCacheSize = 42,
104 L1dCacheGeometry = 43,
105 L2CacheSize = 44,
106 L2CacheGeometry = 45,
107 L3CacheSize = 46,
108 L3CacheGeometry = 47,
109
110 /// Minimal stack size for signal delivery.
111 MinSigStkSz = 51,
112}
113
114impl AuxVarType {
115 pub const fn val(self) -> usize {
116 self as _
117 }
118
119 /// If this is true, the value of the key should be interpreted as pointer into
120 /// the aux vector data area. Otherwise, the value of the key is an immediate value/integer.
121 // TODO move to AuxVar?!
122 pub const fn value_in_data_area(self) -> bool {
123 // this info can be found here:
124 // https://elixir.bootlin.com/linux/latest/source/fs/binfmt_elf.c#L259
125 match self {
126 AuxVarType::Null => false,
127 AuxVarType::Ignore => false,
128 AuxVarType::ExecFd => false,
129 AuxVarType::Phdr => false,
130 AuxVarType::Phent => false,
131 AuxVarType::Phnum => false,
132 AuxVarType::Pagesz => false,
133 AuxVarType::Base => false,
134 AuxVarType::Flags => false,
135 AuxVarType::Entry => false,
136 AuxVarType::NotElf => false,
137 AuxVarType::Uid => false,
138 AuxVarType::EUid => false,
139 AuxVarType::Gid => false,
140 AuxVarType::EGid => false,
141 // references C-str
142 AuxVarType::Platform => true,
143 AuxVarType::HwCap => false,
144 AuxVarType::Clktck => false,
145 AuxVarType::Secure => false,
146 // references C-str
147 AuxVarType::BasePlatform => true,
148 // references random bytes
149 AuxVarType::Random => true,
150 AuxVarType::HwCap2 => false,
151 // references C-str
152 AuxVarType::ExecFn => true,
153 AuxVarType::SysinfoEhdr => false,
154 AuxVarType::Sysinfo => false,
155 AuxVarType::L1iCacheSize => false,
156 AuxVarType::L1iCacheGeometry => false,
157 AuxVarType::L1dCacheSize => false,
158 AuxVarType::L1dCacheGeometry => false,
159 AuxVarType::L2CacheSize => false,
160 AuxVarType::L2CacheGeometry => false,
161 AuxVarType::L3CacheSize => false,
162 AuxVarType::L3CacheGeometry => false,
163 AuxVarType::MinSigStkSz => false,
164 }
165 }
166
167 /// Most of the auxiliary vector entries where [`Self::value_is_cstr`] is true,
168 /// represent a null-terminated C-string.
169 pub fn value_is_cstr(self) -> bool {
170 self.value_in_data_area()
171 && [Self::Platform, Self::BasePlatform, Self::ExecFn].contains(&self)
172 }
173
174 /// The payload of some [`AuxVarType`] is stored in the aux var data area. Some of these
175 /// data is null-terminated. Some has a fixed size. This helps to find out if there
176 /// is a fixed size.
177 pub const fn data_area_val_size_hint(self) -> Option<usize> {
178 match self {
179 AuxVarType::Random => Some(16),
180 _ => None,
181 }
182 }
183}
184
185impl From<usize> for AuxVarType {
186 fn from(val: usize) -> Self {
187 for variant in Self::into_enum_iter() {
188 if variant.val() == val {
189 return variant;
190 }
191 }
192 panic!("invalid variant {}", val);
193 }
194}
195
196impl PartialOrd for AuxVarType {
197 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
198 if matches!(self, Self::Null) && !matches!(other, Self::Null) {
199 Some(Ordering::Greater)
200 } else {
201 self.val().partial_cmp(&other.val())
202 }
203 }
204}
205
206impl Ord for AuxVarType {
207 fn cmp(&self, other: &Self) -> Ordering {
208 self.partial_cmp(other).unwrap()
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215 use std::collections::BTreeSet;
216
217 /// Tests that the ATNull entry always comes last in an ordered collection. This enables
218 /// us to easily write all AT-VARs at once but keep the terminating null entry at the end.
219 #[test]
220 fn test_aux_var_key_order() {
221 let mut set = BTreeSet::new();
222 set.insert(AuxVarType::ExecFn);
223 set.insert(AuxVarType::Platform);
224 set.insert(AuxVarType::Null);
225 set.insert(AuxVarType::Clktck);
226 set.insert(AuxVarType::ExecFn);
227 assert_eq!(set.into_iter().last().unwrap(), AuxVarType::Null);
228 }
229}