Coverage Report

Created: 2026-11-11 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/goblin-0.10.7/src/elf/symver.rs
Line
Count
Source
1
//! Symbol versioning
2
//!
3
//! Implementation of the GNU symbol versioning extension according to
4
//! [LSB Core Specification - Symbol Versioning][lsb-symver].
5
//!
6
//! # Examples
7
//!
8
//! List the dependencies of an ELF file that have [version needed][lsb-verneed] information along
9
//! with the versions needed for each dependency.
10
//! ```rust
11
//! use goblin::error::Error;
12
//!
13
//! pub fn show_verneed(bytes: &[u8]) -> Result<(), Error> {
14
//!     let binary = goblin::elf::Elf::parse(&bytes)?;
15
//!
16
//!     if let Some(verneed) = binary.verneed {
17
//!         for need_file in verneed.iter() {
18
//!             println!(
19
//!                 "Depend on {:?} with version(s):",
20
//!                 binary.dynstrtab.get_at(need_file.vn_file)
21
//!             );
22
//!             for need_ver in need_file.iter() {
23
//!                 println!("{:?}", binary.dynstrtab.get_at(need_ver.vna_name));
24
//!             }
25
//!         }
26
//!     }
27
//!
28
//!     Ok(())
29
//! }
30
//! ```
31
//!
32
//! List the [version defined][lsb-verdef] information of an ELF file, effectively listing the version
33
//! defined by this ELF file.
34
//! ```rust
35
//! use goblin::error::Error;
36
//!
37
//! pub fn show_verdef(bytes: &[u8]) -> Result<(), Error> {
38
//!     let binary = goblin::elf::Elf::parse(&bytes)?;
39
//!
40
//!     if let Some(verdef) = &binary.verdef {
41
//!         for def in verdef.iter() {
42
//!             for (n, aux) in def.iter().enumerate() {
43
//!                 let name = binary.dynstrtab.get_at(aux.vda_name);
44
//!                 match n {
45
//!                     0 => print!("Name: {:?}", name),
46
//!                     1 => print!(" Parent: {:?}", name),
47
//!                     _ => print!(", {:?}", name),
48
//!                 }
49
//!             }
50
//!             print!("\n");
51
//!         }
52
//!     }
53
//!
54
//!     Ok(())
55
//! }
56
//! ```
57
//!
58
//! [lsb-symver]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html
59
//! [lsb-verneed]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERRQMTS
60
//! [lsb-verdef]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERDEFS
61
62
use crate::container;
63
use crate::elf::section_header::{SHT_GNU_VERDEF, SHT_GNU_VERNEED, SHT_GNU_VERSYM, SectionHeader};
64
use crate::error::Result;
65
use core::iter::FusedIterator;
66
use scroll::Pread;
67
68
/******************
69
 *  ELF Constants *
70
 ******************/
71
72
// Versym constants.
73
74
/// Constant describing a local symbol, see [`Versym::is_local`].
75
pub const VER_NDX_LOCAL: u16 = 0;
76
/// Constant describing a global symbol, see [`Versym::is_global`].
77
pub const VER_NDX_GLOBAL: u16 = 1;
78
/// Bitmask to check hidden bit, see [`Versym::is_hidden`].
79
pub const VERSYM_HIDDEN: u16 = 0x8000;
80
/// Bitmask to get version information, see [`Versym::version`].
81
pub const VERSYM_VERSION: u16 = 0x7fff;
82
83
// Verdef constants.
84
85
/// Bitmask to check `base` flag in [`Verdef::vd_flags`].
86
pub const VER_FLG_BASE: u16 = 0x1;
87
/// Bitmask to check `weak` flag in [`Verdef::vd_flags`].
88
pub const VER_FLG_WEAK: u16 = 0x2;
89
/// Bitmask to check `info` flag in [`Verdef::vd_flags`].
90
pub const VER_FLG_INFO: u16 = 0x4;
91
92
/********************
93
 *  ELF Structures  *
94
 ********************/
