summaryrefslogtreecommitdiff
path: root/plugins/warp/src/plugin/function.rs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/warp/src/plugin/function.rs')
-rw-r--r--plugins/warp/src/plugin/function.rs133
1 files changed, 133 insertions, 0 deletions
diff --git a/plugins/warp/src/plugin/function.rs b/plugins/warp/src/plugin/function.rs
new file mode 100644
index 00000000..130e8582
--- /dev/null
+++ b/plugins/warp/src/plugin/function.rs
@@ -0,0 +1,133 @@
+use crate::cache::{cached_function_guid, try_cached_function_guid};
+use crate::{get_warp_include_tag_type, INCLUDE_TAG_NAME};
+use binaryninja::background_task::BackgroundTask;
+use binaryninja::binary_view::{BinaryView, BinaryViewExt};
+use binaryninja::command::{Command, FunctionCommand};
+use binaryninja::function::Function;
+use binaryninja::rc::Guard;
+use rayon::iter::ParallelIterator;
+use std::thread;
+use warp::signature::function::FunctionGUID;
+
+pub struct IncludeFunction;
+
+impl FunctionCommand for IncludeFunction {
+ fn action(&self, view: &BinaryView, func: &Function) {
+ let sym_name = func.symbol().short_name();
+ let sym_name_str = sym_name.to_string_lossy();
+ let should_add_tag = func.function_tags(None, Some(INCLUDE_TAG_NAME)).is_empty();
+ let insert_tag_type = get_warp_include_tag_type(view);
+ match should_add_tag {
+ true => {
+ log::info!(
+ "Including selected function '{}' at 0x{:x}",
+ sym_name_str,
+ func.start()
+ );
+ func.add_tag(&insert_tag_type, "", None, false, None);
+ }
+ false => {
+ log::info!(
+ "Removing included function '{}' at 0x{:x}",
+ sym_name_str,
+ func.start()
+ );
+ func.remove_tags_of_type(&insert_tag_type, None, false, None);
+ }
+ }
+ }
+
+ fn valid(&self, _view: &BinaryView, _func: &Function) -> bool {
+ // TODO: Only allow if the function is named?
+ true
+ }
+}
+
+pub struct CopyFunctionGUID;
+
+impl FunctionCommand for CopyFunctionGUID {
+ fn action(&self, _view: &BinaryView, func: &Function) {
+ let Ok(lifted_il) = func.lifted_il() else {
+ log::error!("Could not get lifted il for copied function");
+ return;
+ };
+ let guid = cached_function_guid(func, &lifted_il);
+ log::info!(
+ "Function GUID for {:?}... {}",
+ func.symbol().short_name(),
+ guid
+ );
+ if let Ok(mut clipboard) = arboard::Clipboard::new() {
+ let _ = clipboard.set_text(guid.to_string());
+ }
+ }
+
+ fn valid(&self, _view: &BinaryView, _func: &Function) -> bool {
+ true
+ }
+}
+
+pub struct FindFunctionFromGUID;
+
+impl Command for FindFunctionFromGUID {
+ fn action(&self, view: &BinaryView) {
+ let Some(guid_str) = binaryninja::interaction::get_text_line_input(
+ "Function GUID",
+ "Find Function from GUID",
+ ) else {
+ return;
+ };
+
+ let Ok(searched_guid) = guid_str.parse::<FunctionGUID>() else {
+ log::error!("Failed to parse function guid... {}", guid_str);
+ return;
+ };
+
+ log::info!("Searching functions for GUID... {}", searched_guid);
+ let funcs = view.functions();
+ let view = view.to_owned();
+ thread::spawn(move || {
+ let background_task = BackgroundTask::new(
+ &format!("Searching functions for GUID... {}", searched_guid),
+ false,
+ );
+
+ // Only run this for functions which have already generated a GUID.
+ let matched: Vec<Guard<Function>> = funcs
+ .par_iter()
+ .filter(|func| {
+ try_cached_function_guid(func).is_some_and(|guid| guid == searched_guid)
+ })
+ .collect();
+
+ if matched.is_empty() {
+ log::info!("No matches found for GUID... {}", searched_guid);
+ } else {
+ for func in &matched {
+ // Also navigate the user, as that is probably what they want.
+ if matched.len() == 1 {
+ let current_view = view.file().current_view();
+ if view
+ .file()
+ .navigate_to(&current_view, func.start())
+ .is_err()
+ {
+ log::error!(
+ "Failed to navigate to found function 0x{:0x} in view {}",
+ func.start(),
+ current_view
+ );
+ }
+ }
+ log::info!("Match found at function... 0x{:0x}", func.start());
+ }
+ }
+
+ background_task.finish();
+ });
+ }
+
+ fn valid(&self, _view: &BinaryView) -> bool {
+ true
+ }
+}