use lief_ffi as ffi;
use bitflags::bitflags;
use crate::to_slice;
use crate::Error;
use crate::common::FromFFI;
use crate::to_conv_result;
use super::aarch64;
use super::arm;
use super::ebpf;
use super::mips;
use super::powerpc;
use super::riscv;
use super::x86;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MemoryAccess: u64 {
const NONE = 0;
const READ = 1 << 0;
const WRITE = 1 << 1;
}
}
pub trait Instruction: std::fmt::Display {
#[doc(hidden)]
fn as_generic(&self) -> &ffi::asm_Instruction;
fn address(&self) -> u64 {
self.as_generic().address()
}
fn size(&self) -> u64 {
self.as_generic().size()
}
fn raw(&self) -> &[u8] {
to_slice!(self.as_generic().raw());
}
fn mnemonic(&self) -> String {
self.as_generic().mnemonic().to_string()
}
fn to_string_no_address(&self) -> String {
self.as_generic().to_string_no_address().to_string()
}
fn is_call(&self) -> bool {
self.as_generic().is_call()
}
fn is_terminator(&self) -> bool {
self.as_generic().is_terminator()
}
fn is_branch(&self) -> bool {
self.as_generic().is_branch()
}
fn is_syscall(&self) -> bool {
self.as_generic().is_syscall()
}
fn is_memory_access(&self) -> bool {
self.as_generic().is_memory_access()
}
fn is_move_reg(&self) -> bool {
self.as_generic().is_move_reg()
}
fn is_add(&self) -> bool {
self.as_generic().is_add()
}
fn is_trap(&self) -> bool {
self.as_generic().is_trap()
}
fn is_barrier(&self) -> bool {
self.as_generic().is_barrier()
}
fn is_return(&self) -> bool {
self.as_generic().is_return()
}
fn is_indirect_branch(&self) -> bool {
self.as_generic().is_indirect_branch()
}
fn is_conditional_branch(&self) -> bool {
self.as_generic().is_conditional_branch()
}
fn is_unconditional_branch(&self) -> bool {
self.as_generic().is_unconditional_branch()
}
fn is_compare(&self) -> bool {
self.as_generic().is_compare()
}
fn is_move_immediate(&self) -> bool {
self.as_generic().is_move_immediate()
}
fn is_bitcast(&self) -> bool {
self.as_generic().is_bitcast()
}
fn memory_access(&self) -> MemoryAccess {
MemoryAccess::from_bits_truncate(self.as_generic().memory_access())
}
fn branch_target(&self) -> Result<u64, Error> {
to_conv_result!(
ffi::asm_Instruction::branch_target,
self.as_generic(),
|value| value
);
}
}
pub enum Instructions {
AArch64(aarch64::Instruction),
X86(x86::Instruction),
ARM(arm::Instruction),
EBPF(ebpf::Instruction),
PowerPC(powerpc::Instruction),
Mips(mips::Instruction),
RiscV(riscv::Instruction),
Generic(Generic),
}
impl FromFFI<ffi::asm_Instruction> for Instructions {
fn from_ffi(ptr: cxx::UniquePtr<ffi::asm_Instruction>) -> Self {
unsafe {
let inst_ref = ptr.as_ref().unwrap();
if ffi::asm_aarch64_Instruction::classof(inst_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::asm_Instruction>;
type To = cxx::UniquePtr<ffi::asm_aarch64_Instruction>;
std::mem::transmute::<From, To>(ptr)
};
return Instructions::AArch64(aarch64::Instruction::from_ffi(raw));
} else if ffi::asm_x86_Instruction::classof(inst_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::asm_Instruction>;
type To = cxx::UniquePtr<ffi::asm_x86_Instruction>;
std::mem::transmute::<From, To>(ptr)
};
return Instructions::X86(x86::Instruction::from_ffi(raw));
} else if ffi::asm_arm_Instruction::classof(inst_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::asm_Instruction>;
type To = cxx::UniquePtr<ffi::asm_arm_Instruction>;
std::mem::transmute::<From, To>(ptr)
};
return Instructions::ARM(arm::Instruction::from_ffi(raw));
} else if ffi::asm_mips_Instruction::classof(inst_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::asm_Instruction>;
type To = cxx::UniquePtr<ffi::asm_mips_Instruction>;
std::mem::transmute::<From, To>(ptr)
};
return Instructions::Mips(mips::Instruction::from_ffi(raw));
} else if ffi::asm_powerpc_Instruction::classof(inst_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::asm_Instruction>;
type To = cxx::UniquePtr<ffi::asm_powerpc_Instruction>;
std::mem::transmute::<From, To>(ptr)
};
return Instructions::PowerPC(powerpc::Instruction::from_ffi(raw));
} else if ffi::asm_riscv_Instruction::classof(inst_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::asm_Instruction>;
type To = cxx::UniquePtr<ffi::asm_riscv_Instruction>;
std::mem::transmute::<From, To>(ptr)
};
return Instructions::RiscV(riscv::Instruction::from_ffi(raw));
} else if ffi::asm_ebpf_Instruction::classof(inst_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::asm_Instruction>;
type To = cxx::UniquePtr<ffi::asm_ebpf_Instruction>;
std::mem::transmute::<From, To>(ptr)
};
return Instructions::EBPF(ebpf::Instruction::from_ffi(raw));
}
Instructions::Generic(Generic::from_ffi(ptr))
}
}
}
impl Instruction for Instructions {
#[doc(hidden)]
fn as_generic(&self) -> &ffi::asm_Instruction {
match &self {
Instructions::Generic(inst) => inst.as_generic(),
Instructions::AArch64(inst) => inst.as_generic(),
Instructions::X86(inst) => inst.as_generic(),
Instructions::ARM(inst) => inst.as_generic(),
Instructions::Mips(inst) => inst.as_generic(),
Instructions::PowerPC(inst) => inst.as_generic(),
Instructions::EBPF(inst) => inst.as_generic(),
Instructions::RiscV(inst) => inst.as_generic(),
}
}
}
impl std::fmt::Display for Instructions {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.as_generic().to_string())
}
}
pub struct Generic {
ptr: cxx::UniquePtr<ffi::asm_Instruction>,
}
impl FromFFI<ffi::asm_Instruction> for Generic {
fn from_ffi(ptr: cxx::UniquePtr<ffi::asm_Instruction>) -> Self {
Self { ptr }
}
}
impl Instruction for Generic {
#[doc(hidden)]
fn as_generic(&self) -> &ffi::asm_Instruction {
self.ptr.as_ref().unwrap()
}
}
impl std::fmt::Display for Generic {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.as_generic().to_string())
}
}