LCOV - code coverage report
Current view: top level - src/elf - symbol_versioning.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 82.4 % 148 122
Test Date: 2026-04-12:00:00:00 Functions: 77.1 % 35 27

            Line data    Source code
       1              : use crate::common::{into_optional, FromFFI};
       2              : use crate::declare_iterator;
       3              : use lief_ffi as ffi;
       4              : use std::fmt;
       5              : use std::marker::PhantomData;
       6              : 
       7              : /// Structure which represents an entry defined in the `DT_VERSYM`
       8              : /// dynamic entry
       9              : pub struct SymbolVersion<'a> {
      10              :     ptr: cxx::UniquePtr<ffi::ELF_SymbolVersion>,
      11              :     _owner: PhantomData<&'a ffi::ELF_Binary>,
      12              : }
      13              : 
      14              : impl SymbolVersion<'_> {
      15              :     /// Value associated with the symbol
      16              :     ///
      17              :     /// If the given [`SymbolVersion`] doesn't have [`SymbolVersion::symbol_version_auxiliary`]:
      18              :     ///
      19              :     /// * `0` means **Local**
      20              :     /// * `1` means **Global**
      21        61178 :     pub fn value(&self) -> u16 {
      22        61178 :         self.ptr.value()
      23        61178 :     }
      24              : 
      25              :     /// SymbolVersionAux associated with the current Version if any.
      26        61178 :     pub fn symbol_version_auxiliary(&self) -> Option<SymbolVersionAux<'_>> {
      27        61178 :         into_optional(self.ptr.symbol_version_auxiliary())
      28        61178 :     }
      29              : 
      30              :     /// Drop the versioning requirement and replace the value (local/global)
      31            0 :     pub fn drop_version(&mut self, value: u16) {
      32            0 :         self.ptr.pin_mut().drop_version(value)
      33            0 :     }
      34              : 
      35              :     /// Redefine this version as local by dropping its auxiliary version
      36              :     ///
      37              :     /// See: [`SymbolVersion::as_global`], [`SymbolVersion::drop_version`]
      38            0 :     pub fn as_local(&mut self) {
      39            0 :         self.ptr.pin_mut().as_local()
      40            0 :     }
      41              : 
      42              :     /// Redefine this version as global by dropping its auxiliary version
      43              :     ///
      44              :     /// See: [`SymbolVersion::as_local`], [`SymbolVersion::drop_version`]
      45            0 :     pub fn as_global(&mut self) {
      46            0 :         self.ptr.pin_mut().as_global()
      47            0 :     }
      48              : }
      49              : 
      50              : impl fmt::Debug for SymbolVersion<'_> {
      51        61178 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
      52        61178 :         f.debug_struct("SymbolVersion")
      53        61178 :             .field("value", &self.value())
      54        61178 :             .field("symbol_version_auxiliary", &self.symbol_version_auxiliary())
      55        61178 :             .finish()
      56        61178 :     }
      57              : }
      58              : 
      59              : impl FromFFI<ffi::ELF_SymbolVersion> for SymbolVersion<'_> {
      60        61178 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersion>) -> Self {
      61        61178 :         Self {
      62        61178 :             ptr,
      63        61178 :             _owner: PhantomData,
      64        61178 :         }
      65        61178 :     }
      66              : }
      67              : 
      68              : pub struct SymbolVersionAux<'a> {
      69              :     ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAux>,
      70              :     _owner: PhantomData<&'a ()>,
      71              : }
      72              : 
      73              : impl SymbolVersionAux<'_> {
      74        33345 :     pub fn name(&self) -> String {
      75        33345 :         self.ptr.name().to_string()
      76        33345 :     }
      77              : }
      78              : 
      79              : impl fmt::Debug for SymbolVersionAux<'_> {
      80        33345 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
      81        33345 :         f.debug_struct("SymbolVersionAux")
      82        33345 :             .field("name", &self.name())
      83        33345 :             .finish()
      84        33345 :     }
      85              : }
      86              : 
      87              : impl FromFFI<ffi::ELF_SymbolVersionAux> for SymbolVersionAux<'_> {
      88        33345 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAux>) -> Self {
      89        33345 :         Self {
      90        33345 :             ptr,
      91        33345 :             _owner: PhantomData,
      92        33345 :         }
      93        33345 :     }
      94              : }
      95              : 
      96              : pub struct SymbolVersionAuxRequirement<'a> {
      97              :     ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAuxRequirement>,
      98              :     _owner: PhantomData<&'a ()>,
      99              : }
     100              : 
     101              : impl SymbolVersionAuxRequirement<'_> {
     102              :     /// Hash value of the dependency name (use ELF hashing function)
     103          650 :     pub fn hash(&self) -> u32 {
     104          650 :         self.ptr.hash()
     105          650 :     }
     106              :     /// Bitmask of flags
     107          650 :     pub fn flags(&self) -> u16 {
     108          650 :         self.ptr.flags()
     109          650 :     }
     110              : 
     111              :     /// It returns the unique version index for the file which is used in the
     112              :     /// version symbol table. If the highest bit (bit 15) is set this
     113              :     /// is a hidden symbol which cannot be referenced from outside the
     114              :     /// object.
     115          650 :     pub fn other(&self) -> u16 {
     116          650 :         self.ptr.other()
     117          650 :     }
     118              : 
     119              :     /// Symbol's aux name (e.g. `GLIBC_2.2.5`)
     120            0 :     pub fn name(&self) -> String {
     121            0 :         self.ptr.name().to_string()
     122            0 :     }
     123              : }
     124              : 
     125              : impl fmt::Debug for SymbolVersionAuxRequirement<'_> {
     126          650 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     127          650 :         f.debug_struct("SymbolVersionAuxRequirement")
     128          650 :             .field("hash", &self.hash())
     129          650 :             .field("flags", &self.flags())
     130          650 :             .field("other", &self.other())
     131          650 :             .finish()
     132          650 :     }
     133              : }
     134              : 
     135              : impl FromFFI<ffi::ELF_SymbolVersionAuxRequirement> for SymbolVersionAuxRequirement<'_> {
     136          650 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAuxRequirement>) -> Self {
     137          650 :         Self {
     138          650 :             ptr,
     139          650 :             _owner: PhantomData,
     140          650 :         }
     141          650 :     }
     142              : }
     143              : 
     144              : /// Structure which represents an entry defined in `DT_VERDEF` or `.gnu.version_d`
     145              : pub struct SymbolVersionDefinition<'a> {
     146              :     ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionDefinition>,
     147              :     _owner: PhantomData<&'a ()>,
     148              : }
     149              : 
     150              : impl SymbolVersionDefinition<'_> {
     151              :     /// Version revision
     152              :     ///
     153              :     /// This field should always have the value `1`. It will be changed
     154              :     /// if the versioning implementation has to be changed in an incompatible way.
     155           39 :     pub fn version(&self) -> u16 {
     156           39 :         self.ptr.version()
     157           39 :     }
     158              : 
     159              :     /// Version information
     160           39 :     pub fn flags(&self) -> u16 {
     161           39 :         self.ptr.flags()
     162           39 :     }
     163              : 
     164              :     /// Version index
     165              :     /// Numeric value used as an index in the [`SymbolVersion`] table
     166           39 :     pub fn ndx(&self) -> u16 {
     167           39 :         self.ptr.ndx()
     168           39 :     }
     169              : 
     170              :     /// Hash value of the symbol's name (using ELF hash function)
     171           39 :     pub fn hash(&self) -> u32 {
     172           39 :         self.ptr.hash()
     173           39 :     }
     174              : 
     175              :     /// Iterator over the [`SymbolVersionAux`] associated with this entry
     176           39 :     pub fn auxiliary_symbols(&self) -> DefAuxiliarySymbols<'_> {
     177           39 :         DefAuxiliarySymbols::new(self.ptr.sym_aux())
     178           39 :     }
     179              : }
     180              : 
     181              : impl fmt::Debug for SymbolVersionDefinition<'_> {
     182           39 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     183           39 :         f.debug_struct("SymbolVersionDefinition")
     184           39 :             .field("version", &self.version())
     185           39 :             .field("flags", &self.flags())
     186           39 :             .field("ndx", &self.ndx())
     187           39 :             .field("hash", &self.hash())
     188           39 :             .finish()
     189           39 :     }
     190              : }
     191              : 
     192              : impl FromFFI<ffi::ELF_SymbolVersionDefinition> for SymbolVersionDefinition<'_> {
     193           39 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionDefinition>) -> Self {
     194           39 :         Self {
     195           39 :             ptr,
     196           39 :             _owner: PhantomData,
     197           39 :         }
     198           39 :     }
     199              : }
     200              : 
     201              : /// Structure which represents an entry in the `DT_VERNEED` or `.gnu.version_r` table
     202              : pub struct SymbolVersionRequirement<'a> {
     203              :     ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionRequirement>,
     204              :     _owner: PhantomData<&'a ()>,
     205              : }
     206              : 
     207              : impl SymbolVersionRequirement<'_> {
     208              :     /// Version revision
     209              :     ///
     210              :     /// This field should always have the value `1`. It will be changed
     211              :     /// if the versioning implementation has to be changed in an incompatible way.
     212          221 :     pub fn version(&self) -> u16 {
     213          221 :         self.ptr.version()
     214          221 :     }
     215              : 
     216              :     /// Number of auxiliary entries
     217          221 :     pub fn cnt(&self) -> u32 {
     218          221 :         self.ptr.cnt()
     219          221 :     }
     220              : 
     221              :     /// Return the library name associated with this requirement (e.g. `libc.so.6`)
     222          221 :     pub fn name(&self) -> String {
     223          221 :         self.ptr.name().to_string()
     224          221 :     }
     225              : 
     226              :     /// Auxiliary entries as an iterator over [`SymbolVersionAuxRequirement`]
     227          221 :     pub fn auxiliary_symbols(&self) -> AuxiliarySymbols<'_> {
     228          221 :         AuxiliarySymbols::new(self.ptr.auxiliary_symbols())
     229          221 :     }
     230              : 
     231            0 :     pub fn set_name(&mut self, name: &str) {
     232            0 :         self.ptr.pin_mut().set_name(name.to_string());
     233            0 :     }
     234              : 
     235            0 :     pub fn set_version(&mut self, version: u16) {
     236            0 :         self.ptr.pin_mut().set_version(version);
     237            0 :     }
     238              : 
     239              :     /// Try to find the [`SymbolVersionAuxRequirement`] with the given name (e.g. `GLIBC_2.27`)
     240            0 :     pub fn find_aux(&self, name: &str) -> Option<SymbolVersionAuxRequirement<'_>> {
     241            0 :         into_optional(self.ptr.find_aux(name.to_string()))
     242            0 :     }
     243              : 
     244              :     /// Try to remove the auxiliary requirement symbol with the given name.
     245              :     /// The function returns true if the operation succeed, false otherwise.
     246              :     ///
     247              :     /// **warning**:
     248              :     ///
     249              :     /// This function invalidates all the references of
     250              :     /// [`SymbolVersionAuxRequirement`]. Therefore, the user is reponsible
     251              :     /// to ensure that the auxiliary requirement is no longer used in the
     252              :     /// ELF binary (e.g. in [`SymbolVersion`])
     253            0 :     pub fn remove_aux_requirement_by_name(&mut self, name: &str) -> bool {
     254            0 :         self.ptr
     255            0 :             .pin_mut()
     256            0 :             .remove_aux_requirement_by_name(name.to_string())
     257            0 :     }
     258              : }
     259              : 
     260              : impl fmt::Debug for SymbolVersionRequirement<'_> {
     261          221 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     262          221 :         f.debug_struct("SymbolVersionRequirement")
     263          221 :             .field("verison", &self.version())
     264          221 :             .field("cnt", &self.cnt())
     265          221 :             .field("name", &self.name())
     266          221 :             .finish()
     267          221 :     }
     268              : }
     269              : 
     270              : impl FromFFI<ffi::ELF_SymbolVersionRequirement> for SymbolVersionRequirement<'_> {
     271          221 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionRequirement>) -> Self {
     272          221 :         Self {
     273          221 :             ptr,
     274          221 :             _owner: PhantomData,
     275          221 :         }
     276          221 :     }
     277              : }
     278              : 
     279          650 : declare_iterator!(
     280          650 :     AuxiliarySymbols,
     281          650 :     SymbolVersionAuxRequirement<'a>,
     282          650 :     ffi::ELF_SymbolVersionAuxRequirement,
     283          650 :     ffi::ELF_SymbolVersionRequirement,
     284          650 :     ffi::ELF_SymbolVersionRequirement_it_auxiliary_symbols
     285          650 : );
     286           39 : declare_iterator!(
     287           39 :     DefAuxiliarySymbols,
     288           39 :     SymbolVersionAux<'a>,
     289           39 :     ffi::ELF_SymbolVersionAux,
     290           39 :     ffi::ELF_SymbolVersionDefinition,
     291           39 :     ffi::ELF_SymbolVersionDefinition_it_auxiliary_symbols
     292           39 : );
        

Generated by: LCOV version 2.1-1