diff options
| author | Michael Krasnitski <michael.krasnitski@gmail.com> | 2023-01-06 14:13:55 -0500 |
|---|---|---|
| committer | Kyle Martin <krm504@nyu.edu> | 2023-01-10 00:11:27 -0500 |
| commit | 7eb2b8fc3bd39324a74e02652c8f678073947812 (patch) | |
| tree | 45fb2d86ce5241163e09df0fb03baec9d0d2f210 /rust/src/logger.rs | |
| parent | aa1e35b055feea170e421cc375b79eed2d46dad2 (diff) | |
Move `logger` module into its own file
Diffstat (limited to 'rust/src/logger.rs')
| -rw-r--r-- | rust/src/logger.rs | 137 |
1 files changed, 137 insertions, 0 deletions
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<L: LogListener> { + ctxt: *mut L, +} + +impl<L: LogListener> Drop for LogGuard<L> { + fn drop(&mut self) { + use binaryninjacore_sys::BNUnregisterLogListener; + + let mut bn_obj = BNLogListener { + context: self.ctxt as *mut _, + log: Some(cb_log::<L>), + close: Some(cb_close::<L>), + getLogLevel: Some(cb_level::<L>), + }; + + unsafe { + BNUnregisterLogListener(&mut bn_obj); + BNUpdateLogListeners(); + + let _listener = Box::from_raw(self.ctxt); + } + } +} + +pub fn register_listener<L: LogListener>(listener: L) -> LogGuard<L> { + 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::<L>), + close: Some(cb_close::<L>), + getLogLevel: Some(cb_level::<L>), + }; + + unsafe { + BNRegisterLogListener(&mut bn_obj); + BNUpdateLogListeners(); + } + + LogGuard { ctxt: raw } +} + +extern "C" fn cb_log<L>( + 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<L>(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<L>(ctxt: *mut c_void) -> Level +where + L: LogListener, +{ + ffi_wrap!("LogListener::log", unsafe { + let listener = &*(ctxt as *const L); + listener.level() + }) +} |
