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