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 add_instruction_data(&self, data: &[u8]) {
231 unsafe {
232 BNBasicBlockAddInstructionData(self.handle, data.as_ptr() as *const _, data.len());
233 }
234 }
235
236 pub fn instruction_data(&self, addr: u64) -> &[u8] {
237 unsafe {
238 let mut size: usize = 0;
239 let data = BNBasicBlockGetInstructionData(self.handle, addr, &mut size);
240 if data.is_null() {
241 return &[];
242 }
243
244 std::slice::from_raw_parts(data, size)
245 }
246 }
247
248 pub fn set_has_invalid_instructions(&self, value: bool) {
249 unsafe {
250 BNBasicBlockSetHasInvalidInstructions(self.handle, value);
251 }
252 }
253
254 pub fn has_invalid_instructions(&self) -> bool {
255 unsafe { BNBasicBlockHasInvalidInstructions(self.handle) }
256 }
257
258 pub fn raw_length(&self) -> u64 {
259 unsafe { BNGetBasicBlockLength(self.handle) }
260 }
261
262 pub fn incoming_edges(&self) -> Array<Edge<'_, C>> {
263 unsafe {
264 let mut count = 0;
265 let edges = BNGetBasicBlockIncomingEdges(self.handle, &mut count);
266 Array::new(
267 edges,
268 count,
269 EdgeContext {
270 dir: EdgeDirection::Incoming,
271 orig_block: self,
272 },
273 )
274 }
275 }
276
277 pub fn outgoing_edges(&self) -> Array<Edge<'_, C>> {
278 unsafe {
279 let mut count = 0;
280 let edges = BNGetBasicBlockOutgoingEdges(self.handle, &mut count);
281 Array::new(
282 edges,
283 count,
284 EdgeContext {
285 dir: EdgeDirection::Outgoing,
286 orig_block: self,
287 },
288 )
289 }
290 }
291
292 pub fn pending_outgoing_edges(&self) -> Array<PendingBasicBlockEdge> {
294 unsafe {
295 let mut count = 0;
296 let edges_ptr = BNGetBasicBlockPendingOutgoingEdges(self.handle, &mut count);
297 Array::new(edges_ptr, count, ())
298 }
299 }
300
301 pub fn add_pending_outgoing_edge(&self, edge: &PendingBasicBlockEdge) {
302 unsafe {
303 BNBasicBlockAddPendingOutgoingEdge(
304 self.handle,
305 edge.branch_type,
306 edge.target,
307 edge.arch.handle,
308 edge.fallthrough,
309 );
310 }
311 }
312
313 pub fn clear_pending_outgoing_edges(&self) {
314 unsafe {
315 BNClearBasicBlockPendingOutgoingEdges(self.handle);
316 }
317 }
318
319 pub fn set_fallthrough_to_function(&self, value: bool) {
320 unsafe {
321 BNBasicBlockSetFallThroughToFunction(self.handle, value);
322 }
323 }
324
325 pub fn is_fallthrough_to_function(&self) -> bool {
326 unsafe { BNBasicBlockIsFallThroughToFunction(self.handle) }
327 }
328
329 pub fn has_undetermined_outgoing_edges(&self) -> bool {
331 unsafe { BNBasicBlockHasUndeterminedOutgoingEdges(self.handle) }
332 }
333
334 pub fn set_undetermined_outgoing_edges(&self, value: bool) {
335 unsafe {
336 BNBasicBlockSetUndeterminedOutgoingEdges(self.handle, value);
337 }
338 }
339
340 pub fn can_exit(&self) -> bool {
341 unsafe { BNBasicBlockCanExit(self.handle) }
342 }
343
344 pub fn set_can_exit(&self, value: bool) {
345 unsafe {
346 BNBasicBlockSetCanExit(self.handle, value);
347 }
348 }
349
350 pub fn index(&self) -> usize {
352 unsafe { BNGetBasicBlockIndex(self.handle) }
353 }
354
355 pub fn immediate_dominator(&self) -> Option<Ref<Self>> {
356 unsafe {
357 let block = BNGetBasicBlockImmediateDominator(self.handle, false);
359 if block.is_null() {
360 return None;
361 }
362 Some(BasicBlock::ref_from_raw(block, self.context.clone()))
363 }
364 }
365
366 pub fn dominators(&self) -> Array<BasicBlock<C>> {
367 unsafe {
368 let mut count = 0;
369 let blocks = BNGetBasicBlockDominators(self.handle, &mut count, false);
371 Array::new(blocks, count, self.context.clone())
372 }
373 }
374
375 pub fn strict_dominators(&self) -> Array<BasicBlock<C>> {
376 unsafe {
377 let mut count = 0;
378 let blocks = BNGetBasicBlockStrictDominators(self.handle, &mut count, false);
380 Array::new(blocks, count, self.context.clone())
381 }
382 }
383
384 pub fn dominator_tree_children(&self) -> Array<BasicBlock<C>> {
385 unsafe {
386 let mut count = 0;
387 let blocks = BNGetBasicBlockDominatorTreeChildren(self.handle, &mut count, false);
389 Array::new(blocks, count, self.context.clone())
390 }
391 }
392
393 pub fn dominance_frontier(&self) -> Array<BasicBlock<C>> {
394 unsafe {
395 let mut count = 0;
396 let blocks = BNGetBasicBlockDominanceFrontier(self.handle, &mut count, false);
398 Array::new(blocks, count, self.context.clone())
399 }
400 }
401
402 }
404
405impl<C: BlockContext> Hash for BasicBlock<C> {
406 fn hash<H: Hasher>(&self, state: &mut H) {
407 self.function().hash(state);
408 self.block_type().hash(state);
409 state.write_usize(self.index());
410 }
411}
412
413impl<C: BlockContext> PartialEq for BasicBlock<C> {
414 fn eq(&self, other: &Self) -> bool {
415 self.function() == other.function()
416 && self.index() == other.index()
417 && self.block_type() == other.block_type()
418 }
419}
420
421impl<C: BlockContext> Eq for BasicBlock<C> {}
422
423impl<C: BlockContext> IntoIterator for &BasicBlock<C> {
424 type Item = C::Instruction;
425 type IntoIter = C::Iter;
426
427 fn into_iter(self) -> Self::IntoIter {
428 self.iter()
429 }
430}
431
432impl<C: BlockContext> IntoIterator for BasicBlock<C> {
433 type Item = C::Instruction;
434 type IntoIter = C::Iter;
435
436 fn into_iter(self) -> Self::IntoIter {
437 self.iter()
438 }
439}
440
441impl<C: fmt::Debug + BlockContext> fmt::Debug for BasicBlock<C> {
442 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
443 f.debug_struct("BasicBlock")
444 .field("context", &self.context)
445 .field("start_index", &self.start_index())
446 .field("end_index", &self.end_index())
447 .field("raw_length", &self.raw_length())
448 .finish()
449 }
450}
451
452impl<C: BlockContext> ToOwned for BasicBlock<C> {
453 type Owned = Ref<Self>;
454
455 fn to_owned(&self) -> Self::Owned {
456 unsafe { RefCountable::inc_ref(self) }
457 }
458}
459
460unsafe impl<C: BlockContext> RefCountable for BasicBlock<C> {
461 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
462 Ref::new(Self {
463 handle: BNNewBasicBlockReference(handle.handle),
464 context: handle.context.clone(),
465 })
466 }
467
468 unsafe fn dec_ref(handle: &Self) {
469 BNFreeBasicBlock(handle.handle);
470 }
471}
472
473impl<C: BlockContext> CoreArrayProvider for BasicBlock<C> {
474 type Raw = *mut BNBasicBlock;
475 type Context = C;
476 type Wrapped<'a>
477 = Guard<'a, BasicBlock<C>>
478 where
479 C: 'a;
480}
481
482unsafe impl<C: BlockContext> CoreArrayProviderInner for BasicBlock<C> {
483 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
484 BNFreeBasicBlockList(raw, count);
485 }
486
487 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
488 Guard::new(BasicBlock::from_raw(*raw, context.clone()), context)
489 }
490}
491
492unsafe impl<C: BlockContext> Send for BasicBlock<C> {}
493unsafe impl<C: BlockContext> Sync for BasicBlock<C> {}