From 7eb2b8fc3bd39324a74e02652c8f678073947812 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Fri, 6 Jan 2023 14:13:55 -0500 Subject: Move `logger` module into its own file --- rust/src/logger.rs | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 rust/src/logger.rs (limited to 'rust/src/logger.rs') diff --git a/rust/src/logger.rs b/rust/src/logger.rs new file mode 100644 index 00000000..2b067892 --- /dev/null +++ b/rust/src/logger.rs @@ -0,0 +1,137 @@ +use std::os::raw::{c_char, c_void}; + +use log; + +use crate::string::BnStr; + +pub use binaryninjacore_sys::BNLogLevel as Level; +use binaryninjacore_sys::{BNLogListener, BNUpdateLogListeners}; + +struct Logger; +static LOGGER: Logger = Logger; + +impl log::Log for Logger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + use self::Level::*; + use binaryninjacore_sys::BNLog; + use log::Level; + use std::ffi::CString; + + let level = match record.level() { + Level::Error => ErrorLog, + Level::Warn => WarningLog, + Level::Info => InfoLog, + Level::Debug | Level::Trace => DebugLog, + }; + + if let Ok(msg) = CString::new(format!("{}", record.args())) { + unsafe { + BNLog(0, level, std::ptr::null(), 0, msg.as_ptr()); + } + }; + } + + fn flush(&self) {} +} + +/// Uses BinaryNinja's logging functionality as the sink for +/// Rust's `log` crate. +pub fn init(filter: log::LevelFilter) -> Result<(), log::SetLoggerError> { + log::set_max_level(filter); + log::set_logger(&LOGGER) +} + +pub trait LogListener: 'static + Sync { + fn log(&self, session: usize, level: Level, msg: &BnStr, logger_name: &BnStr, tid: usize); + fn level(&self) -> Level; + fn close(&self) {} +} + +pub struct LogGuard { + ctxt: *mut L, +} + +impl Drop for LogGuard { + fn drop(&mut self) { + use binaryninjacore_sys::BNUnregisterLogListener; + + let mut bn_obj = BNLogListener { + context: self.ctxt as *mut _, + log: Some(cb_log::), + close: Some(cb_close::), + getLogLevel: Some(cb_level::), + }; + + unsafe { + BNUnregisterLogListener(&mut bn_obj); + BNUpdateLogListeners(); + + let _listener = Box::from_raw(self.ctxt); + } + } +} + +pub fn register_listener(listener: L) -> LogGuard { + use binaryninjacore_sys::BNRegisterLogListener; + + let raw = Box::into_raw(Box::new(listener)); + let mut bn_obj = BNLogListener { + context: raw as *mut _, + log: Some(cb_log::), + close: Some(cb_close::), + getLogLevel: Some(cb_level::), + }; + + unsafe { + BNRegisterLogListener(&mut bn_obj); + BNUpdateLogListeners(); + } + + LogGuard { ctxt: raw } +} + +extern "C" fn cb_log( + ctxt: *mut c_void, + session: usize, + level: Level, + msg: *const c_char, + logger_name: *const c_char, + tid: usize, +) where + L: LogListener, +{ + ffi_wrap!("LogListener::log", unsafe { + let listener = &*(ctxt as *const L); + listener.log( + session, + level, + BnStr::from_raw(msg), + BnStr::from_raw(logger_name), + tid, + ); + }) +} + +extern "C" fn cb_close(ctxt: *mut c_void) +where + L: LogListener, +{ + ffi_wrap!("LogListener::close", unsafe { + let listener = &*(ctxt as *const L); + listener.close(); + }) +} + +extern "C" fn cb_level(ctxt: *mut c_void) -> Level +where + L: LogListener, +{ + ffi_wrap!("LogListener::log", unsafe { + let listener = &*(ctxt as *const L); + listener.level() + }) +} -- cgit v1.3.1