summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorMark Rowe <mark@vector35.com>2025-07-17 11:32:16 -0700
committerMark Rowe <mark@vector35.com>2025-12-11 21:09:38 -0800
commit290bbcf333679ffa057d57d1b540608e3bec8ada (patch)
treef8c576eed0fdde52735e4555dfce3dbd7e692f1d /python
parente902d25c22f2bf1426d2619933587ace06a38921 (diff)
Specify fixed underlying types for enums exposed by core
This allows a few widely-used enums to be shrunk from 4 bytes to 1 byte, improving packing when they're used as struct members. To remain compatible with C, we follow CoreFoundation's approach and use a macro when defining the enum: ``` #if defined(__cplusplus) || __has_extension(c_fixed_enum) #define BN_ENUM(type, name) enum name : type #else #define BN_ENUM(type, name) typedef type name; enum #endif BN_ENUM(uint8_t, SomeEnum) { ... } ``` In C++ and C23 this will expand to an enum with a fixed underlying type. In older C language versions, this will result in the enum type being a typedef of the underlying type, with an unnamed enum providing the enum values. Minor changes were needed within the Python bindings to update places that made assumptions about the underlying type of the enums.
Diffstat (limited to 'python')
-rw-r--r--python/binaryview.py4
-rw-r--r--python/generator.cpp25
-rw-r--r--python/lowlevelil.py2
-rw-r--r--python/mediumlevelil.py2
-rw-r--r--python/pluginmanager.py2
-rw-r--r--python/typeprinter.py18
6 files changed, 35 insertions, 18 deletions
diff --git a/python/binaryview.py b/python/binaryview.py
index f9afe2b8..47deb136 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -7161,7 +7161,7 @@ class BinaryView:
:rtype: None
"""
value = ctypes.c_char_p()
- string_type = ctypes.c_int()
+ string_type = core.StringTypeEnum()
result = core.BNCheckForStringAnnotationType(self.handle, addr, value, string_type, allow_short_strings, allow_large_strings, child_width)
if result:
result = value.value.decode("utf-8")
@@ -10591,7 +10591,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
if not isinstance(buffer, databuffer.DataBuffer):
raise TypeError("buffer must be an instance of databuffer.DataBuffer")
string = ctypes.c_char_p()
- string_type = ctypes.c_int()
+ string_type = core.StringTypeEnum()
if arch is not None:
arch = arch.handle
if not core.BNStringifyUnicodeData(self.handle, arch, buffer.handle, null_terminates, allow_short_strings, ctypes.byref(string), ctypes.byref(string_type)):
diff --git a/python/generator.cpp b/python/generator.cpp
index 6dd983b4..45ca1e4a 100644
--- a/python/generator.cpp
+++ b/python/generator.cpp
@@ -363,7 +363,23 @@ int main(int argc, char* argv[])
if (name.size() > 2 && name.substr(0, 2) == "BN")
name = name.substr(2);
- fprintf(out, "%sEnum = ctypes.c_int\n", name.c_str());
+ const char* ctypesType = nullptr;
+ switch (i.second->GetWidth())
+ {
+ case 1:
+ ctypesType = i.second->IsSigned() ? "ctypes.c_int8" : "ctypes.c_uint8";
+ break;
+ case 2:
+ ctypesType = i.second->IsSigned() ? "ctypes.c_int16" : "ctypes.c_uint16";
+ break;
+ case 4:
+ ctypesType = i.second->IsSigned() ? "ctypes.c_int32" : "ctypes.c_uint32";
+ break;
+ default:
+ ctypesType = i.second->IsSigned() ? "ctypes.c_int64" : "ctypes.c_uint64";
+ break;
+ }
+ fprintf(out, "%sEnum = %s\n", name.c_str(), ctypesType);
fprintf(enums, "\n\nclass %s(enum.IntEnum):\n", name.c_str());
for (auto& j : i.second->GetEnumeration()->GetMembers())
@@ -465,9 +481,10 @@ int main(int argc, char* argv[])
// Check for a string result, these will be automatically wrapped to free the string
// memory and return a Python string
- bool stringResult = (i.second->GetChildType()->GetClass() == PointerTypeClass)
- && (i.second->GetChildType()->GetChildType()->GetWidth() == 1)
- && (i.second->GetChildType()->GetChildType()->IsSigned());
+ bool stringResult = i.second->GetChildType()->GetClass() == PointerTypeClass
+ && i.second->GetChildType()->GetChildType()->GetClass() == IntegerTypeClass
+ && i.second->GetChildType()->GetChildType()->GetWidth() == 1
+ && i.second->GetChildType()->GetChildType()->IsSigned();
// Pointer returns will be automatically wrapped to return None on null pointer
bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass);
// Enum returns will automatically cast to the enum type
diff --git a/python/lowlevelil.py b/python/lowlevelil.py
index 565ca6a2..f0b130c3 100644
--- a/python/lowlevelil.py
+++ b/python/lowlevelil.py
@@ -871,7 +871,7 @@ class LowLevelILInstruction(BaseILInstruction):
if options is None:
options = []
idx = 0
- option_array = (ctypes.c_int * len(options))()
+ option_array = (core.DataFlowQueryOptionEnum * len(options))()
for option in options:
option_array[idx] = option
idx += 1
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index 61c0bf1b..a38ec0ea 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -822,7 +822,7 @@ class MediumLevelILInstruction(BaseILInstruction):
if options is None:
options = []
idx = 0
- option_array = (ctypes.c_int * len(options))()
+ option_array = (core.DataFlowQueryOptionEnum * len(options))()
for option in options:
option_array[idx] = option
idx += 1
diff --git a/python/pluginmanager.py b/python/pluginmanager.py
index 62066397..75f7bfe2 100644
--- a/python/pluginmanager.py
+++ b/python/pluginmanager.py
@@ -34,7 +34,7 @@ class RepoPlugin:
``RepoPlugin`` is mostly read-only, however you can install/uninstall enable/disable plugins. RepoPlugins are
created by parsing the plugins.json in a plugin repository.
"""
- def __init__(self, handle: core.BNRepoPluginHandle):
+ def __init__(self, handle: 'core.BNRepoPluginHandle'):
self.handle = handle
def __del__(self):
diff --git a/python/typeprinter.py b/python/typeprinter.py
index 091cd803..c73fddd1 100644
--- a/python/typeprinter.py
+++ b/python/typeprinter.py
@@ -316,7 +316,7 @@ class TypePrinter(metaclass=_TypePrinterMetaclass):
i += 1
result = ctypes.c_char_p()
- core.BNTypePrinterDefaultPrintAllTypes(self.handle, cpp_names, cpp_types, len(types_), data.handle, padding_cols, ctypes.c_int(escaping), result)
+ core.BNTypePrinterDefaultPrintAllTypes(self.handle, cpp_names, cpp_types, len(types_), data.handle, padding_cols, core.TokenEscapingTypeEnum(escaping), result)
return core.pyNativeStr(result.value)
def get_type_tokens(self, type: types.Type, platform: Optional[_platform.Platform] = None, name: types.QualifiedNameType = "", base_confidence: int = core.max_confidence, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> List[_function.InstructionTextToken]:
@@ -451,7 +451,7 @@ class CoreTypePrinter(TypePrinter):
count = ctypes.c_ulonglong()
name_cpp = name._to_core_struct()
result_cpp = ctypes.POINTER(core.BNInstructionTextToken)()
- if not core.BNGetTypePrinterTypeTokens(self.handle, type.handle, None if platform is None else platform.handle, name_cpp, base_confidence, ctypes.c_int(escaping), result_cpp, count):
+ if not core.BNGetTypePrinterTypeTokens(self.handle, type.handle, None if platform is None else platform.handle, name_cpp, base_confidence, core.TokenEscapingTypeEnum(escaping), result_cpp, count):
raise RuntimeError("BNGetTypePrinterTypeTokens returned False")
result = _function.InstructionTextToken._from_core_struct(result_cpp, count.value)
@@ -467,7 +467,7 @@ class CoreTypePrinter(TypePrinter):
parent_type_cpp = None
if parent_type is not None:
parent_type_cpp = parent_type.handle
- if not core.BNGetTypePrinterTypeTokensBeforeName(self.handle, type.handle, None if platform is None else platform.handle, base_confidence, parent_type_cpp, ctypes.c_int(escaping), result_cpp, count):
+ if not core.BNGetTypePrinterTypeTokensBeforeName(self.handle, type.handle, None if platform is None else platform.handle, base_confidence, parent_type_cpp, core.TokenEscapingTypeEnum(escaping), result_cpp, count):
raise RuntimeError("BNGetTypePrinterTypeTokensBeforeName returned False")
result = _function.InstructionTextToken._from_core_struct(result_cpp, count.value)
@@ -483,7 +483,7 @@ class CoreTypePrinter(TypePrinter):
parent_type_cpp = None
if parent_type is not None:
parent_type_cpp = parent_type.handle
- if not core.BNGetTypePrinterTypeTokensAfterName(self.handle, type.handle, None if platform is None else platform.handle, base_confidence, parent_type_cpp, ctypes.c_int(escaping), result_cpp, count):
+ if not core.BNGetTypePrinterTypeTokensAfterName(self.handle, type.handle, None if platform is None else platform.handle, base_confidence, parent_type_cpp, core.TokenEscapingTypeEnum(escaping), result_cpp, count):
raise RuntimeError("BNGetTypePrinterTypeTokensAfterName returned False")
result = _function.InstructionTextToken._from_core_struct(result_cpp, count.value)
@@ -496,7 +496,7 @@ class CoreTypePrinter(TypePrinter):
if not isinstance(name, types.QualifiedName):
name = types.QualifiedName(name)
result_cpp = ctypes.c_char_p()
- if not core.BNGetTypePrinterTypeString(self.handle, type.handle, None if platform is None else platform.handle, name._to_core_struct(), ctypes.c_int(escaping), result_cpp):
+ if not core.BNGetTypePrinterTypeString(self.handle, type.handle, None if platform is None else platform.handle, name._to_core_struct(), core.TokenEscapingTypeEnum(escaping), result_cpp):
raise RuntimeError("BNGetTypePrinterTypeString returned False")
result = core.pyNativeStr(result_cpp.value)
@@ -506,7 +506,7 @@ class CoreTypePrinter(TypePrinter):
def get_type_string_before_name(self, type: types.Type, platform: Optional[_platform.Platform] = None,
escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str:
result_cpp = ctypes.c_char_p()
- if not core.BNGetTypePrinterTypeStringBeforeName(self.handle, type.handle, None if platform is None else platform.handle, ctypes.c_int(escaping), result_cpp):
+ if not core.BNGetTypePrinterTypeStringBeforeName(self.handle, type.handle, None if platform is None else platform.handle, core.TokenEscapingTypeEnum(escaping), result_cpp):
raise RuntimeError("BNGetTypePrinterTypeStringBeforeName returned False")
result = core.pyNativeStr(result_cpp.value)
@@ -516,7 +516,7 @@ class CoreTypePrinter(TypePrinter):
def get_type_string_after_name(self, type: types.Type, platform: Optional[_platform.Platform] = None,
escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str:
result_cpp = ctypes.c_char_p()
- if not core.BNGetTypePrinterTypeStringAfterName(self.handle, type.handle, None if platform is None else platform.handle, ctypes.c_int(escaping), result_cpp):
+ if not core.BNGetTypePrinterTypeStringAfterName(self.handle, type.handle, None if platform is None else platform.handle, core.TokenEscapingTypeEnum(escaping), result_cpp):
raise RuntimeError("BNGetTypePrinterTypeStringAfterName returned False")
result = core.pyNativeStr(result_cpp.value)
@@ -532,7 +532,7 @@ class CoreTypePrinter(TypePrinter):
name = types.QualifiedName(name)
count = ctypes.c_ulonglong()
core_lines = ctypes.POINTER(core.BNTypeDefinitionLine)()
- if not core.BNGetTypePrinterTypeLines(self.handle, type.handle, container.handle, name._to_core_struct(), padding_cols, collapsed, ctypes.c_int(escaping), core_lines, count):
+ if not core.BNGetTypePrinterTypeLines(self.handle, type.handle, container.handle, name._to_core_struct(), padding_cols, collapsed, core.TokenEscapingTypeEnum(escaping), core_lines, count):
raise RuntimeError("BNGetTypePrinterTypeLines returned False")
lines = []
for i in range(count.value):
@@ -552,5 +552,5 @@ class CoreTypePrinter(TypePrinter):
i += 1
result = ctypes.c_char_p()
- core.BNTypePrinterPrintAllTypes(self.handle, cpp_names, cpp_types, len(types_), data.handle, padding_cols, ctypes.c_int(escaping), result)
+ core.BNTypePrinterPrintAllTypes(self.handle, cpp_names, cpp_types, len(types_), data.handle, padding_cols, core.TokenEscapingTypeEnum(escaping), result)
return core.pyNativeStr(result.value)