binaryninja/high_level_il/
function.rs1use std::fmt::{Debug, Formatter};
2use std::hash::{Hash, Hasher};
3
4use binaryninjacore_sys::*;
5
6use super::{
7 HighLevelExpressionIndex, HighLevelILBlock, HighLevelILInstruction, HighLevelInstructionIndex,
8};
9use crate::basic_block::BasicBlock;
10use crate::function::{Function, Location};
11use crate::rc::{Array, Ref, RefCountable};
12use crate::variable::{SSAVariable, Variable};
13
14pub struct HighLevelILFunction {
15 pub(crate) full_ast: bool,
16 pub(crate) handle: *mut BNHighLevelILFunction,
17}
18
19impl HighLevelILFunction {
20 pub(crate) unsafe fn from_raw(handle: *mut BNHighLevelILFunction, full_ast: bool) -> Self {
21 debug_assert!(!handle.is_null());
22 Self { handle, full_ast }
23 }
24
25 pub(crate) unsafe fn ref_from_raw(
26 handle: *mut BNHighLevelILFunction,
27 full_ast: bool,
28 ) -> Ref<Self> {
29 debug_assert!(!handle.is_null());
30 Ref::new(Self { handle, full_ast })
31 }
32
33 pub fn instruction_from_index(
34 &self,
35 index: HighLevelInstructionIndex,
36 ) -> Option<HighLevelILInstruction> {
37 if index.0 >= self.instruction_count() {
38 None
39 } else {
40 Some(HighLevelILInstruction::from_instr_index(
41 self.to_owned(),
42 index,
43 ))
44 }
45 }
46
47 pub fn instruction_from_expr_index(
48 &self,
49 expr_index: HighLevelExpressionIndex,
50 ) -> Option<HighLevelILInstruction> {
51 if expr_index.0 >= self.expression_count() {
52 None
53 } else {
54 Some(HighLevelILInstruction::from_expr_index(
55 self.to_owned(),
56 expr_index,
57 ))
58 }
59 }
60
61 pub fn root_expression_index(&self) -> HighLevelExpressionIndex {
62 HighLevelExpressionIndex(unsafe { BNGetHighLevelILRootExpr(self.handle) })
63 }
64
65 pub fn root(&self) -> HighLevelILInstruction {
66 self.instruction_from_expr_index(self.root_expression_index())
67 .expect("Invalid root expression index")
68 }
69
70 pub fn set_root(&self, new_root: &HighLevelILInstruction) {
71 unsafe { BNSetHighLevelILRootExpr(self.handle, new_root.expr_index.0) }
72 }
73
74 pub fn instruction_count(&self) -> usize {
75 unsafe { BNGetHighLevelILInstructionCount(self.handle) }
76 }
77
78 pub fn expression_count(&self) -> usize {
79 unsafe { BNGetHighLevelILExprCount(self.handle) }
80 }
81
82 pub fn ssa_form(&self) -> Ref<HighLevelILFunction> {
83 let ssa = unsafe { BNGetHighLevelILSSAForm(self.handle) };
84 assert!(!ssa.is_null());
85 unsafe { HighLevelILFunction::ref_from_raw(ssa, self.full_ast) }
86 }
87
88 pub fn function(&self) -> Ref<Function> {
89 unsafe {
90 let func = BNGetHighLevelILOwnerFunction(self.handle);
91 Function::ref_from_raw(func)
92 }
93 }
94
95 pub fn basic_blocks(&self) -> Array<BasicBlock<HighLevelILBlock>> {
96 let mut count = 0;
97 let blocks = unsafe { BNGetHighLevelILBasicBlockList(self.handle, &mut count) };
98 let context = HighLevelILBlock {
99 function: self.to_owned(),
100 };
101 unsafe { Array::new(blocks, count, context) }
102 }
103
104 pub fn as_ast(&self) -> Ref<HighLevelILFunction> {
105 Self {
106 handle: self.handle,
107 full_ast: true,
108 }
109 .to_owned()
110 }
111
112 pub fn as_non_ast(&self) -> Ref<HighLevelILFunction> {
113 Self {
114 handle: self.handle,
115 full_ast: false,
116 }
117 .to_owned()
118 }
119
120 pub fn current_address(&self) -> Location {
122 let addr = unsafe { BNHighLevelILGetCurrentAddress(self.handle) };
123 Location::from(addr)
124 }
125
126 pub fn set_current_address(&self, location: impl Into<Location>) {
128 let location = location.into();
129 let arch = location
130 .arch
131 .map(|a| a.handle)
132 .unwrap_or_else(std::ptr::null_mut);
133 unsafe { BNHighLevelILSetCurrentAddress(self.handle, arch, location.addr) }
134 }
135
136 pub fn ssa_variable_definition(&self, variable: SSAVariable) -> Option<HighLevelILInstruction> {
141 let index = unsafe {
142 BNGetHighLevelILSSAVarDefinition(
143 self.handle,
144 &variable.variable.into(),
145 variable.version,
146 )
147 };
148 self.instruction_from_index(HighLevelInstructionIndex(index))
149 }
150
151 pub fn ssa_memory_definition(&self, version: usize) -> Option<HighLevelILInstruction> {
152 let index = unsafe { BNGetHighLevelILSSAMemoryDefinition(self.handle, version) };
153 self.instruction_from_index(HighLevelInstructionIndex(index))
154 }
155
156 pub fn ssa_variable_uses(&self, variable: SSAVariable) -> Array<HighLevelILInstruction> {
158 let mut count = 0;
159 let instrs = unsafe {
160 BNGetHighLevelILSSAVarUses(
161 self.handle,
162 &variable.variable.into(),
163 variable.version,
164 &mut count,
165 )
166 };
167 assert!(!instrs.is_null());
168 unsafe { Array::new(instrs, count, self.to_owned()) }
169 }
170
171 pub fn ssa_memory_uses(&self, version: usize) -> Array<HighLevelILInstruction> {
172 let mut count = 0;
173 let instrs = unsafe { BNGetHighLevelILSSAMemoryUses(self.handle, version, &mut count) };
174 assert!(!instrs.is_null());
175 unsafe { Array::new(instrs, count, self.to_owned()) }
176 }
177
178 pub fn is_ssa_variable_live(&self, variable: SSAVariable) -> bool {
180 unsafe {
181 BNIsHighLevelILSSAVarLive(self.handle, &variable.variable.into(), variable.version)
182 }
183 }
184
185 pub fn is_ssa_variable_live_at(
187 &self,
188 variable: SSAVariable,
189 instr: &HighLevelILInstruction,
190 ) -> bool {
191 unsafe {
192 BNIsHighLevelILSSAVarLiveAt(
193 self.handle,
194 &variable.variable.into(),
195 variable.version,
196 instr.expr_index.0,
197 )
198 }
199 }
200
201 pub fn variable_definitions(&self, variable: Variable) -> Array<HighLevelILInstruction> {
202 let mut count = 0;
203 let defs = unsafe {
204 BNGetHighLevelILVariableDefinitions(self.handle, &variable.into(), &mut count)
205 };
206 assert!(!defs.is_null());
207 unsafe { Array::new(defs, count, self.to_owned()) }
208 }
209
210 pub fn variable_uses(&self, variable: Variable) -> Array<HighLevelILInstruction> {
211 let mut count = 0;
212 let instrs =
213 unsafe { BNGetHighLevelILVariableUses(self.handle, &variable.into(), &mut count) };
214 assert!(!instrs.is_null());
215 unsafe { Array::new(instrs, count, self.to_owned()) }
216 }
217
218 pub fn is_variable_live_at(&self, variable: Variable, instr: &HighLevelILInstruction) -> bool {
220 unsafe { BNIsHighLevelILVarLiveAt(self.handle, &variable.into(), instr.expr_index.0) }
221 }
222
223 pub fn variables(&self) -> Array<Variable> {
227 let mut count = 0;
228 let variables = unsafe { BNGetHighLevelILVariables(self.handle, &mut count) };
229 assert!(!variables.is_null());
230 unsafe { Array::new(variables, count, ()) }
231 }
232
233 pub fn aliased_variables(&self) -> Array<Variable> {
237 let mut count = 0;
238 let variables = unsafe { BNGetHighLevelILAliasedVariables(self.handle, &mut count) };
239 assert!(!variables.is_null());
240 unsafe { Array::new(variables, count, ()) }
241 }
242
243 pub fn ssa_variables(&self, variable: &Variable) -> Array<SSAVariable> {
245 let mut count = 0;
246 let raw_variable = BNVariable::from(variable);
247 let variables =
248 unsafe { BNGetHighLevelILVariableSSAVersions(self.handle, &raw_variable, &mut count) };
249 unsafe { Array::new(variables, count, *variable) }
250 }
251}
252
253impl Debug for HighLevelILFunction {
254 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
255 f.debug_struct("HighLevelILFunction")
256 .field("arch", &self.function().arch())
257 .field("instruction_count", &self.instruction_count())
258 .field("expression_count", &self.expression_count())
259 .field("root", &self.root())
260 .field("root", &self.root())
261 .finish()
262 }
263}
264
265unsafe impl Send for HighLevelILFunction {}
266unsafe impl Sync for HighLevelILFunction {}
267
268impl Eq for HighLevelILFunction {}
269impl PartialEq for HighLevelILFunction {
270 fn eq(&self, rhs: &Self) -> bool {
271 self.function().eq(&rhs.function())
272 }
273}
274
275impl Hash for HighLevelILFunction {
276 fn hash<H: Hasher>(&self, state: &mut H) {
277 self.function().hash(state)
278 }
279}
280
281impl ToOwned for HighLevelILFunction {
282 type Owned = Ref<Self>;
283
284 fn to_owned(&self) -> Self::Owned {
285 unsafe { RefCountable::inc_ref(self) }
286 }
287}
288
289unsafe impl RefCountable for HighLevelILFunction {
290 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
291 Ref::new(Self {
292 handle: BNNewHighLevelILFunctionReference(handle.handle),
293 full_ast: handle.full_ast,
294 })
295 }
296
297 unsafe fn dec_ref(handle: &Self) {
298 BNFreeHighLevelILFunction(handle.handle);
299 }
300}