diff options
| -rw-r--r-- | arch/armv7/arch_armv7.cpp | 4 | ||||
| -rw-r--r-- | binaryninjaapi.h | 420 | ||||
| -rw-r--r-- | binaryninjacore.h | 34 | ||||
| -rw-r--r-- | demangler/msvc/demangle_msvc.cpp | 4 | ||||
| -rw-r--r-- | exceptions.cpp | 10 | ||||
| -rw-r--r-- | ffi.h | 6 | ||||
| -rw-r--r-- | log.cpp | 301 | ||||
| -rw-r--r-- | mainthread.cpp | 2 | ||||
| -rw-r--r-- | plugins/rtti/itanium.cpp | 2 | ||||
| -rw-r--r-- | plugins/rtti/plugin.cpp | 8 | ||||
| -rw-r--r-- | rust/src/logger.rs | 26 | ||||
| -rw-r--r-- | ui/logview.h | 2 | ||||
| -rw-r--r-- | ui/progresstask.h | 6 | ||||
| -rw-r--r-- | view/elf/elfview.cpp | 6 | ||||
| -rw-r--r-- | view/macho/machoview.cpp | 4 | ||||
| -rw-r--r-- | view/md1rom/md1rom.cpp | 6 | ||||
| -rw-r--r-- | view/pe/peview.cpp | 6 | ||||
| -rw-r--r-- | view/pe/teview.cpp | 6 | ||||
| -rw-r--r-- | view/sharedcache/core/SharedCacheBuilder.cpp | 2 |
19 files changed, 817 insertions, 38 deletions
diff --git a/arch/armv7/arch_armv7.cpp b/arch/armv7/arch_armv7.cpp index a851b5ad..e30ecf78 100644 --- a/arch/armv7/arch_armv7.cpp +++ b/arch/armv7/arch_armv7.cpp @@ -1389,9 +1389,9 @@ public: } } } - catch (exception&) + catch (exception& e) { - LogWarn("Failed to disassemble instruction with encoding: %" PRIx32 "\n", *(uint32_t*)data); + LogWarnForException(e, "Failed to disassemble instruction with encoding: %" PRIx32 "\n", *(uint32_t*)data); } return true; } diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 4566ddd3..2173dd19 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -588,6 +588,8 @@ namespace BinaryNinja { class LogListener { static void LogMessageCallback(void* ctxt, size_t session, BNLogLevel level, const char* msg, const char* logger_name = "", size_t tid = 0); + static void LogMessageWithStackTraceCallback(void* ctxt, size_t session, BNLogLevel level, + const char* stackTrace, const char* msg, const char* logger_name = "", size_t tid = 0); static void CloseLogCallback(void* ctxt); static BNLogLevel GetLogLevelCallback(void* ctxt); @@ -599,6 +601,8 @@ namespace BinaryNinja { static void UpdateLogListeners(); virtual void LogMessage(size_t session, BNLogLevel level, const std::string& msg, const std::string& logger_name = "", size_t tid = 0) = 0; + virtual void LogMessageWithStackTrace(size_t session, BNLogLevel level, const std::string& stackTrace, + const std::string& msg, const std::string& logger_name = "", size_t tid = 0); virtual void CloseLog() {} virtual BNLogLevel GetLogLevel() { return WarningLog; } }; @@ -711,6 +715,104 @@ namespace BinaryNinja { BN_PRINTF_ATTRIBUTE(1, 2) void LogAlert(const char* fmt, ...); + /*! Logs to the error console with the given BNLogLevel. + + @threadsafe + + \ingroup logging + + \param level BNLogLevel debug log level + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + BN_PRINTF_ATTRIBUTE(3, 4) + void LogForException(BNLogLevel level, const std::exception& e, const char* fmt, ...); + + /*! LogTraceForException only writes text to the error console if the console is set to log level: DebugLog + Log level and the build is not a DEBUG build (i.e. the preprocessor directive _DEBUG is defined) + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + BN_PRINTF_ATTRIBUTE(2, 3) + void LogTraceForException(const std::exception& e, const char* fmt, ...); + + /*! LogDebugForException only writes text to the error console if the console is set to log level: DebugLog + Log level DebugLog is the most verbose logging level in release builds. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + BN_PRINTF_ATTRIBUTE(2, 3) + void LogDebugForException(const std::exception& e, const char* fmt, ...); + + /*! LogInfoForException always writes text to the error console, and corresponds to the log level: InfoLog. + Log level InfoLog is the second most verbose logging level. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + BN_PRINTF_ATTRIBUTE(2, 3) + void LogInfoForException(const std::exception& e, const char* fmt, ...); + + /*! LogWarnForException writes text to the error console including a warning icon, + and also shows a warning icon in the bottom pane. LogWarn corresponds to the log level: WarningLog. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + BN_PRINTF_ATTRIBUTE(2, 3) + void LogWarnForException(const std::exception& e, const char* fmt, ...); + + /*! LogErrorForException writes text to the error console and pops up the error console. Additionally, + Errors in the console log include a error icon. LogError corresponds to the log level: ErrorLog. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + BN_PRINTF_ATTRIBUTE(2, 3) + void LogErrorForException(const std::exception& e, const char* fmt, ...); + + /*! LogAlertForException pops up a message box displaying the alert message and logs to the error console. + LogAlert corresponds to the log level: AlertLog. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + BN_PRINTF_ATTRIBUTE(2, 3) + void LogAlertForException(const std::exception& e, const char* fmt, ...); + // Implementation detail void LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args); void LogTraceFV(fmt::string_view format, fmt::format_args args); @@ -719,6 +821,13 @@ namespace BinaryNinja { void LogWarnFV(fmt::string_view format, fmt::format_args args); void LogErrorFV(fmt::string_view format, fmt::format_args args); void LogAlertFV(fmt::string_view format, fmt::format_args args); + void LogForExceptionFV(BNLogLevel level, const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogTraceForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogDebugForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogInfoForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogWarnForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogErrorForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogAlertForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); /*! Logs to the error console with the given BNLogLevel. @@ -832,6 +941,125 @@ namespace BinaryNinja { LogAlertFV(format, fmt::make_format_args(args...)); } + /*! Logs to the error console with the given BNLogLevel. + + @threadsafe + + \ingroup logging + + \param level BNLogLevel debug log level + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogForExceptionF(BNLogLevel level, const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogWithForExceptionFV(level, e, format, fmt::make_format_args(args...)); + } + + /*! LogTraceForExceptionF only writes text to the error console if the console is set to log level: DebugLog + Log level and the build is not a DEBUG build (i.e. the preprocessor directive _DEBUG is defined) + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogTraceForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogTraceForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogDebugForExceptionF only writes text to the error console if the console is set to log level: DebugLog + Log level DebugLog is the most verbose logging level in release builds. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogDebugForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogDebugForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogInfoForExceptionF always writes text to the error console, and corresponds to the log level: InfoLog. + Log level InfoLog is the second most verbose logging level. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogInfoForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogInfoForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogWarnForExceptionF writes text to the error console including a warning icon, + and also shows a warning icon in the bottom pane. LogWarn corresponds to the log level: WarningLog. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogWarnForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogWarnForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogErrorForExceptionF writes text to the error console and pops up the error console. Additionally, + Errors in the console log include a error icon. LogError corresponds to the log level: ErrorLog. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogErrorForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogErrorForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogAlertForExceptionF pops up a message box displaying the alert message and logs to the error console. + LogAlert corresponds to the log level: AlertLog. + + @threadsafe + + \ingroup logging + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogAlertForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogAlertForExceptionFV(e, format, fmt::make_format_args(args...)); + } + /*! Redirects the minimum level passed to standard out @threadsafe @@ -890,6 +1118,15 @@ namespace BinaryNinja { void LogErrorFV(fmt::string_view format, fmt::format_args args); void LogAlertFV(fmt::string_view format, fmt::format_args args); + void LogForExceptionFV( + BNLogLevel level, const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogTraceForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogDebugForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogInfoForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogWarnForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogErrorForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + void LogAlertForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args); + public: Logger(BNLogger* logger); @@ -988,6 +1225,83 @@ namespace BinaryNinja { @threadsafe \param level BNLogLevel debug log level + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + void LogForException(BNLogLevel level, const std::exception& e, const char* fmt, ...); + + /*! LogTraceForException only writes text to the error console if the console is set to log level: + DebugLog Log level and the build is not a DEBUG build (i.e. the preprocessor directive _DEBUG is defined) + + @threadsafe + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + void LogTraceForException(const std::exception& e, const char* fmt, ...); + + /*! LogDebugForException only writes text to the error console if the console is set to log level: + DebugLog Log level DebugLog is the most verbose logging level in release builds. + + @threadsafe + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + void LogDebugForException(const std::exception& e, const char* fmt, ...); + + /*! LogInfoForException always writes text to the error console, and corresponds to the log level: + InfoLog. Log level InfoLog is the second most verbose logging level. + + @threadsafe + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + void LogInfoForException(const std::exception& e, const char* fmt, ...); + + /*! LogWarnForException writes text to the error console including a warning icon, + and also shows a warning icon in the bottom pane. LogWarn corresponds to the log level: WarningLog. + + @threadsafe + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + void LogWarnForException(const std::exception& e, const char* fmt, ...); + + /*! LogErrorForException writes text to the error console and pops up the error console. Additionally, + Errors in the console log include a error icon. LogError corresponds to the log level: ErrorLog. + + @threadsafe + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + void LogErrorForException(const std::exception& e, const char* fmt, ...); + + /*! LogAlertForException pops up a message box displaying the alert message and logs to the error console. + LogAlert corresponds to the log level: AlertLog. + + @threadsafe + + \param e Exception being handled. + \param fmt C-style format string. + \param ... Variable arguments corresponding to the format string. + */ + void LogAlertForException(const std::exception& e, const char* fmt, ...); + + /*! Logs to the error console with the given BNLogLevel. + + @threadsafe + + \param level BNLogLevel debug log level \param format fmt-style format string. \param ... Variable arguments corresponding to the format string. */ @@ -1081,6 +1395,112 @@ namespace BinaryNinja { LogAlertFV(format, fmt::make_format_args(args...)); } + /*! Logs to the error console with the given BNLogLevel and a stack trace. + + @threadsafe + + \param level BNLogLevel debug log level + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogForExceptionF( + BNLogLevel level, const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogWithForExceptionFV(level, e, format, fmt::make_format_args(args...)); + } + + /*! LogTraceForExceptionF only writes text to the error console if the console is set to log level: + DebugLog Log level and the build is not a DEBUG build (i.e. the preprocessor directive _DEBUG is defined) + + @threadsafe + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogTraceForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogTraceForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogDebugForExceptionF only writes text to the error console if the console is set to log level: + DebugLog Log level DebugLog is the most verbose logging level in release builds. + + @threadsafe + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogDebugForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogDebugForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogInfoForExceptionF always writes text to the error console, and corresponds to the log level: + InfoLog. Log level InfoLog is the second most verbose logging level. + + @threadsafe + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogInfoForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogInfoForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogWarnForExceptionF writes text to the error console including a warning icon, + and also shows a warning icon in the bottom pane. LogWarn corresponds to the log level: WarningLog. + + @threadsafe + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogWarnForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogWarnForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogErrorForExceptionF writes text to the error console and pops up the error console. Additionally, + Errors in the console log include a error icon. LogError corresponds to the log level: ErrorLog. + + @threadsafe + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogErrorForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogErrorForExceptionFV(e, format, fmt::make_format_args(args...)); + } + + /*! LogAlertForExceptionF pops up a message box displaying the alert message and logs to the error + console. LogAlert corresponds to the log level: AlertLog. + + @threadsafe + + \param e Exception being handled. + \param format fmt-style format string. + \param ... Variable arguments corresponding to the format string. + */ + template <typename... T> + void LogAlertForExceptionF(const std::exception& e, fmt::format_string<T...> format, T&&... args) + { + LogAlertForExceptionFV(e, format, fmt::make_format_args(args...)); + } + /*! Get the name registered for this Logger @threadsafe diff --git a/binaryninjacore.h b/binaryninjacore.h index 01b1c178..b7f9e63a 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -37,14 +37,14 @@ // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, // new types, or modifications to existing functions or types. -#define BN_CURRENT_CORE_ABI_VERSION 127 +#define BN_CURRENT_CORE_ABI_VERSION 128 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and // will require rebuilding. The minimum version is increased when there are // incompatible changes that break binary compatibility, such as changes to // existing types or functions. -#define BN_MINIMUM_CORE_ABI_VERSION 124 +#define BN_MINIMUM_CORE_ABI_VERSION 128 #ifdef __GNUC__ #ifdef BINARYNINJACORE_LIBRARY @@ -1560,6 +1560,8 @@ extern "C" { void* context; void (*log)(void* ctxt, size_t sessionId, BNLogLevel level, const char* msg, const char* logger_name, size_t tid); + void (*logWithStackTrace)(void* ctxt, size_t sessionId, BNLogLevel level, const char* stackTrace, + const char* msg, const char* logger_name, size_t tid); void (*close)(void* ctxt); BNLogLevel (*getLogLevel)(void* ctxt); } BNLogListener; @@ -3869,6 +3871,28 @@ extern "C" BINARYNINJACOREAPI void BNLogString( size_t session, BNLogLevel level, const char* logger_name, size_t tid, const char* str); + BN_PRINTF_ATTRIBUTE(6, 7) + BINARYNINJACOREAPI void BNLogWithStackTrace(size_t session, BNLogLevel level, const char* logger_name, size_t tid, + const char* stackTrace, const char* fmt, ...); + + BN_PRINTF_ATTRIBUTE(2, 3) + BINARYNINJACOREAPI void BNLogDebugWithStackTrace(const char* stackTrace, const char* fmt, ...); + + BN_PRINTF_ATTRIBUTE(2, 3) + BINARYNINJACOREAPI void BNLogInfoWithStackTrace(const char* stackTrace, const char* fmt, ...); + + BN_PRINTF_ATTRIBUTE(2, 3) + BINARYNINJACOREAPI void BNLogWarnWithStackTrace(const char* stackTrace, const char* fmt, ...); + + BN_PRINTF_ATTRIBUTE(2, 3) + BINARYNINJACOREAPI void BNLogErrorWithStackTrace(const char* stackTrace, const char* fmt, ...); + + BN_PRINTF_ATTRIBUTE(2, 3) + BINARYNINJACOREAPI void BNLogAlertWithStackTrace(const char* stackTrace, const char* fmt, ...); + + BINARYNINJACOREAPI void BNLogStringWithStackTrace( + size_t session, BNLogLevel level, const char* logger_name, size_t tid, const char* stackTrace, const char* str); + BINARYNINJACOREAPI BNLogger* BNNewLoggerReference(BNLogger* logger); BINARYNINJACOREAPI void BNFreeLogger(BNLogger* logger); @@ -3877,6 +3901,12 @@ extern "C" BINARYNINJACOREAPI void BNLoggerLog(BNLogger* logger, BNLogLevel level, const char* fmt, ...); BINARYNINJACOREAPI void BNLoggerLogString(BNLogger* logger, BNLogLevel level, const char* msg); + BN_PRINTF_ATTRIBUTE(4, 5) + BINARYNINJACOREAPI void BNLoggerLogWithStackTrace( + BNLogger* logger, BNLogLevel level, const char* stackTrace, const char* fmt, ...); + BINARYNINJACOREAPI void BNLoggerLogStringWithStackTrace( + BNLogger* logger, BNLogLevel level, const char* stackTrace, const char* msg); + BINARYNINJACOREAPI char* BNLoggerGetName(BNLogger* logger); BINARYNINJACOREAPI size_t BNLoggerGetSessionId(BNLogger* logger); BINARYNINJACOREAPI void BNLoggerIndent(BNLogger* logger); diff --git a/demangler/msvc/demangle_msvc.cpp b/demangler/msvc/demangle_msvc.cpp index 9966db38..c82d816a 100644 --- a/demangler/msvc/demangle_msvc.cpp +++ b/demangler/msvc/demangle_msvc.cpp @@ -1828,7 +1828,7 @@ bool Demangle::DemangleMS(Architecture* arch, const string& mangledName, Ref<Typ } catch (DemangleException &e) { - LogDebug("Demangling Failed '%s' '%s;", mangledName.c_str(), e.what()); + LogDebugForException(e, "Demangling Failed '%s' '%s;", mangledName.c_str(), e.what()); return false; } return true; @@ -1851,7 +1851,7 @@ bool Demangle::DemangleMS(const string& mangledName, Ref<Type>& outType, } catch (DemangleException &e) { - LogDebug("Demangling Failed '%s' '%s;", mangledName.c_str(), e.what()); + LogDebugForException(e, "Demangling Failed '%s' '%s;", mangledName.c_str(), e.what()); return false; } return true; diff --git a/exceptions.cpp b/exceptions.cpp index e57b8d09..4dcf01a2 100644 --- a/exceptions.cpp +++ b/exceptions.cpp @@ -32,11 +32,6 @@ BinaryNinja::ExceptionWithStackTrace::ExceptionWithStackTrace(const std::string& if (stackTrace) { m_stackTrace = stackTrace; - if (var) - { - m_message += "\n"; - m_message += stackTrace; - } BNFreeString(stackTrace); } } @@ -97,11 +92,6 @@ BinaryNinja::ExceptionWithStackTrace::ExceptionWithStackTrace(std::exception_ptr if (stackTrace) { m_stackTrace = stackTrace; - if (var) - { - m_message += "\n"; - m_message += stackTrace; - } BNFreeString(stackTrace); } } @@ -149,7 +149,7 @@ namespace BinaryNinja //region Try/Catch Helpers // Forward declare this, so we don't have to depend on binaryninjaapi.h - void LogError(const char*, ...); + void LogErrorForException(const std::exception& e, const char*, ...); /*! Wrap a throwable block in a try/catch, passing through the return value on success, and @@ -200,7 +200,7 @@ namespace BinaryNinja { // TODO: How to handle this? // g_lastExceptionMessage = e.what(); - LogError("%s", e.what()); + LogErrorForException(e, "%s", e.what()); return nullptr; } catch (...) @@ -237,7 +237,7 @@ namespace BinaryNinja { // TODO: How to handle this? // g_lastExceptionMessage = e.what(); - LogError("%s", e.what()); + LogErrorForException(e, "%s", e.what()); return false; } catch (...) @@ -34,6 +34,14 @@ void LogListener::LogMessageCallback(void* ctxt, size_t session, BNLogLevel leve } +void LogListener::LogMessageWithStackTraceCallback(void* ctxt, size_t session, BNLogLevel level, const char* stackTrace, + const char* msg, const char* logger_name, size_t tid) +{ + LogListener* listener = (LogListener*)ctxt; + listener->LogMessageWithStackTrace(session, level, stackTrace, msg, logger_name, tid); +} + + void LogListener::CloseLogCallback(void* ctxt) { LogListener* listener = (LogListener*)ctxt; @@ -53,6 +61,7 @@ void LogListener::RegisterLogListener(LogListener* listener) BNLogListener callbacks; callbacks.context = listener; callbacks.log = LogMessageCallback; + callbacks.logWithStackTrace = LogMessageWithStackTraceCallback; callbacks.close = CloseLogCallback; callbacks.getLogLevel = GetLogLevelCallback; BNRegisterLogListener(&callbacks); @@ -64,7 +73,9 @@ void LogListener::UnregisterLogListener(LogListener* listener) BNLogListener callbacks; callbacks.context = listener; callbacks.log = LogMessageCallback; + callbacks.logWithStackTrace = LogMessageWithStackTraceCallback; callbacks.close = CloseLogCallback; + callbacks.getLogLevel = GetLogLevelCallback; BNUnregisterLogListener(&callbacks); } @@ -75,6 +86,13 @@ void LogListener::UpdateLogListeners() } +void LogListener::LogMessageWithStackTrace(size_t session, BNLogLevel level, const std::string&, const std::string& msg, + const std::string& logger_name, size_t tid) +{ + LogMessage(session, level, msg, logger_name, tid); +} + + static void PerformLog(size_t session, BNLogLevel level, const string& logger_name, size_t tid, const char* fmt, va_list args) { #if defined(_MSC_VER) @@ -97,6 +115,52 @@ static void PerformLog(size_t session, BNLogLevel level, const string& logger_na } +static std::optional<string> GetStackTraceForException(const std::exception& e) +{ + const ExceptionWithStackTrace* est = dynamic_cast<const ExceptionWithStackTrace*>(&e); + if (est) + { + if (est->m_stackTrace.empty()) + return std::nullopt; + return est->m_stackTrace; + } + return std::nullopt; +} + + +static void PerformLogForException(size_t session, BNLogLevel level, const string& logger_name, size_t tid, + const std::exception& e, const char* fmt, va_list args) +{ +#if defined(_MSC_VER) + int len = _vscprintf(fmt, args); + if (len < 0) + return; + char* msg = (char*)malloc(len + 1); + if (!msg) + return; + if (vsnprintf(msg, len + 1, fmt, args) >= 0) + { + auto stackTrace = GetStackTraceForException(e); + if (stackTrace.has_value()) + BNLogWithStackTrace(session, level, logger_name.c_str(), tid, stackTrace.value().c_str(), "%s", msg); + else + BNLog(session, level, logger_name.c_str(), tid, "%s", msg); + } + free(msg); +#else + char* msg; + if (vasprintf(&msg, fmt, args) < 0) + return; + auto stackTrace = GetStackTraceForException(e); + if (stackTrace.has_value()) + BNLogWithStackTrace(session, level, logger_name.c_str(), tid, stackTrace.value().c_str(), "%s", msg); + else + BNLog(session, level, logger_name.c_str(), tid, "%s", msg); + free(msg); +#endif +} + + void BinaryNinja::Log(BNLogLevel level, const char* fmt, ...) { va_list args; @@ -162,6 +226,71 @@ void BinaryNinja::LogAlert(const char* fmt, ...) } +void BinaryNinja::LogForException(BNLogLevel level, const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException(0, level, "", 0, e, fmt, args); + va_end(args); +} + + +void BinaryNinja::LogTraceForException(const std::exception& e, const char* fmt, ...) +{ +#ifdef _DEBUG + va_list args; + va_start(args, fmt); + PerformLogForException(0, DebugLog, "", 0, e, fmt, args); + va_end(args); +#endif +} + + +void BinaryNinja::LogDebugForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException(0, DebugLog, "", 0, e, fmt, args); + va_end(args); +} + + +void BinaryNinja::LogInfoForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException(0, InfoLog, "", 0, e, fmt, args); + va_end(args); +} + + +void BinaryNinja::LogWarnForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException(0, WarningLog, "", 0, e, fmt, args); + va_end(args); +} + + +void BinaryNinja::LogErrorForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException(0, ErrorLog, "", 0, e, fmt, args); + va_end(args); +} + + +void BinaryNinja::LogAlertForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException(0, AlertLog, "", 0, e, fmt, args); + va_end(args); +} + + void BinaryNinja::LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); @@ -211,6 +340,56 @@ void BinaryNinja::LogAlertFV(fmt::string_view format, fmt::format_args args) } +void BinaryNinja::LogForExceptionFV( + BNLogLevel level, const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogForException(level, e, "%s", value.c_str()); +} + + +void BinaryNinja::LogTraceForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogTraceForException(e, "%s", value.c_str()); +} + + +void BinaryNinja::LogDebugForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogDebugForException(e, "%s", value.c_str()); +} + + +void BinaryNinja::LogInfoForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogInfoForException(e, "%s", value.c_str()); +} + + +void BinaryNinja::LogWarnForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogWarnForException(e, "%s", value.c_str()); +} + + +void BinaryNinja::LogErrorForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogErrorForException(e, "%s", value.c_str()); +} + + +void BinaryNinja::LogAlertForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogAlertForException(e, "%s", value.c_str()); +} + + void BinaryNinja::LogToStdout(BNLogLevel minimumLevel) { BNLogToStdout(minimumLevel); @@ -316,6 +495,78 @@ void Logger::LogAlert(const char* fmt, ...) } +void Logger::LogForException(BNLogLevel level, const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException( + GetSessionId(), level, GetName(), GetThreadId(), e, fmt::format("{}{}", GetIndent(), fmt).c_str(), args); + va_end(args); +} + + +void Logger::LogTraceForException(const std::exception& e, const char* fmt, ...) +{ +#ifdef _DEBUG + va_list args; + va_start(args, fmt); + PerformLogForException( + GetSessionId(), DebugLog, GetName(), GetThreadId(), e, fmt::format("{}{}", GetIndent(), fmt).c_str(), args); + va_end(args); +#endif +} + + +void Logger::LogDebugForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException( + GetSessionId(), DebugLog, GetName(), GetThreadId(), e, fmt::format("{}{}", GetIndent(), fmt).c_str(), args); + va_end(args); +} + + +void Logger::LogInfoForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException( + GetSessionId(), InfoLog, GetName(), GetThreadId(), e, fmt::format("{}{}", GetIndent(), fmt).c_str(), args); + va_end(args); +} + + +void Logger::LogWarnForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException( + GetSessionId(), WarningLog, GetName(), GetThreadId(), e, fmt::format("{}{}", GetIndent(), fmt).c_str(), args); + va_end(args); +} + + +void Logger::LogErrorForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException( + GetSessionId(), ErrorLog, GetName(), GetThreadId(), e, fmt::format("{}{}", GetIndent(), fmt).c_str(), args); + va_end(args); +} + + +void Logger::LogAlertForException(const std::exception& e, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + PerformLogForException( + GetSessionId(), AlertLog, GetName(), GetThreadId(), e, fmt::format("{}{}", GetIndent(), fmt).c_str(), args); + va_end(args); +} + + void Logger::LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); @@ -365,6 +616,56 @@ void Logger::LogAlertFV(fmt::string_view format, fmt::format_args args) } +void Logger::LogForExceptionFV( + BNLogLevel level, const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogForException(level, e, "%s", value.c_str()); +} + + +void Logger::LogTraceForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogTraceForException(e, "%s", value.c_str()); +} + + +void Logger::LogDebugForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogDebugForException(e, "%s", value.c_str()); +} + + +void Logger::LogInfoForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogInfoForException(e, "%s", value.c_str()); +} + + +void Logger::LogWarnForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogWarnForException(e, "%s", value.c_str()); +} + + +void Logger::LogErrorForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogErrorForException(e, "%s", value.c_str()); +} + + +void Logger::LogAlertForExceptionFV(const std::exception& e, fmt::string_view format, fmt::format_args args) +{ + std::string value = fmt::vformat(format, args); + LogAlertForException(e, "%s", value.c_str()); +} + + string Logger::GetName() { char* name = BNLoggerGetName(m_object); diff --git a/mainthread.cpp b/mainthread.cpp index dd503cae..6a0f1321 100644 --- a/mainthread.cpp +++ b/mainthread.cpp @@ -64,7 +64,7 @@ static void ExecuteAction(void* ctxt) } catch (const std::exception& e) { - LogError("Exception in main thread handler: %s", e.what()); + LogErrorForException(e, "Exception in main thread handler: %s", e.what()); fprintf(stderr, "Exception in main thread handler: %s\n", e.what()); abort(); } diff --git a/plugins/rtti/itanium.cpp b/plugins/rtti/itanium.cpp index ad6d6e6d..dae85b46 100644 --- a/plugins/rtti/itanium.cpp +++ b/plugins/rtti/itanium.cpp @@ -748,7 +748,7 @@ void ItaniumRTTIProcessor::ProcessRTTI() } catch (std::exception& e) { - m_logger->LogWarn("Failed to process object at %llx... skipping", currAddr); + m_logger->LogWarnForException(e, "Failed to process object at %llx... skipping", currAddr); } } }; diff --git a/plugins/rtti/plugin.cpp b/plugins/rtti/plugin.cpp index d94be592..6f1a3e2f 100644 --- a/plugins/rtti/plugin.cpp +++ b/plugins/rtti/plugin.cpp @@ -29,7 +29,7 @@ void RTTIAnalysis(const Ref<AnalysisContext>& analysisContext) } catch (std::exception& e) { - LogError("MSVC RTTI Analysis failed with uncaught exception: %s", e.what()); + LogErrorForException(e, "MSVC RTTI Analysis failed with uncaught exception: %s", e.what()); } } @@ -41,7 +41,7 @@ void RTTIAnalysis(const Ref<AnalysisContext>& analysisContext) } catch (std::exception& e) { - LogError("Itanium RTTI Analysis failed with uncaught exception: %s", e.what()); + LogErrorForException(e, "Itanium RTTI Analysis failed with uncaught exception: %s", e.what()); } } @@ -60,7 +60,7 @@ void VFTAnalysis(const Ref<AnalysisContext>& analysisContext) } catch (std::exception& e) { - LogError("MSVC VFT Analysis failed with uncaught exception: %s", e.what()); + LogErrorForException(e, "MSVC VFT Analysis failed with uncaught exception: %s", e.what()); } try @@ -71,7 +71,7 @@ void VFTAnalysis(const Ref<AnalysisContext>& analysisContext) } catch (std::exception& e) { - LogError("Itanium VFT Analysis failed with uncaught exception: %s", e.what()); + LogErrorForException(e, "Itanium VFT Analysis failed with uncaught exception: %s", e.what()); } } diff --git a/rust/src/logger.rs b/rust/src/logger.rs index 2735dd2f..ceba29ec 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -162,6 +162,10 @@ pub trait LogListener: 'static + Sync { fn log(&self, session: usize, level: Level, msg: &str, logger_name: &str, tid: usize); fn level(&self) -> Level; fn close(&self) {} + + fn log_with_stack_trace(&self, session: usize, level: Level, _stack_trace: &str, msg: &str, logger_name: &str, tid: usize) { + self.log(session, level, msg, logger_name, tid); + } } pub struct LogGuard<L: LogListener> { @@ -175,6 +179,7 @@ impl<L: LogListener> Drop for LogGuard<L> { let mut bn_obj = BNLogListener { context: self.ctxt as *mut _, log: Some(cb_log::<L>), + logWithStackTrace: Some(cb_log_with_stack_trace::<L>), close: Some(cb_close::<L>), getLogLevel: Some(cb_level::<L>), }; @@ -195,6 +200,7 @@ pub fn register_listener<L: LogListener>(listener: L) -> LogGuard<L> { let mut bn_obj = BNLogListener { context: raw as *mut _, log: Some(cb_log::<L>), + logWithStackTrace: Some(cb_log_with_stack_trace::<L>), close: Some(cb_close::<L>), getLogLevel: Some(cb_level::<L>), }; @@ -225,6 +231,26 @@ extern "C" fn cb_log<L>( }) } +extern "C" fn cb_log_with_stack_trace<L>( + ctxt: *mut c_void, + session: usize, + level: Level, + stack_trace: *const c_char, + msg: *const c_char, + logger_name: *const c_char, + tid: usize, +) where + L: LogListener, +{ + ffi_wrap!("LogListener::log_with_stack_trace", unsafe { + let listener = &*(ctxt as *const L); + let stack_trace_str = raw_to_string(stack_trace).unwrap(); + let msg_str = raw_to_string(msg).unwrap(); + let logger_name_str = raw_to_string(logger_name).unwrap(); + listener.log_with_stack_trace(session, level, &stack_trace_str, &msg_str, &logger_name_str, tid); + }) +} + extern "C" fn cb_close<L>(ctxt: *mut c_void) where L: LogListener, diff --git a/ui/logview.h b/ui/logview.h index 36f0f080..b1ce57a1 100644 --- a/ui/logview.h +++ b/ui/logview.h @@ -130,6 +130,8 @@ class BINARYNINJAUIAPI LogListModel : public QAbstractItemModel, BinaryNinja::Lo void clear(); virtual void LogMessage(size_t sessionId, BNLogLevel level, const std::string& msg, const std::string& loggerName = "", size_t tid = 0) override; + virtual void LogMessageWithStackTrace(size_t sessionId, BNLogLevel level, const std::string& stackTrace, + const std::string& msg, const std::string& loggerName = "", size_t tid = 0) override; virtual BNLogLevel GetLogLevel() override; QString getFormattedMessage(const LogListItem& item) const; diff --git a/ui/progresstask.h b/ui/progresstask.h index 6765ec2d..58bfb7d3 100644 --- a/ui/progresstask.h +++ b/ui/progresstask.h @@ -352,7 +352,8 @@ class BINARYNINJAUIAPI BackgroundThread : public QObject // Just print an error and keep going catch (std::exception& e) { - BinaryNinja::LogError("Exception thrown in BackgroundThread::finally(): %s", e.what()); + BinaryNinja::LogErrorForException( + e, "Exception thrown in BackgroundThread::finally(): %s", e.what()); } catch (...) { @@ -413,7 +414,8 @@ class BINARYNINJAUIAPI BackgroundThread : public QObject // Just print an error and keep going catch (std::exception& e) { - BinaryNinja::LogError("Exception thrown in BackgroundThread::finally(): %s", e.what()); + BinaryNinja::LogErrorForException( + e, "Exception thrown in BackgroundThread::finally(): %s", e.what()); } catch (...) { diff --git a/view/elf/elfview.cpp b/view/elf/elfview.cpp index ae751269..5eb9cea7 100644 --- a/view/elf/elfview.cpp +++ b/view/elf/elfview.cpp @@ -2814,7 +2814,8 @@ Ref<BinaryView> ElfViewType::Create(BinaryView* data) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } @@ -2828,7 +2829,8 @@ Ref<BinaryView> ElfViewType::Parse(BinaryView* data) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } diff --git a/view/macho/machoview.cpp b/view/macho/machoview.cpp index 4e45b362..1da2bda7 100644 --- a/view/macho/machoview.cpp +++ b/view/macho/machoview.cpp @@ -3920,7 +3920,7 @@ Ref<BinaryView> MachoViewType::Create(BinaryView* data) } catch (std::exception& e) { - m_logger->LogErrorF("{}<BinaryViewType> failed to create view! {:?}", GetName(), e.what()); + m_logger->LogErrorForExceptionF(e, "{}<BinaryViewType> failed to create view! {:?}", GetName(), e.what()); return nullptr; } } @@ -3934,7 +3934,7 @@ Ref<BinaryView> MachoViewType::Parse(BinaryView* data) } catch (std::exception& e) { - m_logger->LogErrorF("{}<BinaryViewType> failed to create view! {:?}", GetName(), e.what()); + m_logger->LogErrorForExceptionF(e, "{}<BinaryViewType> failed to create view! {:?}", GetName(), e.what()); return nullptr; } } diff --git a/view/md1rom/md1rom.cpp b/view/md1rom/md1rom.cpp index b302cfb0..d0480cbe 100644 --- a/view/md1rom/md1rom.cpp +++ b/view/md1rom/md1rom.cpp @@ -380,7 +380,8 @@ Ref<BinaryView> Md1romViewType::Create(BinaryView* data) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } @@ -394,7 +395,8 @@ Ref<BinaryView> Md1romViewType::Parse(BinaryView* data) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } diff --git a/view/pe/peview.cpp b/view/pe/peview.cpp index c223d12b..1272c9af 100644 --- a/view/pe/peview.cpp +++ b/view/pe/peview.cpp @@ -3035,7 +3035,8 @@ Ref<BinaryView> PEViewType::Create(BinaryView* data) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } @@ -3049,7 +3050,8 @@ Ref<BinaryView> PEViewType::Parse(BinaryView* data) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } diff --git a/view/pe/teview.cpp b/view/pe/teview.cpp index 4c27c21a..5b0b75b9 100644 --- a/view/pe/teview.cpp +++ b/view/pe/teview.cpp @@ -333,7 +333,8 @@ Ref<BinaryView> TEViewType::Create(BinaryView* bv) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } @@ -346,7 +347,8 @@ Ref<BinaryView> TEViewType::Parse(BinaryView* bv) } catch (std::exception& e) { - m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + m_logger->LogErrorForException( + e, "%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } diff --git a/view/sharedcache/core/SharedCacheBuilder.cpp b/view/sharedcache/core/SharedCacheBuilder.cpp index 11fadefd..5422d751 100644 --- a/view/sharedcache/core/SharedCacheBuilder.cpp +++ b/view/sharedcache/core/SharedCacheBuilder.cpp @@ -46,7 +46,7 @@ bool SharedCacheBuilder::AddFile( catch (const std::exception& e) { // Just return false so the view init can continue. - m_logger->LogErrorF("Failed to add file '{}': {}", fileName, e.what()); + m_logger->LogErrorForExceptionF(e, "Failed to add file '{}': {}", fileName, e.what()); return false; } |