95
96
/// An ELF `Symbol Version` entry.
97
///
98
/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERTBL
99
#[repr(C)]
100
#[derive(Debug, Pread)]
101
struct ElfVersym {
102
    vs_val: u16,
103
}
104
105
/// An ELF `Version Definition` entry Elfxx_Verdef.
106
///
107
/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFENTRIES
108
#[repr(C)]
109
#[derive(Debug, Pread)]
110
struct ElfVerdef {
111
    vd_version: u16,
112
    vd_flags: u16,
113
    vd_ndx: u16,
114
    vd_cnt: u16,
115
    vd_hash: u32,
116
    vd_aux: u32,
117
    vd_next: u32,
118
}
119
120
/// An ELF `Version Definition Auxiliary` entry Elfxx_Verdaux.
121
///
122
/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFEXTS
123
#[repr(C)]
124
#[derive(Debug, Pread)]
125
struct ElfVerdaux {
126
    vda_name: u32,
127
    vda_next: u32,
128
}
129
130
/// An ELF `Version Need` entry Elfxx_Verneed.
131
///
132
/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDFIG
133
#[repr(C)]
134
#[derive(Debug, Pread)]
135
struct ElfVerneed {
136
    vn_version: u16,
137
    vn_cnt: u16,
138
    vn_file: u32,
139
    vn_aux: u32,
140
    vn_next: u32,
141
}
142
143
/// An ELF `Version Need Auxiliary` entry Elfxx_Vernaux.
144
///
145
/// https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDEXTFIG
146
#[repr(C)]
147
#[derive(Debug, Pread)]
148
struct ElfVernaux {
149
    vna_hash: u32,
150
    vna_flags: u16,
151
    vna_other: u16,
152
    vna_name: u32,
153
    vna_next: u32,
154
}
155
156
/********************
157
 *  Symbol Version  *
158
 ********************/
159
160
/// Helper struct to iterate over [Symbol Version][Versym] entries.
161
#[derive(Debug)]
162
pub struct VersymSection<'a> {
163
    bytes: &'a [u8],
164
    ctx: container::Ctx,
165
}
166
167
impl<'a> VersymSection<'a> {
168
595
    pub fn parse(
169
595
        bytes: &'a [u8],
170
595
        shdrs: &[SectionHeader],
171
595
        ctx: container::Ctx,
172
595
    ) -> Result<Option<VersymSection<'a>>> {
173
        // Get fields needed from optional `symbol version` section.
174
33
        let (offset, size) =
175
22.3k
            if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERSYM) {
176
33
                (shdr.sh_offset as usize, shdr.sh_size as usize)
177
            } else {
178
562
                return Ok(None);
179
            };
180
181
        // Get a slice of bytes of the `version definition` section content.
182
33
        let bytes: &'a [u8] = bytes.pread_with(offset, size)?;
183
184
30
        Ok(Some(VersymSection { bytes, ctx }))
185
595
    }
186
187
    /// Get an iterator over the [`Versym`] entries.
188
    #[inline]
189
0
    pub fn iter(&'a self) -> VersymIter<'a> {
190
0
        self.into_iter()
191
0
    }
192
193
    /// True if there are no [`Versym`] entries.
194
    #[inline]
195
0
    pub fn is_empty(&self) -> bool {
196
0
        self.bytes.is_empty()
197
0
    }
198
199
    /// Number of [`Versym`] entries.
200
    #[inline]
201
0
    pub fn len(&self) -> usize {
202
0
        let entsize = core::mem::size_of::<ElfVersym>();
203
204
0
        self.bytes.len() / entsize
205
0
    }
206
207
    /// Get [`Versym`] entry at index.
208
    #[inline]
209
0
    pub fn get_at(&self, idx: usize) -> Option<Versym> {
210
0
        let entsize = core::mem::size_of::<ElfVersym>();
211
0
        let offset = idx.checked_mul(entsize)?;
212
213
0
        self.bytes
214
0
            .pread_with::<ElfVersym>(offset, self.ctx.le)
215
0
            .ok()
216
0
            .map(Versym::from)
217
0
    }
218
}
219
220
impl<'a> IntoIterator for &'_ VersymSection<'a> {
221
    type Item = <VersymIter<'a> as Iterator>::Item;
