LCOV - code coverage report
Current view: top level - src/elf - symbol_versioning.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 83.6 % 146 122
Test Date: 2025-06-29:00:00:00 Functions: 77.1 % 35 27

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

Generated by: LCOV version 2.1-1