LCOV - code coverage report
Current view: top level - src/assembly - instruction.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 0.0 % 155 0
Test Date: 2026-04-12:00:00:00 Functions: 0.0 % 60 0

            Line data    Source code
       1              : //! Module related to assembly instructions
       2              : 
       3              : use lief_ffi as ffi;
       4              : 
       5              : use bitflags::bitflags;
       6              : 
       7              : use crate::to_slice;
       8              : 
       9              : use crate::common::FromFFI;
      10              : use crate::to_conv_result;
      11              : use crate::Error;
      12              : 
      13              : use super::aarch64;
      14              : use super::arm;
      15              : use super::ebpf;
      16              : use super::mips;
      17              : use super::powerpc;
      18              : use super::riscv;
      19              : use super::x86;
      20              : 
      21            0 : bitflags! {
      22            0 :     #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
      23            0 :     pub struct MemoryAccess: u64 {
      24            0 :         const NONE = 0;
      25            0 :         const READ = 1 << 0;
      26            0 :         const WRITE = 1 << 1;
      27            0 :     }
      28            0 : }
      29              : 
      30              : /// This trait is shared by all [`Instructions`] supported by LIEF
      31              : pub trait Instruction {
      32              :     #[doc(hidden)]
      33              :     fn as_generic(&self) -> &ffi::asm_Instruction;
      34              : 
      35              :     /// Address of the instruction
      36            0 :     fn address(&self) -> u64 {
      37            0 :         self.as_generic().address()
      38            0 :     }
      39              : 
      40              :     /// Size of the instruction in bytes
      41            0 :     fn size(&self) -> u64 {
      42            0 :         self.as_generic().size()
      43            0 :     }
      44              : 
      45              :     /// Raw bytes of the current instruction
      46            0 :     fn raw(&self) -> &[u8] {
      47            0 :         to_slice!(self.as_generic().raw());
      48            0 :     }
      49              : 
      50              :     /// Instruction mnemonic (e.g. `br`)
      51            0 :     fn mnemonic(&self) -> String {
      52            0 :         self.as_generic().mnemonic().to_string()
      53            0 :     }
      54              : 
      55              :     /// Representation of the current instruction in a pretty assembly way
      56            0 :     fn to_string(&self) -> String {
      57            0 :         self.as_generic().to_string().to_string()
      58            0 :     }
      59              : 
      60              :     /// Same as [`Instruction::to_string`] but without the address as prefix
      61            0 :     fn to_string_no_address(&self) -> String {
      62            0 :         self.as_generic().to_string_no_address().to_string()
      63            0 :     }
      64              : 
      65              :     /// True if the instruction is a call
      66            0 :     fn is_call(&self) -> bool {
      67            0 :         self.as_generic().is_call()
      68            0 :     }
      69              : 
      70              :     /// True if the instruction marks the end of a basic block
      71            0 :     fn is_terminator(&self) -> bool {
      72            0 :         self.as_generic().is_terminator()
      73            0 :     }
      74              : 
      75              :     /// True if the instruction is a branch
      76            0 :     fn is_branch(&self) -> bool {
      77            0 :         self.as_generic().is_branch()
      78            0 :     }
      79              : 
      80              :     /// True if the instruction is a syscall
      81            0 :     fn is_syscall(&self) -> bool {
      82            0 :         self.as_generic().is_syscall()
      83            0 :     }
      84              : 
      85              :     /// True if the instruction performs a memory access
      86            0 :     fn is_memory_access(&self) -> bool {
      87            0 :         self.as_generic().is_memory_access()
      88            0 :     }
      89              : 
      90              :     /// True if the instruction is a register to register move.
      91            0 :     fn is_move_reg(&self) -> bool {
      92            0 :         self.as_generic().is_move_reg()
      93            0 :     }
      94              : 
      95              :     /// True if the instruction performs an arithmetic addition.
      96            0 :     fn is_add(&self) -> bool {
      97            0 :         self.as_generic().is_add()
      98            0 :     }
      99              : 
     100              :     /// True if the instruction is a trap.
     101              :     ///
     102              :     /// - On `x86/x86-64` this includes the `ud1/ud2` instructions
     103              :     /// - On `AArch64` this includes the `brk/udf` instructions
     104            0 :     fn is_trap(&self) -> bool {
     105            0 :         self.as_generic().is_trap()
     106            0 :     }
     107              : 
     108              :     /// True if the instruction prevents executing the instruction
     109              :     /// that immediatly follows the current. This includes return
     110              :     /// or unconditional branch instructions
     111            0 :     fn is_barrier(&self) -> bool {
     112            0 :         self.as_generic().is_barrier()
     113            0 :     }
     114              : 
     115              :     /// True if the instruction is a return
     116            0 :     fn is_return(&self) -> bool {
     117            0 :         self.as_generic().is_return()
     118            0 :     }
     119              : 
     120              :     /// True if the instruction is and indirect branch.
     121              :     ///
     122              :     /// This includes instructions that branch through a register (e.g. `jmp rax`,
     123              :     /// `br x1`).
     124            0 :     fn is_indirect_branch(&self) -> bool {
     125            0 :         self.as_generic().is_indirect_branch()
     126            0 :     }
     127              : 
     128              :     /// True if the instruction is **conditionally** jumping to the next
     129              :     /// instruction **or** an instruction into some other basic block.
     130            0 :     fn is_conditional_branch(&self) -> bool {
     131            0 :         self.as_generic().is_conditional_branch()
     132            0 :     }
     133              : 
     134              :     /// True if the instruction is jumping (**unconditionally**) to some other
     135              :     /// basic block.
     136            0 :     fn is_unconditional_branch(&self) -> bool {
     137            0 :         self.as_generic().is_unconditional_branch()
     138            0 :     }
     139              : 
     140              :     /// True if the instruction is a comparison
     141            0 :     fn is_compare(&self) -> bool {
     142            0 :         self.as_generic().is_compare()
     143            0 :     }
     144              : 
     145              :     /// True if the instruction is moving an immediate
     146            0 :     fn is_move_immediate(&self) -> bool {
     147            0 :         self.as_generic().is_move_immediate()
     148            0 :     }
     149              : 
     150              :     /// True if the instruction is doing a bitcast
     151            0 :     fn is_bitcast(&self) -> bool {
     152            0 :         self.as_generic().is_bitcast()
     153            0 :     }
     154              : 
     155              :     /// Memory access flags
     156            0 :     fn memory_access(&self) -> MemoryAccess {
     157            0 :         MemoryAccess::from_bits_truncate(self.as_generic().memory_access())
     158            0 :     }
     159              : 
     160              :     /// Given a [`Instruction::is_branch`] instruction, try to evaluate the address of the
     161              :     /// destination.
     162            0 :     fn branch_target(&self) -> Result<u64, Error> {
     163            0 :         to_conv_result!(
     164            0 :             ffi::asm_Instruction::branch_target,
     165            0 :             self.as_generic(),
     166            0 :             |value| value
     167              :         );
     168            0 :     }
     169              : }
     170              : 
     171              : /// All instruction variants supported by LIEF
     172              : pub enum Instructions {
     173              :     /// An AArch64 instruction
     174              :     AArch64(aarch64::Instruction),
     175              : 
     176              :     /// A x86/x86-64 instruction
     177              :     X86(x86::Instruction),
     178              : 
     179              :     /// An ARM/thumb instruction
     180              :     ARM(arm::Instruction),
     181              : 
     182              :     /// An eBPF instruction
     183              :     EBPF(ebpf::Instruction),
     184              : 
     185              :     /// A PowerPC (ppc64/ppc32) instruction
     186              :     PowerPC(powerpc::Instruction),
     187              : 
     188              :     /// A Mips (mips32/mips64) instruction
     189              :     Mips(mips::Instruction),
     190              : 
     191              :     /// A RISC-V (32 or 64 bit) instruction
     192              :     RiscV(riscv::Instruction),
     193              : 
     194              :     /// A generic instruction that doesn't have an extended structure
     195              :     Generic(Generic),
     196              : }
     197              : 
     198              : impl FromFFI<ffi::asm_Instruction> for Instructions {
     199            0 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::asm_Instruction>) -> Self {
     200            0 :         unsafe {
     201            0 :             let inst_ref = ptr.as_ref().unwrap();
     202            0 :             if ffi::asm_aarch64_Instruction::classof(inst_ref) {
     203            0 :                 let raw = {
     204            0 :                     type From = cxx::UniquePtr<ffi::asm_Instruction>;
     205            0 :                     type To = cxx::UniquePtr<ffi::asm_aarch64_Instruction>;
     206            0 :                     std::mem::transmute::<From, To>(ptr)
     207            0 :                 };
     208            0 :                 return Instructions::AArch64(aarch64::Instruction::from_ffi(raw));
     209            0 :             } else if ffi::asm_x86_Instruction::classof(inst_ref) {
     210            0 :                 let raw = {
     211            0 :                     type From = cxx::UniquePtr<ffi::asm_Instruction>;
     212            0 :                     type To = cxx::UniquePtr<ffi::asm_x86_Instruction>;
     213            0 :                     std::mem::transmute::<From, To>(ptr)
     214            0 :                 };
     215            0 :                 return Instructions::X86(x86::Instruction::from_ffi(raw));
     216            0 :             } else if ffi::asm_arm_Instruction::classof(inst_ref) {
     217            0 :                 let raw = {
     218            0 :                     type From = cxx::UniquePtr<ffi::asm_Instruction>;
     219            0 :                     type To = cxx::UniquePtr<ffi::asm_arm_Instruction>;
     220            0 :                     std::mem::transmute::<From, To>(ptr)
     221            0 :                 };
     222            0 :                 return Instructions::ARM(arm::Instruction::from_ffi(raw));
     223            0 :             } else if ffi::asm_mips_Instruction::classof(inst_ref) {
     224            0 :                 let raw = {
     225            0 :                     type From = cxx::UniquePtr<ffi::asm_Instruction>;
     226            0 :                     type To = cxx::UniquePtr<ffi::asm_mips_Instruction>;
     227            0 :                     std::mem::transmute::<From, To>(ptr)
     228            0 :                 };
     229            0 :                 return Instructions::Mips(mips::Instruction::from_ffi(raw));
     230            0 :             } else if ffi::asm_powerpc_Instruction::classof(inst_ref) {
     231            0 :                 let raw = {
     232            0 :                     type From = cxx::UniquePtr<ffi::asm_Instruction>;
     233            0 :                     type To = cxx::UniquePtr<ffi::asm_powerpc_Instruction>;
     234            0 :                     std::mem::transmute::<From, To>(ptr)
     235            0 :                 };
     236            0 :                 return Instructions::PowerPC(powerpc::Instruction::from_ffi(raw));
     237            0 :             } else if ffi::asm_riscv_Instruction::classof(inst_ref) {
     238            0 :                 let raw = {
     239            0 :                     type From = cxx::UniquePtr<ffi::asm_Instruction>;
     240            0 :                     type To = cxx::UniquePtr<ffi::asm_riscv_Instruction>;
     241            0 :                     std::mem::transmute::<From, To>(ptr)
     242            0 :                 };
     243            0 :                 return Instructions::RiscV(riscv::Instruction::from_ffi(raw));
     244            0 :             } else if ffi::asm_ebpf_Instruction::classof(inst_ref) {
     245            0 :                 let raw = {
     246            0 :                     type From = cxx::UniquePtr<ffi::asm_Instruction>;
     247            0 :                     type To = cxx::UniquePtr<ffi::asm_ebpf_Instruction>;
     248            0 :                     std::mem::transmute::<From, To>(ptr)
     249            0 :                 };
     250            0 :                 return Instructions::EBPF(ebpf::Instruction::from_ffi(raw));
     251            0 :             }
     252            0 :             Instructions::Generic(Generic::from_ffi(ptr))
     253              :         }
     254            0 :     }
     255              : }
     256              : 
     257              : impl Instruction for Instructions {
     258              :     #[doc(hidden)]
     259            0 :     fn as_generic(&self) -> &ffi::asm_Instruction {
     260            0 :         match &self {
     261            0 :             Instructions::Generic(inst) => inst.as_generic(),
     262            0 :             Instructions::AArch64(inst) => inst.as_generic(),
     263            0 :             Instructions::X86(inst) => inst.as_generic(),
     264            0 :             Instructions::ARM(inst) => inst.as_generic(),
     265            0 :             Instructions::Mips(inst) => inst.as_generic(),
     266            0 :             Instructions::PowerPC(inst) => inst.as_generic(),
     267            0 :             Instructions::EBPF(inst) => inst.as_generic(),
     268            0 :             Instructions::RiscV(inst) => inst.as_generic(),
     269              :         }
     270            0 :     }
     271              : }
     272              : 
     273              : /// Generic Instruction
     274              : pub struct Generic {
     275              :     ptr: cxx::UniquePtr<ffi::asm_Instruction>,
     276              : }
     277              : 
     278              : impl FromFFI<ffi::asm_Instruction> for Generic {
     279            0 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::asm_Instruction>) -> Self {
     280            0 :         Self { ptr }
     281            0 :     }
     282              : }
     283              : 
     284              : impl Instruction for Generic {
     285              :     #[doc(hidden)]
     286            0 :     fn as_generic(&self) -> &ffi::asm_Instruction {
     287            0 :         self.ptr.as_ref().unwrap()
     288            0 :     }
     289              : }
        

Generated by: LCOV version 2.1-1