elf/
gnu_symver.rs

1//! Parsing GNU extension sections for dynamic symbol versioning `.gnu.version.*`
2use crate::abi;
3use crate::endian::EndianParse;
4use crate::file::Class;
5use crate::parse::{ParseAt, ParseError, ParsingTable};
6use crate::string_table::StringTable;
7
8#[derive(Debug, PartialEq, Eq)]
9pub struct SymbolRequirement<'data> {
10    pub file: &'data str,
11    pub name: &'data str,
12    pub hash: u32,
13    pub flags: u16,
14    pub hidden: bool,
15}
16
17#[derive(Debug)]
18pub struct SymbolDefinition<'data, E: EndianParse> {
19    pub hash: u32,
20    pub flags: u16,
21    pub names: SymbolNamesIterator<'data, E>,
22    pub hidden: bool,
23}
24
25#[derive(Debug)]
26pub struct SymbolNamesIterator<'data, E: EndianParse> {
27    vda_iter: VerDefAuxIterator<'data, E>,
28    strtab: &'data StringTable<'data>,
29}
30
31impl<'data, E: EndianParse> SymbolNamesIterator<'data, E> {
32    pub fn new(vda_iter: VerDefAuxIterator<'data, E>, strtab: &'data StringTable<'data>) -> Self {
33        SymbolNamesIterator { vda_iter, strtab }
34    }
35}
36
37impl<'data, E: EndianParse> Iterator for SymbolNamesIterator<'data, E> {
38    type Item = Result<&'data str, ParseError>;
39    fn next(&mut self) -> Option<Self::Item> {
40        let vda = self.vda_iter.next();
41        match vda {
42            Some(vda) => Some(self.strtab.get(vda.vda_name as usize)),
43            None => None,
44        }
45    }
46}
47
48#[derive(Debug)]
49pub struct SymbolVersionTable<'data, E: EndianParse> {
50    version_ids: VersionIndexTable<'data, E>,
51
52    verneeds: Option<(VerNeedIterator<'data, E>, StringTable<'data>)>,
53    verdefs: Option<(VerDefIterator<'data, E>, StringTable<'data>)>,
54}
55
56impl<'data, E: EndianParse> SymbolVersionTable<'data, E> {
57    pub fn new(
58        version_ids: VersionIndexTable<'data, E>,
59        verneeds: Option<(VerNeedIterator<'data, E>, StringTable<'data>)>,
60        verdefs: Option<(VerDefIterator<'data, E>, StringTable<'data>)>,
61    ) -> Self {
62        SymbolVersionTable {
63            version_ids,
64            verneeds,
65            verdefs,
66        }
67    }
68
69    pub fn get_requirement(
70        &self,
71        sym_idx: usize,
72    ) -> Result<Option<SymbolRequirement<'_>>, ParseError> {
73        let (verneeds, verneed_strs) = match self.verneeds {
74            Some(verneeds) => verneeds,
75            None => {
76                return Ok(None);
77            }
78        };
79
80        let ver_ndx = self.version_ids.get(sym_idx)?;
81        let iter = verneeds;
82        for (vn, vna_iter) in iter {
83            for vna in vna_iter {
84                if vna.vna_other != ver_ndx.index() {
85                    continue;
86                }
87
88                let file = verneed_strs.get(vn.vn_file as usize)?;
89                let name = verneed_strs.get(vna.vna_name as usize)?;
90                let hash = vna.vna_hash;
91                let hidden = ver_ndx.is_hidden();
92                return Ok(Some(SymbolRequirement {
93                    file,
94                    name,
95                    hash,
96                    flags: vna.vna_flags,
97                    hidden,
98                }));
99            }
100        }
101
102        // Maybe we should treat this as a ParseError instead of returning an
103        // empty Option? This can only happen if .gnu.versions[N] contains an
104        // index that doesn't exist, which is likely a file corruption or
105        // programmer error (i.e asking for a requirement for a defined symbol)
106        Ok(None)
107    }
108
109    pub fn get_definition(
110        &self,
111        sym_idx: usize,
112    ) -> Result<Option<SymbolDefinition<'_, E>>, ParseError> {
113        let (ref verdefs, ref verdef_strs) = match self.verdefs {
114            Some(ref verdefs) => verdefs,
115            None => {
116                return Ok(None);
117            }
118        };
119
120        let ver_ndx = self.version_ids.get(sym_idx)?;
121        let iter = *verdefs;
122        for (vd, vda_iter) in iter {
123            if vd.vd_ndx != ver_ndx.index() {
124                continue;
125            }
126
127            let flags = vd.vd_flags;
128            let hash = vd.vd_hash;
129            let hidden = ver_ndx.is_hidden();
130            return Ok(Some(SymbolDefinition {
131                hash,
132                flags,
133                names: SymbolNamesIterator {
134                    vda_iter,
135                    strtab: verdef_strs,
136                },
137                hidden,
138            }));
139        }
140
141        // Maybe we should treat this as a ParseError instead of returning an
142        // empty Option? This can only happen if .gnu.versions[N] contains an
143        // index that doesn't exist, which is likely a file corruption or
144        // programmer error (i.e asking for a definition for an undefined symbol)
145        Ok(None)
146    }
147}
148
149////////////////////////////////////////////////////////////////////
150//                                                 _              //
151//       __ _ _ __  _   _      __   _____ _ __ ___(_) ___  _ __   //
152//      / _` | '_ \| | | |     \ \ / / _ \ '__/ __| |/ _ \| '_ \  //
153//  _  | (_| | | | | |_| |  _   \ V /  __/ |  \__ \ | (_) | | | | //
154// (_)  \__, |_| |_|\__,_| (_)   \_/ \___|_|  |___/_|\___/|_| |_| //
155//      |___/                                                     //
156////////////////////////////////////////////////////////////////////
157
158pub type VersionIndexTable<'data, E> = ParsingTable<'data, E, VersionIndex>;
159
160/// The special GNU extension section .gnu.version has a section type of SHT_GNU_VERSYM.
161/// This section shall have the same number of entries as the Dynamic Symbol Table in
162/// the .dynsym section. The .gnu.version section shall contain an array of
163/// elements of type Elfxx_Half (both of which are 16-bit unsigned integers).
164///
165/// The .gnu.version section and VersionIndex values act as a lookup table for specifying
166/// the version defined for or required by the corresponding symbol in the Dynamic Symbol Table.
167///
168/// For example, the symbol at index N in the .dynsym Symbol Table will have a VersionIndex
169/// value located in the versym table at .gnu.version\[N\] which identifies
170/// structures in the .gnu.version_d and .gnu.version_r sections. These values
171/// are located in identifiers provided by the the vna_other member of the VerNeedAux
172/// structure or the vd_ndx member of the VerDef structure.
173#[derive(Debug, PartialEq, Eq)]
174pub struct VersionIndex(pub u16);
175
176impl VersionIndex {
177    pub fn index(&self) -> u16 {
178        self.0 & abi::VER_NDX_VERSION
179    }
180
181    pub fn is_local(&self) -> bool {
182        self.index() == abi::VER_NDX_LOCAL
183    }
184
185    pub fn is_global(&self) -> bool {
186        self.index() == abi::VER_NDX_GLOBAL
187    }
188
189    pub fn is_hidden(&self) -> bool {
190        (self.0 & abi::VER_NDX_HIDDEN) != 0
191    }
192}
193
194impl ParseAt for VersionIndex {
195    fn parse_at<E: EndianParse>(
196        endian: E,
197        _class: Class,
198        offset: &mut usize,
199        data: &[u8],
200    ) -> Result<Self, ParseError> {
201        Ok(VersionIndex(endian.parse_u16_at(offset, data)?))
202    }
203
204    #[inline]
205    fn size_for(_class: Class) -> usize {
206        core::mem::size_of::<u16>()
207    }
208}
209
210///////////////////////////////////////////////////////////////////////////////
211//                                                 _                      _  //
212//       __ _ _ __  _   _      __   _____ _ __ ___(_) ___  _ __        __| | //
213//      / _` | '_ \| | | |     \ \ / / _ \ '__/ __| |/ _ \| '_ \      / _` | //
214//  _  | (_| | | | | |_| |  _   \ V /  __/ |  \__ \ | (_) | | | |    | (_| | //
215// (_)  \__, |_| |_|\__,_| (_)   \_/ \___|_|  |___/_|\___/|_| |_|_____\__,_| //
216//      |___/                                                   |_____|      //
217///////////////////////////////////////////////////////////////////////////////
218
219/// The special GNU extension section .gnu.version_d has a section type of SHT_GNU_VERDEF
220/// This section shall contain symbol version definitions. The number of entries
221/// in this section shall be contained in the DT_VERDEFNUM entry of the Dynamic
222/// Section .dynamic, and also the sh_info member of the section header.
223/// The sh_link member of the section header shall point to the section that
224/// contains the strings referenced by this section.
225///
226/// The .gnu.version_d section shall contain an array of VerDef structures
227/// optionally followed by an array of VerDefAux structures.
228#[derive(Debug, PartialEq, Eq)]
229pub struct VerDef {
230    /// Version information flag bitmask.
231    pub vd_flags: u16,
232    /// VersionIndex value referencing the SHT_GNU_VERSYM section.
233    pub vd_ndx: u16,
234    /// Number of associated verdaux array entries.
235    pub vd_cnt: u16,
236    /// Version name hash value (ELF hash function).
237    pub vd_hash: u32,
238    /// Offset in bytes to a corresponding entry in an array of VerDefAux structures.
239    vd_aux: u32,
240    /// Offset to the next VerDef entry, in bytes.
241    vd_next: u32,
242}
243
244impl ParseAt for VerDef {
245    fn parse_at<E: EndianParse>(
246        endian: E,
247        _class: Class,
248        offset: &mut usize,
249        data: &[u8],
250    ) -> Result<Self, ParseError> {
251        let vd_version = endian.parse_u16_at(offset, data)?;
252        if vd_version != abi::VER_DEF_CURRENT {
253            return Err(ParseError::UnsupportedVersion((
254                vd_version as u64,
255                abi::VER_DEF_CURRENT as u64,
256            )));
257        }
258
259        Ok(VerDef {
260            vd_flags: endian.parse_u16_at(offset, data)?,
261            vd_ndx: endian.parse_u16_at(offset, data)?,
262            vd_cnt: endian.parse_u16_at(offset, data)?,
263            vd_hash: endian.parse_u32_at(offset, data)?,
264            vd_aux: endian.parse_u32_at(offset, data)?,
265            vd_next: endian.parse_u32_at(offset, data)?,
266        })
267    }
268
269    #[inline]
270    fn size_for(_class: Class) -> usize {
271        ELFVERDEFSIZE
272    }
273}
274
275const ELFVERDEFSIZE: usize = 20;
276
277#[derive(Debug, Clone, Copy)]
278pub struct VerDefIterator<'data, E: EndianParse> {
279    endian: E,
280    class: Class,
281    /// The number of entries in this iterator is given by the .dynamic DT_VERDEFNUM entry
282    /// and also in the .gnu.version_d section header's sh_info field.
283    count: u64,
284    data: &'data [u8],
285    offset: usize,
286}
287
288impl<'data, E: EndianParse> VerDefIterator<'data, E> {
289    pub fn new(
290        endian: E,
291        class: Class,
292        count: u64,
293        starting_offset: usize,
294        data: &'data [u8],
295    ) -> Self {
296        VerDefIterator {
297            endian,
298            class,
299            count,
300            data,
301            offset: starting_offset,
302        }
303    }
304}
305
306impl<'data, E: EndianParse> Iterator for VerDefIterator<'data, E> {
307    type Item = (VerDef, VerDefAuxIterator<'data, E>);
308    fn next(&mut self) -> Option<Self::Item> {
309        if self.data.is_empty() || self.count == 0 {
310            return None;
311        }
312
313        let mut start = self.offset;
314        let vd = VerDef::parse_at(self.endian, self.class, &mut start, self.data).ok()?;
315        let vda_iter = VerDefAuxIterator::new(
316            self.endian,
317            self.class,
318            vd.vd_cnt,
319            self.offset + vd.vd_aux as usize,
320            self.data,
321        );
322
323        // If offset overflows, silently end iteration
324        match self.offset.checked_add(vd.vd_next as usize) {
325            Some(new_off) => self.offset = new_off,
326            None => self.count = 0,
327        }
328        self.count -= 1;
329
330        // Silently end iteration early if the next link stops pointing somewhere new
331        // TODO: Make this an error condition by allowing the iterator to yield a ParseError
332        if self.count > 0 && vd.vd_next == 0 {
333            self.count = 0
334        }
335        Some((vd, vda_iter))
336    }
337}
338
339/// Version Definition Auxiliary Entries from the .gnu.version_d section
340#[derive(Debug, PartialEq, Eq)]
341pub struct VerDefAux {
342    /// Offset to the version or dependency name string in the linked string table, in bytes.
343    pub vda_name: u32,
344    /// Offset to the next VerDefAux entry, in bytes.
345    vda_next: u32,
346}
347
348impl ParseAt for VerDefAux {
349    fn parse_at<E: EndianParse>(
350        endian: E,
351        _class: Class,
352        offset: &mut usize,
353        data: &[u8],
354    ) -> Result<Self, ParseError> {
355        Ok(VerDefAux {
356            vda_name: endian.parse_u32_at(offset, data)?,
357            vda_next: endian.parse_u32_at(offset, data)?,
358        })
359    }
360
361    #[inline]
362    fn size_for(_class: Class) -> usize {
363        8
364    }
365}
366
367#[derive(Debug)]
368pub struct VerDefAuxIterator<'data, E: EndianParse> {
369    endian: E,
370    class: Class,
371    count: u16,
372    data: &'data [u8],
373    offset: usize,
374}
375
376impl<'data, E: EndianParse> VerDefAuxIterator<'data, E> {
377    pub fn new(
378        endian: E,
379        class: Class,
380        count: u16,
381        starting_offset: usize,
382        data: &'data [u8],
383    ) -> Self {
384        VerDefAuxIterator {
385            endian,
386            class,
387            count,
388            data,
389            offset: starting_offset,
390        }
391    }
392}
393
394impl<'data, E: EndianParse> Iterator for VerDefAuxIterator<'data, E> {
395    type Item = VerDefAux;
396    fn next(&mut self) -> Option<Self::Item> {
397        if self.data.is_empty() || self.count == 0 {
398            return None;
399        }
400
401        // N.B. This offset handling is maybe unnecessary, but faithful to the
402        // spec. As far as I've observed, VerDefAux entries for a VerDef are all
403        // encoded sequentially after the VerDef, so we could likely just
404        // use the normal pattern here and pass in &mut self.offset here.
405        //
406        // The spec claims that "The section shall contain an array of
407        // Elfxx_Verdef structures, optionally followed by an array of
408        // Elfxx_Verdaux structures." This reads a bit ambiguously
409        // (is there one big array of Verdefs followed by one big array of
410        // Verdauxs?). If so, the vd_next and vda_next links seem unnecessary
411        // given the vd_cnt field. In practice, it appears that all the VerDefAux
412        // fields for a given VerDef are sequentially following the VerDef, meaning
413        // they're contiguous, but intersersed. The _next fields could theoretically
414        // give non-contiguous linked-list-like configurations, though (but only linking
415        // forward, not backward, since the link is a u32).
416        //
417        // The vd_next and vda_next fields are also not "pointers" i.e. offsets from
418        // the start of the section, but rather "increments" in telling how far to
419        // advance from where you just read the containing struct for where you should
420        // read the next. Given the sequentially-following nature described, these vd_next
421        // and vda_next fields end up being 0x14 and 0x8 (the size of the VerDef and
422        // VerDefAux structs).
423        //
424        // So observationally, we could likely get away with using self.offset and count here
425        // and ignoring the vda_next field, but that'd break things if they weren't contiguous.
426        let mut start = self.offset;
427        let vda = VerDefAux::parse_at(self.endian, self.class, &mut start, self.data).ok()?;
428
429        // If offset overflows, silently end iteration
430        match self.offset.checked_add(vda.vda_next as usize) {
431            Some(new_off) => self.offset = new_off,
432            None => self.count = 0,
433        }
434        self.count -= 1;
435
436        // Silently end iteration early if the next link stops pointing somewhere new
437        // TODO: Make this an error condition by allowing the iterator to yield a ParseError
438        if self.count > 0 && vda.vda_next == 0 {
439            self.count = 0
440        }
441        Some(vda)
442    }
443}
444
445///////////////////////////////////////////////////////////////////////////////
446//                                                 _                         //
447//       __ _ _ __  _   _      __   _____ _ __ ___(_) ___  _ __        _ __  //
448//      / _` | '_ \| | | |     \ \ / / _ \ '__/ __| |/ _ \| '_ \      | '__| //
449//  _  | (_| | | | | |_| |  _   \ V /  __/ |  \__ \ | (_) | | | |     | |    //
450// (_)  \__, |_| |_|\__,_| (_)   \_/ \___|_|  |___/_|\___/|_| |_|_____|_|    //
451//      |___/                                                   |_____|      //
452///////////////////////////////////////////////////////////////////////////////
453
454/// The GNU extension section .gnu.version_r has a section type of SHT_GNU_VERNEED.
455/// This section contains required symbol version definitions. The number of
456/// entries in this section shall be contained in the DT_VERNEEDNUM entry of the
457/// Dynamic Section .dynamic and also the sh_info member of the section header.
458/// The sh_link member of the section header shall point to the referenced
459/// string table section.
460///
461/// The section shall contain an array of VerNeed structures optionally
462/// followed by an array of VerNeedAux structures.
463#[derive(Debug, PartialEq, Eq)]
464pub struct VerNeed {
465    /// Number of associated verneed array entries.
466    pub vn_cnt: u16,
467    /// Offset to the file name string in the linked string table, in bytes.
468    pub vn_file: u32,
469    /// Offset to a corresponding entry in the VerNeedAux array, in bytes.
470    vn_aux: u32,
471    /// Offset to the next VerNeed entry, in bytes.
472    vn_next: u32,
473}
474
475impl ParseAt for VerNeed {
476    fn parse_at<E: EndianParse>(
477        endian: E,
478        _class: Class,
479        offset: &mut usize,
480        data: &[u8],
481    ) -> Result<Self, ParseError> {
482        let vd_version = endian.parse_u16_at(offset, data)?;
483        if vd_version != abi::VER_NEED_CURRENT {
484            return Err(ParseError::UnsupportedVersion((
485                vd_version as u64,
486                abi::VER_DEF_CURRENT as u64,
487            )));
488        }
489        Ok(VerNeed {
490            vn_cnt: endian.parse_u16_at(offset, data)?,
491            vn_file: endian.parse_u32_at(offset, data)?,
492            vn_aux: endian.parse_u32_at(offset, data)?,
493            vn_next: endian.parse_u32_at(offset, data)?,
494        })
495    }
496
497    #[inline]
498    fn size_for(_class: Class) -> usize {
499        ELFVERNEEDSIZE
500    }
501}
502
503const ELFVERNEEDSIZE: usize = 16;
504
505#[derive(Debug, Copy, Clone)]
506pub struct VerNeedIterator<'data, E: EndianParse> {
507    endian: E,
508    class: Class,
509    /// The number of entries in this iterator is given by the .dynamic DT_VERNEEDNUM entry
510    /// and also in the .gnu.version_r section header's sh_info field.
511    count: u64,
512    data: &'data [u8],
513    offset: usize,
514}
515
516impl<'data, E: EndianParse> VerNeedIterator<'data, E> {
517    pub fn new(
518        endian: E,
519        class: Class,
520        count: u64,
521        starting_offset: usize,
522        data: &'data [u8],
523    ) -> Self {
524        VerNeedIterator {
525            endian,
526            class,
527            count,
528            data,
529            offset: starting_offset,
530        }
531    }
532}
533
534impl<'data, E: EndianParse> Iterator for VerNeedIterator<'data, E> {
535    type Item = (VerNeed, VerNeedAuxIterator<'data, E>);
536    fn next(&mut self) -> Option<Self::Item> {
537        if self.data.is_empty() || self.count == 0 {
538            return None;
539        }
540
541        let mut start = self.offset;
542        let vn = VerNeed::parse_at(self.endian, self.class, &mut start, self.data).ok()?;
543        let vna_iter = VerNeedAuxIterator::new(
544            self.endian,
545            self.class,
546            vn.vn_cnt,
547            self.offset + vn.vn_aux as usize,
548            self.data,
549        );
550
551        // If offset overflows, silently end iteration
552        match self.offset.checked_add(vn.vn_next as usize) {
553            Some(new_off) => self.offset = new_off,
554            None => self.count = 0,
555        }
556        self.count -= 1;
557
558        // Silently end iteration early if the next link stops pointing somewhere new
559        // TODO: Make this an error condition by allowing the iterator to yield a ParseError
560        if self.count > 0 && vn.vn_next == 0 {
561            self.count = 0
562        }
563        Some((vn, vna_iter))
564    }
565}
566
567/// Version Need Auxiliary Entries from the .gnu.version_r section
568#[derive(Debug, PartialEq, Eq)]
569pub struct VerNeedAux {
570    /// Dependency name hash value (ELF hash function).
571    pub vna_hash: u32,
572    /// Dependency information flag bitmask.
573    pub vna_flags: u16,
574    /// VersionIndex value used in the .gnu.version symbol version array.
575    pub vna_other: u16,
576    /// Offset to the dependency name string in the linked string table, in bytes.
577    pub vna_name: u32,
578    /// Offset to the next vernaux entry, in bytes.
579    vna_next: u32,
580}
581
582impl ParseAt for VerNeedAux {
583    fn parse_at<E: EndianParse>(
584        endian: E,
585        _class: Class,
586        offset: &mut usize,
587        data: &[u8],
588    ) -> Result<Self, ParseError> {
589        Ok(VerNeedAux {
590            vna_hash: endian.parse_u32_at(offset, data)?,
591            vna_flags: endian.parse_u16_at(offset, data)?,
592            vna_other: endian.parse_u16_at(offset, data)?,
593            vna_name: endian.parse_u32_at(offset, data)?,
594            vna_next: endian.parse_u32_at(offset, data)?,
595        })
596    }
597
598    #[inline]
599    fn size_for(_class: Class) -> usize {
600        16
601    }
602}
603
604#[derive(Debug)]
605pub struct VerNeedAuxIterator<'data, E: EndianParse> {
606    endian: E,
607    class: Class,
608    count: u16,
609    data: &'data [u8],
610    offset: usize,
611}
612
613impl<'data, E: EndianParse> VerNeedAuxIterator<'data, E> {
614    pub fn new(
615        endian: E,
616        class: Class,
617        count: u16,
618        starting_offset: usize,
619        data: &'data [u8],
620    ) -> Self {
621        VerNeedAuxIterator {
622            endian,
623            class,
624            count,
625            data,
626            offset: starting_offset,
627        }
628    }
629}
630
631impl<'data, E: EndianParse> Iterator for VerNeedAuxIterator<'data, E> {
632    type Item = VerNeedAux;
633    fn next(&mut self) -> Option<Self::Item> {
634        if self.data.is_empty() || self.count == 0 {
635            return None;
636        }
637
638        let mut start = self.offset;
639        let vna = VerNeedAux::parse_at(self.endian, self.class, &mut start, self.data).ok()?;
640
641        // If offset overflows, silently end iteration
642        match self.offset.checked_add(vna.vna_next as usize) {
643            Some(new_off) => self.offset = new_off,
644            None => self.count = 0,
645        }
646        self.count -= 1;
647
648        // Silently end iteration early if the next link stops pointing somewhere new
649        // TODO: Make this an error condition by allowing the iterator to yield a ParseError
650        if self.count > 0 && vna.vna_next == 0 {
651            self.count = 0
652        }
653        Some(vna)
654    }
655}
656
657//////////////////////////////
658//  _____         _         //
659// |_   _|__  ___| |_ ___   //
660//   | |/ _ \/ __| __/ __|  //
661//   | |  __/\__ \ |_\__ \  //
662//   |_|\___||___/\__|___/  //
663//                          //
664//////////////////////////////
665
666#[cfg(test)]
667mod iter_tests {
668    use super::*;
669    use crate::endian::LittleEndian;
670
671    #[rustfmt::skip]
672    const GNU_VERNEED_STRINGS: [u8; 65] = [
673        // ZLIB_1.2.0 (0x1)
674        0x00, 0x5a, 0x4c, 0x49, 0x42, 0x5f, 0x31, 0x2e, 0x32, 0x2e, 0x30, 0x00,
675        // GLIBC_2.33 (0xC)
676        0x47, 0x4c, 0x49, 0x42, 0x43, 0x5f, 0x32, 0x2e, 0x33, 0x33, 0x00,
677        // GLIBC_2.2.5 (0x17)
678        0x47, 0x4c, 0x49, 0x42, 0x43, 0x5f, 0x32, 0x2e, 0x32, 0x2e, 0x35, 0x00,
679        // libz.so.1 (0x23)
680        0x6c, 0x69, 0x62, 0x7a, 0x2e, 0x73, 0x6f, 0x2e, 0x31, 0x00,
681        // libc.so.6 (0x2D)
682        0x6c, 0x69, 0x62, 0x63, 0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00,
683        // GLIBC_2.3 (0x37)
684        0x47, 0x4c, 0x49, 0x42, 0x43, 0x5f, 0x32, 0x2e, 0x33, 0x00,
685    ];
686
687    #[rustfmt::skip]
688    const GNU_VERNEED_DATA: [u8; 96] = [
689    // {vn_version, vn_cnt,     vn_file,                vn_aux,                 vn_next               }
690        0x01, 0x00, 0x01, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
691    // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
692        0xc0, 0xe5, 0x27, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693    // {vn_version, vn_cnt,     vn_file,                vn_aux,                 vn_next               }
694        0x01, 0x00, 0x03, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695    // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
696        0x13, 0x69, 0x69, 0x0d, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
697    // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
698        0xb3, 0x91, 0x96, 0x06, 0x00, 0x00, 0x0b, 0x00, 0x17, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
699    // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
700        0x94, 0x91, 0x96, 0x06, 0x00, 0x00, 0x09, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701    ];
702
703    #[test]
704    fn verneed_iter() {
705        let iter = VerNeedIterator::new(LittleEndian, Class::ELF64, 2, 0, &GNU_VERNEED_DATA);
706        let entries: Vec<(VerNeed, Vec<VerNeedAux>)> =
707            iter.map(|(vn, iter)| (vn, iter.collect())).collect();
708
709        assert_eq!(entries.len(), 2);
710    }
711
712    #[test]
713    fn verneed_iter_early_termination_on_broken_next_link() {
714        // set count = 3 even though there's only 2 entries
715        let iter = VerNeedIterator::new(LittleEndian, Class::ELF64, 3, 0, &GNU_VERNEED_DATA);
716        let entries: Vec<(VerNeed, Vec<VerNeedAux>)> =
717            iter.map(|(vn, iter)| (vn, iter.collect())).collect();
718
719        // TODO: make this a ParseError condition instead of silently returning only the good data.
720        assert_eq!(entries.len(), 2);
721    }
722
723    #[test]
724    fn verneedaux_iter_one_entry() {
725        let mut iter =
726            VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 1, 0x10, &GNU_VERNEED_DATA);
727        let aux1 = iter.next().expect("Failed to parse");
728        assert_eq!(
729            aux1,
730            VerNeedAux {
731                vna_hash: 0x0827e5c0,
732                vna_flags: 0,
733                vna_other: 0x0a,
734                vna_name: 0x01,
735                vna_next: 0
736            }
737        );
738        assert!(iter.next().is_none());
739    }
740
741    #[test]
742    fn verneedaux_iter_multiple_entries() {
743        let mut iter =
744            VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 3, 0x30, &GNU_VERNEED_DATA);
745        let aux1 = iter.next().expect("Failed to parse");
746        assert_eq!(
747            aux1,
748            VerNeedAux {
749                vna_hash: 0x0d696913,
750                vna_flags: 0,
751                vna_other: 0x0c,
752                vna_name: 0x0c,
753                vna_next: 0x10
754            }
755        );
756        let aux2 = iter.next().expect("Failed to parse");
757        assert_eq!(
758            aux2,
759            VerNeedAux {
760                vna_hash: 0x069691b3,
761                vna_flags: 0,
762                vna_other: 0x0b,
763                vna_name: 0x17,
764                vna_next: 0x10
765            }
766        );
767        let aux3 = iter.next().expect("Failed to parse");
768        assert_eq!(
769            aux3,
770            VerNeedAux {
771                vna_hash: 0x06969194,
772                vna_flags: 0,
773                vna_other: 0x09,
774                vna_name: 0x37,
775                vna_next: 0
776            }
777        );
778        assert!(iter.next().is_none());
779    }
780
781    // Hypothetical case where VerDefAux entries are non-contiguous
782    #[test]
783    fn verneedaux_iter_two_lists_interspersed() {
784        #[rustfmt::skip]
785        let data: [u8; 64] = [
786        // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
787            0xc0, 0xe5, 0x27, 0x08, 0x00, 0x00, 0x0a, 0x00, 0xcc, 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
788        // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
789            0x13, 0x69, 0x69, 0x0d, 0x00, 0x00, 0x0c, 0x00, 0xd7, 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
790        // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
791            0xb3, 0x91, 0x96, 0x06, 0x00, 0x00, 0x0b, 0x00, 0xe1, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
792        // {vn_hash,                vn_flags,   vn_other,   vn_name,                vn_next               }
793            0x94, 0x91, 0x96, 0x06, 0x00, 0x00, 0x09, 0x00, 0xec, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794        ];
795
796        let mut iter1 = VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 2, 0, &data);
797        let mut iter2 = VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 2, 0x10, &data);
798
799        let aux1_1 = iter1.next().expect("Failed to parse");
800        assert_eq!(
801            aux1_1,
802            VerNeedAux {
803                vna_hash: 0x0827e5c0,
804                vna_flags: 0,
805                vna_other: 0x0a,
806                vna_name: 0x0ccc,
807                vna_next: 0x20,
808            }
809        );
810        let aux2_1 = iter2.next().expect("Failed to parse");
811        assert_eq!(
812            aux2_1,
813            VerNeedAux {
814                vna_hash: 0x0d696913,
815                vna_flags: 0,
816                vna_other: 0x0c,
817                vna_name: 0x0cd7,
818                vna_next: 0x20
819            }
820        );
821        let aux1_2 = iter1.next().expect("Failed to parse");
822        assert_eq!(
823            aux1_2,
824            VerNeedAux {
825                vna_hash: 0x069691b3,
826                vna_flags: 0,
827                vna_other: 0x0b,
828                vna_name: 0x0ce1,
829                vna_next: 0
830            }
831        );
832        let aux2_2 = iter2.next().expect("Failed to parse");
833        assert_eq!(
834            aux2_2,
835            VerNeedAux {
836                vna_hash: 0x06969194,
837                vna_flags: 0,
838                vna_other: 0x09,
839                vna_name: 0x0cec,
840                vna_next: 0
841            }
842        );
843        assert!(iter1.next().is_none());
844        assert!(iter2.next().is_none());
845    }
846
847    #[test]
848    fn verneedaux_iter_early_termination_on_broken_next_link() {
849        // set count = 7 even though there's only 1 entry
850        let iter = VerNeedAuxIterator::new(LittleEndian, Class::ELF64, 7, 0x10, &GNU_VERNEED_DATA);
851        let entries: Vec<VerNeedAux> = iter.collect();
852
853        // TODO: make this a ParseError condition instead of silently returning only the good data.
854        assert_eq!(entries.len(), 1);
855    }
856
857    #[rustfmt::skip]
858    const GNU_VERDEF_STRINGS: [u8; 34] = [
859        // LIBCTF_1.0 (0x1)
860        0x00, 0x4c, 0x49, 0x42, 0x43, 0x54, 0x46, 0x5f, 0x31, 0x2e, 0x30, 0x00,
861        // LIBCTF_1.1 (0xC)
862        0x4c, 0x49, 0x42, 0x43, 0x54, 0x46, 0x5f, 0x31, 0x2e, 0x31, 0x00,
863        // LIBCTF_1.2 (0x17)
864        0x4c, 0x49, 0x42, 0x43, 0x54, 0x46, 0x5f, 0x31, 0x2e, 0x32, 0x00,
865    ];
866
867    // Sample .gnu.version_d section contents
868    #[rustfmt::skip]
869    const GNU_VERDEF_DATA: [u8; 128] = [
870    // {vd_version, vd_flags,   vd_ndx,     vd_cnt
871        0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
872    //  vd_hash,                vd_aux,
873        0xb0, 0x7a, 0x07, 0x0b, 0x14, 0x00, 0x00, 0x00,
874    //  vd_next},               {vda_name,
875        0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
876    //  vda_next},             {vd_version, vd_flags,
877        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
878    //  vd_ndx,     vd_cnt,     vd_hash,
879        0x02, 0x00, 0x01, 0x00, 0x70, 0x2f, 0x8f, 0x08,
880    //  vd_aux,                 vd_next},
881        0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
882    // {vda_name,               vda_next},
883        0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
884    // {vd_version, vd_flags,   vd_ndx,     vd_cnt
885        0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
886    //  vd_hash,                vd_aux,
887        0x71, 0x2f, 0x8f, 0x08, 0x14, 0x00, 0x00, 0x00,
888    //  vd_next},               {vda_name,
889        0x24, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
890    //  vda_next},              {vda_name,
891        0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
892    //  vda_next},             {vd_version, vd_flags,
893        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
894    //  vd_ndx,     vd_cnt,     vd_hash,
895        0x04, 0x00, 0x02, 0x00, 0x72, 0x2f, 0x8f, 0x08,
896    //  vd_aux,                 vd_next},
897        0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
898    // {vda_name,               vda_next},
899        0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
900    // {vda_name,               vda_next},
901        0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
902    ];
903
904    #[test]
905    fn verdef_iter() {
906        let iter = VerDefIterator::new(LittleEndian, Class::ELF64, 4, 0, &GNU_VERDEF_DATA);
907        let entries: Vec<(VerDef, Vec<VerDefAux>)> =
908            iter.map(|(vd, iter)| (vd, iter.collect())).collect();
909
910        assert_eq!(entries.len(), 4);
911
912        assert_eq!(
913            entries,
914            vec![
915                (
916                    VerDef {
917                        vd_flags: 1,
918                        vd_ndx: 1,
919                        vd_cnt: 1,
920                        vd_hash: 0x0B077AB0,
921                        vd_aux: 20,
922                        vd_next: 28,
923                    },
924                    vec![VerDefAux {
925                        vda_name: 0x1,
926                        vda_next: 0
927                    }]
928                ),
929                (
930                    VerDef {
931                        vd_flags: 0,
932                        vd_ndx: 2,
933                        vd_cnt: 1,
934                        vd_hash: 0x088f2f70,
935                        vd_aux: 20,
936                        vd_next: 28,
937                    },
938                    vec![VerDefAux {
939                        vda_name: 0xC,
940                        vda_next: 0
941                    }]
942                ),
943                (
944                    VerDef {
945                        vd_flags: 0,
946                        vd_ndx: 3,
947                        vd_cnt: 2,
948                        vd_hash: 0x088f2f71,
949                        vd_aux: 20,
950                        vd_next: 36,
951                    },
952                    vec![
953                        VerDefAux {
954                            vda_name: 0x17,
955                            vda_next: 8
956                        },
957                        VerDefAux {
958                            vda_name: 0xC,
959                            vda_next: 0
960                        }
961                    ]
962                ),
963                (
964                    VerDef {
965                        vd_flags: 0,
966                        vd_ndx: 4,
967                        vd_cnt: 2,
968                        vd_hash: 0x088f2f72,
969                        vd_aux: 20,
970                        vd_next: 0,
971                    },
972                    vec![
973                        VerDefAux {
974                            vda_name: 0xC,
975                            vda_next: 8
976                        },
977                        VerDefAux {
978                            vda_name: 0x17,
979                            vda_next: 0
980                        }
981                    ]
982                ),
983            ]
984        );
985    }
986
987    #[test]
988    fn verdef_iter_early_termination_on_broken_next_link() {
989        // set count = 7 even though there's only 4 entries
990        let iter = VerDefIterator::new(LittleEndian, Class::ELF64, 7, 0, &GNU_VERDEF_DATA);
991        let entries: Vec<(VerDef, Vec<VerDefAux>)> =
992            iter.map(|(vn, iter)| (vn, iter.collect())).collect();
993
994        // TODO: make this a ParseError condition instead of silently returning only the good data.
995        assert_eq!(entries.len(), 4);
996    }
997
998    #[test]
999    fn verdefaux_iter_one_entry() {
1000        let mut iter =
1001            VerDefAuxIterator::new(LittleEndian, Class::ELF64, 1, 0x14, &GNU_VERDEF_DATA);
1002        let aux1 = iter.next().expect("Failed to parse");
1003        assert_eq!(
1004            aux1,
1005            VerDefAux {
1006                vda_name: 0x01,
1007                vda_next: 0
1008            }
1009        );
1010        assert!(iter.next().is_none());
1011    }
1012
1013    #[test]
1014    fn verdefaux_iter_multiple_entries() {
1015        let mut iter =
1016            VerDefAuxIterator::new(LittleEndian, Class::ELF64, 2, 0x4C, &GNU_VERDEF_DATA);
1017        let aux1 = iter.next().expect("Failed to parse");
1018        assert_eq!(
1019            aux1,
1020            VerDefAux {
1021                vda_name: 0x17,
1022                vda_next: 8
1023            }
1024        );
1025        let aux1 = iter.next().expect("Failed to parse");
1026        assert_eq!(
1027            aux1,
1028            VerDefAux {
1029                vda_name: 0xC,
1030                vda_next: 0
1031            }
1032        );
1033        assert!(iter.next().is_none());
1034    }
1035
1036    // Hypothetical case where VerDefAux entries are non-contiguous
1037    #[test]
1038    fn verdefaux_iter_two_lists_interspersed() {
1039        #[rustfmt::skip]
1040        let data: [u8; 32] = [
1041            0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // list 1 entry 1
1042            0xA1, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // list 2 entry 1
1043            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // list 1 entry 2
1044            0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // list 2 entry 2
1045        ];
1046
1047        let mut iter1 = VerDefAuxIterator::new(LittleEndian, Class::ELF64, 2, 0, &data);
1048        let mut iter2 = VerDefAuxIterator::new(LittleEndian, Class::ELF64, 2, 8, &data);
1049
1050        let aux1_1 = iter1.next().expect("Failed to parse");
1051        assert_eq!(
1052            aux1_1,
1053            VerDefAux {
1054                vda_name: 0x0001,
1055                vda_next: 0x10,
1056            }
1057        );
1058        let aux2_1 = iter2.next().expect("Failed to parse");
1059        assert_eq!(
1060            aux2_1,
1061            VerDefAux {
1062                vda_name: 0x00A1,
1063                vda_next: 0x10,
1064            }
1065        );
1066        let aux1_2 = iter1.next().expect("Failed to parse");
1067        assert_eq!(
1068            aux1_2,
1069            VerDefAux {
1070                vda_name: 0x0002,
1071                vda_next: 0,
1072            }
1073        );
1074        let aux2_2 = iter2.next().expect("Failed to parse");
1075        assert_eq!(
1076            aux2_2,
1077            VerDefAux {
1078                vda_name: 0x00A2,
1079                vda_next: 0,
1080            }
1081        );
1082        assert!(iter1.next().is_none());
1083        assert!(iter2.next().is_none());
1084    }
1085
1086    #[test]
1087    fn verdefaux_iter_early_termination_on_broken_next_link() {
1088        // set count = 7 even though there's only 1 entry
1089        let iter = VerDefAuxIterator::new(LittleEndian, Class::ELF64, 7, 0x14, &GNU_VERDEF_DATA);
1090        let entries: Vec<VerDefAux> = iter.collect();
1091
1092        // TODO: make this a ParseError condition instead of silently returning only the good data.
1093        assert_eq!(entries.len(), 1);
1094    }
1095
1096    #[test]
1097    fn version_table() {
1098        let ver_idx_buf: [u8; 10] = [0x02, 0x00, 0x03, 0x00, 0x09, 0x00, 0x0A, 0x00, 0xff, 0xff];
1099        let version_ids = VersionIndexTable::new(LittleEndian, Class::ELF64, &ver_idx_buf);
1100        let verdefs = VerDefIterator::new(LittleEndian, Class::ELF64, 4, 0, &GNU_VERDEF_DATA);
1101        let verneed_strs = StringTable::new(&GNU_VERNEED_STRINGS);
1102        let verneeds = VerNeedIterator::new(LittleEndian, Class::ELF64, 2, 0, &GNU_VERNEED_DATA);
1103        let verdef_strs = StringTable::new(&GNU_VERDEF_STRINGS);
1104
1105        let table = SymbolVersionTable::new(
1106            version_ids,
1107            Some((verneeds, verneed_strs)),
1108            Some((verdefs, verdef_strs)),
1109        );
1110
1111        let def1 = table
1112            .get_definition(0)
1113            .expect("Failed to parse definition")
1114            .expect("Failed to find def");
1115        assert_eq!(def1.hash, 0x088f2f70);
1116        assert_eq!(def1.flags, 0);
1117        let def1_names: Vec<&str> = def1
1118            .names
1119            .map(|res| res.expect("Failed to parse"))
1120            .collect();
1121        assert_eq!(def1_names, ["LIBCTF_1.1"]);
1122        assert!(!def1.hidden);
1123
1124        let def2 = table
1125            .get_definition(1)
1126            .expect("Failed to parse definition")
1127            .expect("Failed to find def");
1128        assert_eq!(def2.hash, 0x088f2f71);
1129        assert_eq!(def2.flags, 0);
1130        let def2_names: Vec<&str> = def2
1131            .names
1132            .map(|res| res.expect("Failed to parse"))
1133            .collect();
1134        assert_eq!(def2_names, ["LIBCTF_1.2", "LIBCTF_1.1"]);
1135        assert!(!def2.hidden);
1136
1137        let req1 = table
1138            .get_requirement(2)
1139            .expect("Failed to parse definition")
1140            .expect("Failed to find req");
1141        assert_eq!(
1142            req1,
1143            SymbolRequirement {
1144                file: "libc.so.6",
1145                name: "GLIBC_2.3",
1146                hash: 0x6969194,
1147                flags: 0,
1148                hidden: false
1149            }
1150        );
1151
1152        let req2 = table
1153            .get_requirement(3)
1154            .expect("Failed to parse definition")
1155            .expect("Failed to find req");
1156        assert_eq!(
1157            req2,
1158            SymbolRequirement {
1159                file: "libz.so.1",
1160                name: "ZLIB_1.2.0",
1161                hash: 0x827E5C0,
1162                flags: 0,
1163                hidden: false
1164            }
1165        );
1166
1167        // The last version_index points to non-existent definitions. Maybe we should treat
1168        // this as a ParseError instead of returning an empty Option? This can only happen
1169        // if .gnu.versions[N] contains an index that doesn't exist, which is likely a file corruption
1170        // or programmer error (i.e asking for a definition for an undefined symbol)
1171        assert!(table.get_definition(4).expect("Failed to parse").is_none());
1172        assert!(table.get_requirement(4).expect("Failed to parse").is_none());
1173    }
1174}
1175
1176#[cfg(test)]
1177mod parse_tests {
1178    use super::*;
1179    use crate::endian::{BigEndian, LittleEndian};
1180    use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
1181
1182    #[test]
1183    fn parse_verndx32_lsb() {
1184        test_parse_for(LittleEndian, Class::ELF32, VersionIndex(0x0100));
1185    }
1186
1187    #[test]
1188    fn parse_verndx32_msb() {
1189        test_parse_for(BigEndian, Class::ELF32, VersionIndex(0x0001));
1190    }
1191
1192    #[test]
1193    fn parse_verndx64_lsb() {
1194        test_parse_for(LittleEndian, Class::ELF64, VersionIndex(0x0100));
1195    }
1196
1197    #[test]
1198    fn parse_verndx64_msb() {
1199        test_parse_for(BigEndian, Class::ELF64, VersionIndex(0x0001));
1200    }
1201
1202    #[test]
1203    fn parse_verndx32_lsb_fuzz_too_short() {
1204        test_parse_fuzz_too_short::<_, VersionIndex>(LittleEndian, Class::ELF32);
1205    }
1206
1207    #[test]
1208    fn parse_verndx32_msb_fuzz_too_short() {
1209        test_parse_fuzz_too_short::<_, VersionIndex>(BigEndian, Class::ELF32);
1210    }
1211
1212    #[test]
1213    fn parse_verndx64_lsb_fuzz_too_short() {
1214        test_parse_fuzz_too_short::<_, VersionIndex>(LittleEndian, Class::ELF64);
1215    }
1216
1217    #[test]
1218    fn parse_verndx64_msb_fuzz_too_short() {
1219        test_parse_fuzz_too_short::<_, VersionIndex>(BigEndian, Class::ELF64);
1220    }
1221
1222    //
1223    // VerDef
1224    //
1225    #[test]
1226    fn parse_verdef32_lsb() {
1227        let mut data = [0u8; ELFVERDEFSIZE];
1228        for (n, elem) in data.iter_mut().enumerate().take(ELFVERDEFSIZE) {
1229            *elem = n as u8;
1230        }
1231        data[0] = 1;
1232        data[1] = 0;
1233
1234        let mut offset = 0;
1235        let entry = VerDef::parse_at(LittleEndian, Class::ELF32, &mut offset, data.as_ref())
1236            .expect("Failed to parse VerDef");
1237
1238        assert_eq!(
1239            entry,
1240            VerDef {
1241                vd_flags: 0x0302,
1242                vd_ndx: 0x0504,
1243                vd_cnt: 0x0706,
1244                vd_hash: 0x0B0A0908,
1245                vd_aux: 0x0F0E0D0C,
1246                vd_next: 0x13121110,
1247            }
1248        );
1249        assert_eq!(offset, ELFVERDEFSIZE);
1250    }
1251
1252    #[test]
1253    fn parse_verdef32_fuzz_too_short() {
1254        let mut data = [0u8; ELFVERDEFSIZE];
1255        data[1] = 1;
1256        for n in 0..ELFVERDEFSIZE {
1257            let buf = data.split_at(n).0;
1258            let mut offset: usize = 0;
1259            let error = VerDef::parse_at(BigEndian, Class::ELF32, &mut offset, buf)
1260                .expect_err("Expected an error");
1261            assert!(
1262                matches!(error, ParseError::SliceReadError(_)),
1263                "Unexpected Error type found: {error}"
1264            );
1265        }
1266    }
1267
1268    #[test]
1269    fn parse_verdef64_msb() {
1270        let mut data = [0u8; ELFVERDEFSIZE];
1271        for (n, elem) in data.iter_mut().enumerate().take(ELFVERDEFSIZE).skip(2) {
1272            *elem = n as u8;
1273        }
1274        data[1] = 1;
1275
1276        let mut offset = 0;
1277        let entry = VerDef::parse_at(BigEndian, Class::ELF64, &mut offset, data.as_ref())
1278            .expect("Failed to parse VerDef");
1279
1280        assert_eq!(
1281            entry,
1282            VerDef {
1283                vd_flags: 0x0203,
1284                vd_ndx: 0x0405,
1285                vd_cnt: 0x0607,
1286                vd_hash: 0x08090A0B,
1287                vd_aux: 0x0C0D0E0F,
1288                vd_next: 0x10111213,
1289            }
1290        );
1291        assert_eq!(offset, ELFVERDEFSIZE);
1292    }
1293
1294    #[test]
1295    fn parse_verdef64_fuzz_too_short() {
1296        let mut data = [0u8; ELFVERDEFSIZE];
1297        data[1] = 1;
1298        for n in 0..ELFVERDEFSIZE {
1299            let buf = data.split_at(n).0;
1300            let mut offset: usize = 0;
1301            let error = VerDef::parse_at(BigEndian, Class::ELF64, &mut offset, buf)
1302                .expect_err("Expected an error");
1303            assert!(
1304                matches!(error, ParseError::SliceReadError(_)),
1305                "Unexpected Error type found: {error}"
1306            );
1307        }
1308    }
1309
1310    #[test]
1311    fn parse_verdef_bad_version_errors() {
1312        let data = [0u8; ELFVERDEFSIZE];
1313        // version is 0, which is not 1, which is bad :)
1314
1315        let mut offset = 0;
1316        let err = VerDef::parse_at(BigEndian, Class::ELF64, &mut offset, data.as_ref())
1317            .expect_err("Expected an error");
1318        assert!(
1319            matches!(err, ParseError::UnsupportedVersion((0, 1))),
1320            "Unexpected Error type found: {err}"
1321        );
1322    }
1323
1324    //
1325    // VerDefAux
1326    //
1327    #[test]
1328    fn parse_verdefaux32_lsb() {
1329        test_parse_for(
1330            LittleEndian,
1331            Class::ELF32,
1332            VerDefAux {
1333                vda_name: 0x03020100,
1334                vda_next: 0x07060504,
1335            },
1336        );
1337    }
1338
1339    #[test]
1340    fn parse_verdefaux32_msb() {
1341        test_parse_for(
1342            BigEndian,
1343            Class::ELF32,
1344            VerDefAux {
1345                vda_name: 0x00010203,
1346                vda_next: 0x04050607,
1347            },
1348        );
1349    }
1350
1351    #[test]
1352    fn parse_verdefaux64_lsb() {
1353        test_parse_for(
1354            LittleEndian,
1355            Class::ELF64,
1356            VerDefAux {
1357                vda_name: 0x03020100,
1358                vda_next: 0x07060504,
1359            },
1360        );
1361    }
1362
1363    #[test]
1364    fn parse_verdefaux64_msb() {
1365        test_parse_for(
1366            BigEndian,
1367            Class::ELF64,
1368            VerDefAux {
1369                vda_name: 0x00010203,
1370                vda_next: 0x04050607,
1371            },
1372        );
1373    }
1374
1375    #[test]
1376    fn parse_verdefaux32_lsb_fuzz_too_short() {
1377        test_parse_fuzz_too_short::<_, VerDefAux>(LittleEndian, Class::ELF32);
1378    }
1379
1380    #[test]
1381    fn parse_verdefaux32_msb_fuzz_too_short() {
1382        test_parse_fuzz_too_short::<_, VerDefAux>(BigEndian, Class::ELF32);
1383    }
1384
1385    #[test]
1386    fn parse_verdefaux64_lsb_fuzz_too_short() {
1387        test_parse_fuzz_too_short::<_, VerDefAux>(LittleEndian, Class::ELF64);
1388    }
1389
1390    #[test]
1391    fn parse_verdefaux64_msb_fuzz_too_short() {
1392        test_parse_fuzz_too_short::<_, VerDefAux>(BigEndian, Class::ELF64);
1393    }
1394
1395    //
1396    // VerNeed
1397    //
1398    #[test]
1399    fn parse_verneed32_lsb() {
1400        let mut data = [0u8; ELFVERNEEDSIZE];
1401        for (n, elem) in data.iter_mut().enumerate().take(ELFVERNEEDSIZE) {
1402            *elem = n as u8;
1403        }
1404        data[0] = 1;
1405        data[1] = 0;
1406
1407        let mut offset = 0;
1408        let entry = VerNeed::parse_at(LittleEndian, Class::ELF32, &mut offset, data.as_ref())
1409            .expect("Failed to parse VerNeed");
1410
1411        assert_eq!(
1412            entry,
1413            VerNeed {
1414                vn_cnt: 0x0302,
1415                vn_file: 0x07060504,
1416                vn_aux: 0x0B0A0908,
1417                vn_next: 0x0F0E0D0C,
1418            }
1419        );
1420        assert_eq!(offset, ELFVERNEEDSIZE);
1421    }
1422
1423    #[test]
1424    fn parse_verneed32_fuzz_too_short() {
1425        let mut data = [0u8; ELFVERNEEDSIZE];
1426        data[1] = 1;
1427        for n in 0..ELFVERNEEDSIZE {
1428            let buf = data.split_at(n).0;
1429            let mut offset: usize = 0;
1430            let error = VerNeed::parse_at(BigEndian, Class::ELF32, &mut offset, buf)
1431                .expect_err("Expected an error");
1432            assert!(
1433                matches!(error, ParseError::SliceReadError(_)),
1434                "Unexpected Error type found: {error}"
1435            );
1436        }
1437    }
1438
1439    #[test]
1440    fn parse_verneed64_msb() {
1441        let mut data = [0u8; ELFVERNEEDSIZE];
1442        for (n, elem) in data.iter_mut().enumerate().take(ELFVERNEEDSIZE) {
1443            *elem = n as u8;
1444        }
1445        data[1] = 1;
1446
1447        let mut offset = 0;
1448        let entry = VerNeed::parse_at(BigEndian, Class::ELF64, &mut offset, data.as_ref())
1449            .expect("Failed to parse VerNeed");
1450
1451        assert_eq!(
1452            entry,
1453            VerNeed {
1454                vn_cnt: 0x0203,
1455                vn_file: 0x04050607,
1456                vn_aux: 0x08090A0B,
1457                vn_next: 0x0C0D0E0F,
1458            }
1459        );
1460        assert_eq!(offset, ELFVERNEEDSIZE);
1461    }
1462
1463    #[test]
1464    fn parse_verneed64_fuzz_too_short() {
1465        let mut data = [0u8; ELFVERNEEDSIZE];
1466        data[1] = 1;
1467        for n in 0..ELFVERNEEDSIZE {
1468            let buf = data.split_at(n).0;
1469            let mut offset: usize = 0;
1470            let error = VerNeed::parse_at(BigEndian, Class::ELF64, &mut offset, buf)
1471                .expect_err("Expected an error");
1472            assert!(
1473                matches!(error, ParseError::SliceReadError(_)),
1474                "Unexpected Error type found: {error}"
1475            );
1476        }
1477    }
1478
1479    //
1480    // VerNeedAux
1481    //
1482    #[test]
1483    fn parse_verneedaux32_lsb() {
1484        test_parse_for(
1485            LittleEndian,
1486            Class::ELF32,
1487            VerNeedAux {
1488                vna_hash: 0x03020100,
1489                vna_flags: 0x0504,
1490                vna_other: 0x0706,
1491                vna_name: 0x0B0A0908,
1492                vna_next: 0x0F0E0D0C,
1493            },
1494        );
1495    }
1496
1497    #[test]
1498    fn parse_verneedaux32_msb() {
1499        test_parse_for(
1500            BigEndian,
1501            Class::ELF32,
1502            VerNeedAux {
1503                vna_hash: 0x00010203,
1504                vna_flags: 0x0405,
1505                vna_other: 0x0607,
1506                vna_name: 0x08090A0B,
1507                vna_next: 0x0C0D0E0F,
1508            },
1509        );
1510    }
1511
1512    #[test]
1513    fn parse_verneedaux64_lsb() {
1514        test_parse_for(
1515            LittleEndian,
1516            Class::ELF64,
1517            VerNeedAux {
1518                vna_hash: 0x03020100,
1519                vna_flags: 0x0504,
1520                vna_other: 0x0706,
1521                vna_name: 0x0B0A0908,
1522                vna_next: 0x0F0E0D0C,
1523            },
1524        );
1525    }
1526
1527    #[test]
1528    fn parse_verneedaux64_msb() {
1529        test_parse_for(
1530            BigEndian,
1531            Class::ELF64,
1532            VerNeedAux {
1533                vna_hash: 0x00010203,
1534                vna_flags: 0x0405,
1535                vna_other: 0x0607,
1536                vna_name: 0x08090A0B,
1537                vna_next: 0x0C0D0E0F,
1538            },
1539        );
1540    }
1541
1542    #[test]
1543    fn parse_verneedaux32_lsb_fuzz_too_short() {
1544        test_parse_fuzz_too_short::<_, VerNeedAux>(LittleEndian, Class::ELF32);
1545    }
1546
1547    #[test]
1548    fn parse_verneedaux32_msb_fuzz_too_short() {
1549        test_parse_fuzz_too_short::<_, VerNeedAux>(BigEndian, Class::ELF32);
1550    }
1551
1552    #[test]
1553    fn parse_verneedaux64_lsb_fuzz_too_short() {
1554        test_parse_fuzz_too_short::<_, VerNeedAux>(LittleEndian, Class::ELF64);
1555    }
1556
1557    #[test]
1558    fn parse_verneedaux64_msb_fuzz_too_short() {
1559        test_parse_fuzz_too_short::<_, VerNeedAux>(BigEndian, Class::ELF64);
1560    }
1561}
1562
1563#[cfg(test)]
1564mod version_index_tests {
1565    use super::*;
1566
1567    #[test]
1568    fn is_local() {
1569        let idx = VersionIndex(0);
1570        assert!(idx.is_local());
1571    }
1572
1573    #[test]
1574    fn is_global() {
1575        let idx = VersionIndex(1);
1576        assert!(idx.is_global());
1577    }
1578
1579    #[test]
1580    fn index_visible() {
1581        let idx = VersionIndex(42);
1582        assert_eq!(idx.index(), 42);
1583        assert!(!idx.is_hidden());
1584    }
1585
1586    #[test]
1587    fn index_hidden() {
1588        let idx = VersionIndex(42 | abi::VER_NDX_HIDDEN);
1589        assert_eq!(idx.index(), 42);
1590        assert!(idx.is_hidden());
1591    }
1592}