From 8e06d9a4262ab086a0d0f62dd89c4a428e7cfa50 Mon Sep 17 00:00:00 2001 From: Benjamin Klum Date: Thu, 15 Aug 2024 14:14:45 +0200 Subject: [PATCH] High-level API: Include module path in panic message --- main/high/src/debug_util.rs | 3 +- main/high/src/log_util.rs | 59 +++++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/main/high/src/debug_util.rs b/main/high/src/debug_util.rs index 731d1f03..198fa114 100644 --- a/main/high/src/debug_util.rs +++ b/main/high/src/debug_util.rs @@ -58,8 +58,7 @@ fn resolve_multiple_symbols( ", addresses.len() )); - let our_module_info = determine_module_info() - .ok_or("Couldn't get own module info ... maybe we are not on Windows?")?; + let our_module_info = determine_module_info()?; if let Some(our_module_size) = our_module_info.size { if our_module_size != their_module_size { warn(format!( diff --git a/main/high/src/log_util.rs b/main/high/src/log_util.rs index af228344..6270d7e2 100644 --- a/main/high/src/log_util.rs +++ b/main/high/src/log_util.rs @@ -1,8 +1,10 @@ +use std::ffi::CString; +use std::os::raw::c_char; use std::panic::PanicInfo; -use backtrace::Backtrace; - use crate::Reaper; +use backtrace::Backtrace; +use reaper_low::Swell; /// Creates a panic hook which logs the error both to the logging system and optionally to REAPER /// console. This is just a convenience function. You can easily write your own panic hook if you @@ -45,9 +47,10 @@ pub fn create_default_console_msg_formatter( ) -> impl Fn(&PanicInfo, &Backtrace) -> String { move |panic_info, backtrace| { let module_info = determine_module_info(); - let (module_base_address_label, module_size_label) = match module_info { - None => (hyphen(), hyphen()), - Some(mi) => ( + let (module_path, module_base_address_label, module_size_label) = match module_info { + Err(_) => (hyphen(), hyphen(), hyphen()), + Ok(mi) => ( + mi.path, format_as_hex(mi.base_address), mi.size.map(format_as_hex).unwrap_or_else(hyphen), ), @@ -75,6 +78,7 @@ Thank you for your support! REAPER version: {reaper_version} Module name: {plugin_name} Module version: {plugin_version} +Module path: {module_path} Module base address: {module_base_address_label} Module size: {module_size_label} @@ -103,30 +107,61 @@ pub fn log_panic(panic_info: &PanicInfo, backtrace: &Backtrace) { ); } +#[derive(Default)] pub(crate) struct ModuleInfo { pub base_address: usize, pub size: Option, + pub path: String, } -pub(crate) fn determine_module_info() -> Option { +pub(crate) fn determine_module_info() -> Result { + let hinstance = Reaper::get() + .medium_reaper() + .plugin_context() + .h_instance() + .ok_or("couldn't obtain HINSTANCE/HMODULE")?; #[cfg(target_family = "windows")] { - let hinstance = Reaper::get() - .medium_reaper() - .plugin_context() - .h_instance()?; let info = ModuleInfo { base_address: hinstance.as_ptr() as usize, size: determine_module_size(hinstance), + path: determine_module_path(hinstance), }; - Some(info) + Ok(info) } #[cfg(not(target_family = "windows"))] { - None + let info = ModuleInfo { + base_address: 0, + size: None, + path: determine_module_path(hinstance), + }; + Ok(info) } } +fn determine_module_path(hinstance: reaper_medium::Hinstance) -> String { + let (cstring, size) = with_string_buffer(1000, |buf, max_size| unsafe { + Swell::get().GetModuleFileName(hinstance.as_ptr(), buf, max_size as _) + }); + if size == 0 { + return String::new(); + } + cstring.to_string_lossy().to_string() +} + +fn with_string_buffer( + max_size: u32, + fill_buffer: impl FnOnce(*mut c_char, i32) -> T, +) -> (CString, T) { + let vec: Vec = vec![1; max_size as usize]; + let c_string = unsafe { CString::from_vec_unchecked(vec) }; + let raw = c_string.into_raw(); + let result = fill_buffer(raw, max_size as i32); + let string = unsafe { CString::from_raw(raw) }; + (string, result) +} + #[cfg(target_family = "windows")] fn determine_module_size(hinstance: reaper_medium::Hinstance) -> Option { let size = unsafe {