diff --git a/python/__init__.py b/python/__init__.py index 1de3ff400..9fa3dcfe2 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -21,6 +21,7 @@ import atexit import sys import ctypes +import inspect from time import gmtime, struct_time import os from typing import Mapping, Optional @@ -103,6 +104,13 @@ from .firmwareninja import * +def _get_parameter_count(callback): + if sys.version_info >= (3, 14): + import annotationlib + return len(inspect.signature(callback, annotation_format=annotationlib.Format.STRING).parameters) + return len(inspect.signature(callback).parameters) + + def shutdown(): """ ``shutdown`` cleanly shuts down the core, stopping all workers and closing all log files. diff --git a/python/demangle.py b/python/demangle.py index 4b8e77704..326d018fa 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -19,7 +19,6 @@ # IN THE SOFTWARE. import ctypes -import inspect import warnings # Binary Ninja components @@ -445,6 +444,7 @@ class Demangler(metaclass=_DemanglerMetaclass): _cached_name = None def __init__(self, handle=None): + self._uses_legacy_demangle_signature = False if handle is not None: self.handle = core.handle_of_type(handle, core.BNDemangler) self.__dict__["name"] = core.BNGetDemanglerName(handle) @@ -464,6 +464,22 @@ def register(cls): assert demangler.__class__.name is not None assert demangler.handle is None + try: + parameter_count = binaryninja._get_parameter_count(demangler.demangle) + except (TypeError, ValueError): + parameter_count = 2 + demangler._uses_legacy_demangle_signature = parameter_count == 3 + if demangler._uses_legacy_demangle_signature: + warnings.warn( + deprecation.DeprecatedWarning( + "Custom Demangler.demangle(arch, name, view)", + "5.4", + None, + "Use Demangler.demangle(name, config) instead." + ), + stacklevel=2 + ) + demangler._cb = core.BNDemanglerCallbacks() demangler._cb.context = 0 demangler._cb.isMangledString = demangler._cb.isMangledString.__class__(demangler._is_mangled_string) @@ -518,18 +534,7 @@ def _demangle(self, ctxt, name, config, result): api_config = DemanglerConfig._from_core_struct(config) demangle = self.demangle - try: - parameter_count = len(inspect.signature(demangle).parameters) - except (TypeError, ValueError): - parameter_count = 2 - - if parameter_count == 3: - warnings.warn( - "Custom Demangler.demangle(arch, name, view) is deprecated; " - "use Demangler.demangle(name, config)", - DeprecationWarning, - stacklevel=2 - ) + if self._uses_legacy_demangle_signature: arch = api_config.platform.arch if api_config.platform is not None else None demangle_result = demangle(arch, core.pyNativeStr(name), api_config.view) else: