LCOV - code coverage report
Current view: top level - src - generic.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 43.8 % 233 102
Test Date: 2026-04-12:00:00:00 Functions: 34.1 % 179 61

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

Generated by: LCOV version 2.1-1