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::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::string::{BnString, IntoCStr};
16use std::ffi::c_char;
17use std::ptr;
18use std::ptr::NonNull;
19
20pub mod activity;
21pub use activity::Activity;
22
23#[repr(transparent)]
24pub struct AnalysisContext {
28 handle: NonNull<BNAnalysisContext>,
29}
30
31impl AnalysisContext {
32 pub(crate) unsafe fn from_raw(handle: NonNull<BNAnalysisContext>) -> Self {
33 Self { handle }
34 }
35
36 #[allow(unused)]
37 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNAnalysisContext>) -> Ref<Self> {
38 Ref::new(Self { handle })
39 }
40
41 pub fn view(&self) -> Ref<BinaryView> {
43 let result = unsafe { BNAnalysisContextGetBinaryView(self.handle.as_ptr()) };
44 assert!(!result.is_null());
45 unsafe { BinaryView::ref_from_raw(result) }
46 }
47
48 pub fn function(&self) -> Ref<Function> {
50 let result = unsafe { BNAnalysisContextGetFunction(self.handle.as_ptr()) };
51 assert!(!result.is_null());
52 unsafe { Function::ref_from_raw(result) }
53 }
54
55 pub unsafe fn lifted_il_function(&self) -> Option<Ref<LowLevelILMutableFunction>> {
57 let result = unsafe { BNAnalysisContextGetLiftedILFunction(self.handle.as_ptr()) };
58 unsafe {
59 Some(LowLevelILMutableFunction::ref_from_raw(
60 NonNull::new(result)?.as_ptr(),
61 ))
62 }
63 }
64
65 pub fn set_lifted_il_function(&self, value: &LowLevelILRegularFunction) {
66 unsafe { BNSetLiftedILFunction(self.handle.as_ptr(), value.handle) }
67 }
68
69 pub unsafe fn llil_function(&self) -> Option<Ref<LowLevelILMutableFunction>> {
71 let result = unsafe { BNAnalysisContextGetLowLevelILFunction(self.handle.as_ptr()) };
72 unsafe {
73 Some(LowLevelILMutableFunction::ref_from_raw(
74 NonNull::new(result)?.as_ptr(),
75 ))
76 }
77 }
78
79 pub fn set_llil_function(&self, value: &LowLevelILRegularFunction) {
80 unsafe { BNSetLowLevelILFunction(self.handle.as_ptr(), value.handle) }
81 }
82
83 pub fn mlil_function(&self) -> Option<Ref<MediumLevelILFunction>> {
85 let result = unsafe { BNAnalysisContextGetMediumLevelILFunction(self.handle.as_ptr()) };
86 unsafe {
87 Some(MediumLevelILFunction::ref_from_raw(
88 NonNull::new(result)?.as_ptr(),
89 ))
90 }
91 }
92
93 pub fn set_mlil_function(&self, value: &MediumLevelILFunction) {
94 unsafe {
96 BNSetMediumLevelILFunction(
97 self.handle.as_ptr(),
98 value.handle,
99 ptr::null_mut(),
100 0,
101 ptr::null_mut(),
102 0,
103 )
104 }
105 }
106
107 pub fn hlil_function(&self, full_ast: bool) -> Option<Ref<HighLevelILFunction>> {
109 let result = unsafe { BNAnalysisContextGetHighLevelILFunction(self.handle.as_ptr()) };
110 unsafe {
111 Some(HighLevelILFunction::ref_from_raw(
112 NonNull::new(result)?.as_ptr(),
113 full_ast,
114 ))
115 }
116 }
117
118 pub fn inform(&self, request: &str) -> bool {
119 let request = request.to_cstr();
120 unsafe { BNAnalysisContextInform(self.handle.as_ptr(), request.as_ptr()) }
121 }
122
123 pub fn set_basic_blocks<I>(&self, blocks: I)
124 where
125 I: IntoIterator<Item = BasicBlock<NativeBlock>>,
126 {
127 let blocks: Vec<_> = blocks.into_iter().collect();
128 let mut blocks_raw: Vec<*mut BNBasicBlock> =
129 blocks.iter().map(|block| block.handle).collect();
130 unsafe { BNSetBasicBlockList(self.handle.as_ptr(), blocks_raw.as_mut_ptr(), blocks.len()) }
131 }
132}
133
134impl ToOwned for AnalysisContext {
135 type Owned = Ref<Self>;
136
137 fn to_owned(&self) -> Self::Owned {
138 unsafe { RefCountable::inc_ref(self) }
139 }
140}
141
142unsafe impl RefCountable for AnalysisContext {
143 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
144 Ref::new(Self {
145 handle: NonNull::new(BNNewAnalysisContextReference(handle.handle.as_ptr()))
146 .expect("valid handle"),
147 })
148 }
149
150 unsafe fn dec_ref(handle: &Self) {
151 BNFreeAnalysisContext(handle.handle.as_ptr());
152 }
153}
154
155#[repr(transparent)]
156pub struct Workflow {
157 handle: NonNull<BNWorkflow>,
158}
159
160impl Workflow {
161 pub(crate) unsafe fn from_raw(handle: NonNull<BNWorkflow>) -> Self {
162 Self { handle }
163 }
164
165 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNWorkflow>) -> Ref<Self> {
166 Ref::new(Self { handle })
167 }
168
169 pub fn build(name: &str) -> WorkflowBuilder {
174 let name = name.to_cstr();
175 let result = unsafe { BNCreateWorkflow(name.as_ptr()) };
176 WorkflowBuilder {
177 handle: unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) },
178 }
179 }
180
181 pub fn clone_to(&self, name: &str) -> WorkflowBuilder {
186 self.clone_to_with_root(name, "")
187 }
188
189 pub fn clone_to_with_root(&self, name: &str, root_activity: &str) -> WorkflowBuilder {
194 let raw_name = name.to_cstr();
195 let activity = root_activity.to_cstr();
196 let workflow = unsafe {
197 Self::ref_from_raw(
198 NonNull::new(BNWorkflowClone(
199 self.handle.as_ptr(),
200 raw_name.as_ptr(),
201 activity.as_ptr(),
202 ))
203 .unwrap(),
204 )
205 };
206 WorkflowBuilder { handle: workflow }
207 }
208
209 pub fn get(name: &str) -> Option<Ref<Workflow>> {
211 let name = name.to_cstr();
212 let result = unsafe { BNWorkflowGet(name.as_ptr()) };
213 let handle = NonNull::new(result)?;
214 Some(unsafe { Workflow::ref_from_raw(handle) })
215 }
216
217 pub fn cloned(name: &str) -> Option<WorkflowBuilder> {
220 Self::get(name).map(|workflow| workflow.clone_to(name))
221 }
222
223 pub fn list() -> Array<Workflow> {
225 let mut count = 0;
226 let result = unsafe { BNGetWorkflowList(&mut count) };
227 assert!(!result.is_null());
228 unsafe { Array::new(result, count, ()) }
229 }
230
231 pub fn name(&self) -> String {
232 let result = unsafe { BNGetWorkflowName(self.handle.as_ptr()) };
233 assert!(!result.is_null());
234 unsafe { BnString::into_string(result) }
235 }
236
237 pub fn contains(&self, activity: &str) -> bool {
239 let activity = activity.to_cstr();
240 unsafe { BNWorkflowContains(self.handle.as_ptr(), activity.as_ptr()) }
241 }
242
243 pub fn configuration(&self) -> String {
245 self.configuration_with_activity("")
246 }
247
248 pub fn configuration_with_activity(&self, activity: &str) -> String {
253 let activity = activity.to_cstr();
254 let result = unsafe { BNWorkflowGetConfiguration(self.handle.as_ptr(), activity.as_ptr()) };
255 assert!(!result.is_null());
256 unsafe { BnString::into_string(result) }
257 }
258
259 pub fn registered(&self) -> bool {
261 unsafe { BNWorkflowIsRegistered(self.handle.as_ptr()) }
262 }
263
264 pub fn size(&self) -> usize {
265 unsafe { BNWorkflowSize(self.handle.as_ptr()) }
266 }
267
268 pub fn activity(&self, name: &str) -> Option<Ref<Activity>> {
270 let name = name.to_cstr();
271 let result = unsafe { BNWorkflowGetActivity(self.handle.as_ptr(), name.as_ptr()) };
272 NonNull::new(result).map(|a| unsafe { Activity::ref_from_raw(a) })
273 }
274
275 pub fn activity_roots(&self, activity: &str) -> Array<BnString> {
280 let activity = activity.to_cstr();
281 let mut count = 0;
282 let result = unsafe {
283 BNWorkflowGetActivityRoots(self.handle.as_ptr(), activity.as_ptr(), &mut count)
284 };
285 assert!(!result.is_null());
286 unsafe { Array::new(result as *mut *mut c_char, count, ()) }
287 }
288
289 pub fn subactivities(&self, activity: &str, immediate: bool) -> Array<BnString> {
294 let activity = activity.to_cstr();
295 let mut count = 0;
296 let result = unsafe {
297 BNWorkflowGetSubactivities(
298 self.handle.as_ptr(),
299 activity.as_ptr(),
300 immediate,
301 &mut count,
302 )
303 };
304 assert!(!result.is_null());
305 unsafe { Array::new(result as *mut *mut c_char, count, ()) }
306 }
307
308 pub fn graph(&self, activity: &str, sequential: Option<bool>) -> Option<Ref<FlowGraph>> {
313 let sequential = sequential.unwrap_or(false);
314 let activity = activity.to_cstr();
315 let graph =
316 unsafe { BNWorkflowGetGraph(self.handle.as_ptr(), activity.as_ptr(), sequential) };
317 if graph.is_null() {
318 return None;
319 }
320 Some(unsafe { FlowGraph::ref_from_raw(graph) })
321 }
322
323 pub fn show_metrics(&self) {
325 unsafe { BNWorkflowShowReport(self.handle.as_ptr(), c"metrics".as_ptr()) }
326 }
327
328 pub fn show_topology(&self) {
330 unsafe { BNWorkflowShowReport(self.handle.as_ptr(), c"topology".as_ptr()) }
331 }
332
333 pub fn show_trace(&self) {
335 unsafe { BNWorkflowShowReport(self.handle.as_ptr(), c"trace".as_ptr()) }
336 }
337}
338
339impl ToOwned for Workflow {
340 type Owned = Ref<Self>;
341
342 fn to_owned(&self) -> Self::Owned {
343 unsafe { RefCountable::inc_ref(self) }
344 }
345}
346
347unsafe impl RefCountable for Workflow {
348 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
349 Ref::new(Self {
350 handle: NonNull::new(BNNewWorkflowReference(handle.handle.as_ptr()))
351 .expect("valid handle"),
352 })
353 }
354
355 unsafe fn dec_ref(handle: &Self) {
356 BNFreeWorkflow(handle.handle.as_ptr());
357 }
358}
359
360impl CoreArrayProvider for Workflow {
361 type Raw = *mut BNWorkflow;
362 type Context = ();
363 type Wrapped<'a> = Guard<'a, Workflow>;
364}
365
366unsafe impl CoreArrayProviderInner for Workflow {
367 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
368 BNFreeWorkflowList(raw, count)
369 }
370
371 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
372 Guard::new(
373 Workflow::from_raw(NonNull::new(*raw).expect("valid handle")),
374 context,
375 )
376 }
377}
378
379#[must_use = "Workflow is not registered until `register` is called"]
380pub struct WorkflowBuilder {
381 handle: Ref<Workflow>,
382}
383
384impl WorkflowBuilder {
385 fn raw_handle(&self) -> *mut BNWorkflow {
386 self.handle.handle.as_ptr()
387 }
388
389 pub fn activity_before(self, activity: &Activity, sibling: &str) -> Result<Self, ()> {
394 self.register_activity(activity)?
395 .insert(sibling, vec![activity.name()])
396 }
397
398 pub fn activity_after(self, activity: &Activity, sibling: &str) -> Result<Self, ()> {
403 self.register_activity(activity)?
404 .insert_after(sibling, vec![activity.name()])
405 }
406
407 pub fn register_activity(self, activity: &Activity) -> Result<Self, ()> {
411 self.register_activity_with_subactivities::<Vec<String>>(activity, vec![])
412 }
413
414 pub fn register_activity_with_subactivities<I>(
419 self,
420 activity: &Activity,
421 subactivities: I,
422 ) -> Result<Self, ()>
423 where
424 I: IntoIterator,
425 I::Item: IntoCStr,
426 {
427 let subactivities_raw: Vec<_> = subactivities.into_iter().map(|x| x.to_cstr()).collect();
428 let mut subactivities_ptr: Vec<*const _> =
429 subactivities_raw.iter().map(|x| x.as_ptr()).collect();
430 let result = unsafe {
431 BNWorkflowRegisterActivity(
432 self.raw_handle(),
433 activity.handle.as_ptr(),
434 subactivities_ptr.as_mut_ptr(),
435 subactivities_ptr.len(),
436 )
437 };
438 let Some(activity_ptr) = NonNull::new(result) else {
439 return Err(());
440 };
441 let _ = unsafe { Activity::ref_from_raw(activity_ptr) };
442 Ok(self)
443 }
444
445 pub fn register(self) -> Result<Ref<Workflow>, ()> {
447 self.register_with_config("")
448 }
449
450 pub fn register_with_config(self, config: &str) -> Result<Ref<Workflow>, ()> {
454 let config = config.to_cstr();
456 if unsafe { BNRegisterWorkflow(self.raw_handle(), config.as_ptr()) } {
457 Ok(self.handle)
458 } else {
459 Err(())
460 }
461 }
462
463 pub fn subactivities<I>(self, activity: &str, activities: I) -> Result<Self, ()>
468 where
469 I: IntoIterator,
470 I::Item: IntoCStr,
471 {
472 let activity = activity.to_cstr();
473 let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect();
474 let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect();
475 let result = unsafe {
476 BNWorkflowAssignSubactivities(
477 self.raw_handle(),
478 activity.as_ptr(),
479 input_list_ptr.as_mut_ptr(),
480 input_list.len(),
481 )
482 };
483 if result {
484 Ok(self)
485 } else {
486 Err(())
487 }
488 }
489
490 pub fn clear(self) -> Result<Self, ()> {
492 let result = unsafe { BNWorkflowClear(self.raw_handle()) };
493 if result {
494 Ok(self)
495 } else {
496 Err(())
497 }
498 }
499
500 pub fn insert<I>(self, activity: &str, activities: I) -> Result<Self, ()>
505 where
506 I: IntoIterator,
507 I::Item: IntoCStr,
508 {
509 let activity = activity.to_cstr();
510 let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect();
511 let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect();
512 let result = unsafe {
513 BNWorkflowInsert(
514 self.raw_handle(),
515 activity.as_ptr(),
516 input_list_ptr.as_mut_ptr(),
517 input_list.len(),
518 )
519 };
520 if result {
521 Ok(self)
522 } else {
523 Err(())
524 }
525 }
526
527 pub fn insert_after<I>(self, activity: &str, activities: I) -> Result<Self, ()>
532 where
533 I: IntoIterator,
534 I::Item: IntoCStr,
535 {
536 let activity = activity.to_cstr();
537 let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect();
538 let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect();
539 let result = unsafe {
540 BNWorkflowInsertAfter(
541 self.raw_handle(),
542 activity.as_ptr(),
543 input_list_ptr.as_mut_ptr(),
544 input_list.len(),
545 )
546 };
547 if result {
548 Ok(self)
549 } else {
550 Err(())
551 }
552 }
553
554 pub fn remove(self, activity: &str) -> Result<Self, ()> {
556 let activity = activity.to_cstr();
557 let result = unsafe { BNWorkflowRemove(self.raw_handle(), activity.as_ptr()) };
558 if result {
559 Ok(self)
560 } else {
561 Err(())
562 }
563 }
564
565 pub fn replace(self, activity: &str, new_activity: &str) -> Result<Self, ()> {
570 let activity = activity.to_cstr();
571 let new_activity = new_activity.to_cstr();
572 let result = unsafe {
573 BNWorkflowReplace(self.raw_handle(), activity.as_ptr(), new_activity.as_ptr())
574 };
575 if result {
576 Ok(self)
577 } else {
578 Err(())
579 }
580 }
581}