summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorPeter LaFosse <peter@vector35.com>2022-02-01 11:35:10 -0500
committerPeter LaFosse <peter@vector35.com>2022-03-16 08:05:27 -0400
commit5ce116e4d1d3c30537f3635c06d7a0c619e55e43 (patch)
treedd96aa9d6b55b26dd247cd0b7e4d0bdfc6a15681 /python
parentefb5d8ba056fbae3f57a80f813a18c4a6da60f28 (diff)
Add support for structured logging
Diffstat (limited to 'python')
-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
5 files changed, 62 insertions, 24 deletions
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(