pub mod mapper; pub mod settings; use crate::mapper::DeviceMapper; use crate::settings::LoadSettings; use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}; use binaryninja::command::Command; use binaryninja::logger::Logger; use binaryninja::workflow::{activity, Activity, AnalysisContext, Workflow}; use log::LevelFilter; struct LoadSVDFile; impl Command for LoadSVDFile { fn action(&self, view: &BinaryView) { let Some(file) = binaryninja::interaction::get_open_filename_input("Select a .svd file", "*.svd") else { return; }; let file_content = match std::fs::read_to_string(&file) { Ok(content) => content, Err(e) => { log::error!("Failed to read file: {}", e); return; } }; match svd_parser::parse(&file_content) { Ok(device) => { // We have a supported svd device. map it! let load_settings = LoadSettings::from_view_settings(view); let address_size = view.address_size(); let mapper = DeviceMapper::new(load_settings, address_size, device); mapper.map_to_view(view); view.update_analysis(); } Err(e) => { log::error!("Failed to parse SVD file: {}", e); } } } fn valid(&self, _view: &BinaryView) -> bool { true } } #[no_mangle] #[allow(non_snake_case)] #[cfg(not(feature = "demo"))] pub extern "C" fn CorePluginInit() -> bool { if plugin_init().is_err() { log::error!("Failed to initialize SVD plug-in"); return false; } true } #[no_mangle] #[allow(non_snake_case)] #[cfg(feature = "demo")] pub extern "C" fn SVDPluginInit() -> bool { if plugin_init().is_err() { log::error!("Failed to initialize SVD plug-in"); return false; } true } fn plugin_init() -> Result<(), ()> { Logger::new("SVD").with_level(LevelFilter::Debug).init(); binaryninja::command::register_command( "Load SVD File", "Loads an SVD file into the current view.", LoadSVDFile {}, ); // Register settings globally. LoadSettings::register(); let loader_activity = |ctx: &AnalysisContext| { let view = ctx.view(); let load_settings = LoadSettings::from_view_settings(&view); let Some(file) = &load_settings.auto_load_file else { log::debug!("No SVD file specified, skipping..."); return; }; let file_content = match std::fs::read_to_string(file) { Ok(content) => content, Err(e) => { log::error!("Failed to read file: {}", e); return; } }; match svd_parser::parse(&file_content) { Ok(device) => { let address_size = view.address_size(); let mapper = DeviceMapper::new(load_settings, address_size, device); mapper.map_to_view(&view); } Err(e) => { log::error!("Failed to parse SVD file: {}", e); } } }; // Register new workflow activity to load svd information. let loader_config = activity::Config::action( "analysis.svd.loader", "SVD Loader", "This analysis step applies SVD info to the view...", ) .eligibility(activity::Eligibility::auto().run_once(true)); let loader_activity = Activity::new_with_action(loader_config, loader_activity); Workflow::cloned("core.module.metaAnalysis") .ok_or(())? .activity_before(&loader_activity, "core.module.loadDebugInfo")? .register()?; Ok(()) }