diff options
| author | Mason Reed <mason@vector35.com> | 2024-10-28 21:20:03 -0400 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2024-10-28 21:21:55 -0400 |
| commit | a38d13f32326b72e59503a8280f610c52e018366 (patch) | |
| tree | 44ea154e651489cc3d3e5a5fb5d17f894ace784d /plugins | |
| parent | 08f1c49f0cb7f74d0f50dcf60289e974ae9d5c3a (diff) | |
Refactor WARP to use a module workflow for matching
Also flush caches on view destruction and improve performance
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/warp/src/cache.rs | 181 | ||||
| -rw-r--r-- | plugins/warp/src/matcher.rs | 123 | ||||
| -rw-r--r-- | plugins/warp/src/plugin.rs | 27 | ||||
| -rw-r--r-- | plugins/warp/src/plugin/create.rs | 8 | ||||
| -rw-r--r-- | plugins/warp/src/plugin/types.rs | 2 | ||||
| -rw-r--r-- | plugins/warp/src/plugin/workflow.rs | 66 |
6 files changed, 251 insertions, 156 deletions
diff --git a/plugins/warp/src/cache.rs b/plugins/warp/src/cache.rs index bafc4ede..54ce339f 100644 --- a/plugins/warp/src/cache.rs +++ b/plugins/warp/src/cache.rs @@ -1,10 +1,14 @@ +use crate::convert::from_bn_symbol; +use crate::{build_function, function_guid}; use binaryninja::architecture::Architecture; use binaryninja::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; use binaryninja::function::Function as BNFunction; -use binaryninja::llil; use binaryninja::llil::{FunctionMutability, NonSSA, NonSSAVariant}; use binaryninja::rc::Guard; use binaryninja::rc::Ref as BNRef; +use binaryninja::symbol::Symbol as BNSymbol; +use binaryninja::{llil, ObjectDestructor}; +use dashmap::mapref::one::Ref; use dashmap::try_result::TryResult; use dashmap::DashMap; use std::collections::HashSet; @@ -13,12 +17,47 @@ use std::sync::OnceLock; use warp::signature::function::constraints::FunctionConstraint; use warp::signature::function::{Function, FunctionGUID}; -use crate::convert::from_bn_symbol; -use crate::{build_function, function_guid}; - +pub static MATCHED_FUNCTION_CACHE: OnceLock<DashMap<ViewID, MatchedFunctionCache>> = + OnceLock::new(); pub static FUNCTION_CACHE: OnceLock<DashMap<ViewID, FunctionCache>> = OnceLock::new(); pub static GUID_CACHE: OnceLock<DashMap<ViewID, GUIDCache>> = OnceLock::new(); +pub fn register_cache_destructor() { + pub static mut CACHE_DESTRUCTOR: CacheDestructor = CacheDestructor; + unsafe { CACHE_DESTRUCTOR.register() }; +} + +pub fn cached_function_match<F>(function: &BNFunction, f: F) -> Option<Function> +where + F: Fn() -> Option<Function>, +{ + let view = function.view(); + let view_id = ViewID::from(view.as_ref()); + let function_id = FunctionID::from(function); + let function_cache = MATCHED_FUNCTION_CACHE.get_or_init(Default::default); + match function_cache.get(&view_id) { + Some(cache) => cache.get_or_insert(&function_id, f).to_owned(), + None => { + let cache = MatchedFunctionCache::default(); + let matched = cache.get_or_insert(&function_id, f).to_owned(); + function_cache.insert(view_id, cache); + matched + } + } +} + +pub fn try_cached_function_match(function: &BNFunction) -> Option<Function> { + let view = function.view(); + let view_id = ViewID::from(view); + let function_id = FunctionID::from(function); + let function_cache = MATCHED_FUNCTION_CACHE.get_or_init(Default::default); + function_cache + .get(&view_id)? + .get(&function_id)? + .value() + .to_owned() +} + pub fn cached_function<A: Architecture, M: FunctionMutability, V: NonSSAVariant>( function: &BNFunction, llil: &llil::Function<A, M, NonSSA<V>>, @@ -85,6 +124,38 @@ pub fn cached_function_guid<A: Architecture, M: FunctionMutability, V: NonSSAVar } } +pub fn try_cached_function_guid(function: &BNFunction) -> Option<FunctionGUID> { + let view = function.view(); + let view_id = ViewID::from(view); + let guid_cache = GUID_CACHE.get_or_init(Default::default); + guid_cache.get(&view_id)?.try_function_guid(function) +} + +#[derive(Clone, Debug, Default)] +pub struct MatchedFunctionCache { + pub cache: DashMap<FunctionID, Option<Function>>, +} + +impl MatchedFunctionCache { + pub fn get_or_insert<F>( + &self, + function_id: &FunctionID, + f: F, + ) -> Ref<'_, FunctionID, Option<Function>> + where + F: FnOnce() -> Option<Function>, + { + self.cache.get(function_id).unwrap_or_else(|| { + self.cache.insert(*function_id, f()); + self.cache.get(function_id).unwrap() + }) + } + + pub fn get(&self, function_id: &FunctionID) -> Option<Ref<'_, FunctionID, Option<Function>>> { + self.cache.get(function_id) + } +} + #[derive(Clone, Debug, Default)] pub struct FunctionCache { pub cache: DashMap<FunctionID, Function>, @@ -119,22 +190,33 @@ impl GUIDCache { let view = function.view(); let func_id = FunctionID::from(function); let func_start = function.start(); + let func_platform = function.platform(); let mut constraints = HashSet::new(); for call_site in &function.call_sites() { - for cs_ref in &view.get_code_refs(call_site.address) { - let cs_ref_func = cs_ref.function(); - let cs_ref_func_id = FunctionID::from(cs_ref_func); - if cs_ref_func_id != func_id { - let call_site_offset: i64 = func_start as i64 - call_site.address as i64; - let function_constraint = match cs_ref_func.low_level_il_if_available() { - Some(cs_ref_func_llil) => self.function_constraint_with_guid( - cs_ref_func, - &cs_ref_func_llil, - call_site_offset, - ), - None => self.function_constraint(cs_ref_func, call_site_offset), - }; - constraints.insert(function_constraint); + for cs_ref_addr in view.get_code_refs_from(call_site.address, Some(function)) { + match view.function_at(&func_platform, cs_ref_addr) { + Ok(cs_ref_func) => { + // Call site is a function, constrain on it. + let cs_ref_func_id = FunctionID::from(cs_ref_func.as_ref()); + if cs_ref_func_id != func_id { + let call_site_offset: i64 = + func_start as i64 - call_site.address as i64; + constraints + .insert(self.function_constraint(&cs_ref_func, call_site_offset)); + } + } + Err(_) => { + // We could be dealing with an extern symbol, get the symbol as a constraint. + let call_site_offset: i64 = func_start as i64 - call_site.address as i64; + if let Ok(call_site_sym) = view.symbol_by_address(cs_ref_addr) { + constraints.insert( + self.function_constraint_from_symbol( + &call_site_sym, + call_site_offset, + ), + ); + } + } } } } @@ -152,19 +234,10 @@ impl GUIDCache { for curr_func in &view.functions_at(func_start_addr) { let curr_func_id = FunctionID::from(curr_func.as_ref()); if curr_func_id != func_id { - // NOTE: We have to get the llil here for the function which is problematic for running - // NOTE: within a workflow (before analysis has finished) + // NOTE: For this to work the GUID has to have already been cached. If not it will just be the symbol. // Function adjacent to another function, constrain on the pattern. let curr_addr_offset = (func_start_addr as i64) - func_start as i64; - let function_constraint = match curr_func.low_level_il_if_available() { - Some(curr_func_llil) => self.function_constraint_with_guid( - &curr_func, - &curr_func_llil, - curr_addr_offset, - ), - None => self.function_constraint(&curr_func, curr_addr_offset), - }; - constraints.insert(function_constraint); + constraints.insert(self.function_constraint(&curr_func, curr_addr_offset)); } } }; @@ -186,29 +259,24 @@ impl GUIDCache { /// Construct a function constraint, must pass the offset at which it is located. pub fn function_constraint(&self, function: &BNFunction, offset: i64) -> FunctionConstraint { + let guid = self.try_function_guid(function); let symbol = from_bn_symbol(&function.symbol()); FunctionConstraint { - guid: None, + guid, symbol: Some(symbol), offset, } } - /// Construct a function constraint, must pass the offset at which it is located. - pub fn function_constraint_with_guid< - A: Architecture, - M: FunctionMutability, - V: NonSSAVariant, - >( + /// Construct a function constraint from a symbol, typically used for extern function call sites, must pass the offset at which it is located. + pub fn function_constraint_from_symbol( &self, - function: &BNFunction, - llil: &llil::Function<A, M, NonSSA<V>>, + symbol: &BNSymbol, offset: i64, ) -> FunctionConstraint { - let guid = self.function_guid(function, llil); - let symbol = from_bn_symbol(&function.symbol()); + let symbol = from_bn_symbol(symbol); FunctionConstraint { - guid: Some(guid), + guid: None, symbol: Some(symbol), offset, } @@ -227,9 +295,19 @@ impl GUIDCache { self.cache.insert(function_id, function_guid); function_guid } - TryResult::Locked => function_guid(function, llil), + TryResult::Locked => { + log::warn!("Failed to acquire function guid cache"); + function_guid(function, llil) + } } } + + pub fn try_function_guid(&self, function: &BNFunction) -> Option<FunctionGUID> { + let function_id = FunctionID::from(function); + self.cache + .get(&function_id) + .map(|function_guid| function_guid.value().to_owned()) + } } /// A unique view ID, used for caching. @@ -284,3 +362,22 @@ impl From<Guard<'_, BNFunction>> for FunctionID { Self::from(value.as_ref()) } } + +pub struct CacheDestructor; + +impl ObjectDestructor for CacheDestructor { + fn destruct_view(&self, view: &BinaryView) { + // Clear caches as the view is no longer alive. + let view_id = ViewID::from(view); + if let Some(cache) = MATCHED_FUNCTION_CACHE.get() { + cache.remove(&view_id); + } + if let Some(cache) = FUNCTION_CACHE.get() { + cache.remove(&view_id); + } + if let Some(cache) = GUID_CACHE.get() { + cache.remove(&view_id); + } + log::debug!("Removed WARP caches for {:?}", view); + } +} diff --git a/plugins/warp/src/matcher.rs b/plugins/warp/src/matcher.rs index 46ddd88c..81755af9 100644 --- a/plugins/warp/src/matcher.rs +++ b/plugins/warp/src/matcher.rs @@ -1,14 +1,11 @@ -use binaryninja::architecture::{Architecture as BNArchitecture, Architecture}; +use binaryninja::architecture::Architecture as BNArchitecture; use binaryninja::backgroundtask::BackgroundTask; use binaryninja::binaryview::{BinaryView, BinaryViewExt}; use binaryninja::function::{Function as BNFunction, FunctionUpdateType}; -use binaryninja::llil; -use binaryninja::llil::{FunctionMutability, NonSSA, NonSSAVariant}; use binaryninja::platform::Platform; use binaryninja::rc::Guard; use binaryninja::rc::Ref as BNRef; use dashmap::DashMap; -use fastbloom::BloomFilter; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::hash::{DefaultHasher, Hasher}; @@ -18,44 +15,41 @@ use walkdir::{DirEntry, WalkDir}; use warp::r#type::class::TypeClass; use warp::r#type::guid::TypeGUID; use warp::r#type::Type; -use warp::signature::basic_block::BasicBlock; use warp::signature::function::{Function, FunctionGUID}; use warp::signature::Data; -use crate::cache::{cached_call_site_constraints, cached_function_guid, FunctionID}; +use crate::cache::{cached_call_site_constraints, cached_function_match, try_cached_function_guid}; use crate::convert::to_bn_type; -use crate::entry_basic_block_guid; use crate::plugin::on_matched_function; -pub const TRIVIAL_LLIL_THRESHOLD: usize = 8; +pub const TRIVIAL_FUNCTION_DELTA_THRESHOLD: u64 = 8; pub static PLAT_MATCHER_CACHE: OnceLock<DashMap<PlatformID, Matcher>> = OnceLock::new(); -pub fn cached_function_match<A: Architecture, M: FunctionMutability, V: NonSSAVariant>( - function: &BNFunction, - llil: &llil::Function<A, M, NonSSA<V>>, -) { +pub fn cached_function_matcher(function: &BNFunction) { let platform = function.platform(); let platform_id = PlatformID::from(platform.as_ref()); let matcher_cache = PLAT_MATCHER_CACHE.get_or_init(Default::default); match matcher_cache.get(&platform_id) { - Some(matcher) => matcher.match_function(function, llil), + Some(matcher) => matcher.match_function(function), None => { let matcher = Matcher::from_platform(platform); - matcher.match_function(function, llil); + matcher.match_function(function); matcher_cache.insert(platform_id, matcher); } } } +// TODO: Maybe just clear individual platforms? This works well enough either way. +pub fn invalidate_function_matcher_cache() { + let matcher_cache = PLAT_MATCHER_CACHE.get_or_init(Default::default); + matcher_cache.clear(); +} + pub struct Matcher { - pub matched_functions: DashMap<FunctionID, Function>, pub functions: DashMap<FunctionGUID, Vec<Function>>, pub types: DashMap<TypeGUID, Type>, pub named_types: DashMap<String, Type>, - /// This is used to fast-fail on functions not in the dataset. - /// NOTE: This can only handle one basic block classification, right now that is the entry block. - basic_block_filter: BloomFilter, } impl Matcher { @@ -83,20 +77,8 @@ impl Matcher { // TODO: If a user signature has the same name as a core signature, remove the core signature. - task.set_progress_text("Gathering entry blocks for matcher filtering..."); - - // Get entry_blocks for filtering. - let entry_blocks = data - .iter() - .flat_map(|(_, data)| data.functions.iter().map(|function| &function.entry)) - .collect::<Vec<_>>(); - // TODO: We need to disable this if we get a None basic block, as it will then fail to match all cases. - let basic_block_filter = BloomFilter::with_false_pos(0.1).items(entry_blocks); - task.set_progress_text("Gathering matcher functions..."); - // TODO: Merge like functions, right now we just hope and pray. - // Get functions for comprehensive matching. let functions = data .iter() @@ -148,9 +130,7 @@ impl Matcher { log::debug!("Loaded signatures: {:?}", data.keys()); Self { - matched_functions: Default::default(), functions, - basic_block_filter, types, named_types, } @@ -239,18 +219,8 @@ impl Matcher { inner_add_type_to_view(self, view, arch, &mut HashSet::new(), ty) } - pub fn match_function<A: Architecture, M: FunctionMutability, V: NonSSAVariant>( - &self, - function: &BNFunction, - llil: &llil::Function<A, M, NonSSA<V>>, - ) { - let function_id = FunctionID::from(function); - if let Some(matched_function) = self.matched_functions.get(&function_id) { - // Skip computing the match for already matched function. - // We do still need to apply the match data through analysis updates. - return on_matched_function(function, &matched_function); - } - + pub fn match_function(&self, function: &BNFunction) { + // Call this the first time you matched on the function. let on_new_match = |matched: &Function| { // We also want to resolve the types here. if let TypeClass::Function(c) = matched.ty.class.as_ref() { @@ -263,51 +233,32 @@ impl Matcher { for in_member in &c.in_members { self.add_type_to_view(&view, &arch, &in_member.ty); } - } else { - // This should never happen. - log::error!( - "Matched function is not of function type class... 0x{:x}", - function.start() - ); } - on_matched_function(function, matched); - - // We matched on the function, great! Now make sure we don't do this again :3 - self.matched_functions - .insert(function_id, matched.to_owned()); // Also mark this for updates. // TODO: Does this do anything? function.mark_updates_required(FunctionUpdateType::UserFunctionUpdate); }; - // TODO: Expand this check to be less broad. - let is_function_trivial = { llil.instruction_count() < TRIVIAL_LLIL_THRESHOLD }; - - // Check to see if the functions entry block is even in the dataset - let entry_block = entry_basic_block_guid(function, llil).map(BasicBlock::new); - if self.basic_block_filter.contains(&entry_block) { - // Build the full function guid now - let warp_func_guid = cached_function_guid(function, llil); - if let Some(matched) = self.functions.get(&warp_func_guid) { - if matched.len() == 1 && !is_function_trivial { + if let Some(matched_function) = cached_function_match(function, || { + // We have yet to match on this function. + // TODO: Expand this check to be less broad. + let function_delta = function.highest_address() - function.lowest_address(); + let is_function_trivial = { function_delta < TRIVIAL_FUNCTION_DELTA_THRESHOLD }; + let warp_func_guid = try_cached_function_guid(function)?; + match self.functions.get(&warp_func_guid) { + Some(matched) if matched.len() == 1 && !is_function_trivial => { on_new_match(&matched[0]); - } else if let Some(matched_function) = - self.match_function_from_constraints(function, &matched) - { - log::debug!( - "Found best matching function `{}`... 0x{:x}", - matched_function.symbol.name, - function.start() - ); - on_new_match(matched_function); - } else { - log::debug!( - "Failed to find matching function `{}`... 0x{:x}", - matched.len(), - function.start() - ); + Some(matched[0].to_owned()) } + Some(matched) => { + let matched_on = self.match_function_from_constraints(function, &matched)?; + on_new_match(matched_on); + Some(matched_on.to_owned()) + } + None => None, } + }) { + on_matched_function(function, &matched_function); } } @@ -387,7 +338,17 @@ impl Matcher { match highest_guid_count.cmp(&highest_symbol_count) { Ordering::Less => matched_symbol_func, Ordering::Greater => matched_guid_func, - Ordering::Equal => None, + Ordering::Equal => { + // If the two highest our the same we can use it. + let ty_is_same = matched_guid_func?.ty == matched_symbol_func?.ty; + let sym_is_same = matched_guid_func?.symbol == matched_symbol_func?.symbol; + if ty_is_same && sym_is_same { + matched_guid_func + } else { + // We matched equally on two different functions + None + } + } } } } diff --git a/plugins/warp/src/plugin.rs b/plugins/warp/src/plugin.rs index 3373cafd..ad08e842 100644 --- a/plugins/warp/src/plugin.rs +++ b/plugins/warp/src/plugin.rs @@ -1,5 +1,11 @@ use log::LevelFilter; +use crate::build_function; +use crate::cache::{ + register_cache_destructor, ViewID, FUNCTION_CACHE, GUID_CACHE, MATCHED_FUNCTION_CACHE, +}; +use crate::convert::{to_bn_symbol_at_address, to_bn_type}; +use crate::matcher::{PlatformID, PLAT_MATCHER_CACHE}; use binaryninja::binaryview::{BinaryView, BinaryViewExt}; use binaryninja::command::{Command, FunctionCommand}; use binaryninja::function::Function; @@ -7,11 +13,6 @@ use binaryninja::rc::Ref; use binaryninja::tags::TagType; use warp::signature::function::Function as WarpFunction; -use crate::build_function; -use crate::cache::{ViewID, FUNCTION_CACHE, GUID_CACHE}; -use crate::convert::{to_bn_symbol_at_address, to_bn_type}; -use crate::matcher::{PlatformID, PLAT_MATCHER_CACHE}; - mod apply; mod copy; mod create; @@ -67,12 +68,17 @@ struct DebugCache; impl Command for DebugCache { fn action(&self, view: &BinaryView) { - let function_cache = FUNCTION_CACHE.get_or_init(Default::default); let view_id = ViewID::from(view); + let function_cache = FUNCTION_CACHE.get_or_init(Default::default); if let Some(cache) = function_cache.get(&view_id) { log::info!("View functions: {}", cache.cache.len()); } + let matched_function_cache = MATCHED_FUNCTION_CACHE.get_or_init(Default::default); + if let Some(cache) = matched_function_cache.get(&view_id) { + log::info!("View matched functions: {}", cache.cache.len()); + } + let function_guid_cache = GUID_CACHE.get_or_init(Default::default); if let Some(cache) = function_guid_cache.get(&view_id) { log::info!("View function guids: {}", cache.cache.len()); @@ -84,10 +90,6 @@ impl Command for DebugCache { if let Some(cache) = plat_cache.get(&platform_id) { log::info!("Platform functions: {}", cache.functions.len()); log::info!("Platform types: {}", cache.types.len()); - log::info!( - "Platform matched functions: {}", - cache.matched_functions.len() - ); } } } @@ -102,7 +104,10 @@ impl Command for DebugCache { pub extern "C" fn CorePluginInit() -> bool { binaryninja::logger::init(LevelFilter::Debug).unwrap(); - workflow::insert_matcher_workflow(); + // Make sure caches are flushed when the views get destructed. + register_cache_destructor(); + + workflow::insert_workflow(); binaryninja::command::register( "WARP\\Apply Signature File Types", diff --git a/plugins/warp/src/plugin/create.rs b/plugins/warp/src/plugin/create.rs index b404ae1c..966c69ca 100644 --- a/plugins/warp/src/plugin/create.rs +++ b/plugins/warp/src/plugin/create.rs @@ -1,5 +1,6 @@ use crate::cache::cached_function; use crate::convert::from_bn_type; +use crate::matcher::invalidate_function_matcher_cache; use binaryninja::binaryview::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; use rayon::prelude::*; @@ -15,7 +16,6 @@ pub struct CreateSignatureFile; impl Command for CreateSignatureFile { fn action(&self, view: &BinaryView) { let mut signature_dir = binaryninja::user_directory().unwrap().join("signatures/"); - // TODO: This needs to split out each platform into its own bucket... if let Some(default_plat) = view.default_platform() { // If there is a default platform, put the signature in there. signature_dir.push(default_plat.name().to_string()); @@ -53,7 +53,11 @@ impl Command for CreateSignatureFile { // TODO: Should we overwrite? Prompt user. if let Ok(mut file) = std::fs::File::create(&save_file) { match file.write_all(&data.to_bytes()) { - Ok(_) => log::info!("Signature file saved successfully."), + Ok(_) => { + log::info!("Signature file saved successfully."); + // Force rebuild platform matcher. + invalidate_function_matcher_cache(); + } Err(e) => log::error!("Failed to write data to signature file: {:?}", e), } } else { diff --git a/plugins/warp/src/plugin/types.rs b/plugins/warp/src/plugin/types.rs index ecb60428..5ddff403 100644 --- a/plugins/warp/src/plugin/types.rs +++ b/plugins/warp/src/plugin/types.rs @@ -23,7 +23,7 @@ impl Command for LoadTypesCommand { log::error!("Could not get data from signature file: {:?}", file); return; }; - + let Some(arch) = view.default_arch() else { log::error!("Could not get default architecture"); return; diff --git a/plugins/warp/src/plugin/workflow.rs b/plugins/warp/src/plugin/workflow.rs index da8473f0..bd47c117 100644 --- a/plugins/warp/src/plugin/workflow.rs +++ b/plugins/warp/src/plugin/workflow.rs @@ -1,38 +1,66 @@ -use crate::matcher::cached_function_match; +use crate::cache::cached_function_guid; +use crate::matcher::cached_function_matcher; +use binaryninja::backgroundtask::BackgroundTask; +use binaryninja::binaryview::BinaryViewExt; use binaryninja::llil; use binaryninja::workflow::{Activity, AnalysisContext, Workflow}; +use std::time::Instant; -const MATCHER_ACTIVITY_NAME: &str = "analysis.plugins.WARPMatcher"; +const MATCHER_ACTIVITY_NAME: &str = "analysis.plugins.warp.matcher"; // NOTE: runOnce is off because previously matched functions need info applied. const MATCHER_ACTIVITY_CONFIG: &str = r#"{ - "name": "analysis.plugins.WARPMatcher", + "name": "analysis.plugins.warp.matcher", "title" : "WARP Matcher", "description": "This analysis step applies WARP info to matched functions...", "eligibility": { - "auto": { "default": true }, + "auto": {}, "runOnce": false } }"#; -pub fn insert_matcher_workflow() { +const GUID_ACTIVITY_NAME: &str = "analysis.plugins.warp.guid"; +const GUID_ACTIVITY_CONFIG: &str = r#"{ + "name": "analysis.plugins.warp.guid", + "title" : "WARP GUID Generator", + "description": "This analysis step generates the GUID for all analyzed functions...", + "eligibility": { + "auto": {}, + "runOnce": true + } +}"#; + +pub fn insert_workflow() { let matcher_activity = |ctx: &AnalysisContext| { - let function = ctx.function(); - if function.has_user_annotations() { - // User has touched the function, stop trying to match on it! - return; - } + let view = ctx.view(); + let background_task = BackgroundTask::new("Matching on functions...", false).unwrap(); + let start = Instant::now(); + view.functions() + .iter() + .for_each(|function| cached_function_matcher(&function)); + log::info!("Function matching took {:?}", start.elapsed()); + background_task.finish(); + }; + let guid_activity = |ctx: &AnalysisContext| { + let function = ctx.function(); if let Some(llil) = unsafe { ctx.llil_function::<llil::NonSSA<llil::RegularNonSSA>>() } { - cached_function_match(&function, &llil); + cached_function_guid(&function, &llil); } }; - let meta_workflow = Workflow::new_from_copy("core.function.metaAnalysis"); - let activity = Activity::new_with_action(MATCHER_ACTIVITY_CONFIG, matcher_activity); - meta_workflow.register_activity(&activity).unwrap(); - meta_workflow.insert( - "core.function.runFunctionRecognizers", - [MATCHER_ACTIVITY_NAME], - ); - meta_workflow.register().unwrap(); + let function_meta_workflow = Workflow::new_from_copy("core.function.metaAnalysis"); + let guid_activity = Activity::new_with_action(GUID_ACTIVITY_CONFIG, guid_activity); + function_meta_workflow + .register_activity(&guid_activity) + .unwrap(); + function_meta_workflow.insert("core.function.runFunctionRecognizers", [GUID_ACTIVITY_NAME]); + function_meta_workflow.register().unwrap(); + + let module_meta_workflow = Workflow::new_from_copy("core.module.metaAnalysis"); + let matcher_activity = Activity::new_with_action(MATCHER_ACTIVITY_CONFIG, matcher_activity); + module_meta_workflow + .register_activity(&matcher_activity) + .unwrap(); + module_meta_workflow.insert("core.module.notifyCompletion", [MATCHER_ACTIVITY_NAME]); + module_meta_workflow.register().unwrap(); } |
