Skip to content

Commit 9adf6a6

Browse files
committed
More rust cleanup
- Make workflow cloning explicit - Add workflow tests - Add missing property string list getting for settings - Remove IntoActivityName (see #6257)
1 parent 9f4b673 commit 9adf6a6

File tree

6 files changed

+200
-73
lines changed

6 files changed

+200
-73
lines changed

plugins/warp/src/plugin/workflow.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,17 @@ pub fn insert_workflow() {
7878
}
7979
};
8080

81-
let function_meta_workflow = Workflow::new_from_copy("core.function.metaAnalysis");
81+
let old_function_meta_workflow = Workflow::instance("core.function.metaAnalysis");
82+
let function_meta_workflow = old_function_meta_workflow.clone("core.function.metaAnalysis");
8283
let guid_activity = Activity::new_with_action(GUID_ACTIVITY_CONFIG, guid_activity);
8384
function_meta_workflow
8485
.register_activity(&guid_activity)
8586
.unwrap();
8687
function_meta_workflow.insert("core.function.runFunctionRecognizers", [GUID_ACTIVITY_NAME]);
8788
function_meta_workflow.register().unwrap();
8889

89-
let module_meta_workflow = Workflow::new_from_copy("core.module.metaAnalysis");
90+
let old_module_meta_workflow = Workflow::instance("core.module.metaAnalysis");
91+
let module_meta_workflow = old_module_meta_workflow.clone("core.module.metaAnalysis");
9092
let matcher_activity = Activity::new_with_action(MATCHER_ACTIVITY_CONFIG, matcher_activity);
9193
module_meta_workflow
9294
.register_activity(&matcher_activity)

rust/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ fn main() {
3434
println!("{}:", func.symbol().full_name());
3535
}
3636
}
37-
3837
```
3938

4039
## Getting Started
@@ -61,7 +60,7 @@ binaryninjacore-sys = { git = "https://github.com/Vector35/binaryninja-api.git",
6160
```
6261