222
    type IntoIter = VersymIter<'a>;
223
224
0
    fn into_iter(self) -> Self::IntoIter {
225
0
        VersymIter {
226
0
            bytes: self.bytes,
227
0
            offset: 0,
228
0
            ctx: self.ctx,
229
0
        }
230
0
    }
231
}
232
233
/// Iterator over the [`Versym`] entries from the [`SHT_GNU_VERSYM`] section.
234
pub struct VersymIter<'a> {
235
    bytes: &'a [u8],
236
    offset: usize,
237
    ctx: container::Ctx,
238
}
239
240
impl<'a> Iterator for VersymIter<'a> {
241
    type Item = Versym;
242
243
0
    fn next(&mut self) -> Option<Self::Item> {
244
0
        if self.offset >= self.bytes.len() {
245
0
            None
246
        } else {
247
0
            self.bytes
248
0
                .gread_with::<ElfVersym>(&mut self.offset, self.ctx.le)
249
0
                .ok()
250
0
                .map(Versym::from)
251
0
                .or_else(|| {
252
                    // self.bytes are not a multiple of ElfVersym.
253
                    // Adjust offset to continue yielding Nones.
254
0
                    self.offset = self.bytes.len();
255
0
                    None
256
0
                })
257
        }
258
0
    }
259
260
    #[inline]
261
0
    fn size_hint(&self) -> (usize, Option<usize>) {
262
0
        let len = (self.bytes.len() - self.offset) / core::mem::size_of::<Self::Item>();
263
0
        (len, Some(len))
264
0
    }
265
}
266
267
impl ExactSizeIterator for VersymIter<'_> {}
268
269
impl FusedIterator for VersymIter<'_> {}
270
271
/// An ELF [Symbol Version][lsb-versym] entry.
272
///
273
/// [lsb-versym]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#SYMVERTBL
274
#[derive(Debug)]
275
pub struct Versym {
276
    pub vs_val: u16,
277
}
278
279
impl Versym {
280
    /// Returns true if the symbol is local and not available outside the object according to
281
    /// [`VER_NDX_LOCAL`].
282
    #[inline]
283
0
    pub fn is_local(&self) -> bool {
284
0
        self.vs_val == VER_NDX_LOCAL
285
0
    }
286
287
    /// Returns true if the symbol is defined in this object and globally available according
288
    /// to [`VER_NDX_GLOBAL`].
289
    #[inline]
290
0
    pub fn is_global(&self) -> bool {
291
0
        self.vs_val == VER_NDX_GLOBAL
292
0
    }
293
294
    /// Returns true if the `hidden` bit is set according to the [`VERSYM_HIDDEN`] bitmask.
295
    #[inline]
296
0
    pub fn is_hidden(&self) -> bool {
297
0
        (self.vs_val & VERSYM_HIDDEN) == VERSYM_HIDDEN
298
0
    }
299
300
    /// Returns the symbol version index according to the [`VERSYM_VERSION`] bitmask.
301
    #[inline]
302
0
    pub fn version(&self) -> u16 {
303
0
        self.vs_val & VERSYM_VERSION
304
0
    }
305
}
306
307
impl From<ElfVersym> for Versym {
308
0
    fn from(ElfVersym { vs_val }: ElfVersym) -> Self {
309
0
        Versym { vs_val }
310
0
    }
311
}
312
313
/************************
314
 *  Version Definition  *
315
 ************************/
316
317
/// Helper struct to iterate over [Version Definition][Verdef] and [Version Definition
318
/// Auxiliary][Verdaux] entries.
319
#[derive(Debug)]
320
pub struct VerdefSection<'a> {
321
    /// String table used to resolve version strings.
322
    bytes: &'a [u8],
323
    count: usize,
324
    ctx: container::Ctx,
