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