6362
`build.rs`:
64-
```rust
63+
```doctestinjectablerust
6564
fn main() {
6665
let link_path =
6766
std::env::var_os("DEP_BINARYNINJACORE_PATH").expect("DEP_BINARYNINJACORE_PATH not specified");

rust/examples/workflow.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ pub fn main() {
5050
binaryninja::headless::Session::new().expect("Failed to initialize session");
5151

5252
println!("Registering workflow...");
53-
let meta_workflow = Workflow::new_from_copy("core.function.metaAnalysis");
53+
let old_meta_workflow = Workflow::instance("core.function.metaAnalysis");
54+
let meta_workflow = old_meta_workflow.clone("core.function.metaAnalysis");
5455
let activity = Activity::new_with_action(RUST_ACTIVITY_CONFIG, example_activity);
5556
meta_workflow.register_activity(&activity).unwrap();
5657
meta_workflow.insert("core.function.runFunctionRecognizers", [RUST_ACTIVITY_NAME]);

rust/src/settings.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,28 @@ impl Settings {
215215
}
216216
}
217217

218+
pub fn get_property_string_list<S: BnStrCompatible>(
219+
&self,
220+
key: S,
221+
property: S,
222+
) -> Array<BnString> {
223+
let key = key.into_bytes_with_nul();
224+
let property = property.into_bytes_with_nul();
225+
let mut size: usize = 0;
226+
unsafe {
227+
Array::new(
228+
BNSettingsQueryPropertyStringList(
229+
self.handle,
230+
key.as_ref().as_ptr() as *mut _,
231+
property.as_ref().as_ptr() as *mut _,
232+
&mut size,
233+
) as *mut *mut c_char,
234+
size,
235+
(),
236+
)
237+
}
238+
}
239+
218240
pub fn get_json<S: BnStrCompatible>(
219241
&self,
220242
key: S,

rust/src/workflow.rs

Lines changed: 81 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -236,22 +236,6 @@ unsafe impl RefCountable for Activity {
236236
}
237237
}
238238

239-
pub trait IntoActivityName {
240-
fn activity_name(self) -> BnString;
241-
}
242-
243-
impl IntoActivityName for &Activity {
244-
fn activity_name(self) -> BnString {
245-
self.name()
246-
}
247-
}
248-
249-
impl<S: BnStrCompatible> IntoActivityName for S {
250-
fn activity_name(self) -> BnString {
251-
BnString::new(self)
252-
}
253-
}
254-
255239
// TODO: We need to hide the JSON here behind a sensible/typed API.
256240
#[repr(transparent)]
257241
pub struct Workflow {
@@ -269,7 +253,7 @@ impl Workflow {
269253

270254
/// Create a new unregistered [Workflow] with no activities.
271255
///
272-
/// To get a copy of an existing registered [Workflow] use [Workflow::new_from_copy].
256+
/// To get a copy of an existing registered [Workflow] use [Workflow::clone].
273257
pub fn new<S: BnStrCompatible>(name: S) -> Self {
274258
let name = name.into_bytes_with_nul();
275259
let result = unsafe { BNCreateWorkflow(name.as_ref().as_ptr() as *const c_char) };
@@ -280,28 +264,26 @@ impl Workflow {
280264
///
281265
/// * `name` - the name for the new [Workflow]
282266
#[must_use]
283-
pub fn new_from_copy<S: BnStrCompatible + Clone>(name: S) -> Workflow {
284-
Self::new_from_copy_with_root(name, "")
267+
pub fn clone<S: BnStrCompatible + Clone>(&self, name: S) -> Workflow {
268+
self.clone_with_root(name, "")
285269
}
286270

287271
/// Make a new unregistered [Workflow], copying all activities, within `root_activity`, and the execution strategy.
288272
///
289273
/// * `name` - the name for the new [Workflow]
290274
/// * `root_activity` - perform the clone operation with this activity as the root
291275
#[must_use]
292-
pub fn new_from_copy_with_root<S: BnStrCompatible + Clone, A: IntoActivityName>(
276+
pub fn clone_with_root<S: BnStrCompatible, A: BnStrCompatible>(
277+
&self,
293278
name: S,
294279
root_activity: A,
295280
) -> Workflow {
296-
let raw_name = name.clone().into_bytes_with_nul();
297-
let activity = root_activity.activity_name();
298-
// I can't think of a single reason as to why we should let users pass a workflow handle into this.
299-
// To prevent warning being emitted we default to the name.
300-
let placeholder_workflow = Workflow::instance(name);
281+
let raw_name = name.into_bytes_with_nul();
282+
let activity = root_activity.into_bytes_with_nul();
301283
unsafe {
302284
Self::from_raw(
303285
NonNull::new(BNWorkflowClone(
304-
placeholder_workflow.handle.as_ptr(),
286+
self.handle.as_ptr(),
305287
raw_name.as_ref().as_ptr() as *const c_char,
306288
activity.as_ref().as_ptr() as *const c_char,
307289
))
@@ -371,14 +353,16 @@ impl Workflow {
371353
) -> Result<Activity, ()>
372354
where
373355
I: IntoIterator,
374-
I::Item: IntoActivityName,
356+
I::Item: BnStrCompatible,
375357
{
376-
let subactivities_raw: Vec<BnString> = subactivities
358+
let subactivities_raw: Vec<_> = subactivities
377359
.into_iter()
378-
.map(|x| x.activity_name())
360+
.map(|x| x.into_bytes_with_nul())
361+
.collect();
362+
let mut subactivities_ptr: Vec<*const _> = subactivities_raw
363+
.iter()
364+
.map(|x| x.as_ref().as_ptr() as *const c_char)
379365
.collect();
380-
let mut subactivities_ptr: Vec<*const _> =
381-
subactivities_raw.iter().map(|x| x.as_ptr()).collect();
382366
let result = unsafe {
383367
BNWorkflowRegisterActivity(
384368
self.handle.as_ptr(),
@@ -392,17 +376,30 @@ impl Workflow {
392376
}
393377

394378
/// Determine if an Activity exists in this [Workflow].
395-
pub fn contains<A: IntoActivityName>(&self, activity: A) -> bool {
396-
unsafe { BNWorkflowContains(self.handle.as_ptr(), activity.activity_name().as_ptr()) }
379+
pub fn contains<A: BnStrCompatible>(&self, activity: A) -> bool {
380+
unsafe {
381+
BNWorkflowContains(
382+
self.handle.as_ptr(),
383+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
384+
)
385+
}
386+
}
387+
388+
/// Retrieve the configuration as an adjacency list in JSON for the [Workflow].
389+
pub fn configuration(&self) -> BnString {
390+
self.configuration_with_activity("")
397391
}
398392

399393
/// Retrieve the configuration as an adjacency list in JSON for the
400-
/// [Workflow], or if specified just for the given `activity`.
394+
/// [Workflow], just for the given `activity`.
401395
///
402-
/// `activity` - if specified, return the configuration for the `activity`
403-
pub fn configuration<A: IntoActivityName>(&self, activity: A) -> BnString {
396+
/// `activity` - return the configuration for the `activity`
397+
pub fn configuration_with_activity<A: BnStrCompatible>(&self, activity: A) -> BnString {
404398
let result = unsafe {
405-
BNWorkflowGetConfiguration(self.handle.as_ptr(), activity.activity_name().as_ptr())
399+
BNWorkflowGetConfiguration(
400+
self.handle.as_ptr(),
401+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
402+
)
406403
};
407404
assert!(!result.is_null());
408405
unsafe { BnString::from_raw(result) }
@@ -433,12 +430,12 @@ impl Workflow {
433430
/// specified just for the given `activity`.
434431
///
435432
/// * `activity` - if specified, return the roots for the `activity`
436-
pub fn activity_roots<A: IntoActivityName>(&self, activity: A) -> Array<BnString> {
433+
pub fn activity_roots<A: BnStrCompatible>(&self, activity: A) -> Array<BnString> {
437434
let mut count = 0;
438435
let result = unsafe {
439436
BNWorkflowGetActivityRoots(
440437
self.handle.as_ptr(),
441-
activity.activity_name().as_ptr(),
438+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
442439
&mut count,
443440
)
444441
};
@@ -450,7 +447,7 @@ impl Workflow {
450447
///
451448
/// * `activity` - if specified, return the direct children and optionally the descendants of the `activity` (includes `activity`)
452449
/// * `immediate` - whether to include only direct children of `activity` or all descendants
453-
pub fn subactivities<A: IntoActivityName>(
450+
pub fn subactivities<A: BnStrCompatible>(
454451
&self,
455452
activity: A,
456453
immediate: bool,
@@ -459,7 +456,7 @@ impl Workflow {
459456
let result = unsafe {
460457
BNWorkflowGetSubactivities(
461458
self.handle.as_ptr(),
462-
activity.activity_name().as_ptr(),
459+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
463460
immediate,
464461
&mut count,
465462
)
@@ -474,20 +471,23 @@ impl Workflow {
474471
/// * `activities` - the list of Activities to assign
475472
pub fn assign_subactivities<A, I>(&self, activity: A, activities: I) -> bool
476473
where
477-
A: IntoActivityName,
474+
A: BnStrCompatible,
478475
I: IntoIterator,
479-
I::Item: IntoActivityName,
476+
I::Item: BnStrCompatible,
480477
{
481-
let mut input_list: Vec<BnString> =
482-
activities.into_iter().map(|a| a.activity_name()).collect();
483-
// SAFETY: this works because BnString and *mut ffi::c_char are
484-
// transmutable
485-
let input_list_ptr = input_list.as_mut_ptr() as *mut *const c_char;
478+
let input_list: Vec<_> = activities
479+
.into_iter()
480+
.map(|a| a.into_bytes_with_nul())
481+
.collect();
482+
let mut input_list_ptr: Vec<*const _> = input_list
483+
.iter()
484+
.map(|x| x.as_ref().as_ptr() as *const c_char)
485+
.collect();
486486
unsafe {
487487
BNWorkflowAssignSubactivities(
488488
self.handle.as_ptr(),
489-
activity.activity_name().as_ptr(),
490-
input_list_ptr,
489+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
490+
input_list_ptr.as_mut_ptr(),
491491
input_list.len(),
492492
)
493493
}
@@ -504,44 +504,52 @@ impl Workflow {
504504
/// * `activities` - the list of Activities to insert
505505
pub fn insert<A, I>(&self, activity: A, activities: I) -> bool
506506
where
507-
A: IntoActivityName,
507+
A: BnStrCompatible,
508508
I: IntoIterator,
509-
I::Item: IntoActivityName,
509+
I::Item: BnStrCompatible,
510510
{
511-
let mut input_list: Vec<BnString> =
512-
activities.into_iter().map(|a| a.activity_name()).collect();
513-
// SAFETY: this works because BnString and *mut ffi::c_char are
514-
// transmutable
515-
let input_list_ptr = input_list.as_mut_ptr() as *mut *const c_char;
511+
let input_list: Vec<_> = activities
512+
.into_iter()
513+
.map(|a| a.into_bytes_with_nul())
514+
.collect();
515+
let mut input_list_ptr: Vec<*const _> = input_list
516+
.iter()
517+
.map(|x| x.as_ref().as_ptr() as *const c_char)
518+
.collect();
516519
unsafe {
517520
BNWorkflowInsert(
518521
self.handle.as_ptr(),
519-
activity.activity_name().as_ptr(),
520-
input_list_ptr,
522+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
523+
input_list_ptr.as_mut_ptr(),
521524
input_list.len(),
522525
)
523526
}
524527
}
525528

526529
/// Remove the specified `activity`
527-
pub fn remove<A: IntoActivityName>(&self, activity: A) -> bool {
528-
unsafe { BNWorkflowRemove(self.handle.as_ptr(), activity.activity_name().as_ptr()) }
530+
pub fn remove<A: BnStrCompatible>(&self, activity: A) -> bool {
531+
unsafe {
532+
BNWorkflowRemove(
533+
self.handle.as_ptr(),
534+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
535+
)
536+
}
529537
}
530538

531539
/// Replace the specified `activity`.
532540
///
533541
/// * `activity` - the Activity to replace
534542
/// * `new_activity` - the replacement Activity
535-
pub fn replace<A: IntoActivityName, N: IntoActivityName>(
543+
pub fn replace<A: BnStrCompatible, N: BnStrCompatible>(
536544
&self,
537545
activity: A,
538546
new_activity: N,
539547
) -> bool {
540548
unsafe {
541549
BNWorkflowReplace(
542550
self.handle.as_ptr(),
543-
activity.activity_name().as_ptr(),
544-
new_activity.activity_name().as_ptr(),
551+
activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
552+
new_activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char,
545553
)
546554
}
547555
}
@@ -550,15 +558,20 @@ impl Workflow {
550558
///
551559
/// * `activity` - if specified, generate the Flowgraph using `activity` as the root
552560
/// * `sequential` - whether to generate a **Composite** or **Sequential** style graph
553-
pub fn graph<A: IntoActivityName>(
561+
pub fn graph<A: BnStrCompatible>(
554562
&self,
555563
activity: A,
556564
sequential: Option<bool>,
557565
) -> Option<FlowGraph> {
558566
let sequential = sequential.unwrap_or(false);
559-
let activity_name = activity.activity_name();
560-
let graph =
561-
unsafe { BNWorkflowGetGraph(self.handle.as_ptr(), activity_name.as_ptr(), sequential) };
567+
let activity_name = activity.into_bytes_with_nul();
568+
let graph = unsafe {
569+
BNWorkflowGetGraph(
570+
self.handle.as_ptr(),
571+
activity_name.as_ref().as_ptr() as *const c_char,
572+
sequential,
573+
)
574+
};
562575
if graph.is_null() {
563576
return None;
564577
}

0 commit comments

Comments
 (0)