325
}
326
327
impl<'a> VerdefSection<'a> {
328
592
    pub fn parse(
329
592
        bytes: &'a [u8],
330
592
        shdrs: &[SectionHeader],
331
592
        ctx: container::Ctx,
332
592
    ) -> Result<Option<VerdefSection<'a>>> {
333
        // Get fields needed from optional `version definition` section.
334
0
        let (offset, size, count) =
335
23.0k
            if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERDEF) {
336
0
                (
337
0
                    shdr.sh_offset as usize,
338
0
                    shdr.sh_size as usize,
339
0
                    shdr.sh_info as usize, // Encodes the number of ElfVerdef entries.
340
0
                )
341
            } else {
342
592
                return Ok(None);
343
            };
344
345
        // Get a slice of bytes of the `version definition` section content.
346
0
        let bytes: &'a [u8] = bytes.pread_with(offset, size)?;
347
348
0
        Ok(Some(VerdefSection { bytes, count, ctx }))
349
592
    }
350
351
    /// Get an iterator over the [`Verdef`] entries.
352
    #[inline]
353
0
    pub fn iter(&'a self) -> VerdefIter<'a> {
354
0
        self.into_iter()
355
0
    }
356
}
357
358
impl<'a> IntoIterator for &'_ VerdefSection<'a> {
359
    type Item = <VerdefIter<'a> as Iterator>::Item;
360
    type IntoIter = VerdefIter<'a>;
361
362
    #[inline]
363
0
    fn into_iter(self) -> Self::IntoIter {
364
0
        VerdefIter {
365
0
            bytes: self.bytes,
366
0
            count: self.count,
367
0
            index: 0,
368
0
            offset: 0,
369
0
            ctx: self.ctx,
370
0
        }
371
0
    }
372
}
373
374
/// Iterator over the [`Verdef`] entries from the [`SHT_GNU_VERDEF`] section.
375
pub struct VerdefIter<'a> {
376
    bytes: &'a [u8],
377
    count: usize,
378
    index: usize,
379
    offset: usize,
380
    ctx: container::Ctx,
381
}
382
383
impl<'a> Iterator for VerdefIter<'a> {
384
    type Item = Verdef<'a>;
385
386
0
    fn next(&mut self) -> Option<Self::Item> {
387
0
        if self.index >= self.count {
388
0
            None
389
        } else {
390
0
            self.index += 1;
391
392
0
            let do_next = |iter: &mut Self| {
393
                let ElfVerdef {
394
0
                    vd_version,
395
0
                    vd_flags,
396
0
                    vd_ndx,
397
0
                    vd_cnt,
398
0
                    vd_hash,
399
0
                    vd_aux,
400
0
                    vd_next,
401
0
                } = iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?;
402
403
                // Validate offset to first ElfVerdaux entry.
404
0
                let offset = iter.offset.checked_add(vd_aux as usize)?;
405
406
                // Validate if offset is valid index into bytes slice.
407
0
                if offset >= iter.bytes.len() {
408
0
                    return None;
409
0
                }
410
411
                // Get a slice of bytes starting with the first ElfVerdaux entry.
412
0
                let bytes: &'a [u8] = &iter.bytes[offset..];
413
414
                // Bump the offset to the next ElfVerdef entry.
415
0
                iter.offset = iter.offset.checked_add(vd_next as usize)?;
416
417
                // Start yielding None on the next call if there is no next offset.
418
0
                if vd_next == 0 {
419
0
                    iter.index = iter.count;
420
0
                }
421
422
0
                Some(Verdef {
423
0
                    vd_version,
424
0
                    vd_flags,
425
0
                    vd_ndx,
426
0
                    vd_cnt,
427
0
                    vd_hash,
428
0
                    vd_aux,
429
0
                    vd_next,
430
0
                    bytes,
431
0
                    ctx: iter.ctx,
432
0
                })
433
0
            };
434
435
0
            do_next(self).or_else(|| {
436
                // Adjust current index to count in case of an error.
437
0
                self.index = self.count;
438
0
                None
439
0
            })
440
        }
441
0
    }
442
443
    #[inline]
444
0
    fn size_hint(&self) -> (usize, Option<usize>) {
445
0
        let len = self.count - self.index;
446
0
        (0, Some(len))
447
0
    }
448
}
449
450
impl ExactSizeIterator for VerdefIter<'_> {}
451
452
impl FusedIterator for VerdefIter<'_> {}
453
454
/// An ELF [Version Definition][lsb-verdef] entry .
455
///
456
/// [lsb-verdef]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFENTRIES
457
#[derive(Debug)]
458
pub struct Verdef<'a> {
459
    /// Version revision. This field shall be set to 1.
