LCOV - code coverage report
Current view: top level - src - generic.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 47.5 % 200 95
Test Date: 2025-10-27:00:00:00 Functions: 37.3 % 158 59

            Line data    Source code
       1              : use lief_ffi as ffi;
       2              : use bitflags::bitflags;
       3              : use crate::{to_slice, declare_fwd_iterator, to_opt_trait};
       4              : use crate::common::{into_optional, FromFFI};
       5              : use crate::assembly::{Instructions, AssemblerConfig};
       6              : 
       7              : use std::pin::Pin;
       8              : 
       9              : /// Trait shared by all the symbols in executable formats
      10              : pub trait Symbol {
      11              :     #[doc(hidden)]
      12              :     fn as_generic(&self) -> &ffi::AbstractSymbol;
      13              : 
      14              :     #[doc(hidden)]
      15              :     fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractSymbol>;
      16              : 
      17              :     /// Symbol's name
      18      1949100 :     fn name(&self) -> String {
      19      1949100 :         self.as_generic().name().to_string()
      20      1949100 :     }
      21              :     /// Symbol's value whose interpretation depends on the symbol's kind.
      22              :     /// Usually this is the address of the symbol though.
      23      1018608 :     fn value(&self) -> u64 {
      24      1018608 :         self.as_generic().value()
      25      1018608 :     }
      26              :     /// Size of the symbol (can be 0)
      27      1018608 :     fn size(&self) -> u64 {
      28      1018608 :         self.as_generic().size()
      29      1018608 :     }
      30              : 
      31            0 :     fn set_name(&mut self, name: &str) {
      32            0 :         self.as_pin_mut_generic().set_name(name.to_string());
      33            0 :     }
      34              : 
      35            0 :     fn set_value(&mut self, value: u64) {
      36            0 :         self.as_pin_mut_generic().set_value(value);
      37            0 :     }
      38              : 
      39            0 :     fn set_size(&mut self, size: u64) {
      40            0 :         self.as_pin_mut_generic().set_size(size);
      41            0 :     }
      42              : }
      43              : 
      44              : impl std::fmt::Debug for &dyn Symbol {
      45      1009284 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      46      1009284 :         f.debug_struct("Symbol")
      47      1009284 :             .field("name", &self.name())
      48      1009284 :             .field("value", &self.value())
      49      1009284 :             .field("size", &self.size())
      50      1009284 :             .finish()
      51      1009284 :     }
      52              : }
      53              : 
      54              : /// Trait shared by all the sections in executable formats
      55              : pub trait Section {
      56              :     #[doc(hidden)]
      57              :     fn as_generic(&self) -> &ffi::AbstractSection;
      58              : 
      59              :     /// Name of the section
      60       304608 :     fn name(&self) -> String {
      61       304608 :         self.as_generic().name().to_string()
      62       304608 :     }
      63              : 
      64              :     /// Size of the section **in the file**
      65       291120 :     fn size(&self) -> u64 {
      66       291120 :         self.as_generic().size()
      67       291120 :     }
      68              : 
      69              :     /// Offset of the section **in the file**
      70       291036 :     fn offset(&self) -> u64 {
      71       291036 :         self.as_generic().offset()
      72       291036 :     }
      73              : 
      74              :     /// Address of the section **in memory**
      75       291036 :     fn virtual_address(&self) -> u64 {
      76       291036 :         self.as_generic().virtual_address()
      77       291036 :     }
      78              : 
      79              :     /// Content of the section
      80            0 :     fn content(&self) -> &[u8] {
      81            0 :         to_slice!(self.as_generic().content());
      82            0 :     }
      83              : }
      84              : 
      85              : impl std::fmt::Debug for &dyn Section {
      86       288648 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      87       288648 :         f.debug_struct("Section")
      88       288648 :             .field("name", &self.name())
      89       288648 :             .field("size", &self.size())
      90       288648 :             .field("offset", &self.offset())
      91       288648 :             .field("virtual_address", &self.virtual_address())
      92       288648 :             .finish()
      93       288648 :     }
      94              : }
      95              : 
      96              : pub trait Relocation {
      97              :     #[doc(hidden)]
      98              :     fn as_generic(&self) -> &ffi::AbstractRelocation;
      99              : 
     100              :     /// Address where the relocation should take place
     101      2728104 :     fn address(&self) -> u64 {
     102      2728104 :         self.as_generic().address()
     103      2728104 :     }
     104              : 
     105              :     /// Size of the relocation
     106      2728104 :     fn size(&self) -> u64 {
     107      2728104 :         self.as_generic().size()
     108      2728104 :     }
     109              : }
     110              : 
     111              : impl std::fmt::Debug for &dyn Relocation {
     112      2728104 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     113      2728104 :         f.debug_struct("Relocation")
     114      2728104 :             .field("address", &self.address())
     115      2728104 :             .field("size", &self.size())
     116      2728104 :             .finish()
     117      2728104 :     }
     118              : }
     119              : 
     120              : /// Generic interface representing a binary executable.
     121              : ///
     122              : /// This trait provides a unified interface across multiple binary formats
     123              : /// such as ELF, PE, Mach-O, and others. It enables users to access binary
     124              : /// components like headers, sections, symbols, relocations,
     125              : /// and functions in a format-agnostic way.
     126              : pub trait Binary {
     127              :     #[doc(hidden)]
     128              :     fn as_generic(&self) -> &ffi::AbstractBinary;
     129              : 
     130              :     #[doc(hidden)]
     131              :     fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary>;
     132              : 
     133              :     /// Binary's entrypoint
     134           51 :     fn entrypoint(&self) -> u64 {
     135           51 :         self.as_generic().entrypoint()
     136           51 :     }
     137              : 
     138              :     /// Default base address where the binary should be mapped
     139            8 :     fn imagebase(&self) -> u64 {
     140            8 :         self.as_generic().imagebase()
     141            8 :     }
     142              : 
     143              :     /// Size of the binary when mapped in memory
     144            0 :     fn virtual_size(&self) -> u64 {
     145            0 :         self.as_generic().virtual_size()
     146            0 :     }
     147              : 
     148              :     /// Whether the current binary is **an executable** and **position independent**
     149            8 :     fn is_pie(&self) -> bool {
     150            8 :         self.as_generic().is_pie()
     151            8 :     }
     152              : 
     153              :     /// Whether the binary defines a non-executable stack
     154            8 :     fn has_nx(&self) -> bool {
     155            8 :         self.as_generic().has_nx()
     156            8 :     }
     157              : 
     158              :     /// Original file size of the binary
     159            8 :     fn original_size(&self) -> u64 {
     160            8 :         self.as_generic().original_size()
     161            8 :     }
     162              : 
     163              :     /// Return the debug info if present. It can be either a
     164              :     /// [`crate::pdb::DebugInfo`] or [`crate::dwarf::DebugInfo`].
     165              :     ///
     166              :     /// For ELF and Mach-O binaries, it returns the given DebugInfo object **only**
     167              :     /// if the binary embeds the DWARF debug info in the binary itself.
     168              :     ///
     169              :     /// For PE file, this function tries to find the **external** PDB using
     170              :     /// the [`crate::pe::debug::CodeViewPDB::filename`] output (if present). One can also
     171              :     /// use [`crate::pdb::load`] or [`crate::pdb::DebugInfo::from`] to get PDB debug
     172              :     /// info.
     173              :     ///
     174              :     /// <div class="warning">
     175              :     /// This function requires LIEF's extended version otherwise it always return `None`
     176              :     /// </div>
     177            0 :     fn debug_info(&self) -> Option<crate::DebugInfo> {
     178            0 :         into_optional(self.as_generic().debug_info())
     179            0 :     }
     180              : 
     181              :     /// Disassemble code starting at the given virtual address and with the given
     182              :     /// size.
     183              :     ///
     184              :     /// ```
     185              :     /// let insts = binary.disassemble(0xacde, 100);
     186              :     /// for inst in insts {
     187              :     ///     println!("{}", inst.to_string());
     188              :     /// }
     189              :     /// ```
     190              :     ///
     191              :     /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
     192            0 :     fn disassemble(&self, address: u64, size: u64) -> InstructionsIt {
     193            0 :         InstructionsIt::new(self.as_generic().disassemble(address, size))
     194            0 :     }
     195              : 
     196              :     /// Disassemble code for the given symbol name
     197              :     ///
     198              :     /// ```
     199              :     /// let insts = binary.disassemble_symbol("__libc_start_main");
     200              :     /// for inst in insts {
     201              :     ///     println!("{}", inst.to_string());
     202              :     /// }
     203              :     /// ```
     204              :     ///
     205              :     /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
     206            0 :     fn disassemble_symbol(&self, name: &str) -> InstructionsIt {
     207            0 :         InstructionsIt::new(self.as_generic().disassemble_function(name.to_string()))
     208            0 :     }
     209              : 
     210              :     /// Disassemble code at the given virtual address
     211              :     ///
     212              :     /// ```
     213              :     /// let insts = binary.disassemble_address(0xacde);
     214              :     /// for inst in insts {
     215              :     ///     println!("{}", inst.to_string());
     216              :     /// }
     217              :     /// ```
     218              :     ///
     219              :     /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
     220            0 :     fn disassemble_address(&self, address: u64) -> InstructionsIt {
     221            0 :         InstructionsIt::new(self.as_generic().disassemble_address(address))
     222            0 :     }
     223              : 
     224              :     /// Disassemble code provided by the given slice at the specified `address` parameter.
     225              :     ///
     226              :     /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
     227            0 :     fn disassemble_slice(&self, slice: &[u8], address: u64) -> InstructionsIt {
     228            0 :         unsafe {
     229            0 :             InstructionsIt::new(self.as_generic().disassemble_buffer(
     230            0 :                     slice.as_ptr(), slice.len().try_into().unwrap(),
     231            0 :                     address))
     232            0 :         }
     233            0 :     }
     234              : 
     235              :     /// Assemble **and patch** the provided assembly code at the specified address.
     236              :     ///
     237              :     /// The generated assembly is returned by the function
     238              :     ///
     239              :     /// ```
     240              :     /// let mut bin = get_binary();
     241              :     ///
     242              :     /// let Vec<u8> bytes = bin.assemble(0x12000440, r#"
     243              :     ///     xor rax, rbx;
     244              :     ///     mov rcx, rax;
     245              :     /// "#);
     246              :     /// ```
     247            0 :     fn assemble(&mut self, address: u64, asm: &str) -> Vec<u8> {
     248            0 :         Vec::from(self.as_pin_mut_generic().assemble(address, asm).as_slice())
     249            0 :     }
     250              : 
     251              :     /// Same as [`Binary::assemble`] but this function takes an extra [`AssemblerConfig`] that
     252              :     /// is used to configure the assembly engine: dialect, symbols definitions.
     253            0 :     fn assemble_with_config(&mut self, address: u64, asm: &str, config: &AssemblerConfig) -> Vec<u8> {
     254            0 :         let ffi_config = config.into_ffi();
     255            0 :         Vec::from(self.as_pin_mut_generic().assemble_with_config(address, asm, ffi_config.as_ref()).as_slice())
     256            0 :     }
     257              : 
     258              :     /// Get the default memory page size according to the architecture and the format of the
     259              :     /// current binary
     260            0 :     fn page_size(&self) -> u64 {
     261            0 :         self.as_generic().page_size()
     262            0 :     }
     263              : 
     264              :     /// Load and associate an external debug file (e.g., DWARF or PDB) with this binary.
     265              :     ///
     266              :     /// This method attempts to load the debug information from the file located at the given path,
     267              :     /// and binds it to the current binary instance. If successful, it returns the
     268              :     /// loaded [`crate::DebugInfo`] object.
     269              :     ///
     270              :     /// <div class="warning">
     271              :     /// It is the caller's responsibility to ensure that the debug file is
     272              :     /// compatible with the binary. Incorrect associations may lead to
     273              :     /// inconsistent or invalid results.
     274              :     /// </div>
     275              :     ///
     276              :     /// <div class="note">
     277              :     /// This function does not verify that the debug file matches the binary's unique
     278              :     /// identifier (e.g., build ID, GUID).
     279              :     /// </div>
     280            0 :     fn load_debug_info(&mut self, path: &std::path::Path) -> Option<crate::DebugInfo> {
     281            0 :         into_optional(self.as_pin_mut_generic().load_debug_info(path.to_str().unwrap()))
     282            0 :     }
     283              : }
     284              : 
     285              : /// This class provides a generic interface for accessing debug information
     286              : /// from different formats such as DWARF and PDB.
     287              : ///
     288              : /// Users can use this interface to access high-level debug features like
     289              : /// resolving function addresses.
     290              : ///
     291              : /// See: [`crate::pdb::DebugInfo`], [`crate::dwarf::DebugInfo`]
     292              : pub trait DebugInfo {
     293              :     #[doc(hidden)]
     294              :     fn as_generic(&self) -> &ffi::AbstracDebugInfo;
     295              : 
     296              :     /// Attempt to resolve the address of the function specified by `name`.
     297            0 :     fn find_function_address(&self, name: &str) -> Option<u64> {
     298            0 :         to_opt_trait!(
     299            0 :             &lief_ffi::AbstracDebugInfo::find_function_address,
     300            0 :             self.as_generic(),
     301            0 :             name
     302            0 :         );
     303            0 :     }
     304              : }
     305              : 
     306            0 : bitflags! {
     307            0 :     /// Flags used to characterize the semantics of the function
     308       868788 :     #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
     309            0 :     pub struct FunctionFlags: u32 {
     310            0 :         const NONE = 0x0;
     311            0 :         /// The function acts as constructor.
     312            0 :         ///
     313            0 :         /// Usually this flag is associated with functions
     314            0 :         /// that are located in the `.init_array`, `__mod_init_func` or `.tls` sections
     315            0 :         const CONSTRUCTOR = 0x1;
     316            0 : 
     317            0 :         /// The function acts as a destructor.
     318            0 :         ///
     319            0 :         /// Usually this flag is associated with functions
     320            0 :         /// that are located in the `.fini_array` or `__mod_term_func` sections
     321            0 :         const DESTRUCTOR = 0x2;
     322            0 : 
     323            0 :         /// The function is associated with Debug information
     324            0 :         const DEBUG_INFO = 0x4;
     325            0 : 
     326            0 :         /// The function is exported by the binary and the [`Function::address`]
     327            0 :         /// returns its virtual address in the binary
     328            0 :         const EXPORTED = 0x8;
     329            0 : 
     330            0 :         /// The function is **imported** by the binary and the [`Function::address`]
     331            0 :         /// should return 0
     332            0 :         const IMPORTED = 0x10;
     333            0 :     }
     334            0 : }
     335              : 
     336              : 
     337              : impl From<u32> for FunctionFlags {
     338       868788 :     fn from(value: u32) -> Self {
     339       868788 :         FunctionFlags::from_bits_truncate(value)
     340       868788 :     }
     341              : }
     342              : 
     343              : impl From<FunctionFlags> for u32 {
     344            0 :     fn from(value: FunctionFlags) -> Self {
     345            0 :         value.bits()
     346            0 :     }
     347              : }
     348              : 
     349              : impl std::fmt::Display for FunctionFlags {
     350            0 :     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
     351            0 :         bitflags::parser::to_writer(self, f)
     352            0 :     }
     353              : }
     354              : 
     355              : /// Structure that represents a binary's function
     356              : pub struct Function {
     357              :     ptr: cxx::UniquePtr<ffi::AbstractFunction>,
     358              : }
     359              : 
     360              : impl FromFFI<ffi::AbstractFunction> for Function {
     361       868788 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::AbstractFunction>) -> Self {
     362       868788 :         Self {
     363       868788 :             ptr,
     364       868788 :         }
     365       868788 :     }
     366              : }
     367              : 
     368              : impl Symbol for Function {
     369       868788 :     fn as_generic(&self) -> &lief_ffi::AbstractSymbol {
     370       868788 :         self.ptr.as_ref().unwrap().as_ref()
     371       868788 :     }
     372              : 
     373            0 :     fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractSymbol> {
     374            0 :         unsafe {
     375            0 :             Pin::new_unchecked({
     376            0 :                 (self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractSymbol
     377            0 :                     as *mut ffi::AbstractSymbol)
     378            0 :                     .as_mut()
     379            0 :                     .unwrap()
     380            0 :             })
     381            0 :         }
     382            0 :     }
     383              : }
     384              : 
     385              : impl Function {
     386              :     /// Flags characterizing the semantics of the function
     387       868788 :     pub fn flags(&self) -> FunctionFlags {
     388       868788 :         FunctionFlags::from(self.ptr.flags())
     389       868788 :     }
     390              : 
     391              :     /// Address of the function (if not imported)
     392       868788 :     pub fn address(&self) -> u64 {
     393       868788 :         self.ptr.address()
     394       868788 :     }
     395              : }
     396              : 
     397              : impl std::fmt::Debug for Function {
     398       868788 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     399       868788 :         f.debug_struct("Function")
     400       868788 :             .field("name", &self.name())
     401       868788 :             .field("address", &self.address())
     402       868788 :             .field("flags", &self.flags())
     403       868788 :             .finish()
     404       868788 :     }
     405              : }
     406              : 
     407       868788 : declare_fwd_iterator!(
     408       868788 :     Functions,
     409       868788 :     Function,
     410       868788 :     ffi::AbstractFunction,
     411       868788 :     ffi::AbstractBinary,
     412       868788 :     ffi::AbstractBinary_it_functions
     413       868788 : );
     414              : 
     415            0 : declare_fwd_iterator!(
     416            0 :     InstructionsIt,
     417            0 :     Instructions,
     418            0 :     ffi::asm_Instruction,
     419            0 :     ffi::AbstractBinary,
     420            0 :     ffi::AbstractBinary_it_instructions
     421            0 : );
        

Generated by: LCOV version 2.1-1