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 : }
|