460
    pub vd_version: u16,
461
    /// Version information flag bitmask.
462
    pub vd_flags: u16,
463
    /// Version index numeric value referencing the SHT_GNU_versym section.
464
    pub vd_ndx: u16,
465
    /// Number of associated verdaux array entries.
466
    pub vd_cnt: u16,
467
    /// Version name hash value (ELF hash function).
468
    pub vd_hash: u32,
469
    /// Offset in bytes to a corresponding entry in an array of Elfxx_Verdaux structures.
470
    pub vd_aux: u32,
471
    /// Offset to the next verdef entry, in bytes.
472
    pub vd_next: u32,
473
474
    bytes: &'a [u8],
475
    ctx: container::Ctx,
476
}
477
478
impl<'a> Verdef<'a> {
479
    /// Get an iterator over the [`Verdaux`] entries of this [`Verdef`] entry.
480
    #[inline]
481
0
    pub fn iter(&'a self) -> VerdauxIter<'a> {
482
0
        self.into_iter()
483
0
    }
484
}
485
486
impl<'a> IntoIterator for &'_ Verdef<'a> {
487
    type Item = <VerdauxIter<'a> as Iterator>::Item;
488
    type IntoIter = VerdauxIter<'a>;
489
490
0
    fn into_iter(self) -> Self::IntoIter {
491
0
        VerdauxIter {
492
0
            bytes: self.bytes,
493
0
            count: self.vd_cnt,
494
0
            index: 0,
495
0
            offset: 0,
496
0
            ctx: self.ctx,
497
0
        }
498
0
    }
499
}
500
501
/// Iterator over the [`Verdaux`] entries for an specific [`Verdef`] entry.
502
pub struct VerdauxIter<'a> {
503
    bytes: &'a [u8],
504
    count: u16,
505
    index: u16,
506
    offset: usize,
507
    ctx: container::Ctx,
508
}
509
510
impl<'a> Iterator for VerdauxIter<'a> {
511
    type Item = Verdaux;
512
513
0
    fn next(&mut self) -> Option<Self::Item> {
514
0
        if self.index >= self.count {
515
0
            None
516
        } else {
517
0
            self.index += 1;
518
519
0
            let do_next = |iter: &mut Self| {
520
0
                let ElfVerdaux { vda_name, vda_next } =
521
0
                    iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?;
522
523
                // Bump the offset to the next ElfVerdaux entry.
524
0
                iter.offset = iter.offset.checked_add(vda_next as usize)?;
525
526
                // Start yielding None on the next call if there is no next offset.
527
0
                if vda_next == 0 {
528
0
                    iter.index = iter.count;
529
0
                }
530
531
0
                Some(Verdaux {
532
0
                    vda_name: vda_name as usize,
533
0
                    vda_next,
534
0
                })
535
0
            };
536
537
0
            do_next(self).or_else(|| {
538
                // Adjust current index to count in case of an error.
539
0
                self.index = self.count;
540
0
                None
541
0
            })
542
        }
543
0
    }
544
545
    #[inline]
546
0
    fn size_hint(&self) -> (usize, Option<usize>) {
547
0
        let len = usize::from(self.count - self.index);
548
0
        (0, Some(len))
549
0
    }
550
}
551
552
impl ExactSizeIterator for VerdauxIter<'_> {}
553
554
impl FusedIterator for VerdauxIter<'_> {}
555
556
/// An ELF [Version Definition Auxiliary][lsb-verdaux] entry.
557
///
558
/// [lsb-verdaux]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERDEFEXTS
559
#[derive(Debug)]
560
pub struct Verdaux {
561
    /// Offset to the version or dependency name string in the section header, in bytes.
562
    pub vda_name: usize,
563
    /// Offset to the next verdaux entry, in bytes.
564
    pub vda_next: u32,
565
}
566
567
/**************************
568
 *  Version Requirements  *
569
 **************************/
