linux_libc_auxv/
parser.rs

1/*
2MIT License
3
4Copyright (c) 2025 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 crate::aux_var::{AuxVar, AuxVarRaw, AuxVarType};
25use crate::util::count_bytes_until_null;
26use core::ffi::CStr;
27use core::fmt::Debug;
28
29/// Wraps a slice of bytes representing a Linux stack layout allowing to
30/// conveniently parse its content.
31///
32/// The stack layout under Linux contains `argc`, `argv`, `envv`/`envp`, and the
33/// auxiliary vector, all with the additional referenced payloads. More
34/// precisely, the structure contains data in the following order:
35/// - `argc`: Amount of arguments
36/// - `argv`: null-terminated array of pointers into _argv data area_
37/// - `NULL pointer`
38/// - `envv`: null-terminated array of pointers into _envv data area_
39/// - `NULL pointer`
40/// - `auxv` Array of auxiliary variables (AT variables), terminated by an
41///   [`AuxVarType::Null`] entry.
42/// - `NUL[s] for padding`
43/// - `auxv data area`: Possibly payload of auxiliary variables
44/// - `argv data area`: Null-terminated C strings representing the arguments
45/// - `envv data area`: Null-terminated C strings representing the environment
46/// - `NUL[s] for padding`
47///
48/// The parsing code will determine at runtime how long the data actually is,
49/// therefore, it is recommended to pass in a slice that is long enough to
50/// hold the stack layout. For example, passing in a 1 MiB slice is perfectly
51/// fine.
52///
53/// # Safety
54/// Each function that loads data from one of the
55///
56/// ## More Info
57/// - <See <https://lwn.net/Articles/631631/>>
58#[derive(Debug)]
59pub struct StackLayoutRef<'a> {
60    // Might cover more data than the actual content of the stack layout.
61    bytes: &'a [u8],
62    argc: Option<usize>,
63}
64
65impl<'a> StackLayoutRef<'a> {
66    /// Creates a new view into the stack layout.
67    ///
68    /// The `argc` determines whether `bytes` start with the `argc` argument
69    /// (=> `None`) or if `bytes` already point to the start of `argv`.
70    #[must_use]
71    pub fn new(bytes: &'a [u8], argc: Option<usize>) -> Self {
72        assert_eq!(bytes.as_ptr().align_offset(align_of::<usize>()), 0);
73        Self { bytes, argc }
74    }
75
76    // ========== BEGIN buffer get functions ==========
77
78    /// Returns a view into the underlying buffer where the Argument Vector
79    /// (`argv`) begins. The slice ends at the end of the structure.
80    ///
81    /// This enables parsing the data until the end of that area is found.
82    fn get_slice_argv(&self) -> &'a [u8] {
83        match self.argc {
84            None => {
85                let start = size_of::<usize>();
86                // We skip the `argc` argument
87                &self.bytes[start..]
88            }
89            Some(_) => self.bytes,
90        }
91    }
92
93    /// Returns a view into the underlying buffer where the Environmental
94    /// Variable Vector (`envv`) begins. The slice ends at the end of the
95    /// structure.
96    ///
97    /// This enables parsing the data until the end of that area is found.
98    fn get_slice_envv(&self) -> &'a [u8] {
99        // envv starts after argv
100        let base_slice = self.get_slice_argv();
101
102        let start = self.argc() * size_of::<usize>() + size_of::<usize>() /* NUL */;
103        &base_slice[start..]
104    }
105
106    /// Returns a view into the underlying buffer where the Auxiliary Vector
107    /// (`auxv`) begins. The slice ends at the end of the structure.
108    ///
109    /// This enables parsing the data until the end of that area is found.
110    fn get_slice_auxv(&self) -> &'a [u8] {
111        // auxv starts after envv
112        let base_slice = self.get_slice_envv();
113
114        // We skip the terminating null ptr after the envv
115        let start = self.envc() * size_of::<usize>() + size_of::<usize>() /* NUL */;
116        &base_slice[start..]
117    }
118
119    // ========== END buffer get functions ==========
120
121    /// Returns the number of arguments.
122    #[must_use]
123    pub fn argc(&self) -> usize {
124        self.argc.unwrap_or_else(|| unsafe {
125            // the first `usize` is the `argc` argument
126            self.bytes
127                .as_ptr()
128                .cast::<usize>()
129                .as_ref()
130                .copied()
131                .unwrap()
132        })
133    }
134
135    /// Returns the number of environment variables.
136    #[must_use]
137    pub fn envc(&self) -> usize {
138        self.envv_raw_iter().count()
139    }
140
141    /// Returns the number of auxiliary vector entries.
142    #[must_use]
143    pub fn auxvc(&self) -> usize {
144        self.auxv_raw_iter().count()
145    }
146
147    /// Returns an iterator over the raw argument vector's (`argv`)
148    /// [`CStr`] pointers.
149    ///
150    /// # Safety
151    /// The pointers must point to valid memory. If dereferenced, the memory
152    /// **must** be in the address space of the application. Otherwise,
153    /// segmentation faults or UB will occur.
154    pub fn argv_raw_iter(&self) -> impl Iterator<Item = *const u8> {
155        let buffer = self.get_slice_argv();
156        unsafe { NullTermArrIter::new(buffer) }
157    }
158
159    /// Returns an iterator over the raw environment vector's (`envv`)
160    /// [`CStr`] pointers.
161    ///
162    /// # Safety
163    /// The pointers must point to valid memory. If dereferenced, the memory
164    /// **must** be in the address space of the application. Otherwise,
165    /// segmentation faults or UB will occur.
166    pub fn envv_raw_iter(&self) -> impl Iterator<Item = *const u8> {
167        let buffer = self.get_slice_envv();
168        unsafe { NullTermArrIter::new(buffer) }
169    }
170
171    /// Returns an iterator over the auxiliary variables vector's (`auxv`)
172    /// [`AuxVarRaw`] elements.
173    ///
174    /// # Safety
175    /// Any pointers must point to valid memory. If dereferenced, the memory
176    /// **must** be in the address space of the application. Otherwise,
177    /// segmentation faults or UB will occur.
178    pub fn auxv_raw_iter(&self) -> impl Iterator<Item = AuxVarRaw> {
179        AuxVarRawIter::new(self.get_slice_auxv())
180    }
181
182    /// Unsafe version of [`Self::argv_raw_iter`] that only works if all pointers
183    /// are valid. It emits high-level items of type [`CStr`].
184    ///
185    /// This is typically safe if you parse the stack layout you've got from
186    /// Linux but not if you parse some other's stack layout.
187    ///
188    /// # Safety
189    /// The pointers must point to valid memory. If dereferenced, the memory
190    /// **must** be in the address space of the application. Otherwise,
191    /// segmentation faults or UB will occur.
192    pub unsafe fn argv_iter(&self) -> impl Iterator<Item = &'a CStr> {
193        let buffer = self.get_slice_argv();
194        unsafe { CStrArrayIter::new(buffer) }
195    }
196    /// Unsafe version of [`Self::envv_raw_iter`] that only works if all pointers
197    /// are valid. It emits high-level items of type [`CStr`].
198    ///
199    /// This is typically safe if you parse the stack layout you've got from
200    /// Linux but not if you parse some other's stack layout.
201    ///
202    /// # Safety
203    /// The pointers must point to valid memory. If dereferenced, the memory
204    /// **must** be in the address space of the application. Otherwise,
205    /// segmentation faults or UB will occur.
206    pub unsafe fn envv_iter(&self) -> impl Iterator<Item = &'a CStr> {
207        let buffer = self.get_slice_envv();
208        unsafe { CStrArrayIter::new(buffer) }
209    }
210
211    /// Unsafe version of [`Self::argv_raw_iter`] that only works if all pointers
212    /// are valid. It emits high-level items of type [`AuxVar`].
213    ///
214    /// This is typically safe if you parse the stack layout you've got from
215    /// Linux but not if you parse some other's stack layout.
216    ///
217    /// # Safety
218    /// Any pointers must point to valid memory. If dereferenced, the memory
219    /// **must** be in the address space of the application. Otherwise,
220    /// segmentation faults or UB will occur.
221    pub unsafe fn auxv_iter(&self) -> impl Iterator<Item = AuxVar<'a>> {
222        unsafe { AuxVarIter::new(self.get_slice_auxv()) }
223    }
224}
225
226/// Iterator over the entries of a null-terminated array of pointers.
227///
228/// This should not be used to read the raw pointer into a [`CStr`], so that
229/// Miri can verify all our memory accesses are valid.
230#[derive(Debug)]
231struct NullTermArrIter<'a> {
232    // Buffer holds more bytes than necessary because the size of the auxv
233    // array is not known at compile time.
234    buffer: &'a [u8],
235    i: usize,
236}
237
238impl<'a> NullTermArrIter<'a> {
239    // SAFETY: If the pointers point to invalid memory, UB will occur.
240    unsafe fn new(buffer: &'a [u8]) -> Self {
241        assert_eq!(buffer.as_ptr().align_offset(align_of::<usize>()), 0);
242
243        Self { buffer, i: 0 }
244    }
245}
246
247impl Iterator for NullTermArrIter<'_> {
248    type Item = *const u8;
249
250    fn next(&mut self) -> Option<Self::Item> {
251        if self.i >= self.buffer.len() {
252            panic!("null terminated array ended prematurely");
253        }
254
255        let entry_ptr = unsafe {
256            self.buffer
257                .as_ptr()
258                .cast::<*const u8>()
259                // skip i pointers
260                .add(self.i)
261        };
262        let entry = unsafe { entry_ptr.as_ref().copied().unwrap() };
263        if entry.is_null() {
264            return None;
265        }
266
267        self.i += 1;
268        Some(entry)
269    }
270}
271
272/// Iterator over the [`CStr`]s of a null-terminated C-style array.
273///
274/// This should only be used when you know that the memory being referenced is
275/// valid. Otherwise, segmentation faults or UB occur.
276#[derive(Debug)]
277struct CStrArrayIter<'a> {
278    // Buffer holds more bytes than necessary because the size of the auxv
279    // array is not known at compile time.
280    buffer: &'a [u8],
281    i: usize,
282}
283
284impl<'a> CStrArrayIter<'a> {
285    // SAFETY: If the pointers point to invalid memory, UB will occur.
286    unsafe fn new(buffer: &'a [u8]) -> Self {
287        assert_eq!(buffer.as_ptr().align_offset(align_of::<usize>()), 0);
288
289        Self { buffer, i: 0 }
290    }
291}
292
293impl<'a> Iterator for CStrArrayIter<'a> {
294    type Item = &'a CStr;
295
296    fn next(&mut self) -> Option<Self::Item> {
297        if self.i >= self.buffer.len() {
298            panic!("null terminated array ended prematurely");
299        }
300
301        let entry_ptr = unsafe { self.buffer.as_ptr().cast::<*const u8>().add(self.i) };
302        let entry = unsafe { entry_ptr.as_ref().copied().unwrap() };
303        if entry.is_null() {
304            return None;
305        }
306
307        // Assert in range
308        {
309            let end = &raw const self.buffer[self.buffer.len() - 1];
310            assert!(entry > self.buffer.as_ptr());
311            assert!(entry <= end);
312        }
313
314        // offset of the pointer within the buffer
315        let begin_index = entry as usize - self.buffer.as_ptr() as usize;
316        let end_index_rel =
317            count_bytes_until_null(&self.buffer[begin_index..]).expect("should have NUL byte");
318        let end_index = begin_index + end_index_rel + 1 /* NUL byte */;
319        let cstr = CStr::from_bytes_with_nul(&self.buffer[begin_index..end_index]).unwrap();
320
321        self.i += 1;
322        Some(cstr)
323    }
324}
325
326/// Iterates over the `auxv` array with dynamic size until the end key is found.
327///
328/// Emits elements of type [`AuxVarRaw`].
329#[derive(Debug)]
330pub struct AuxVarRawIter<'a> {
331    // Buffer holds more bytes than necessary because the size of the auxv
332    // array is not known at compile time.
333    auxv: &'a [u8],
334    i: usize,
335}
336
337impl<'a> AuxVarRawIter<'a> {
338    const fn new(auxv: &'a [u8]) -> Self {
339        Self { auxv, i: 0 }
340    }
341}
342
343impl<'a> Iterator for AuxVarRawIter<'a> {
344    type Item = AuxVarRaw;
345
346    fn next(&mut self) -> Option<Self::Item> {
347        let entry = unsafe {
348            let entry_ptr = self.auxv.as_ptr().cast::<AuxVarRaw>().add(self.i);
349            entry_ptr.as_ref().unwrap()
350        };
351
352        if let Ok(key) = entry.key() {
353            if key == AuxVarType::Null {
354                None
355            } else {
356                self.i += 1;
357                Some(*entry)
358            }
359        } else {
360            // log error?
361            // invalid data, stop
362            None
363        }
364    }
365}
366
367/// Iterates the [`AuxVar`]s of the stack layout.
368#[derive(Debug)]
369pub struct AuxVarIter<'a> {
370    // Buffer holds more bytes than necessary because the size of the auxv
371    // array is not known at compile time.
372    auxv: &'a [u8],
373    serialized_iter: AuxVarRawIter<'a>,
374}
375
376impl<'a> AuxVarIter<'a> {
377    // SAFETY: If the pointers point to invalid memory, UB will occur.
378    const unsafe fn new(auxv: &'a [u8]) -> Self {
379        Self {
380            serialized_iter: AuxVarRawIter::new(auxv),
381            auxv,
382        }
383    }
384}
385
386impl<'a> Iterator for AuxVarIter<'a> {
387    type Item = AuxVar<'a>;
388
389    fn next(&mut self) -> Option<Self::Item> {
390        unsafe {
391            self.serialized_iter
392                .next()
393                .map(|ref x| AuxVar::from_raw(x, self.auxv))
394        }
395    }
396}
397
398#[cfg(test)]
399mod tests {
400    use crate::StackLayoutRef;
401
402    #[repr(C, align(8))]
403    struct Aligned8<T>(T);
404
405    impl<T> AsRef<T> for Aligned8<T> {
406        fn as_ref(&self) -> &T {
407            &self.0
408        }
409    }
410
411    // Extracted from a Linux application during startup.
412    #[cfg(target_arch = "x86_64")]
413    const TEST_DATA_X86_64: Aligned8<[u8; 1592]> = Aligned8([
414        4, 0, 0, 0, 0, 0, 0, 0, 190, 252, 185, 93, 255, 127, 0, 0, 237, 252, 185, 93, 255, 127, 0,
415        0, 243, 252, 185, 93, 255, 127, 0, 0, 250, 252, 185, 93, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0,
416        0, 0, 0, 253, 185, 93, 255, 127, 0, 0, 109, 253, 185, 93, 255, 127, 0, 0, 191, 253, 185,
417        93, 255, 127, 0, 0, 224, 253, 185, 93, 255, 127, 0, 0, 22, 254, 185, 93, 255, 127, 0, 0,
418        88, 254, 185, 93, 255, 127, 0, 0, 144, 254, 185, 93, 255, 127, 0, 0, 70, 0, 186, 93, 255,
419        127, 0, 0, 133, 0, 186, 93, 255, 127, 0, 0, 155, 0, 186, 93, 255, 127, 0, 0, 179, 0, 186,
420        93, 255, 127, 0, 0, 210, 0, 186, 93, 255, 127, 0, 0, 237, 0, 186, 93, 255, 127, 0, 0, 46,
421        1, 186, 93, 255, 127, 0, 0, 76, 1, 186, 93, 255, 127, 0, 0, 100, 1, 186, 93, 255, 127, 0,
422        0, 126, 1, 186, 93, 255, 127, 0, 0, 152, 1, 186, 93, 255, 127, 0, 0, 178, 1, 186, 93, 255,
423        127, 0, 0, 201, 1, 186, 93, 255, 127, 0, 0, 24, 2, 186, 93, 255, 127, 0, 0, 78, 2, 186, 93,
424        255, 127, 0, 0, 100, 2, 186, 93, 255, 127, 0, 0, 122, 2, 186, 93, 255, 127, 0, 0, 133, 2,
425        186, 93, 255, 127, 0, 0, 179, 2, 186, 93, 255, 127, 0, 0, 192, 2, 186, 93, 255, 127, 0, 0,
426        134, 15, 186, 93, 255, 127, 0, 0, 226, 15, 186, 93, 255, 127, 0, 0, 243, 15, 186, 93, 255,
427        127, 0, 0, 8, 16, 186, 93, 255, 127, 0, 0, 216, 16, 186, 93, 255, 127, 0, 0, 119, 18, 186,
428        93, 255, 127, 0, 0, 215, 18, 186, 93, 255, 127, 0, 0, 251, 18, 186, 93, 255, 127, 0, 0,
429        110, 29, 186, 93, 255, 127, 0, 0, 134, 29, 186, 93, 255, 127, 0, 0, 167, 29, 186, 93, 255,
430        127, 0, 0, 190, 29, 186, 93, 255, 127, 0, 0, 33, 31, 186, 93, 255, 127, 0, 0, 244, 33, 186,
431        93, 255, 127, 0, 0, 8, 34, 186, 93, 255, 127, 0, 0, 189, 35, 186, 93, 255, 127, 0, 0, 236,
432        35, 186, 93, 255, 127, 0, 0, 81, 36, 186, 93, 255, 127, 0, 0, 181, 36, 186, 93, 255, 127,
433        0, 0, 37, 37, 186, 93, 255, 127, 0, 0, 60, 37, 186, 93, 255, 127, 0, 0, 77, 37, 186, 93,
434        255, 127, 0, 0, 100, 37, 186, 93, 255, 127, 0, 0, 130, 37, 186, 93, 255, 127, 0, 0, 157,
435        37, 186, 93, 255, 127, 0, 0, 181, 37, 186, 93, 255, 127, 0, 0, 201, 37, 186, 93, 255, 127,
436        0, 0, 224, 37, 186, 93, 255, 127, 0, 0, 245, 37, 186, 93, 255, 127, 0, 0, 14, 38, 186, 93,
437        255, 127, 0, 0, 34, 38, 186, 93, 255, 127, 0, 0, 194, 39, 186, 93, 255, 127, 0, 0, 227, 39,
438        186, 93, 255, 127, 0, 0, 43, 40, 186, 93, 255, 127, 0, 0, 14, 41, 186, 93, 255, 127, 0, 0,
439        78, 41, 186, 93, 255, 127, 0, 0, 190, 41, 186, 93, 255, 127, 0, 0, 207, 41, 186, 93, 255,
440        127, 0, 0, 239, 41, 186, 93, 255, 127, 0, 0, 108, 49, 186, 93, 255, 127, 0, 0, 124, 49,
441        186, 93, 255, 127, 0, 0, 12, 50, 186, 93, 255, 127, 0, 0, 63, 50, 186, 93, 255, 127, 0, 0,
442        81, 50, 186, 93, 255, 127, 0, 0, 188, 50, 186, 93, 255, 127, 0, 0, 231, 50, 186, 93, 255,
443        127, 0, 0, 140, 51, 186, 93, 255, 127, 0, 0, 193, 51, 186, 93, 255, 127, 0, 0, 253, 51,
444        186, 93, 255, 127, 0, 0, 133, 52, 186, 93, 255, 127, 0, 0, 56, 53, 186, 93, 255, 127, 0, 0,
445        117, 53, 186, 93, 255, 127, 0, 0, 200, 53, 186, 93, 255, 127, 0, 0, 242, 53, 186, 93, 255,
446        127, 0, 0, 253, 53, 186, 93, 255, 127, 0, 0, 210, 56, 186, 93, 255, 127, 0, 0, 220, 56,
447        186, 93, 255, 127, 0, 0, 3, 57, 186, 93, 255, 127, 0, 0, 60, 58, 186, 93, 255, 127, 0, 0,
448        165, 58, 186, 93, 255, 127, 0, 0, 187, 58, 186, 93, 255, 127, 0, 0, 222, 58, 186, 93, 255,
449        127, 0, 0, 15, 59, 186, 93, 255, 127, 0, 0, 38, 59, 186, 93, 255, 127, 0, 0, 120, 59, 186,
450        93, 255, 127, 0, 0, 157, 59, 186, 93, 255, 127, 0, 0, 165, 59, 186, 93, 255, 127, 0, 0, 10,
451        60, 186, 93, 255, 127, 0, 0, 51, 60, 186, 93, 255, 127, 0, 0, 83, 60, 186, 93, 255, 127, 0,
452        0, 130, 60, 186, 93, 255, 127, 0, 0, 152, 60, 186, 93, 255, 127, 0, 0, 172, 60, 186, 93,
453        255, 127, 0, 0, 209, 60, 186, 93, 255, 127, 0, 0, 223, 61, 186, 93, 255, 127, 0, 0, 20, 62,
454        186, 93, 255, 127, 0, 0, 47, 62, 186, 93, 255, 127, 0, 0, 67, 62, 186, 93, 255, 127, 0, 0,
455        81, 62, 186, 93, 255, 127, 0, 0, 99, 62, 186, 93, 255, 127, 0, 0, 112, 62, 186, 93, 255,
456        127, 0, 0, 138, 62, 186, 93, 255, 127, 0, 0, 192, 62, 186, 93, 255, 127, 0, 0, 237, 64,
457        186, 93, 255, 127, 0, 0, 43, 66, 186, 93, 255, 127, 0, 0, 69, 66, 186, 93, 255, 127, 0, 0,
458        29, 76, 186, 93, 255, 127, 0, 0, 52, 76, 186, 93, 255, 127, 0, 0, 83, 76, 186, 93, 255,
459        127, 0, 0, 106, 76, 186, 93, 255, 127, 0, 0, 132, 76, 186, 93, 255, 127, 0, 0, 157, 76,
460        186, 93, 255, 127, 0, 0, 193, 76, 186, 93, 255, 127, 0, 0, 237, 76, 186, 93, 255, 127, 0,
461        0, 30, 77, 186, 93, 255, 127, 0, 0, 76, 77, 186, 93, 255, 127, 0, 0, 109, 77, 186, 93, 255,
462        127, 0, 0, 159, 77, 186, 93, 255, 127, 0, 0, 180, 77, 186, 93, 255, 127, 0, 0, 220, 77,
463        186, 93, 255, 127, 0, 0, 43, 78, 186, 93, 255, 127, 0, 0, 60, 78, 186, 93, 255, 127, 0, 0,
464        81, 78, 186, 93, 255, 127, 0, 0, 115, 78, 186, 93, 255, 127, 0, 0, 211, 78, 186, 93, 255,
465        127, 0, 0, 236, 78, 186, 93, 255, 127, 0, 0, 18, 79, 186, 93, 255, 127, 0, 0, 53, 79, 186,
466        93, 255, 127, 0, 0, 95, 79, 186, 93, 255, 127, 0, 0, 116, 79, 186, 93, 255, 127, 0, 0, 141,
467        79, 186, 93, 255, 127, 0, 0, 170, 79, 186, 93, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33,
468        0, 0, 0, 0, 0, 0, 0, 0, 208, 160, 43, 202, 127, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 48, 14, 0,
469        0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 255, 251, 235, 191, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
470        0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0,
471        0, 0, 0, 0, 0, 64, 144, 123, 202, 20, 86, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0,
472        0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 240, 160,
473        43, 202, 127, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
474        64, 25, 124, 202, 20, 86, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 232, 3, 0, 0, 0, 0, 0, 0, 12, 0,
475        0, 0, 0, 0, 0, 0, 232, 3, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0,
476        0, 14, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
477        0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 153, 240, 185, 93, 255, 127, 0, 0, 26, 0, 0, 0, 0, 0,
478        0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 201, 79, 186, 93, 255, 127, 0, 0,
479        15, 0, 0, 0, 0, 0, 0, 0, 169, 240, 185, 93, 255, 127, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 28, 0,
480        0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
481        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 120, 161, 11, 82, 13, 91, 238, 102,
482        222, 133, 171, 66, 146, 247, 165, 120, 56, 54, 95, 54, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
483        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
484    ]);
485
486    // Extracted from a Linux application during startup.
487    #[cfg(target_arch = "x86")]
488    const TEST_DATA_X86: Aligned8<[u8; 804]> = Aligned8([
489        4, 0, 0, 0, 148, 92, 235, 255, 213, 92, 235, 255, 219, 92, 235, 255, 226, 92, 235, 255, 0,
490        0, 0, 0, 232, 92, 235, 255, 85, 93, 235, 255, 167, 93, 235, 255, 200, 93, 235, 255, 254,
491        93, 235, 255, 64, 94, 235, 255, 120, 94, 235, 255, 30, 95, 235, 255, 93, 95, 235, 255, 115,
492        95, 235, 255, 139, 95, 235, 255, 170, 95, 235, 255, 197, 95, 235, 255, 6, 96, 235, 255, 36,
493        96, 235, 255, 60, 96, 235, 255, 86, 96, 235, 255, 112, 96, 235, 255, 138, 96, 235, 255,
494        161, 96, 235, 255, 240, 96, 235, 255, 38, 97, 235, 255, 60, 97, 235, 255, 82, 97, 235, 255,
495        93, 97, 235, 255, 139, 97, 235, 255, 152, 97, 235, 255, 94, 110, 235, 255, 186, 110, 235,
496        255, 203, 110, 235, 255, 224, 110, 235, 255, 176, 111, 235, 255, 55, 114, 235, 255, 151,
497        114, 235, 255, 186, 114, 235, 255, 45, 125, 235, 255, 69, 125, 235, 255, 102, 125, 235,
498        255, 125, 125, 235, 255, 224, 126, 235, 255, 179, 129, 235, 255, 199, 129, 235, 255, 124,
499        131, 235, 255, 171, 131, 235, 255, 16, 132, 235, 255, 116, 132, 235, 255, 228, 132, 235,
500        255, 251, 132, 235, 255, 12, 133, 235, 255, 35, 133, 235, 255, 65, 133, 235, 255, 92, 133,
501        235, 255, 116, 133, 235, 255, 136, 133, 235, 255, 159, 133, 235, 255, 180, 133, 235, 255,
502        205, 133, 235, 255, 225, 133, 235, 255, 176, 135, 235, 255, 209, 135, 235, 255, 25, 136,
503        235, 255, 252, 136, 235, 255, 60, 137, 235, 255, 172, 137, 235, 255, 189, 137, 235, 255,
504        221, 137, 235, 255, 90, 145, 235, 255, 106, 145, 235, 255, 250, 145, 235, 255, 45, 146,
505        235, 255, 63, 146, 235, 255, 170, 146, 235, 255, 213, 146, 235, 255, 122, 147, 235, 255,
506        175, 147, 235, 255, 235, 147, 235, 255, 115, 148, 235, 255, 38, 149, 235, 255, 99, 149,
507        235, 255, 182, 149, 235, 255, 224, 149, 235, 255, 235, 149, 235, 255, 192, 152, 235, 255,
508        202, 152, 235, 255, 241, 152, 235, 255, 42, 154, 235, 255, 147, 154, 235, 255, 169, 154,
509        235, 255, 204, 154, 235, 255, 253, 154, 235, 255, 20, 155, 235, 255, 102, 155, 235, 255,
510        139, 155, 235, 255, 147, 155, 235, 255, 248, 155, 235, 255, 33, 156, 235, 255, 65, 156,
511        235, 255, 112, 156, 235, 255, 134, 156, 235, 255, 154, 156, 235, 255, 191, 156, 235, 255,
512        205, 157, 235, 255, 2, 158, 235, 255, 29, 158, 235, 255, 49, 158, 235, 255, 63, 158, 235,
513        255, 81, 158, 235, 255, 94, 158, 235, 255, 120, 158, 235, 255, 174, 158, 235, 255, 219,
514        160, 235, 255, 25, 162, 235, 255, 51, 162, 235, 255, 11, 172, 235, 255, 34, 172, 235, 255,
515        65, 172, 235, 255, 88, 172, 235, 255, 114, 172, 235, 255, 139, 172, 235, 255, 175, 172,
516        235, 255, 219, 172, 235, 255, 12, 173, 235, 255, 58, 173, 235, 255, 91, 173, 235, 255, 141,
517        173, 235, 255, 162, 173, 235, 255, 202, 173, 235, 255, 25, 174, 235, 255, 42, 174, 235,
518        255, 63, 174, 235, 255, 97, 174, 235, 255, 193, 174, 235, 255, 218, 174, 235, 255, 0, 175,
519        235, 255, 35, 175, 235, 255, 77, 175, 235, 255, 98, 175, 235, 255, 123, 175, 235, 255, 152,
520        175, 235, 255, 0, 0, 0, 0, 32, 0, 0, 0, 176, 117, 245, 247, 33, 0, 0, 0, 0, 112, 245, 247,
521        51, 0, 0, 0, 48, 14, 0, 0, 16, 0, 0, 0, 255, 251, 235, 191, 6, 0, 0, 0, 0, 16, 0, 0, 17, 0,
522        0, 0, 100, 0, 0, 0, 3, 0, 0, 0, 52, 128, 4, 8, 4, 0, 0, 0, 32, 0, 0, 0, 5, 0, 0, 0, 8, 0,
523        0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 201, 170, 4, 8, 11, 0, 0,
524        0, 232, 3, 0, 0, 12, 0, 0, 0, 232, 3, 0, 0, 13, 0, 0, 0, 100, 0, 0, 0, 14, 0, 0, 0, 100, 0,
525        0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 219, 77, 235, 255, 26, 0, 0, 0, 2, 0, 0, 0, 31,
526        0, 0, 0, 183, 175, 235, 255, 15, 0, 0, 0, 235, 77, 235, 255, 27, 0, 0, 0, 28, 0, 0, 0, 28,
527        0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 213, 250, 168, 134, 233, 229,
528        101, 88, 100, 213, 132, 214, 57, 104, 200, 105, 54, 56, 54, 0, 0, 0, 0, 0,
529    ]);
530
531    #[test]
532    #[cfg(target_arch = "x86_64")]
533    fn test_parse_real_data() {
534        let data = TEST_DATA_X86_64.as_ref();
535        let layout = StackLayoutRef::new(data, None);
536
537        assert_eq!(layout.argc(), 4);
538
539        // argv
540        {
541            assert_eq!(
542                layout
543                    .get_slice_argv()
544                    .as_ptr()
545                    .align_offset(align_of::<usize>()),
546                0
547            );
548            assert_eq!(layout.argv_raw_iter().count(), 4);
549            // Just printing uncovers memory errors
550            layout
551                .argv_raw_iter()
552                .enumerate()
553                .for_each(|(i, ptr)| eprintln!("  arg {i:>2}: {ptr:?}"));
554        }
555
556        // envv
557        {
558            assert_eq!(
559                layout
560                    .get_slice_envv()
561                    .as_ptr()
562                    .align_offset(align_of::<usize>()),
563                0
564            );
565            assert_eq!(layout.envv_raw_iter().count(), 139);
566            // Just printing uncovers memory errors
567            layout
568                .envv_raw_iter()
569                .enumerate()
570                .for_each(|(i, ptr)| eprintln!("  env {i:>2}: {ptr:?}"));
571        }
572
573        // auxv
574        {
575            assert_eq!(
576                layout
577                    .get_slice_auxv()
578                    .as_ptr()
579                    .align_offset(align_of::<usize>()),
580                0
581            );
582            // Just printing uncovers memory errors
583            assert_eq!(layout.auxv_raw_iter().count(), 20);
584            layout
585                .auxv_raw_iter()
586                .enumerate()
587                .for_each(|(i, ptr)| eprintln!("  aux {i:>2}: {ptr:?}"));
588        }
589    }
590
591    #[test]
592    #[cfg(target_arch = "x86")]
593    fn test_parse_real_data() {
594        let data = TEST_DATA_X86.as_ref();
595        let layout = StackLayoutRef::new(data, None);
596
597        assert_eq!(layout.argc(), 4);
598
599        // argv
600        {
601            assert_eq!(
602                layout
603                    .get_slice_argv()
604                    .as_ptr()
605                    .align_offset(align_of::<usize>()),
606                0
607            );
608
609            // Just printing uncovers memory errors
610            layout
611                .argv_raw_iter()
612                .enumerate()
613                .for_each(|(i, ptr)| eprintln!("  arg {i:>2}: {ptr:?}"));
614
615            assert_eq!(layout.argv_raw_iter().count(), 4);
616        }
617
618        // envv
619        {
620            assert_eq!(
621                layout
622                    .get_slice_envv()
623                    .as_ptr()
624                    .align_offset(align_of::<usize>()),
625                0
626            );
627
628            // Just printing uncovers memory errors
629            layout
630                .envv_raw_iter()
631                .enumerate()
632                .for_each(|(i, ptr)| eprintln!("  env {i:>2}: {ptr:?}"));
633
634            assert_eq!(layout.envv_raw_iter().count(), 139);
635        }
636
637        // auxv
638        {
639            assert_eq!(
640                layout
641                    .get_slice_auxv()
642                    .as_ptr()
643                    .align_offset(align_of::<usize>()),
644                0
645            );
646
647            // Just printing uncovers memory errors
648            layout
649                .auxv_raw_iter()
650                .enumerate()
651                .for_each(|(i, ptr)| eprintln!("  aux {i:>2}: {ptr:?}"));
652            assert_eq!(layout.auxv_raw_iter().count(), 21);
653        }
654    }
655}