// Copyright (c) 2015-2024 Vector 35 Inc // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. #define _CRT_SECURE_NO_WARNINGS #include #include #include #include "binaryninjaapi.h" using namespace BinaryNinja; using namespace std; void LogListener::LogMessageCallback(void* ctxt, size_t session, BNLogLevel level, const char* msg, const char* logger_name, size_t tid) { LogListener* listener = (LogListener*)ctxt; listener->LogMessage(session, level, msg, logger_name, tid); } void LogListener::CloseLogCallback(void* ctxt) { LogListener* listener = (LogListener*)ctxt; listener->CloseLog(); } BNLogLevel LogListener::GetLogLevelCallback(void* ctxt) { LogListener* listener = (LogListener*)ctxt; return listener->GetLogLevel(); } void LogListener::RegisterLogListener(LogListener* listener) { BNLogListener callbacks; callbacks.context = listener; callbacks.log = LogMessageCallback; callbacks.close = CloseLogCallback; callbacks.getLogLevel = GetLogLevelCallback; BNRegisterLogListener(&callbacks); } void LogListener::UnregisterLogListener(LogListener* listener) { BNLogListener callbacks; callbacks.context = listener; callbacks.log = LogMessageCallback; callbacks.close = CloseLogCallback; BNUnregisterLogListener(&callbacks); } void LogListener::UpdateLogListeners() { BNUpdateLogListeners(); } 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) 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) BNLog(session, level, logger_name.c_str(), tid, "%s", msg); free(msg); #else char* msg; if (vasprintf(&msg, fmt, args) < 0) return; BNLog(session, level, logger_name.c_str(), tid, "%s", msg); free(msg); #endif } void BinaryNinja::Log(BNLogLevel level, const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(0, level, "", 0, fmt, args); va_end(args); } void BinaryNinja::LogTrace(const char* fmt, ...) { #ifdef _DEBUG va_list args; va_start(args, fmt); PerformLog(0, DebugLog, "", 0, fmt, args); va_end(args); #endif } void BinaryNinja::LogDebug(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(0, DebugLog, "", 0, fmt, args); va_end(args); } void BinaryNinja::LogInfo(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(0, InfoLog, "", 0, fmt, args); va_end(args); } void BinaryNinja::LogWarn(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(0, WarningLog, "", 0, fmt, args); va_end(args); } void BinaryNinja::LogError(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(0, ErrorLog, "", 0, fmt, args); va_end(args); } void BinaryNinja::LogAlert(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(0, AlertLog, "", 0, 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); Log(level, "%s", value.c_str()); } void BinaryNinja::LogTraceFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogTrace("%s", value.c_str()); } void BinaryNinja::LogDebugFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogDebug("%s", value.c_str()); } void BinaryNinja::LogInfoFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogInfo("%s", value.c_str()); } void BinaryNinja::LogWarnFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogWarn("%s", value.c_str()); } void BinaryNinja::LogErrorFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogError("%s", value.c_str()); } void BinaryNinja::LogAlertFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogAlert("%s", value.c_str()); } void BinaryNinja::LogToStdout(BNLogLevel minimumLevel) { BNLogToStdout(minimumLevel); } void BinaryNinja::LogToStderr(BNLogLevel minimumLevel) { BNLogToStderr(minimumLevel); } bool BinaryNinja::LogToFile(BNLogLevel minimumLevel, const string& path, bool append) { return BNLogToFile(minimumLevel, path.c_str(), append); } void BinaryNinja::CloseLogs() { BNCloseLogs(); } size_t Logger::GetThreadId() const { return std::hash{}(std::this_thread::get_id()); } Logger::Logger(BNLogger* logger) { m_object = logger; } Logger::Logger(const string& loggerName, size_t sessionId) { m_object = BNLogCreateLogger(loggerName.c_str(), sessionId); } void Logger::Log(BNLogLevel level, const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(GetSessionId(), level, GetName(), GetThreadId(), fmt, args); va_end(args); } void Logger::LogTrace(const char* fmt, ...) { #ifdef _DEBUG va_list args; va_start(args, fmt); PerformLog(GetSessionId(), DebugLog, GetName(), GetThreadId(), fmt, args); va_end(args); #endif } void Logger::LogDebug(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(GetSessionId(), DebugLog, GetName(), GetThreadId(), fmt, args); va_end(args); } void Logger::LogInfo(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(GetSessionId(), InfoLog, GetName(), GetThreadId(), fmt, args); va_end(args); } void Logger::LogWarn(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(GetSessionId(), WarningLog, GetName(), GetThreadId(), fmt, args); va_end(args); } void Logger::LogError(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(GetSessionId(), ErrorLog, GetName(), GetThreadId(), fmt, args); va_end(args); } void Logger::LogAlert(const char* fmt, ...) { va_list args; va_start(args, fmt); PerformLog(GetSessionId(), AlertLog, GetName(), GetThreadId(), fmt, args); va_end(args); } void Logger::LogFV(BNLogLevel level, fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); Log(level, "%s", value.c_str()); } void Logger::LogTraceFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogTrace("%s", value.c_str()); } void Logger::LogDebugFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogDebug("%s", value.c_str()); } void Logger::LogInfoFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogInfo("%s", value.c_str()); } void Logger::LogWarnFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogWarn("%s", value.c_str()); } void Logger::LogErrorFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogError("%s", value.c_str()); } void Logger::LogAlertFV(fmt::string_view format, fmt::format_args args) { std::string value = fmt::vformat(format, args); LogAlert("%s", value.c_str()); } string Logger::GetName() { char* name = BNLoggerGetName(m_object); string result = name; BNFreeString(name); return result; } size_t Logger::GetSessionId() { return BNLoggerGetSessionId(m_object); } void Logger::Indent() { BNLoggerIndent(m_object); } void Logger::Dedent() { BNLoggerDedent(m_object); } void Logger::ResetIndent() { BNLoggerResetIndent(m_object); } Ref LogRegistry::CreateLogger(const std::string& loggerName, size_t sessionId) { return new Logger(BNLogCreateLogger(loggerName.c_str(), sessionId)); } Ref LogRegistry::GetLogger(const std::string& loggerName, size_t sessionId) { return new Logger(BNLogGetLogger(loggerName.c_str(), sessionId)); } vector LogRegistry::GetLoggerNames() { size_t count = 0; char** names = BNLogGetLoggerNames(&count); vector result; result.reserve(count); for (size_t i = 0; i < count; ++i) result.push_back(names[i]); BNFreeStringList(names, count); return result; }