570
571
/// Helper struct to iterate over [Version Needed][Verneed] and [Version Needed
572
/// Auxiliary][Vernaux] entries.
573
#[derive(Debug)]
574
pub struct VerneedSection<'a> {
575
    bytes: &'a [u8],
576
    count: usize,
577
    ctx: container::Ctx,
578
}
579
580
impl<'a> VerneedSection<'a> {
581
    /// Try to parse the optional [`SHT_GNU_VERNEED`] section.
582
592
    pub fn parse(
583
592
        bytes: &'a [u8],
584
592
        shdrs: &[SectionHeader],
585
592
        ctx: container::Ctx,
586
592
    ) -> Result<Option<VerneedSection<'a>>> {
587
        // Get fields needed from optional `version needed` section.
588
32
        let (offset, size, count) =
589
22.3k
            if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERNEED) {
590
32
                (
591
32
                    shdr.sh_offset as usize,
592
32
                    shdr.sh_size as usize,
593
32
                    shdr.sh_info as usize, // Encodes the number of ElfVerneed entries.
594
32
                )
595
            } else {
596
560
                return Ok(None);
597
            };
598
599
        // Get a slice of bytes of the `version needed` section content.
600
32
        let bytes: &'a [u8] = bytes.pread_with(offset, size)?;
601
602
30
        Ok(Some(VerneedSection { bytes, count, ctx }))
603
592
    }
604
605
    /// Get an iterator over the [`Verneed`] entries.
606
    #[inline]
607
0
    pub fn iter(&'a self) -> VerneedIter<'a> {
608
0
        self.into_iter()
609
0
    }
610
}
611
612
impl<'a> IntoIterator for &'_ VerneedSection<'a> {
613
    type Item = <VerneedIter<'a> as Iterator>::Item;
614
    type IntoIter = VerneedIter<'a>;
615
616
    #[inline]
617
0
    fn into_iter(self) -> Self::IntoIter {
618
0
        VerneedIter {
619
0
            bytes: self.bytes,
620
0
            count: self.count,
621
0
            index: 0,
622
0
            offset: 0,
623
0
            ctx: self.ctx,
624
0
        }
625
0
    }
626
}
627
628
/// Iterator over the [`Verneed`] entries from the [`SHT_GNU_VERNEED`] section.
629
pub struct VerneedIter<'a> {
630
    bytes: &'a [u8],
631
    count: usize,
632
    index: usize,
633
    offset: usize,
634
    ctx: container::Ctx,
