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

Generated by: LCOV version 2.1-1