binaryninja/high_level_il/
function.rs

1use 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    // TODO: Rename to `current_location`?
121    pub fn current_address(&self) -> Location {
122        let addr = unsafe { BNHighLevelILGetCurrentAddress(self.handle) };
123        Location::from(addr)
124    }
125
126    // TODO: Rename to `set_current_location`?
127    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    /// Gets the instruction that contains the given SSA variable's definition.
137    ///
138    /// Since SSA variables can only be defined once, this will return the single instruction where that occurs.
139    /// For SSA variable version 0s, which don't have definitions, this will return None instead.
140    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    /// Gets all the instructions that use the given SSA variable.
157    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    /// Determines if `variable` is live at any point in the function
179    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    /// Determines if `variable` is live at a given point in the function
186    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    /// Determines if `variable` is live at a given point in the function
219    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    /// This gets just the HLIL variables - you may be interested in the union
224    /// of [`Function::parameter_variables`] and [`HighLevelILFunction::aliased_variables`] as well for all the
225    /// variables used in the function
226    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    /// This returns a list of Variables that are taken reference to and used
234    /// elsewhere. You may also wish to consider [`HighLevelILFunction::variables`]
235    /// and [`Function::parameter_variables`]
236    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    /// This gets the HLIL SSA variables for a given [`Variable`].
244    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}