635
}
636
637
impl<'a> Iterator for VerneedIter<'a> {
638
    type Item = Verneed<'a>;
639
640
0
    fn next(&mut self) -> Option<Self::Item> {
641
0
        if self.index >= self.count {
642
0
            None
643
        } else {
644
0
            self.index += 1;
645
646
0
            let do_next = |iter: &mut Self| {
647
                let ElfVerneed {
648
0
                    vn_version,
649
0
                    vn_cnt,
650
0
                    vn_file,
651
0
                    vn_aux,
652
0
                    vn_next,
653
0
                } = iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?;
654
655
                // Validate offset to first ElfVernaux entry.
656
0
                let offset = iter.offset.checked_add(vn_aux as usize)?;
657
658
                // Validate if offset is valid index into bytes slice.
659
0
                if offset >= iter.bytes.len() {
660
0
                    return None;
661
0
                }
662
663
                // Get a slice of bytes starting with the first ElfVernaux entry.
664
0
                let bytes: &'a [u8] = &iter.bytes[offset..];
665
666
                // Bump the offset to the next ElfVerneed entry.
667
0
                iter.offset = iter.offset.checked_add(vn_next as usize)?;
668
669
                // Start yielding None on the next call if there is no next offset.
670
0
                if vn_next == 0 {
671
0
                    iter.index = iter.count;
672
0
                }
673
674
0
                Some(Verneed {
675
0
                    vn_version,
676
0
                    vn_cnt,
677
0
                    vn_file: vn_file as usize,
678
0
                    vn_aux,
679
0
                    vn_next,
680
0
                    bytes,
681
0
                    ctx: iter.ctx,
682
0
                })
683
0
            };
684
685
0
            do_next(self).or_else(|| {
686
                // Adjust current index to count in case of an error.
687
0
                self.index = self.count;
688
0
                None
689
0
            })
690
        }
691
0
    }
692
693
    #[inline]
694
0
    fn size_hint(&self) -> (usize, Option<usize>) {
695
0
        let len = self.count - self.index;
696
0
        (0, Some(len))
697
0
    }
698
}
699
700
impl ExactSizeIterator for VerneedIter<'_> {}
701
702
impl FusedIterator for VerneedIter<'_> {}
703
704
/// An ELF [Version Need][lsb-verneed] entry .
705
///
706
/// [lsb-verneed]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDFIG
707
#[derive(Debug)]
708
pub struct Verneed<'a> {
709
    /// Version of structure. This value is currently set to 1, and will be reset if the versioning
710
    /// implementation is incompatibly altered.
711
    pub vn_version: u16,
712
    /// Number of associated verneed array entries.
713
    pub vn_cnt: u16,
714
    /// Offset to the file name string in the section header, in bytes.
715
    pub vn_file: usize,
716
    /// Offset to a corresponding entry in the vernaux array, in bytes.
717
    pub vn_aux: u32,
718
    /// Offset to the next verneed entry, in bytes.
719
    pub vn_next: u32,
720
721
    bytes: &'a [u8],
722
    ctx: container::Ctx,
723
}
724
725
impl<'a> Verneed<'a> {
726
    /// Get an iterator over the [`Vernaux`] entries of this [`Verneed`] entry.
727
    #[inline]
728
0
    pub fn iter(&'a self) -> VernauxIter<'a> {
729
0
        self.into_iter()
730
0
    }
731
}
732
733
impl<'a> IntoIterator for &'_ Verneed<'a> {
734
    type Item = <VernauxIter<'a> as Iterator>::Item;
735
    type IntoIter = VernauxIter<'a>;
736
737
    #[inline]
738
0
    fn into_iter(self) -> Self::IntoIter {
739
0
        VernauxIter {
740
0
            bytes: self.bytes,
741
0
            count: self.vn_cnt,
742
0
            index: 0,
743
0
            offset: 0,
744
0
            ctx: self.ctx,
745
0
        }
746
0
    }
747
}
748
749
/// Iterator over the [`Vernaux`] entries for an specific [`Verneed`] entry.
750
pub struct VernauxIter<'a> {
751
    bytes: &'a [u8],
752
    count: u16,
753
    index: u16,
754
    offset: usize,
755
    ctx: container::Ctx,
