1use binaryninjacore_sys::*;
2
3#[allow(unused)]
5use crate::binary_view::{memory_map::MemoryMap, BinaryViewBase, BinaryViewExt};
6
7use crate::basic_block::BasicBlock;
8use crate::binary_view::{AddressRange, BinaryView};
9use crate::flowgraph::FlowGraph;
10use crate::function::{Function, NativeBlock};
11use crate::high_level_il::HighLevelILFunction;
12use crate::low_level_il::{LowLevelILMutableFunction, LowLevelILRegularFunction};
13use crate::medium_level_il::MediumLevelILFunction;
14use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
15use crate::section::Section;
16use crate::segment::{Segment, SegmentFlags};
17use crate::string::{BnString, IntoCStr};
18use std::ffi::c_char;
19use std::ptr;
20use std::ptr::NonNull;
21
22pub mod activity;
23pub use activity::Activity;
24
25#[repr(transparent)]
26pub struct AnalysisContext {
30 handle: NonNull<BNAnalysisContext>,
31}
32
33impl AnalysisContext {
34 pub(crate) unsafe fn from_raw(handle: NonNull<BNAnalysisContext>) -> Self {
35 Self { handle }
36 }
37
38 #[allow(unused)]
39 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNAnalysisContext>) -> Ref<Self> {
40 Ref::new(Self { handle })
41 }
42
43 pub fn view(&self) -> Ref<BinaryView> {
45 let result = unsafe { BNAnalysisContextGetBinaryView(self.handle.as_ptr()) };
46 assert!(!result.is_null());
47 unsafe { BinaryView::ref_from_raw(result) }
48 }
49
50 pub fn function(&self) -> Ref<Function> {
52 let result = unsafe { BNAnalysisContextGetFunction(self.handle.as_ptr()) };
53 assert!(!result.is_null());
54 unsafe { Function::ref_from_raw(result) }
55 }
56
57 pub unsafe fn lifted_il_function(&self) -> Option<Ref<LowLevelILMutableFunction>> {
59 let result = unsafe { BNAnalysisContextGetLiftedILFunction(self.handle.as_ptr()) };
60 unsafe {
61 Some(LowLevelILMutableFunction::ref_from_raw(
62 NonNull::new(result)?.as_ptr(),
63 ))
64 }
65 }
66
67 pub fn set_lifted_il_function(&self, value: &LowLevelILRegularFunction) {
68 unsafe { BNSetLiftedILFunction(self.handle.as_ptr(), value.handle) }
69 }
70
71 pub unsafe fn llil_function(&self) -> Option<Ref<LowLevelILMutableFunction>> {
73 let result = unsafe { BNAnalysisContextGetLowLevelILFunction(self.handle.as_ptr()) };
74 unsafe {
75 Some(LowLevelILMutableFunction::ref_from_raw(
76 NonNull::new(result)?.as_ptr(),
77 ))
78 }
79 }
80
81 pub fn set_llil_function(&self, value: &LowLevelILRegularFunction) {
82 unsafe { BNSetLowLevelILFunction(self.handle.as_ptr(), value.handle) }
83 }
84
85 pub fn mlil_function(&self) -> Option<Ref<MediumLevelILFunction>> {
87 let result = unsafe { BNAnalysisContextGetMediumLevelILFunction(self.handle.as_ptr()) };
88 unsafe {
89 Some(MediumLevelILFunction::ref_from_raw(
90 NonNull::new(result)?.as_ptr(),
91 ))
92 }
93 }
94
95 pub fn set_mlil_function(&self, value: &MediumLevelILFunction) {
96 unsafe {
98 BNSetMediumLevelILFunction(
99 self.handle.as_ptr(),
100 value.handle,
101 ptr::null_mut(),
102 0,
103 ptr::null_mut(),
104 0,
105 )
106 }
107 }
108
109 pub fn hlil_function(&self, full_ast: bool) -> Option<Ref<HighLevelILFunction>> {
111 let result = unsafe { BNAnalysisContextGetHighLevelILFunction(self.handle.as_ptr()) };
112 unsafe {
113 Some(HighLevelILFunction::ref_from_raw(
114 NonNull::new(result)?.as_ptr(),
115 full_ast,
116 ))
117 }
118 }
119
120 pub fn inform(&self, request: &str) -> bool {
121 let request = request.to_cstr();
122 unsafe { BNAnalysisContextInform(self.handle.as_ptr(), request.as_ptr()) }
123 }
124
125 pub fn set_basic_blocks<I>(&self, blocks: I)
126 where
127 I: IntoIterator<Item = BasicBlock<NativeBlock>>,
128 {
129 let blocks: Vec<_> = blocks.into_iter().collect();
130 let mut blocks_raw: Vec<*mut BNBasicBlock> =
131 blocks.iter().map(|block| block.handle).collect();
132 unsafe { BNSetBasicBlockList(self.handle.as_ptr(), blocks_raw.as_mut_ptr(), blocks.len()) }
133 }
134
135 pub fn get_setting_bool(&self, key: &str) -> bool {
139 let key = key.to_cstr();
140 unsafe { BNAnalysisContextGetSettingBool(self.handle.as_ptr(), key.as_ptr()) }
141 }
142
143 pub fn get_setting_double(&self, key: &str) -> f64 {
145 let key = key.to_cstr();
146 unsafe { BNAnalysisContextGetSettingDouble(self.handle.as_ptr(), key.as_ptr()) }
147 }
148
149 pub fn get_setting_int64(&self, key: &str) -> i64 {
151 let key = key.to_cstr();
152 unsafe { BNAnalysisContextGetSettingInt64(self.handle.as_ptr(), key.as_ptr()) }
153 }
154
155 pub fn get_setting_uint64(&self, key: &str) -> u64 {
157 let key = key.to_cstr();
158 unsafe { BNAnalysisContextGetSettingUInt64(self.handle.as_ptr(), key.as_ptr()) }
159 }
160
161 pub fn get_setting_string(&self, key: &str) -> BnString {
163 let key = key.to_cstr();
164 unsafe {
165 let result = BNAnalysisContextGetSettingString(self.handle.as_ptr(), key.as_ptr());
166 BnString::from_raw(result)
167 }
168 }
169
170 pub fn get_setting_string_list(&self, key: &str) -> Array<BnString> {
172 let key = key.to_cstr();
173 unsafe {
174 let mut count = 0;
175 let result = BNAnalysisContextGetSettingStringList(
176 self.handle.as_ptr(),
177 key.as_ptr(),
178 &mut count,
179 );
180 Array::new(result, count, ())
181 }
182 }
183
184 pub fn is_offset_valid(&self, offset: u64) -> bool {
188 unsafe { BNAnalysisContextIsValidOffset(self.handle.as_ptr(), offset) }
189 }
190
191 pub fn is_offset_readable(&self, offset: u64) -> bool {
195 unsafe { BNAnalysisContextIsOffsetReadable(self.handle.as_ptr(), offset) }
196 }
197
198 pub fn is_offset_writable(&self, offset: u64) -> bool {
202 unsafe { BNAnalysisContextIsOffsetWritable(self.handle.as_ptr(), offset) }
203 }
204
205 pub fn is_offset_executable(&self, offset: u64) -> bool {
209 unsafe { BNAnalysisContextIsOffsetExecutable(self.handle.as_ptr(), offset) }
210 }
211
212 pub fn is_offset_backed_by_file(&self, offset: u64) -> bool {
216 unsafe { BNAnalysisContextIsOffsetBackedByFile(self.handle.as_ptr(), offset) }
217 }
218
219 pub fn is_offset_code_semantics(&self, offset: u64) -> bool {
223 unsafe { BNAnalysisContextIsOffsetCodeSemantics(self.handle.as_ptr(), offset) }
224 }
225
226 pub fn is_offset_extern_semantics(&self, offset: u64) -> bool {
230 unsafe { BNAnalysisContextIsOffsetExternSemantics(self.handle.as_ptr(), offset) }
231 }
232
233 pub fn is_offset_writable_semantics(&self, offset: u64) -> bool {
237 unsafe { BNAnalysisContextIsOffsetWritableSemantics(self.handle.as_ptr(), offset) }
238 }
239
240 pub fn is_offset_readonly_semantics(&self, offset: u64) -> bool {
244 unsafe { BNAnalysisContextIsOffsetReadOnlySemantics(self.handle.as_ptr(), offset) }
245 }
246
247 pub fn sections(&self) -> Array<Section> {
251 unsafe {
252 let mut count = 0;
253 let sections = BNAnalysisContextGetSections(self.handle.as_ptr(), &mut count);
254 Array::new(sections, count, ())
255 }
256 }
257
258 pub fn section_by_name(&self, name: impl IntoCStr) -> Option<Ref<Section>> {
262 unsafe {
263 let raw_name = name.to_cstr();
264 let name_ptr = raw_name.as_ptr();
265 let raw_section_ptr = BNAnalysisContextGetSectionByName(self.handle.as_ptr(), name_ptr);
266 match raw_section_ptr.is_null() {
267 false => Some(Section::ref_from_raw(raw_section_ptr)),
268 true => None,
269 }
270 }
271 }
272
273 pub fn sections_at(&self, addr: u64) -> Array<Section> {
277 unsafe {
278 let mut count = 0;
279 let sections = BNAnalysisContextGetSectionsAt(self.handle.as_ptr(), addr, &mut count);
280 Array::new(sections, count, ())
281 }
282 }
283
284 pub fn start(&self) -> u64 {
288 unsafe { BNAnalysisContextGetStart(self.handle.as_ptr()) }
289 }
290
291 pub fn end(&self) -> u64 {
295 unsafe { BNAnalysisContextGetEnd(self.handle.as_ptr()) }
296 }
297
298 pub fn length(&self) -> u64 {
302 unsafe { BNAnalysisContextGetLength(self.handle.as_ptr()) }
303 }
304
305 pub fn next_valid_offset(&self, offset: u64) -> u64 {
309 unsafe { BNAnalysisContextGetNextValidOffset(self.handle.as_ptr(), offset) }
310 }
311
312 pub fn next_mapped_address(&self, addr: u64, flags: &SegmentFlags) -> u64 {
314 unsafe {
315 BNAnalysisContextGetNextMappedAddress(self.handle.as_ptr(), addr, flags.into_raw())
316 }
317 }
318
319 pub fn next_backed_address(&self, addr: u64, flags: &SegmentFlags) -> u64 {
321 unsafe {
322 BNAnalysisContextGetNextBackedAddress(self.handle.as_ptr(), addr, flags.into_raw())
323 }
324 }
325
326 pub fn segment_at(&self, addr: u64) -> Option<Ref<Segment>> {
330 unsafe {
331 let result = BNAnalysisContextGetSegmentAt(self.handle.as_ptr(), addr);
332 if result.is_null() {
333 None
334 } else {
335 Some(Segment::ref_from_raw(result))
336 }
337 }
338 }
339
340 pub fn mapped_address_ranges(&self) -> Array<AddressRange> {
342 unsafe {
343 let mut count = 0;
344 let ranges = BNAnalysisContextGetMappedAddressRanges(self.handle.as_ptr(), &mut count);
345 Array::new(ranges, count, ())
346 }
347 }
348
349 pub fn backed_address_ranges(&self) -> Array<AddressRange> {
351 unsafe {
352 let mut count = 0;
353 let ranges = BNAnalysisContextGetBackedAddressRanges(self.handle.as_ptr(), &mut count);
354 Array::new(ranges, count, ())
355 }
356 }
357}
358
359impl ToOwned for AnalysisContext {
360 type Owned = Ref<Self>;
361
362 fn to_owned(&self) -> Self::Owned {
363 unsafe { RefCountable::inc_ref(self) }
364 }
365}
366
367unsafe impl RefCountable for AnalysisContext {
368 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
369 Ref::new(Self {
370 handle: NonNull::new(BNNewAnalysisContextReference(handle.handle.as_ptr()))
371 .expect("valid handle"),
372 })
373 }
374
375 unsafe fn dec_ref(handle: &Self) {
376 BNFreeAnalysisContext(handle.handle.as_ptr());
377 }
378}
379
380#[repr(transparent)]
381pub struct Workflow {
382 handle: NonNull<BNWorkflow>,
383}
384
385impl Workflow {
386 pub(crate) unsafe fn from_raw(handle: NonNull<BNWorkflow>) -> Self {
387 Self { handle }
388 }
389
390 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNWorkflow>) -> Ref<Self> {
391 Ref::new(Self { handle })
392 }
393
394 pub fn build(name: &str) -> WorkflowBuilder {
399 let name = name.to_cstr();
400 let result = unsafe { BNCreateWorkflow(name.as_ptr()) };
401 WorkflowBuilder {
402 handle: unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) },
403 }
404 }
405
406 pub fn clone_to(&self, name: &str) -> WorkflowBuilder {
411 self.clone_to_with_root(name, "")
412 }
413
414 pub fn clone_to_with_root(&self, name: &str, root_activity: &str) -> WorkflowBuilder {
419 let raw_name = name.to_cstr();
420 let activity = root_activity.to_cstr();
421 let workflow = unsafe {
422 Self::ref_from_raw(
423 NonNull::new(BNWorkflowClone(
424 self.handle.as_ptr(),
425 raw_name.as_ptr(),
426 activity.as_ptr(),
427 ))
428 .unwrap(),
429 )
430 };
431 WorkflowBuilder { handle: workflow }
432 }
433
434 pub fn get(name: &str) -> Option<Ref<Workflow>> {
436 let name = name.to_cstr();
437 let result = unsafe { BNWorkflowGet(name.as_ptr()) };
438 let handle = NonNull::new(result)?;
439 Some(unsafe { Workflow::ref_from_raw(handle) })
440 }
441
442 pub fn cloned(name: &str) -> Option<WorkflowBuilder> {
445 Self::get(name).map(|workflow| workflow.clone_to(name))
446 }
447
448 pub fn list() -> Array<Workflow> {
450 let mut count = 0;
451 let result = unsafe { BNGetWorkflowList(&mut count) };
452 assert!(!result.is_null());
453 unsafe { Array::new(result, count, ()) }
454 }
455
456 pub fn name(&self) -> String {
457 let result = unsafe { BNGetWorkflowName(self.handle.as_ptr()) };
458 assert!(!result.is_null());
459 unsafe { BnString::into_string(result) }
460 }
461
462 pub fn contains(&self, activity: &str) -> bool {
464 let activity = activity.to_cstr();
465 unsafe { BNWorkflowContains(self.handle.as_ptr(), activity.as_ptr()) }
466 }
467
468 pub fn configuration(&self) -> String {
470 self.configuration_with_activity("")
471 }
472
473 pub fn configuration_with_activity(&self, activity: &str) -> String {
478 let activity = activity.to_cstr();
479 let result = unsafe { BNWorkflowGetConfiguration(self.handle.as_ptr(), activity.as_ptr()) };
480 assert!(!result.is_null());
481 unsafe { BnString::into_string(result) }
482 }
483
484 pub fn registered(&self) -> bool {
486 unsafe { BNWorkflowIsRegistered(self.handle.as_ptr()) }
487 }
488
489 pub fn size(&self) -> usize {
490 unsafe { BNWorkflowSize(self.handle.as_ptr()) }
491 }
492
493 pub fn activity(&self, name: &str) -> Option<Ref<Activity>> {
495 let name = name.to_cstr();
496 let result = unsafe { BNWorkflowGetActivity(self.handle.as_ptr(), name.as_ptr()) };
497 NonNull::new(result).map(|a| unsafe { Activity::ref_from_raw(a) })
498 }
499
500 pub fn activity_roots(&self, activity: &str) -> Array<BnString> {
505 let activity = activity.to_cstr();
506 let mut count = 0;
507 let result = unsafe {
508 BNWorkflowGetActivityRoots(self.handle.as_ptr(), activity.as_ptr(), &mut count)
509 };
510 assert!(!result.is_null());
511 unsafe { Array::new(result as *mut *mut c_char, count, ()) }
512 }
513
514 pub fn subactivities(&self, activity: &str, immediate: bool) -> Array<BnString> {
519 let activity = activity.to_cstr();
520 let mut count = 0;
521 let result = unsafe {
522 BNWorkflowGetSubactivities(
523 self.handle.as_ptr(),
524 activity.as_ptr(),
525 immediate,
526 &mut count,
527 )
528 };
529 assert!(!result.is_null());
530 unsafe { Array::new(result as *mut *mut c_char, count, ()) }
531 }
532
533 pub fn graph(&self, activity: &str, sequential: Option<bool>) -> Option<Ref<FlowGraph>> {
538 let sequential = sequential.unwrap_or(false);
539 let activity = activity.to_cstr();
540 let graph =
541 unsafe { BNWorkflowGetGraph(self.handle.as_ptr(), activity.as_ptr(), sequential) };
542 if graph.is_null() {
543 return None;
544 }
545 Some(unsafe { FlowGraph::ref_from_raw(graph) })
546 }
547
548 pub fn show_metrics(&self) {
550 unsafe { BNWorkflowShowReport(self.handle.as_ptr(), c"metrics".as_ptr()) }
551 }
552
553 pub fn show_topology(&self) {
555 unsafe { BNWorkflowShowReport(self.handle.as_ptr(), c"topology".as_ptr()) }
556 }
557
558 pub fn show_trace(&self) {
560 unsafe { BNWorkflowShowReport(self.handle.as_ptr(), c"trace".as_ptr()) }
561 }
562}
563
564impl ToOwned for Workflow {
565 type Owned = Ref<Self>;
566
567 fn to_owned(&self) -> Self::Owned {
568 unsafe { RefCountable::inc_ref(self) }
569 }
570}
571
572unsafe impl RefCountable for Workflow {
573 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
574 Ref::new(Self {
575 handle: NonNull::new(BNNewWorkflowReference(handle.handle.as_ptr()))
576 .expect("valid handle"),
577 })
578 }
579
580 unsafe fn dec_ref(handle: &Self) {
581 BNFreeWorkflow(handle.handle.as_ptr());
582 }
583}
584
585impl CoreArrayProvider for Workflow {
586 type Raw = *mut BNWorkflow;
587 type Context = ();
588 type Wrapped<'a> = Guard<'a, Workflow>;
589}
590
591unsafe impl CoreArrayProviderInner for Workflow {
592 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
593 BNFreeWorkflowList(raw, count)
594 }
595
596 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
597 Guard::new(
598 Workflow::from_raw(NonNull::new(*raw).expect("valid handle")),
599 context,
600 )
601 }
602}
603
604#[must_use = "Workflow is not registered until `register` is called"]
605pub struct WorkflowBuilder {
606 handle: Ref<Workflow>,
607}
608
609impl WorkflowBuilder {
610 fn raw_handle(&self) -> *mut BNWorkflow {
611 self.handle.handle.as_ptr()
612 }
613
614 pub fn activity_before(self, activity: &Activity, sibling: &str) -> Result<Self, ()> {
619 self.register_activity(activity)?
620 .insert(sibling, vec![activity.name()])
621 }
622
623 pub fn activity_after(self, activity: &Activity, sibling: &str) -> Result<Self, ()> {
628 self.register_activity(activity)?
629 .insert_after(sibling, vec![activity.name()])
630 }
631
632 pub fn register_activity(self, activity: &Activity) -> Result<Self, ()> {
636 self.register_activity_with_subactivities::<Vec<String>>(activity, vec![])
637 }
638
639 pub fn register_activity_with_subactivities<I>(
644 self,
645 activity: &Activity,
646 subactivities: I,
647 ) -> Result<Self, ()>
648 where
649 I: IntoIterator,
650 I::Item: IntoCStr,
651 {
652 let subactivities_raw: Vec<_> = subactivities.into_iter().map(|x| x.to_cstr()).collect();
653 let mut subactivities_ptr: Vec<*const _> =
654 subactivities_raw.iter().map(|x| x.as_ptr()).collect();
655 let result = unsafe {
656 BNWorkflowRegisterActivity(
657 self.raw_handle(),
658 activity.handle.as_ptr(),
659 subactivities_ptr.as_mut_ptr(),
660 subactivities_ptr.len(),
661 )
662 };
663 let Some(activity_ptr) = NonNull::new(result) else {
664 return Err(());
665 };
666 let _ = unsafe { Activity::ref_from_raw(activity_ptr) };
667 Ok(self)
668 }
669
670 pub fn register(self) -> Result<Ref<Workflow>, ()> {
672 self.register_with_config("")
673 }
674
675 pub fn register_with_config(self, config: &str) -> Result<Ref<Workflow>, ()> {
679 let config = config.to_cstr();
681 if unsafe { BNRegisterWorkflow(self.raw_handle(), config.as_ptr()) } {
682 Ok(self.handle)
683 } else {
684 Err(())
685 }
686 }
687
688 pub fn subactivities<I>(self, activity: &str, activities: I) -> Result<Self, ()>
693 where
694 I: IntoIterator,
695 I::Item: IntoCStr,
696 {
697 let activity = activity.to_cstr();
698 let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect();
699 let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect();
700 let result = unsafe {
701 BNWorkflowAssignSubactivities(
702 self.raw_handle(),
703 activity.as_ptr(),
704 input_list_ptr.as_mut_ptr(),
705 input_list.len(),
706 )
707 };
708 if result {
709 Ok(self)
710 } else {
711 Err(())
712 }
713 }
714
715 pub fn clear(self) -> Result<Self, ()> {
717 let result = unsafe { BNWorkflowClear(self.raw_handle()) };
718 if result {
719 Ok(self)
720 } else {
721 Err(())
722 }
723 }
724
725 pub fn insert<I>(self, activity: &str, activities: I) -> Result<Self, ()>
730 where
731 I: IntoIterator,
732 I::Item: IntoCStr,
733 {
734 let activity = activity.to_cstr();
735 let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect();
736 let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect();
737 let result = unsafe {
738 BNWorkflowInsert(
739 self.raw_handle(),
740 activity.as_ptr(),
741 input_list_ptr.as_mut_ptr(),
742 input_list.len(),
743 )
744 };
745 if result {
746 Ok(self)
747 } else {
748 Err(())
749 }
750 }
751
752 pub fn insert_after<I>(self, activity: &str, activities: I) -> Result<Self, ()>
757 where
758 I: IntoIterator,
759 I::Item: IntoCStr,
760 {
761 let activity = activity.to_cstr();
762 let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect();
763 let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect();
764 let result = unsafe {
765 BNWorkflowInsertAfter(
766 self.raw_handle(),
767 activity.as_ptr(),
768 input_list_ptr.as_mut_ptr(),
769 input_list.len(),
770 )
771 };
772 if result {
773 Ok(self)
774 } else {
775 Err(())
776 }
777 }
778
779 pub fn remove(self, activity: &str) -> Result<Self, ()> {
781 let activity = activity.to_cstr();
782 let result = unsafe { BNWorkflowRemove(self.raw_handle(), activity.as_ptr()) };
783 if result {
784 Ok(self)
785 } else {
786 Err(())
787 }
788 }
789
790 pub fn replace(self, activity: &str, new_activity: &str) -> Result<Self, ()> {
795 let activity = activity.to_cstr();
796 let new_activity = new_activity.to_cstr();
797 let result = unsafe {
798 BNWorkflowReplace(self.raw_handle(), activity.as_ptr(), new_activity.as_ptr())
799 };
800 if result {
801 Ok(self)
802 } else {
803 Err(())
804 }
805 }
806}