1use crate::architecture::CoreArchitecture;
16use crate::function::Function;
17use crate::rc::*;
18use crate::BranchType;
19use binaryninjacore_sys::*;
20use std::fmt;
21use std::fmt::Debug;
22use std::hash::{Hash, Hasher};
23
24enum EdgeDirection {
25 Incoming,
26 Outgoing,
27}
28
29pub struct PendingBasicBlockEdge {
30 pub branch_type: BranchType,
31 pub target: u64,
32 pub arch: CoreArchitecture,
33 pub fallthrough: bool,
34}
35
36pub struct Edge<'a, C: 'a + BlockContext> {
37 pub branch: BranchType,
38 pub back_edge: bool,
39 pub source: Guard<'a, BasicBlock<C>>,
40 pub target: Guard<'a, BasicBlock<C>>,
41}
42
43impl<'a, C: 'a + fmt::Debug + BlockContext> fmt::Debug for Edge<'a, C> {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 write!(
46 f,
47 "{:?} ({}) {:?} -> {:?}",
48 self.branch, self.back_edge, &*self.source, &*self.target
49 )
50 }
51}
52
53pub struct EdgeContext<'a, C: 'a + BlockContext> {
54 dir: EdgeDirection,
55 orig_block: &'a BasicBlock<C>,
56}
57
58impl<'a, C: 'a + BlockContext> CoreArrayProvider for Edge<'a, C> {
59 type Raw = BNBasicBlockEdge;
60 type Context = EdgeContext<'a, C>;
61 type Wrapped<'b>
62 = Edge<'b, C>
63 where
64 'a: 'b;
65}
66
67unsafe impl<'a, C: 'a + BlockContext> CoreArrayProviderInner for Edge<'a, C> {
68 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
69 BNFreeBasicBlockEdgeList(raw, count);
70 }
71
72 unsafe fn wrap_raw<'b>(raw: &'b Self::Raw, context: &'b Self::Context) -> Self::Wrapped<'b> {
73 let edge_target = Guard::new(
74 BasicBlock::from_raw(raw.target, context.orig_block.context.clone()),
75 raw,
76 );
77 let orig_block = Guard::new(
78 BasicBlock::from_raw(
79 context.orig_block.handle,
80 context.orig_block.context.clone(),
81 ),
82 raw,
83 );
84
85 let (source, target) = match context.dir {
86 EdgeDirection::Incoming => (edge_target, orig_block),
87 EdgeDirection::Outgoing => (orig_block, edge_target),
88 };
89
90 Edge {
91 branch: raw.type_,
92 back_edge: raw.backEdge,
93 source,
94 target,
95 }
96 }
97}
98
99pub trait BlockContext: Clone + Sync + Send + Sized {
100 type Instruction;
101 type InstructionIndex: Debug + From<u64>;
102 type Iter: Iterator<Item = Self::Instruction>;
103
104 fn start(&self, block: &BasicBlock<Self>) -> Self::Instruction;
105 fn iter(&self, block: &BasicBlock<Self>) -> Self::Iter;
106}
107
108#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
109pub enum BasicBlockType {
110 Native,
111 LowLevelIL,
112 MediumLevelIL,
113 HighLevelIL,
114}
115
116pub struct BasicBlock<C: BlockContext> {
117 pub(crate) handle: *mut BNBasicBlock,
118 context: C,
119}
120
121impl<C: BlockContext> BasicBlock<C> {
122 pub unsafe fn from_raw(handle: *mut BNBasicBlock, context: C) -> Self {
123 Self { handle, context }
124 }
125
126 pub(crate) unsafe fn ref_from_raw(handle: *mut BNBasicBlock, context: C) -> Ref<Self> {
127 Ref::new(Self::from_raw(handle, context))
128 }
129
130 pub fn function(&self) -> Ref<Function> {
132 unsafe {
133 let func = BNGetBasicBlockFunction(self.handle);
134 Function::ref_from_raw(func)
135 }
136 }
137
138 pub fn arch(&self) -> CoreArchitecture {
139 unsafe {
140 let arch = BNGetBasicBlockArchitecture(self.handle);
141 CoreArchitecture::from_raw(arch)
142 }
143 }
144
145 pub fn block_type(&self) -> BasicBlockType {
146 if unsafe { !BNIsILBasicBlock(self.handle) } {
147 BasicBlockType::Native
148 } else if unsafe { BNIsLowLevelILBasicBlock(self.handle) } {
149 BasicBlockType::LowLevelIL
150 } else if unsafe { BNIsMediumLevelILBasicBlock(self.handle) } {
151 BasicBlockType::MediumLevelIL
152 } else {
153 BasicBlockType::HighLevelIL
155 }
156 }
157
158 pub fn iter(&self) -> C::Iter {
159 self.context.iter(self)
160 }
161
162 pub fn start_index(&self) -> C::InstructionIndex {
163 C::InstructionIndex::from(unsafe { BNGetBasicBlockStart(self.handle) })
164 }
165
166 pub fn end_index(&self) -> C::InstructionIndex {
167 C::InstructionIndex::from(unsafe { BNGetBasicBlockEnd(self.handle) })
168 }
169
170 pub fn start(&self) -> u64 {
171 unsafe { BNGetBasicBlockStart(self.handle) }
172 }
173
174 pub fn end(&self) -> u64 {
175 unsafe { BNGetBasicBlockEnd(self.handle) }
176 }
177
178 pub fn set_end(&self, end: u64) {
179 unsafe {
180 BNSetBasicBlockEnd(self.handle, end);
181 }
182 }
183
184 pub fn add_instruction_data(&self, data: &[u8]) {
185 unsafe {
186 BNBasicBlockAddInstructionData(self.handle, data.as_ptr() as *const _, data.len());
187 }
188 }
189
190 pub fn instruction_data(&self, addr: u64) -> &[u8] {
191 unsafe {
192 let mut size: usize = 0;
193 let data = BNBasicBlockGetInstructionData(self.handle, addr, &mut size);
194 if data.is_null() {
195 return &[];
196 }
197
198 std::slice::from_raw_parts(data, size)
199 }
200 }
201
202 pub fn set_has_invalid_instructions(&self, value: bool) {
203 unsafe {
204 BNBasicBlockSetHasInvalidInstructions(self.handle, value);
205 }
206 }
207
208 pub fn has_invalid_instructions(&self) -> bool {
209 unsafe { BNBasicBlockHasInvalidInstructions(self.handle) }
210 }
211
212 pub fn raw_length(&self) -> u64 {
213 unsafe { BNGetBasicBlockLength(self.handle) }
214 }
215
216 pub fn incoming_edges(&self) -> Array<Edge<'_, C>> {
217 unsafe {
218 let mut count = 0;
219 let edges = BNGetBasicBlockIncomingEdges(self.handle, &mut count);
220 Array::new(
221 edges,
222 count,
223 EdgeContext {
224 dir: EdgeDirection::Incoming,
225 orig_block: self,
226 },
227 )
228 }
229 }
230
231 pub fn outgoing_edges(&self) -> Array<Edge<'_, C>> {
232 unsafe {
233 let mut count = 0;
234 let edges = BNGetBasicBlockOutgoingEdges(self.handle, &mut count);
235 Array::new(
236 edges,
237 count,
238 EdgeContext {
239 dir: EdgeDirection::Outgoing,
240 orig_block: self,
241 },
242 )
243 }
244 }
245
246 pub fn pending_outgoing_edges(&self) -> Vec<PendingBasicBlockEdge> {
247 unsafe {
248 let mut count = 0;
249 let edges_ptr = BNGetBasicBlockPendingOutgoingEdges(self.handle, &mut count);
250 let edges = std::slice::from_raw_parts(edges_ptr, count);
251
252 let mut result = Vec::with_capacity(count);
253 for edge in edges {
254 result.push(PendingBasicBlockEdge {
255 branch_type: edge.type_,
256 target: edge.target,
257 arch: CoreArchitecture::from_raw(edge.arch),
258 fallthrough: edge.fallThrough,
259 });
260 }
261
262 BNFreePendingBasicBlockEdgeList(edges_ptr);
263 result
264 }
265 }
266
267 pub fn add_pending_outgoing_edge(
268 &self,
269 typ: BranchType,
270 addr: u64,
271 arch: CoreArchitecture,
272 fallthrough: bool,
273 ) {
274 unsafe {
275 BNBasicBlockAddPendingOutgoingEdge(self.handle, typ, addr, arch.handle, fallthrough);
276 }
277 }
278
279 pub fn clear_pending_outgoing_edges(&self) {
280 unsafe {
281 BNClearBasicBlockPendingOutgoingEdges(self.handle);
282 }
283 }
284
285 pub fn set_fallthrough_to_function(&self, value: bool) {
286 unsafe {
287 BNBasicBlockSetFallThroughToFunction(self.handle, value);
288 }
289 }
290
291 pub fn is_fallthrough_to_function(&self) -> bool {
292 unsafe { BNBasicBlockIsFallThroughToFunction(self.handle) }
293 }
294
295 pub fn has_undetermined_outgoing_edges(&self) -> bool {
297 unsafe { BNBasicBlockHasUndeterminedOutgoingEdges(self.handle) }
298 }
299
300 pub fn set_undetermined_outgoing_edges(&self, value: bool) {
301 unsafe {
302 BNBasicBlockSetUndeterminedOutgoingEdges(self.handle, value);
303 }
304 }
305
306 pub fn can_exit(&self) -> bool {
307 unsafe { BNBasicBlockCanExit(self.handle) }
308 }
309
310 pub fn set_can_exit(&self, value: bool) {
311 unsafe {
312 BNBasicBlockSetCanExit(self.handle, value);
313 }
314 }
315
316 pub fn index(&self) -> usize {
318 unsafe { BNGetBasicBlockIndex(self.handle) }
319 }
320
321 pub fn immediate_dominator(&self) -> Option<Ref<Self>> {
322 unsafe {
323 let block = BNGetBasicBlockImmediateDominator(self.handle, false);
325 if block.is_null() {
326 return None;
327 }
328 Some(BasicBlock::ref_from_raw(block, self.context.clone()))
329 }
330 }
331
332 pub fn dominators(&self) -> Array<BasicBlock<C>> {
333 unsafe {
334 let mut count = 0;
335 let blocks = BNGetBasicBlockDominators(self.handle, &mut count, false);
337 Array::new(blocks, count, self.context.clone())
338 }
339 }
340
341 pub fn strict_dominators(&self) -> Array<BasicBlock<C>> {
342 unsafe {
343 let mut count = 0;
344 let blocks = BNGetBasicBlockStrictDominators(self.handle, &mut count, false);
346 Array::new(blocks, count, self.context.clone())
347 }
348 }
349
350 pub fn dominator_tree_children(&self) -> Array<BasicBlock<C>> {
351 unsafe {
352 let mut count = 0;
353 let blocks = BNGetBasicBlockDominatorTreeChildren(self.handle, &mut count, false);
355 Array::new(blocks, count, self.context.clone())
356 }
357 }
358
359 pub fn dominance_frontier(&self) -> Array<BasicBlock<C>> {
360 unsafe {
361 let mut count = 0;
362 let blocks = BNGetBasicBlockDominanceFrontier(self.handle, &mut count, false);
364 Array::new(blocks, count, self.context.clone())
365 }
366 }
367
368 }
370
371impl<C: BlockContext> Hash for BasicBlock<C> {
372 fn hash<H: Hasher>(&self, state: &mut H) {
373 self.function().hash(state);
374 self.block_type().hash(state);
375 state.write_usize(self.index());
376 }
377}
378
379impl<C: BlockContext> PartialEq for BasicBlock<C> {
380 fn eq(&self, other: &Self) -> bool {
381 self.function() == other.function()
382 && self.index() == other.index()
383 && self.block_type() == other.block_type()
384 }
385}
386
387impl<C: BlockContext> Eq for BasicBlock<C> {}
388
389impl<C: BlockContext> IntoIterator for &BasicBlock<C> {
390 type Item = C::Instruction;
391 type IntoIter = C::Iter;
392
393 fn into_iter(self) -> Self::IntoIter {
394 self.iter()
395 }
396}
397
398impl<C: BlockContext> IntoIterator for BasicBlock<C> {
399 type Item = C::Instruction;
400 type IntoIter = C::Iter;
401
402 fn into_iter(self) -> Self::IntoIter {
403 self.iter()
404 }
405}
406
407impl<C: fmt::Debug + BlockContext> fmt::Debug for BasicBlock<C> {
408 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
409 f.debug_struct("BasicBlock")
410 .field("context", &self.context)
411 .field("start_index", &self.start_index())
412 .field("end_index", &self.end_index())
413 .field("raw_length", &self.raw_length())
414 .finish()
415 }
416}
417
418impl<C: BlockContext> ToOwned for BasicBlock<C> {
419 type Owned = Ref<Self>;
420
421 fn to_owned(&self) -> Self::Owned {
422 unsafe { RefCountable::inc_ref(self) }
423 }
424}
425
426unsafe impl<C: BlockContext> RefCountable for BasicBlock<C> {
427 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
428 Ref::new(Self {
429 handle: BNNewBasicBlockReference(handle.handle),
430 context: handle.context.clone(),
431 })
432 }
433
434 unsafe fn dec_ref(handle: &Self) {
435 BNFreeBasicBlock(handle.handle);
436 }
437}
438
439impl<C: BlockContext> CoreArrayProvider for BasicBlock<C> {
440 type Raw = *mut BNBasicBlock;
441 type Context = C;
442 type Wrapped<'a>
443 = Guard<'a, BasicBlock<C>>
444 where
445 C: 'a;
446}
447
448unsafe impl<C: BlockContext> CoreArrayProviderInner for BasicBlock<C> {
449 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
450 BNFreeBasicBlockList(raw, count);
451 }
452
453 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
454 Guard::new(BasicBlock::from_raw(*raw, context.clone()), context)
455 }
456}
457
458unsafe impl<C: BlockContext> Send for BasicBlock<C> {}
459unsafe impl<C: BlockContext> Sync for BasicBlock<C> {}