binaryninja/low_level_il/
function.rs1use std::fmt::Debug;
16use std::hash::{Hash, Hasher};
17use std::marker::PhantomData;
18
19use binaryninjacore_sys::*;
20
21use crate::architecture::{CoreArchitecture, CoreFlag};
22use crate::basic_block::BasicBlock;
23use crate::function::Function;
24use crate::low_level_il::block::LowLevelILBlock;
25use crate::rc::*;
26use crate::variable::RegisterValue;
27
28use super::*;
29
30#[derive(Copy, Clone, Debug)]
31pub struct Mutable;
32#[derive(Copy, Clone, Debug)]
33pub struct Finalized;
34
35pub trait FunctionMutability: 'static + Debug + Copy {}
36impl FunctionMutability for Mutable {}
37impl FunctionMutability for Finalized {}
38
39#[derive(Copy, Clone, Debug)]
40pub struct SSA;
41#[derive(Copy, Clone, Debug)]
42pub struct NonSSA;
43
44pub trait FunctionForm: 'static + Debug + Copy {}
45impl FunctionForm for SSA {}
46impl FunctionForm for NonSSA {}
47
48pub struct LowLevelILFunction<M: FunctionMutability, F: FunctionForm> {
49 pub(crate) handle: *mut BNLowLevelILFunction,
50 arch: Option<CoreArchitecture>,
51 _mutability: PhantomData<M>,
52 _form: PhantomData<F>,
53}
54
55impl<M, F> LowLevelILFunction<M, F>
56where
57 M: FunctionMutability,
58 F: FunctionForm,
59{
60 pub(crate) unsafe fn from_raw_with_arch(
61 handle: *mut BNLowLevelILFunction,
62 arch: Option<CoreArchitecture>,
63 ) -> Self {
64 debug_assert!(!handle.is_null());
65
66 Self {
67 handle,
68 arch,
69 _mutability: PhantomData,
70 _form: PhantomData,
71 }
72 }
73
74 pub unsafe fn from_raw(handle: *mut BNLowLevelILFunction) -> Self {
75 Self::from_raw_with_arch(handle, None)
76 }
77
78 pub(crate) unsafe fn ref_from_raw_with_arch(
79 handle: *mut BNLowLevelILFunction,
80 arch: Option<CoreArchitecture>,
81 ) -> Ref<Self> {
82 debug_assert!(!handle.is_null());
83 Ref::new(Self::from_raw_with_arch(handle, arch))
84 }
85
86 pub(crate) unsafe fn ref_from_raw(handle: *mut BNLowLevelILFunction) -> Ref<Self> {
87 Self::ref_from_raw_with_arch(handle, None)
88 }
89
90 pub(crate) fn arch(&self) -> CoreArchitecture {
91 match self.arch {
93 None => self.function().unwrap().arch(),
94 Some(arch) => arch,
95 }
96 }
97
98 pub fn instruction_at<L: Into<Location>>(
99 &self,
100 loc: L,
101 ) -> Option<LowLevelILInstruction<'_, M, F>> {
102 Some(LowLevelILInstruction::new(
103 self,
104 self.instruction_index_at(loc)?,
105 ))
106 }
107
108 pub fn instructions_at<L: Into<Location>>(
110 &self,
111 loc: L,
112 ) -> Vec<LowLevelILInstruction<'_, M, F>> {
113 let loc = loc.into();
114 self.instruction_indexes_at(loc)
115 .iter()
116 .map(|idx| LowLevelILInstruction::new(self, idx))
117 .collect()
118 }
119
120 pub fn instruction_index_at<L: Into<Location>>(
121 &self,
122 loc: L,
123 ) -> Option<LowLevelInstructionIndex> {
124 use binaryninjacore_sys::BNLowLevelILGetInstructionStart;
125 let loc: Location = loc.into();
126 let arch = loc.arch.unwrap_or_else(|| self.arch());
128 let instr_idx =
129 unsafe { BNLowLevelILGetInstructionStart(self.handle, arch.handle, loc.addr) };
130 if instr_idx >= self.instruction_count() {
132 None
133 } else {
134 Some(LowLevelInstructionIndex(instr_idx))
135 }
136 }
137
138 pub fn instruction_indexes_at<L: Into<Location>>(
139 &self,
140 loc: L,
141 ) -> Array<LowLevelInstructionIndex> {
142 let loc: Location = loc.into();
143 let arch = loc.arch.unwrap_or_else(|| self.arch());
145 let mut count = 0;
146 let indexes = unsafe {
147 BNLowLevelILGetInstructionsAt(self.handle, arch.handle, loc.addr, &mut count)
148 };
149 unsafe { Array::new(indexes, count, ()) }
150 }
151
152 pub fn instruction_from_index(
153 &self,
154 index: LowLevelInstructionIndex,
155 ) -> Option<LowLevelILInstruction<'_, M, F>> {
156 if index.0 >= self.instruction_count() {
157 None
158 } else {
159 Some(LowLevelILInstruction::new(self, index))
160 }
161 }
162
163 pub fn instruction_count(&self) -> usize {
164 unsafe {
165 use binaryninjacore_sys::BNGetLowLevelILInstructionCount;
166 BNGetLowLevelILInstructionCount(self.handle)
167 }
168 }
169
170 pub fn expression_count(&self) -> usize {
171 unsafe {
172 use binaryninjacore_sys::BNGetLowLevelILExprCount;
173 BNGetLowLevelILExprCount(self.handle)
174 }
175 }
176
177 pub fn function(&self) -> Option<Ref<Function>> {
178 unsafe {
179 let func = BNGetLowLevelILOwnerFunction(self.handle);
180 if func.is_null() {
181 return None;
182 }
183 Some(Function::ref_from_raw(func))
184 }
185 }
186
187 pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelILBlock<'_, M, F>>> {
188 use binaryninjacore_sys::BNGetLowLevelILBasicBlockList;
189
190 unsafe {
191 let mut count = 0;
192 let blocks = BNGetLowLevelILBasicBlockList(self.handle, &mut count);
193 let context = LowLevelILBlock { function: self };
194 Array::new(blocks, count, context)
195 }
196 }
197
198 pub fn basic_block_containing_index(
202 &self,
203 index: LowLevelInstructionIndex,
204 ) -> Option<Ref<BasicBlock<LowLevelILBlock<'_, M, F>>>> {
205 let block = unsafe { BNGetLowLevelILBasicBlockForInstruction(self.handle, index.0) };
206 if block.is_null() {
207 None
208 } else {
209 Some(unsafe { BasicBlock::ref_from_raw(block, LowLevelILBlock { function: self }) })
210 }
211 }
212}
213
214impl<M: FunctionMutability> LowLevelILFunction<M, NonSSA> {
215 pub fn ssa_form(&self) -> Option<Ref<LowLevelILFunction<M, SSA>>> {
217 let handle = unsafe { BNGetLowLevelILSSAForm(self.handle) };
218 if handle.is_null() {
219 return None;
220 }
221 Some(unsafe { LowLevelILFunction::ref_from_raw(handle) })
222 }
223}
224
225impl LowLevelILFunction<Mutable, NonSSA> {
227 pub fn new(arch: CoreArchitecture, source_func: Option<Function>) -> Ref<Self> {
231 use binaryninjacore_sys::BNCreateLowLevelILFunction;
232
233 let handle = unsafe {
234 match source_func {
235 Some(func) => BNCreateLowLevelILFunction(arch.handle, func.handle),
236 None => BNCreateLowLevelILFunction(arch.handle, std::ptr::null_mut()),
237 }
238 };
239
240 assert!(!handle.is_null());
242
243 unsafe { Self::ref_from_raw_with_arch(handle, Some(arch)) }
244 }
245
246 pub fn generate_ssa_form(&self) {
247 use binaryninjacore_sys::BNGenerateLowLevelILSSAForm;
248 unsafe { BNGenerateLowLevelILSSAForm(self.handle) };
249 }
250}
251
252impl Ref<LowLevelILFunction<Mutable, NonSSA>> {
253 pub fn finalized(self) -> Ref<LowLevelILFunction<Finalized, NonSSA>> {
254 unsafe {
255 BNFinalizeLowLevelILFunction(self.handle);
256 LowLevelILFunction::from_raw_with_arch(self.handle, self.arch).to_owned()
258 }
259 }
260}
261
262impl<M: FunctionMutability> LowLevelILFunction<M, SSA> {
263 #[must_use]
265 pub fn get_ssa_register_uses<R: ArchReg>(
266 &self,
267 reg: LowLevelILSSARegisterKind<R>,
268 ) -> Vec<LowLevelILInstruction<'_, M, SSA>> {
269 use binaryninjacore_sys::BNGetLowLevelILSSARegisterUses;
270 let register_id = match reg {
271 LowLevelILSSARegisterKind::Full { kind, .. } => kind.id(),
272 LowLevelILSSARegisterKind::Partial { partial_reg, .. } => partial_reg.id(),
273 };
274 let mut count = 0;
275 let instrs = unsafe {
276 BNGetLowLevelILSSARegisterUses(
277 self.handle,
278 register_id.into(),
279 reg.version() as usize,
280 &mut count,
281 )
282 };
283 let result = unsafe { std::slice::from_raw_parts(instrs, count) }
284 .iter()
285 .map(|idx| LowLevelILInstruction::new(self, LowLevelInstructionIndex(*idx)))
286 .collect();
287 unsafe { BNFreeILInstructionList(instrs) };
288 result
289 }
290
291 #[must_use]
293 pub fn get_ssa_register_definition<R: ArchReg>(
294 &self,
295 reg: &LowLevelILSSARegisterKind<R>,
296 ) -> Option<LowLevelILInstruction<'_, M, SSA>> {
297 use binaryninjacore_sys::BNGetLowLevelILSSARegisterDefinition;
298 let register_id = match reg {
299 LowLevelILSSARegisterKind::Full { kind, .. } => kind.id(),
300 LowLevelILSSARegisterKind::Partial { partial_reg, .. } => partial_reg.id(),
301 };
302 let instr_idx = unsafe {
303 BNGetLowLevelILSSARegisterDefinition(
304 self.handle,
305 register_id.into(),
306 reg.version() as usize,
307 )
308 };
309 self.instruction_from_index(LowLevelInstructionIndex(instr_idx))
310 }
311
312 #[must_use]
314 pub fn get_ssa_register_value<R: ArchReg>(
315 &self,
316 reg: &LowLevelILSSARegisterKind<R>,
317 ) -> Option<RegisterValue> {
318 let register_id = match reg {
319 LowLevelILSSARegisterKind::Full { kind, .. } => kind.id(),
320 LowLevelILSSARegisterKind::Partial { partial_reg, .. } => partial_reg.id(),
321 };
322 let value = unsafe {
323 BNGetLowLevelILSSARegisterValue(self.handle, register_id.into(), reg.version() as usize)
324 };
325 if value.state == BNRegisterValueType::UndeterminedValue {
326 return None;
327 }
328 Some(value.into())
329 }
330
331 #[must_use]
333 pub fn get_ssa_flag_value(&self, flag: &LowLevelILSSAFlag<CoreFlag>) -> Option<RegisterValue> {
334 let value = unsafe {
335 BNGetLowLevelILSSAFlagValue(self.handle, flag.flag.id().0, flag.version as usize)
336 };
337 if value.state == BNRegisterValueType::UndeterminedValue {
338 return None;
339 }
340 Some(value.into())
341 }
342}
343
344impl<M, F> ToOwned for LowLevelILFunction<M, F>
345where
346 M: FunctionMutability,
347 F: FunctionForm,
348{
349 type Owned = Ref<Self>;
350
351 fn to_owned(&self) -> Self::Owned {
352 unsafe { RefCountable::inc_ref(self) }
353 }
354}
355
356unsafe impl<M, F> RefCountable for LowLevelILFunction<M, F>
357where
358 M: FunctionMutability,
359 F: FunctionForm,
360{
361 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
362 Ref::new(Self {
363 handle: BNNewLowLevelILFunctionReference(handle.handle),
364 arch: handle.arch,
365 _mutability: PhantomData,
366 _form: PhantomData,
367 })
368 }
369
370 unsafe fn dec_ref(handle: &Self) {
371 BNFreeLowLevelILFunction(handle.handle);
372 }
373}
374
375impl<M, F> Debug for LowLevelILFunction<M, F>
376where
377 M: FunctionMutability,
378 F: FunctionForm,
379{
380 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
381 f.debug_struct("LowLevelILFunction")
382 .field("arch", &self.arch())
383 .field("instruction_count", &self.instruction_count())
384 .field("expression_count", &self.expression_count())
385 .finish()
386 }
387}
388
389unsafe impl<M: FunctionMutability, F: FunctionForm> Send for LowLevelILFunction<M, F> {}
390unsafe impl<M: FunctionMutability, F: FunctionForm> Sync for LowLevelILFunction<M, F> {}
391
392impl<M: FunctionMutability, F: FunctionForm> Eq for LowLevelILFunction<M, F> {}
393
394impl<M: FunctionMutability, F: FunctionForm> PartialEq for LowLevelILFunction<M, F> {
395 fn eq(&self, rhs: &Self) -> bool {
396 self.function().eq(&rhs.function())
397 }
398}
399
400impl<M: FunctionMutability, F: FunctionForm> Hash for LowLevelILFunction<M, F> {
401 fn hash<H: Hasher>(&self, state: &mut H) {
402 self.function().hash(state)
403 }
404}