summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h35
-rw-r--r--binaryninjacore.h33
-rw-r--r--binaryview.cpp6
-rw-r--r--docs/about/open-source.md1
-rw-r--r--filemetadata.cpp7
-rw-r--r--log.cpp156
-rw-r--r--python/binaryview.py7
-rw-r--r--python/filemetadata.py4
-rw-r--r--python/function.py5
-rw-r--r--python/log.py58
-rw-r--r--python/types.py12
-rw-r--r--rust/src/lib.rs8
-rw-r--r--suite/api_test.py2
-rw-r--r--ui/filecontext.h1
-rw-r--r--ui/logview.h243
-rw-r--r--ui/uicontext.h2
-rw-r--r--ui/viewframe.h10
17 files changed, 472 insertions, 118 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 351c9797..c9c0ea70 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -38,6 +38,7 @@
#include <type_traits>
#include <variant>
#include <optional>
+#include <memory>
#include "binaryninjacore.h"
#include "json/json.h"
@@ -436,7 +437,7 @@ namespace BinaryNinja {
class LogListener
{
- static void LogMessageCallback(void* ctxt, BNLogLevel level, const char* msg);
+ static void LogMessageCallback(void* ctxt, size_t session, BNLogLevel level, const char* msg, const char* logger_name = "", size_t tid = 0);
static void CloseLogCallback(void* ctxt);
static BNLogLevel GetLogLevelCallback(void* ctxt);
@@ -447,7 +448,7 @@ namespace BinaryNinja {
static void UnregisterLogListener(LogListener* listener);
static void UpdateLogListeners();
- virtual void LogMessage(BNLogLevel level, const std::string& msg) = 0;
+ virtual void LogMessage(size_t session, BNLogLevel level, const std::string& msg, const std::string& logger_name = "", size_t tid = 0) = 0;
virtual void CloseLog() {}
virtual BNLogLevel GetLogLevel() { return WarningLog; }
};
@@ -538,6 +539,33 @@ namespace BinaryNinja {
bool LogToFile(BNLogLevel minimumLevel, const std::string& path, bool append = false);
void CloseLogs();
+ class FileMetadata;
+ class BinaryView;
+ class Logger: public CoreRefCountObject<BNLogger, BNNewLoggerReference, BNFreeLogger>
+ {
+ size_t GetThreadId() const;
+ public:
+ Logger(BNLogger* logger);
+ Logger(const std::string& loggerName, size_t sessionId = 0);
+ void Log(BNLogLevel level, const char* fmt, ...);
+ void LogDebug(const char* fmt, ...);
+ void LogInfo(const char* fmt, ...);
+ void LogWarn(const char* fmt, ...);
+ void LogError(const char* fmt, ...);
+ void LogAlert(const char* fmt, ...);
+ std::string GetName();
+ size_t GetSessionId();
+ };
+
+ class LogRegistry
+ {
+ public:
+ static Ref<Logger> CreateLogger(const std::string& loggerName, size_t sessionId = 0);
+ static Ref<Logger> GetLogger(const std::string& loggerName, size_t sessionId = 0);
+ static std::vector<std::string> GetLoggerNames();
+ static void RegisterLoggerCallback(const std::function<void(const std::string&)>& cb);
+ };
+
std::string EscapeString(const std::string& s);
std::string UnescapeString(const std::string& s);
@@ -1007,6 +1035,7 @@ namespace BinaryNinja {
BinaryNinja::Ref<BinaryNinja::BinaryView> GetViewOfType(const std::string& name);
std::vector<std::string> GetExistingViews() const;
+ size_t GetSessionId() const;
};
class Function;
@@ -2141,6 +2170,8 @@ namespace BinaryNinja {
Ref<Structure> CreateStructureFromOffsetAccess(const QualifiedName& type, bool* newMemberAdded) const;
Confidence<Ref<Type>> CreateStructureMemberFromAccess(const QualifiedName& name, uint64_t offset) const;
+
+ Ref<Logger> CreateLogger(const std::string& name);
};
diff --git a/binaryninjacore.h b/binaryninjacore.h
index c86b501e..53a125c4 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -21,9 +21,15 @@
#ifndef __BINARYNINJACORE_H__
#define __BINARYNINJACORE_H__
+#ifdef __cplusplus
#include <cstdint>
#include <cstddef>
#include <cstdlib>
+#else
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#endif
// 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,
@@ -222,6 +228,7 @@ extern "C"
struct BNDebugInfo;
struct BNDebugInfoParser;
struct BNSecretsProvider;
+ struct BNLogger;
//! Console log levels
@@ -1291,7 +1298,7 @@ extern "C"
struct BNLogListener
{
void* context;
- void (*log)(void* ctxt, BNLogLevel level, const char* msg);
+ void (*log)(void* ctxt, size_t sessionId, BNLogLevel level, const char* msg, const char* logger_name, size_t tid);
void (*close)(void* ctxt);
BNLogLevel (*getLogLevel)(void* ctxt);
};
@@ -2803,10 +2810,10 @@ extern "C"
// Logging
#ifdef __GNUC__
- __attribute__((format(printf, 2, 3)))
+ __attribute__((format(printf, 5, 6)))
#endif
BINARYNINJACOREAPI void
- BNLog(BNLogLevel level, const char* fmt, ...);
+ BNLog(size_t session, BNLogLevel level, const char* logger_name, size_t tid, const char* fmt, ...);
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
@@ -2838,7 +2845,24 @@ extern "C"
BINARYNINJACOREAPI void
BNLogAlert(const char* fmt, ...);
- BINARYNINJACOREAPI void BNLogString(BNLogLevel level, const char* str);
+ BINARYNINJACOREAPI void BNLogString(size_t session, BNLogLevel level, const char* logger_name, size_t tid, const char* str);
+
+
+ BINARYNINJACOREAPI BNLogger* BNNewLoggerReference(BNLogger* logger);
+ BINARYNINJACOREAPI void BNFreeLogger(BNLogger* logger);
+
+#ifdef __GNUC__
+ __attribute__((format(printf, 3, 4)))
+#endif
+ BINARYNINJACOREAPI void BNLoggerLog(BNLogger* logger, BNLogLevel level, const char* fmt, ...);
+ BINARYNINJACOREAPI void BNLoggerLogString(BNLogger* logger, BNLogLevel level, const char* msg);
+
+ BINARYNINJACOREAPI char* BNLoggerGetName(BNLogger* logger);
+ BINARYNINJACOREAPI size_t BNLoggerGetSessionId(BNLogger* logger);
+ BINARYNINJACOREAPI BNLogger* BNLogCreateLogger(const char* loggerName, size_t sessionId);
+ BINARYNINJACOREAPI BNLogger* BNLogGetLogger(const char* loggerName, size_t sessionId);
+ BINARYNINJACOREAPI char** BNLogGetLoggerNames(size_t* count);
+ BINARYNINJACOREAPI void BNLogRegisterLoggerCallback(void (*cb)(const char* name, void* ctxt), void* ctxt);
BINARYNINJACOREAPI void BNRegisterLogListener(BNLogListener* listener);
BINARYNINJACOREAPI void BNUnregisterLogListener(BNLogListener* listener);
@@ -3031,6 +3055,7 @@ extern "C"
BINARYNINJACOREAPI BNBinaryView* BNGetFileViewOfType(BNFileMetadata* file, const char* name);
BINARYNINJACOREAPI char** BNGetExistingViews(BNFileMetadata* file, size_t* count);
+ BINARYNINJACOREAPI size_t BNFileMetadataGetSessionId(BNFileMetadata* file);
BINARYNINJACOREAPI bool BNIsSnapshotDataAppliedWithoutError(BNFileMetadata* view);
diff --git a/binaryview.cpp b/binaryview.cpp
index ba812919..541c6ca9 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -3769,6 +3769,12 @@ Confidence<Ref<Type>> BinaryView::CreateStructureMemberFromAccess(const Qualifie
}
+Ref<Logger> BinaryView::CreateLogger(const string& name)
+{
+ return LogRegistry::CreateLogger(name, GetFile()->GetSessionId());
+}
+
+
Relocation::Relocation(BNRelocation* reloc)
{
m_object = reloc;
diff --git a/docs/about/open-source.md b/docs/about/open-source.md
index 4cb8db19..3fff975b 100644
--- a/docs/about/open-source.md
+++ b/docs/about/open-source.md
@@ -40,6 +40,7 @@ The previous tools are used in the generation of our documentation, but are not
- [curl] ([curl license] - MIT)
- [nom] ([nom license] - MIT)
- [xxHash] ([xxHash License] - 2-clause BSD)
+ - [spdlog] ([spdlog license] - MIT)
* Other
- [yasm] ([yasm license] - 2-clause BSD) used for assembling x86 and x64
diff --git a/filemetadata.cpp b/filemetadata.cpp
index e240cd1b..57ebcc2d 100644
--- a/filemetadata.cpp
+++ b/filemetadata.cpp
@@ -421,6 +421,13 @@ std::vector<std::string> FileMetadata::GetExistingViews() const
return result;
}
+
+size_t FileMetadata::GetSessionId() const
+{
+ return BNFileMetadataGetSessionId(m_object);
+}
+
+
bool FileMetadata::IsSnapshotDataAppliedWithoutError() const
{
return BNIsSnapshotDataAppliedWithoutError(m_object);
diff --git a/log.cpp b/log.cpp
index ba4bf2a2..0c6916b9 100644
--- a/log.cpp
+++ b/log.cpp
@@ -21,16 +21,16 @@
#define _CRT_SECURE_NO_WARNINGS
#include <stdarg.h>
#include <stdio.h>
+#include <thread>
#include "binaryninjaapi.h"
using namespace BinaryNinja;
using namespace std;
-
-void LogListener::LogMessageCallback(void* ctxt, BNLogLevel level, const char* msg)
+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(level, msg);
+ listener->LogMessage(session, level, msg, logger_name, tid);
}
@@ -75,7 +75,7 @@ void LogListener::UpdateLogListeners()
}
-static void PerformLog(BNLogLevel level, const char* fmt, va_list args)
+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);
@@ -85,13 +85,13 @@ static void PerformLog(BNLogLevel level, const char* fmt, va_list args)
if (!msg)
return;
if (vsnprintf(msg, len + 1, fmt, args) >= 0)
- BNLog(level, "%s", msg);
+ BNLog(session, level, logger_name.c_str(), tid, "%s", msg);
free(msg);
#else
char* msg;
if (vasprintf(&msg, fmt, args) < 0)
return;
- BNLog(level, "%s", msg);
+ BNLog(session, level, logger_name.c_str(), tid, "%s", msg);
free(msg);
#endif
}
@@ -101,7 +101,7 @@ void BinaryNinja::Log(BNLogLevel level, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- PerformLog(level, fmt, args);
+ PerformLog(0, level, "", 0, fmt, args);
va_end(args);
}
@@ -110,7 +110,7 @@ void BinaryNinja::LogDebug(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- PerformLog(DebugLog, fmt, args);
+ PerformLog(0, DebugLog, "", 0, fmt, args);
va_end(args);
}
@@ -119,7 +119,7 @@ void BinaryNinja::LogInfo(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- PerformLog(InfoLog, fmt, args);
+ PerformLog(0, InfoLog, "", 0, fmt, args);
va_end(args);
}
@@ -128,7 +128,7 @@ void BinaryNinja::LogWarn(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- PerformLog(WarningLog, fmt, args);
+ PerformLog(0, WarningLog, "", 0, fmt, args);
va_end(args);
}
@@ -137,7 +137,7 @@ void BinaryNinja::LogError(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- PerformLog(ErrorLog, fmt, args);
+ PerformLog(0, ErrorLog, "", 0, fmt, args);
va_end(args);
}
@@ -146,7 +146,7 @@ void BinaryNinja::LogAlert(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- PerformLog(AlertLog, fmt, args);
+ PerformLog(0, AlertLog, "", 0, fmt, args);
va_end(args);
}
@@ -173,3 +173,135 @@ void BinaryNinja::CloseLogs()
{
BNCloseLogs();
}
+
+size_t Logger::GetThreadId() const
+{
+ return std::hash<std::thread::id>{}(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::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);
+}
+
+
+string Logger::GetName()
+{
+ char* name = BNLoggerGetName(m_object);
+ string result = name;
+ BNFreeString(name);
+ return result;
+}
+
+
+size_t Logger::GetSessionId()
+{
+ return BNLoggerGetSessionId(m_object);
+}
+
+
+Ref<Logger> LogRegistry::CreateLogger(const std::string& loggerName, size_t sessionId)
+{
+ return new Logger(BNLogCreateLogger(loggerName.c_str(), sessionId));
+}
+
+
+Ref<Logger> LogRegistry::GetLogger(const std::string& loggerName, size_t sessionId)
+{
+ return new Logger(BNLogGetLogger(loggerName.c_str(), sessionId));
+}
+
+
+vector<string> LogRegistry::GetLoggerNames()
+{
+ size_t count = 0;
+ char** names = BNLogGetLoggerNames(&count);
+ vector<string> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; ++i)
+ result.push_back(names[i]);
+ BNFreeStringList(names, count);
+ return result;
+}
+
+
+struct RegisterLoggerCallbackContext
+{
+ std::function<void(const string&)> func;
+};
+
+
+static void RegisterLoggerCallbackHelper(const char* name, void* ctxt)
+{
+ RegisterLoggerCallbackContext* cb = (RegisterLoggerCallbackContext*)ctxt;
+ cb->func(name);
+}
+
+
+void LogRegistry::RegisterLoggerCallback(const std::function<void(const string&)>& cb)
+{
+ // we leak this LoggerCallback but since you can't unregister them it doesn't really matter
+ auto loggerCallback = new RegisterLoggerCallbackContext;
+ loggerCallback->func = cb;
+ BNLogRegisterLoggerCallback(RegisterLoggerCallbackHelper, loggerCallback);
+}
diff --git a/python/binaryview.py b/python/binaryview.py
index b2df6ca2..3ebe79af 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -39,10 +39,10 @@ import binaryninja
from . import _binaryninjacore as core
from .enums import (
AnalysisState, SymbolType, Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag,
- TypeClass, BinaryViewEventType, FunctionGraphType, TagReferenceType, TagTypeType, RegisterValueType
+ TypeClass, BinaryViewEventType, FunctionGraphType, TagReferenceType, TagTypeType, RegisterValueType, LogLevel
)
from . import associateddatastore # required for _BinaryViewAssociatedDataStore
-from .log import log_error, log_warn
+from .log import log, log_debug, log_info, log_warn, log_error, log_alert, Logger
from . import typelibrary
from . import fileaccessor
from . import databuffer
@@ -7499,6 +7499,9 @@ class BinaryView:
def typed_data_accessor(self, address: int, type: '_types.Type') -> 'TypedDataAccessor':
return TypedDataAccessor(type, address, self, self.endianness)
+ def create_logger(self, logger_name:str) -> Logger:
+ return Logger(self.file.session_id, logger_name)
+
class BinaryReader:
"""
diff --git a/python/filemetadata.py b/python/filemetadata.py
index 5fde78d9..bd9a9954 100644
--- a/python/filemetadata.py
+++ b/python/filemetadata.py
@@ -171,6 +171,10 @@ class FileMetadata:
def nav(self, value: NavigationHandler) -> None:
self._nav = value
+ @property
+ def session_id(self) -> int:
+ return core.BNFileMetadataGetSessionId(self.handle)
+
@classmethod
def _unregister(cls, f):
handle = ctypes.cast(f, ctypes.c_void_p)
diff --git a/python/function.py b/python/function.py
index 2bd64f4a..b1887628 100644
--- a/python/function.py
+++ b/python/function.py
@@ -336,8 +336,9 @@ class Function:
>>> current_function = bv.functions[0]
>>> here = current_function.start
"""
- def __init__(self, view: Optional['binaryview.BinaryView'] = None, handle: Optional[core.BNFunctionHandle] = None):
+ def __init__(self, view: Optional['binaryview.BinaryView'] = None, handle:core.BNFunctionHandle=None):
self._advanced_analysis_requests = 0
+ self.handle = None
assert handle is not None, "creation of standalone 'Function' objects is not implemented"
FunctionHandle = ctypes.POINTER(core.BNFunction)
self.handle = ctypes.cast(handle, FunctionHandle)
@@ -349,7 +350,7 @@ class Function:
self._platform = None
def __del__(self):
- if core is not None:
+ if core is not None and self.handle is not None:
if self._advanced_analysis_requests > 0:
core.BNReleaseAdvancedFunctionAnalysisDataMultiple(self.handle, self._advanced_analysis_requests)
core.BNFreeFunction(self.handle)
diff --git a/python/log.py b/python/log.py
index 98aef1eb..d5a5f3e6 100644
--- a/python/log.py
+++ b/python/log.py
@@ -18,9 +18,12 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
+from typing import Optional, Union, Any
+
# Binary Ninja components
from . import _binaryninjacore as core
from .enums import LogLevel
+import threading
_output_to_log = False
@@ -35,7 +38,7 @@ def is_output_redirected_to_log():
return _output_to_log
-def log(level, text):
+def log(level: LogLevel, text: Union[str, Any], logger: Optional[str]="", session:int=0):
"""
``log`` writes messages to the log console for the given log level.
@@ -55,10 +58,10 @@ def log(level, text):
"""
if not isinstance(text, str):
text = str(text)
- core.BNLogString(level, text)
+ core.BNLogString(session, level, logger, threading.current_thread().ident, text)
-def log_debug(text):
+def log_debug(text: Union[str, Any], logger: Optional[str]=""):
"""
``log_debug`` Logs debugging information messages to the console.
@@ -72,10 +75,10 @@ def log_debug(text):
"""
if not isinstance(text, str):
text = str(text)
- core.BNLogString(LogLevel.DebugLog, text)
+ core.BNLogString(0, LogLevel.DebugLog, logger, threading.current_thread().ident, text)
-def log_info(text):
+def log_info(text: Union[str, Any], logger: Optional[str]=""):
"""
``log_info`` Logs general information messages to the console.
@@ -89,10 +92,10 @@ def log_info(text):
"""
if not isinstance(text, str):
text = str(text)
- core.BNLogString(LogLevel.InfoLog, text)
+ core.BNLogString(0, LogLevel.InfoLog, logger, threading.current_thread().ident, text)
-def log_warn(text):
+def log_warn(text: Union[str, Any], logger: Optional[str]=""):
"""
``log_warn`` Logs message to console, if run through the GUI it logs with **Warning** icon.
@@ -107,10 +110,10 @@ def log_warn(text):
"""
if not isinstance(text, str):
text = str(text)
- core.BNLogString(LogLevel.WarningLog, text)
+ core.BNLogString(0, LogLevel.WarningLog, logger, threading.current_thread().ident, text)
-def log_error(text):
+def log_error(text: Union[str, Any], logger: Optional[str]=""):
"""
``log_error`` Logs message to console, if run through the GUI it logs with **Error** icon, focusing the error console.
@@ -125,10 +128,10 @@ def log_error(text):
"""
if not isinstance(text, str):
text = str(text)
- core.BNLogString(LogLevel.ErrorLog, text)
+ core.BNLogString(0, LogLevel.ErrorLog, logger, threading.current_thread().ident, text)
-def log_alert(text):
+def log_alert(text: Union[str, Any], logger: Optional[str]=""):
"""
``log_alert`` Logs message console and to a pop up window if run through the GUI.
@@ -143,10 +146,10 @@ def log_alert(text):
"""
if not isinstance(text, str):
text = str(text)
- core.BNLogString(LogLevel.AlertLog, text)
+ core.BNLogString(0, LogLevel.AlertLog, logger, threading.current_thread().ident, text)
-def log_to_stdout(min_level=LogLevel.InfoLog):
+def log_to_stdout(min_level: Optional[LogLevel]=LogLevel.InfoLog):
"""
``log_to_stdout`` redirects minimum log level to standard out.
@@ -163,7 +166,7 @@ def log_to_stdout(min_level=LogLevel.InfoLog):
core.BNLogToStdout(min_level)
-def log_to_stderr(min_level):
+def log_to_stderr(min_level: LogLevel):
"""
``log_to_stderr`` redirects minimum log level to standard error.
@@ -173,7 +176,7 @@ def log_to_stderr(min_level):
core.BNLogToStderr(min_level)
-def log_to_file(min_level, path, append=False):
+def log_to_file(min_level: LogLevel, path: str, append: bool=False):
"""
``log_to_file`` redirects minimum log level to a file named ``path``, optionally appending rather than overwriting.
@@ -192,3 +195,28 @@ def close_logs():
:rtype: None
"""
core.BNCloseLogs()
+
+
+class Logger:
+ def __init__(self, session_id:int, logger_name:str):
+ self.session_id = session_id
+ self.logger_name = logger_name
+ self.handle = core.BNLogCreateLogger(logger_name, session_id)
+
+ def log(self, level:LogLevel, message:str) -> None:
+ log(level, message, self.logger_name, self.session_id)
+
+ def log_debug(self, message:str) -> None:
+ log(LogLevel.DebugLog, message, self.logger_name, self.session_id)
+
+ def log_info(self, message:str) -> None:
+ log(LogLevel.InfoLog, message, self.logger_name, self.session_id)
+
+ def log_warn(self, message:str) -> None:
+ log(LogLevel.WarningLog, message, self.logger_name, self.session_id)
+
+ def log_error(self, message:str) -> None:
+ log(LogLevel.ErrorLog, message, self.logger_name, self.session_id)
+
+ def log_alert(self, message:str) -> None:
+ log(LogLevel.AlertLog, message, self.logger_name, self.session_id) \ No newline at end of file
diff --git a/python/types.py b/python/types.py
index 62cc0154..2d29ac2d 100644
--- a/python/types.py
+++ b/python/types.py
@@ -2242,11 +2242,13 @@ class EnumerationType(IntegerType):
count = ctypes.c_ulonglong()
members = core.BNGetEnumerationMembers(self.enum_handle, count)
assert members is not None, "core.BNGetEnumerationMembers returned None"
- result = []
- for i in range(0, count.value):
- result.append(EnumerationMember(members[i].name, members[i].value if not members[i].isDefault else None))
- core.BNFreeEnumerationMemberList(members, count.value)
- return result
+ try:
+ result = []
+ for i in range(0, count.value):
+ result.append(EnumerationMember(members[i].name, members[i].value if not members[i].isDefault else None))
+ return result
+ finally:
+ core.BNFreeEnumerationMemberList(members, count.value)
@classmethod
def create(
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 966f3ff2..da9f5bee 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -129,7 +129,7 @@ pub mod logger {
if let Ok(msg) = CString::new(format!("{}", record.args())) {
unsafe {
- BNLog(level, msg.as_ptr());
+ BNLog(0, level, std::ptr::null(), 0, msg.as_ptr());
}
};
}
@@ -145,7 +145,7 @@ pub mod logger {
}
pub trait LogListener: 'static + Sync {
- fn log(&self, level: Level, msg: &BnStr);
+ fn log(&self, session: usize, level: Level, msg: &BnStr, logger_name: &BnStr, tid: usize);
fn level(&self) -> Level;
fn close(&self) {}
}
@@ -193,13 +193,13 @@ pub mod logger {
LogGuard { ctxt: raw }
}
- extern "C" fn cb_log<L>(ctxt: *mut c_void, level: Level, msg: *const c_char)
+ 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(level, BnStr::from_raw(msg));
+ listener.log(session, level, BnStr::from_raw(msg), BnStr::from_raw(logger_name), tid);
})
}
diff --git a/suite/api_test.py b/suite/api_test.py
index 6c4bc493..ea8378a8 100644
--- a/suite/api_test.py
+++ b/suite/api_test.py
@@ -1507,7 +1507,7 @@ class TestWithFunction(TestWithBinaryView):
assert mlil == self.func.mlil
assert mlil == self.func.mlil_if_available
- mmlil = self.func.mapped_medium_level_il
+ mmlil = self.func.llil.mapped_medium_level_il
assert isinstance(mmlil, MediumLevelILFunction)
assert mmlil == self.func.mmlil
assert mmlil == self.func.mmlil_if_available
diff --git a/ui/filecontext.h b/ui/filecontext.h
index ef98d6a9..37d2ff79 100644
--- a/ui/filecontext.h
+++ b/ui/filecontext.h
@@ -4,6 +4,7 @@
#include <map>
#include <set>
#include <string>
+#include <ctime>
#include "binaryninjaapi.h"
#include "uicontext.h"
diff --git a/ui/logview.h b/ui/logview.h
index 2a83d919..ed99e24a 100644
--- a/ui/logview.h
+++ b/ui/logview.h
@@ -7,6 +7,10 @@
#include <QtWidgets/QStyledItemDelegate>
#include <QtWidgets/QLabel>
#include <QtWidgets/QToolButton>
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QLineEdit>
+#include <QtCore/QSortFilterProxyModel>
+#include <QtWidgets/QStackedWidget>
#include <mutex>
#include <string>
#include <utility>
@@ -15,6 +19,7 @@
#include "binaryninjaapi.h"
#include "action.h"
#include "globalarea.h"
+#include "render.h"
#define LOG_UPDATE_INTERVAL 100
@@ -24,12 +29,41 @@ class ViewFrame;
struct BINARYNINJAUIAPI LogListItem
{
+ size_t sessionId;
BNLogLevel level;
std::string text;
bool selected;
+ std::string logger;
+ size_t threadId{0};
- LogListItem(BNLogLevel level, std::string text, bool selected = false) :
- level(level), text(text), selected(selected) {};
+ LogListItem(size_t sessionId, BNLogLevel level, std::string text, bool selected = false, const std::string& logger_name = "", size_t tid = 0);
+};
+
+enum LoggingScope
+{
+ CurrentTabOnly,
+ CurrentTabAndGlobal,
+ GlobalOnly,
+ AllTabs
+};
+
+class BINARYNINJAUIAPI LogListFilterProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ QString m_loggerName;
+ size_t m_sessionId {0};
+ LoggingScope m_scope;
+
+ public:
+ LogListFilterProxyModel(QObject* parent);
+ virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
+ virtual QVariant data(const QModelIndex& idx, int role) const override;
+ void setScope(LoggingScope scope);
+ LoggingScope getScope() const { return m_scope; }
+ public Q_SLOTS:
+ void updateSession(size_t sessionId);
+ void updateLogger(const QString & loggerName);
+ void updateFilter();
};
@@ -40,34 +74,62 @@ class BINARYNINJAUIAPI LogListModel : public QAbstractItemModel, public BinaryNi
QWidget* m_owner;
std::deque<LogListItem> m_items;
std::deque<LogListItem> m_visibleItems;
- int64_t m_maxSize;
std::vector<LogListItem> m_pendingItems;
std::mutex m_mutex;
std::mutex m_pendingMutex;
+ std::string m_logger;
+ size_t m_sessionId {0};
+
+ bool m_showSessionId {false};
+ bool m_showThreadId {false};
+ bool m_showLoggerName {false};
+ bool m_showLogLevel {false};
- public:
- LogListModel(QWidget* parent);
- ~LogListModel();
+ public:
+ static constexpr int Level = Qt::UserRole + 1;
+ static constexpr int Logger = Qt::UserRole + 2;
+ static constexpr int ThreadId = Qt::UserRole + 3;
+ static constexpr int Message = Qt::UserRole + 4;
+ static constexpr int Session = Qt::UserRole + 5;
+ static constexpr int FormattedMessage = Qt::UserRole + 6;
- void addPendingItems();
- void clear();
- std::vector<LogListItem> getSelectedItems();
- bool hasSelectedItems();
+ LogListModel(QWidget* parent);
+ ~LogListModel();
- virtual void LogMessage(BNLogLevel level, const std::string& msg) override;
- virtual BNLogLevel GetLogLevel() override;
+ void addPendingItems();
+ void clear();
+ std::vector<LogListItem> getSelectedItems();
+ bool hasSelectedItems();
- virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override;
- virtual QModelIndex parent(const QModelIndex& i) const override;
- virtual bool hasChildren(const QModelIndex& parent) const override;
- virtual int rowCount(const QModelIndex& parent) const override;
- virtual int columnCount(const QModelIndex& parent) const override;
- virtual QVariant data(const QModelIndex& i, int role) const override;
- virtual bool setData(const QModelIndex& i, const QVariant& value, int role) override;
+ virtual void LogMessage(size_t sessionId, BNLogLevel level, const std::string& msg, const std::string& loggerName = "", size_t tid = 0) override;
+ virtual BNLogLevel GetLogLevel() override;
- public Q_SLOTS:
- void notifyDataChanged();
+ virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override;
+ virtual QModelIndex parent(const QModelIndex& i) const override;
+ virtual bool hasChildren(const QModelIndex& parent) const override;
+ virtual int rowCount(const QModelIndex& parent) const override;
+ virtual int columnCount(const QModelIndex& parent) const override;
+ virtual QVariant data(const QModelIndex& i, int role) const override;
+ virtual bool setData(const QModelIndex& i, const QVariant& value, int role) override;
+
+ void setDisplaySessionId(bool value);
+ void setDisplayThreadId(bool value);
+ void setDisplayLoggerName(bool value);
+ void setDisplayLogLevel(bool value);
+ void setMinLogLevel(BNLogLevel level);
+ void setMaxLogLength(size_t length);
+
+ size_t getSessionId() const { return m_sessionId; }
+ bool getDisplaySessionId() const { return m_showSessionId; }
+ bool getDisplayThreadId() const { return m_showThreadId; }
+ bool getDisplayLoggerName() const { return m_showLoggerName; }
+ bool getDisplayLogLevel() const { return m_showLogLevel; }
+ Q_SIGNALS:
+ void settingsUpdated();
+
+ public Q_SLOTS:
+ void notifySessionChanged(size_t sessionId);
};
@@ -85,22 +147,22 @@ class BINARYNINJAUIAPI LogItemDelegate : public QStyledItemDelegate
bool IsNavigable(const QString& str, const std::pair<int, int>& offsetLen, uint64_t& value, bool highlight) const;
- public:
- LogItemDelegate(QWidget* parent);
+ public:
+ LogItemDelegate(QWidget* parent);
- void updateFonts();
- virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& idx) const override;
- virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& idx) const override;
+ void updateFonts();
+ virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& idx) const override;
+ virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& idx) const override;
- protected:
- bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
- const QModelIndex& index) override;
+ protected:
+ bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
+ const QModelIndex& index) override;
- Q_SIGNALS:
- void notifyDataChanged();
+ Q_SIGNALS:
+ void notifySessionChanged(size_t sessionId);
- public Q_SLOTS:
- void viewChanged(QWidget* frame);
+ public Q_SLOTS:
+ void viewChanged(QWidget* frame);
};
@@ -112,47 +174,75 @@ class BINARYNINJAUIAPI LogView : public GlobalAreaWidget
std::vector<std::pair<QAction*, bool>> m_actionEnableList;
QListView* m_list;
LogListModel* m_listModel;
+ LogListFilterProxyModel* m_model;
LogItemDelegate* m_itemDelegate;
QTimer* m_updateTimer;
+ QComboBox* m_comboBox;
+ QLineEdit* m_lineEdit;
+ QWidget* m_filterWidget;
+ RenderContext m_render;
+
bool m_doClear;
bool m_scrolledToEnd;
bool m_hasSelection = false;
- public:
- LogView(LogStatus* logStatus);
+ // bool m_subSelectionMode;
+ // size_t m_baseSelectionIndex;
+ // size_t m_baseSelectionOffset;
+ // size_t m_currentSelectionIndex;
+ // size_t m_currentSelectionOffset;
+ // size_t m_visibleRows {1};
+ // size_t m_topLine {0};
+ // size_t m_selectCount {0};
+
+ public:
+ LogView(LogStatus* logStatus);
+ void adjustSize(int width, int height);
- virtual void copy();
- virtual bool canCopy();
+ virtual void copy();
+ virtual bool canCopy();
- static void SetLogLevel(BNLogLevel level);
- static void SetLogSize(size_t maxSize);
- static bool IsHexString(const QString& str, std::pair<int, int> offsetLen);
- static bool StartsWith0x(const QString& str, std::pair<int, int> offsetLen);
+ static void setLogLevel(BNLogLevel level);
+ static void setLogSize(size_t maxSize);
+ static bool IsHexString(const QString& str, std::pair<int, int> offsetLen);
+ static bool StartsWith0x(const QString& str, std::pair<int, int> offsetLen);
- void notifyFontChanged() override;
- void notifyThemeChanged() override;
- void notifyViewChanged(ViewFrame* frame) override;
- void focus() override;
+ void notifyFontChanged() override;
+ void notifyThemeChanged() override;
+ void notifyViewChanged(ViewFrame* frame) override;
+ void focus() override;
- LogListModel* model() { return m_listModel; }
+ LogListModel* model() { return m_listModel; }
+ void updateFilter(const QString& filterText);
+ LoggingScope getScope() const { return m_model->getScope(); }
- protected:
- void contextMenuEvent(QContextMenuEvent* event) override;
+ // std::pair<size_t, size_t> GetSelectionIndexAndOffsetFromPosition(const QPoint& position) const;
+ // virtual void mousePressEvent(QMouseEvent* event) override;
+ // virtual void mouseReleaseEvent(QMouseEvent* event) override;
+ // virtual void mouseMoveEvent(QMouseEvent* event) override;
- Q_SIGNALS:
- void notifyUiStatus();
- void viewChanged(QWidget* frame);
+ // bool IsInSubSelectionMode() const { return m_subSelectionMode; }
+ // std::pair<size_t, size_t> GetSelectionIndicies() const { return {m_baseSelectionOffset, m_currentSelectionOffset}; }
- public Q_SLOTS:
- void clear();
+ protected:
+ void contextMenuEvent(QContextMenuEvent* event) override;
+ virtual void resizeEvent(QResizeEvent* event) override;
- private Q_SLOTS:
- void scrollRangeChanged(int minimum, int maximum);
- void scrollValueChanged(int value);
- void updateSelection(const QItemSelection& selected, const QItemSelection& deselected);
- void updateTimerEvent();
- void updateUiStatus();
+ Q_SIGNALS:
+ void notifyUiStatus();
+ void viewChanged(QWidget* frame);
+
+ public Q_SLOTS:
+ void clear();
+
+ private Q_SLOTS:
+ void scrollRangeChanged(int minimum, int maximum);
+ void scrollValueChanged(int value);
+ void updateSelection(const QItemSelection& selected, const QItemSelection& deselected);
+ void updateTimerEvent();
+ void updateUiStatus();
+ void showContextMenu();
};
@@ -162,19 +252,30 @@ class BINARYNINJAUIAPI LogStatus : public QWidget
QToolButton* m_errorIndicator;
QToolButton* m_warnIndicator;
+ ContextMenuManager* m_contextMenuManager;
+ QMenu* m_menu;
- int m_errorCount = 0;
- int m_warnCount = 0;
-
- public:
- LogStatus(QWidget* parent);
-
- void incrementErrorCount(int count);
- void incrementWarningCount(int count);
- void clearIndicators();
+ std::mutex m_countMutex;
+ int m_totalErrorCount = 0;
+ int m_totalWarnCount = 0;
+ std::map<uint64_t, int> m_sessionErrorCount;
+ std::map<uint64_t, int> m_sessionWarnCount;
+ size_t m_sessionId {0};
+ LogView* m_logView;
+ std::map<size_t, QString> getSessionToNameMap();
- void updateTheme();
+ public:
+ LogStatus(QWidget* parent);
+ void setLogView(LogView* view) { m_logView = view; }
+ void incrementErrorCount(uint64_t session, int count);
+ void incrementWarningCount(uint64_t session, int count);
+ void clearIndicators(bool warnings, bool errors);
+ void checkForErrors();
+ void focusTab(QString tabName);
- private Q_SLOTS:
- void clearStatus();
+ void updateTheme();
+ public Q_SLOTS:
+ void notifySessionChanged(size_t sessionId);
+ private Q_SLOTS:
+ void clearStatus(bool error);
};
diff --git a/ui/uicontext.h b/ui/uicontext.h
index 44c1e53d..94b05b05 100644
--- a/ui/uicontext.h
+++ b/ui/uicontext.h
@@ -339,6 +339,8 @@ class BINARYNINJAUIAPI UIContext
*/
virtual QWidget* getCurrentTab() = 0;
+ virtual QWidget* createNewTab(bool focus = true) = 0;
+
/*!
Get the current View associated with the given QWidget, if it exists
\param tab QWidget which could be a ViewFrame
diff --git a/ui/viewframe.h b/ui/viewframe.h
index 00ec700a..8d123f2b 100644
--- a/ui/viewframe.h
+++ b/ui/viewframe.h
@@ -96,6 +96,14 @@ class TransformParameterDialog;
class ViewPaneHeaderSubtypeWidget;
// struct BinaryNinjaCore::LinearDisassemblyLine;
+class View;
+class InitialNavigation: public BinaryNinja::BinaryDataNotification
+{
+ View* m_view;
+ public:
+ InitialNavigation(View* view);
+ virtual void OnSymbolAdded(BinaryNinja::BinaryView* view, BinaryNinja::Symbol* symbol) override;
+};
class BINARYNINJAUIAPI View
{
@@ -343,6 +351,7 @@ class BINARYNINJAUIAPI ViewFrame : public QWidget
bool m_graphViewPreferred = false;
std::vector<QString> m_viewTypePriority;
int m_preferredSyncGroup = 1;
+ InitialNavigation* m_initialNavigation;
UIActionHandler m_actionHandler;
@@ -487,6 +496,7 @@ class BINARYNINJAUIAPI ViewFrame : public QWidget
void forceSyncFromView();
ViewFrame* getOtherPane();
+ void UnRegisterInitialNavigation();
public Q_SLOTS:
virtual void assemble();