diff --git a/.github/workflows/dec-tests.yml b/.github/workflows/dec-tests.yml index c8f233a..3171708 100644 --- a/.github/workflows/dec-tests.yml +++ b/.github/workflows/dec-tests.yml @@ -43,7 +43,7 @@ jobs: - name: Install Ghidra uses: er28-0652/setup-ghidra@master with: - version: "10.4" + version: "11.1" - name: Pytest run: | # these two test must be run in separate python environments, due to the way ghidra bridge works diff --git a/libbs/__init__.py b/libbs/__init__.py index 15d62bc..8b8a1f4 100644 --- a/libbs/__init__.py +++ b/libbs/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.20.1" +__version__ = "1.21.0" import logging diff --git a/libbs/decompilers/ghidra/compat/imports.py b/libbs/decompilers/ghidra/compat/imports.py index 357ae26..705aec9 100644 --- a/libbs/decompilers/ghidra/compat/imports.py +++ b/libbs/decompilers/ghidra/compat/imports.py @@ -29,7 +29,7 @@ def import_objs(path: str, objs: Iterable[str]): from ghidra.program.model.data import ( DataTypeConflictHandler, StructureDataType, ByteDataType, EnumDataType, CategoryPath, TypedefDataType ) - from ghidra.program.util import ChangeManager, ProgramChangeRecord + from ghidra.program.util import ChangeManager, ProgramChangeRecord, FunctionChangeRecord from ghidra.program.database.function import VariableDB, FunctionDB from ghidra.program.database.symbol import CodeSymbol, FunctionSymbol from ghidra.program.model.listing import CodeUnit @@ -56,7 +56,7 @@ def import_objs(path: str, objs: Iterable[str]): "ghidra.program.model.data", ("DataTypeConflictHandler", "StructureDataType", "ByteDataType", "EnumDataType", "CategoryPath", "TypedefDataType") ) - ChangeManager, ProgramChangeRecord = import_objs("ghidra.program.util", ("ChangeManager", "ProgramChangeRecord")) + ChangeManager, ProgramChangeRecord, FunctionChangeRecord = import_objs("ghidra.program.util", ("ChangeManager", "ProgramChangeRecord", "FunctionChangeRecord")) VariableDB, FunctionDB = import_objs("ghidra.program.database.function", ("VariableDB", "FunctionDB")) CodeSymbol, FunctionSymbol = import_objs("ghidra.program.database.symbol", ("CodeSymbol", "FunctionSymbol")) CodeUnit = import_objs("ghidra.program.model.listing", ("CodeUnit",)) @@ -82,6 +82,7 @@ def import_objs(path: str, objs: Iterable[str]): "SourceType", "ChangeManager", "ProgramChangeRecord", + "FunctionChangeRecord", "VariableDB", "FunctionDB", "CodeSymbol", diff --git a/libbs/decompilers/ghidra/hooks.py b/libbs/decompilers/ghidra/hooks.py index 9c4ef16..9d040bc 100644 --- a/libbs/decompilers/ghidra/hooks.py +++ b/libbs/decompilers/ghidra/hooks.py @@ -14,7 +14,7 @@ def create_data_monitor(deci: "GhidraDecompilerInterface"): from .compat.imports import ( DomainObjectListener, ChangeManager, ProgramChangeRecord, VariableDB, FunctionDB, CodeSymbol, - FunctionSymbol + FunctionSymbol, FunctionChangeRecord ) class DataMonitor(DomainObjectListener): @@ -76,8 +76,8 @@ def do_change_handler(self, ev): new_value = record.getNewValue() obj = record.getObject() if changeType in self.funcEvents: - subType = record.getSubEventType() - if subType == ChangeManager.FUNCTION_CHANGED_RETURN: + func_change_type = record.getSpecificChangeType() + if func_change_type == FunctionChangeRecord.FunctionChangeType.RETURN_TYPE_CHANGED: # Function return type changed header = FunctionHeader( name=None, addr=obj.getEntryPoint().getOffset(), type_=str(obj.getReturnType()) diff --git a/libbs/decompilers/ghidra/interface.py b/libbs/decompilers/ghidra/interface.py index 56d48b2..2fd16fb 100644 --- a/libbs/decompilers/ghidra/interface.py +++ b/libbs/decompilers/ghidra/interface.py @@ -506,7 +506,12 @@ def _set_function_header(self, fheader: FunctionHeader, decompilation=None, **kw params = ghidra_func.getParameters() if len(params) == 0: with Transaction(self.flat_api, msg="BS::set_function_header::update_params"): - HighFunctionDBUtil.commitParamsToDatabase(decompilation.highFunction, True, SourceType.USER_DEFINED) + HighFunctionDBUtil.commitParamsToDatabase( + decompilation.highFunction, + True, + HighFunctionDBUtil.ReturnCommitOption.COMMIT_NO_VOID, + SourceType.USER_DEFINED + ) with Transaction(self.flat_api, msg="BS::set_function_header::set_arguments"): for offset, param in zip(fheader.args, params): diff --git a/tests/test_remote_ghidra.py b/tests/test_remote_ghidra.py index 0cc6223..502473b 100644 --- a/tests/test_remote_ghidra.py +++ b/tests/test_remote_ghidra.py @@ -66,9 +66,15 @@ def func_hit(*args, **kwargs): hits[args[0].__class__].append(args[0]) # function return type main.header.type = 'long' deci.functions[func_addr] = main + time.sleep(5) main.header.type = 'double' deci.functions[func_addr] = main + time.sleep(5) + + # confirm the final type is correct + new_main = deci.functions[func_addr] + assert new_main.header.type == main.header.type assert len(hits[FunctionHeader]) >= old_header_hits + 2