756
}
757
758
impl<'a> Iterator for VernauxIter<'a> {
759
    type Item = Vernaux;
760
761
0
    fn next(&mut self) -> Option<Self::Item> {
762
0
        if self.index >= self.count {
763
0
            None
764
        } else {
765
0
            self.index += 1;
766
767
0
            let do_next = |iter: &mut Self| {
768
                let ElfVernaux {
769
0
                    vna_hash,
770
0
                    vna_flags,
771
0
                    vna_other,
772
0
                    vna_name,
773
0
                    vna_next,
774
0
                } = iter.bytes.pread_with(iter.offset, iter.ctx.le).ok()?;
775
776
                // Bump the offset to the next ElfVernaux entry.
777
0
                iter.offset = iter.offset.checked_add(vna_next as usize)?;
778
779
                // Start yielding None on the next call if there is no next offset.
780
0
                if vna_next == 0 {
781
0
                    iter.index = iter.count;
782
0
                }
783
784
0
                Some(Vernaux {
785
0
                    vna_hash,
786
0
                    vna_flags,
787
0
                    vna_other,
788
0
                    vna_name: vna_name as usize,
789
0
                    vna_next,
790
0
                })
791
0
            };
792
793
0
            do_next(self).or_else(|| {
794
                // Adjust current index to count in case of an error.
795
0
                self.index = self.count;
796
0
                None
797
0
            })
798
        }
799
0
    }
800
801
    #[inline]
802
0
    fn size_hint(&self) -> (usize, Option<usize>) {
803
0
        let len = usize::from(self.count - self.index);
804
0
        (0, Some(len))
805
0
    }
806
}
807
808
impl ExactSizeIterator for VernauxIter<'_> {}
809
810
impl FusedIterator for VernauxIter<'_> {}
811
812
/// An ELF [Version Need Auxiliary][lsb-vernaux] entry.
813
///
814
/// [lsb-vernaux]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/symversion.html#VERNEEDEXTFIG
815
#[derive(Debug)]
816
pub struct Vernaux {
817
    /// Dependency name hash value (ELF hash function).
818
    pub vna_hash: u32,
819
    /// Dependency information flag bitmask.
820
    pub vna_flags: u16,
821
    /// Object file version identifier used in the .gnu.version symbol version array. Bit number 15
822
    /// controls whether or not the object is hidden; if this bit is set, the object cannot be used
823
    /// and the static linker will ignore the symbol's presence in the object.
824
    pub vna_other: u16,
825
    /// Offset to the dependency name string in the section header, in bytes.
826
    pub vna_name: usize,
827
    /// Offset to the next vernaux entry, in bytes.
828
    pub vna_next: u32,
829
}
830
831
#[cfg(test)]
832
mod test {
833
    use super::{ElfVerdaux, ElfVerdef, ElfVernaux, ElfVerneed, ElfVersym};
834
    use super::{VER_NDX_GLOBAL, VER_NDX_LOCAL, VERSYM_HIDDEN, Versym};
835
    use core::mem::size_of;
836
837
    #[test]
838
    fn check_size() {
839
        assert_eq!(2, size_of::<ElfVersym>());
840
        assert_eq!(20, size_of::<ElfVerdef>());
841
        assert_eq!(8, size_of::<ElfVerdaux>());
842
        assert_eq!(16, size_of::<ElfVerneed>());
843
        assert_eq!(16, size_of::<ElfVernaux>());
844
    }
845
846
    #[test]
847
    fn check_versym() {
848
        let local = Versym {
849
            vs_val: VER_NDX_LOCAL,
850
        };
851
        assert_eq!(true, local.is_local());
852
        assert_eq!(false, local.is_global());
853
        assert_eq!(false, local.is_hidden());
854
        assert_eq!(VER_NDX_LOCAL, local.version());
855
856
        let global = Versym {
857
            vs_val: VER_NDX_GLOBAL,
858
        };
859
        assert_eq!(false, global.is_local());
860
        assert_eq!(true, global.is_global());
861
        assert_eq!(false, global.is_hidden());
862
        assert_eq!(VER_NDX_GLOBAL, global.version());
863
864
        let hidden = Versym {
865
            vs_val: VERSYM_HIDDEN,
866
        };
867
        assert_eq!(false, hidden.is_local());
868
        assert_eq!(false, hidden.is_global());
869
        assert_eq!(true, hidden.is_hidden());
870
        assert_eq!(0, hidden.version());
871
872
        let hidden = Versym {
873
            vs_val: VERSYM_HIDDEN | 0x123,
874
        };
875
        assert_eq!(false, hidden.is_local());
876
        assert_eq!(false, hidden.is_global());
877
        assert_eq!(true, hidden.is_hidden());
878
        assert_eq!(0x123, hidden.version());
879
    }
880
}