From f702d0c0fe53fc60a8f2ae77772a76e3a087e491 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Feb 2024 10:51:20 +0000 Subject: [PATCH 01/12] Create draft PR for #45 From 42fafccb6756e941842c4b7707cc3bc053aec04b Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Thu, 22 Feb 2024 12:27:53 +0100 Subject: [PATCH 02/12] Added type FunctionPointer --- decompiler/structures/pseudo/typing.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/decompiler/structures/pseudo/typing.py b/decompiler/structures/pseudo/typing.py index f27086bcc..aff8d5aca 100644 --- a/decompiler/structures/pseudo/typing.py +++ b/decompiler/structures/pseudo/typing.py @@ -218,6 +218,11 @@ def __str__(self) -> str: return f"{self.return_type}({', '.join(str(x) for x in self.parameters)})" +@dataclass(frozen=True, order=True) +class FunctionPointer(FunctionTypeDef): + pass + + class TypeParser: """A type parser in charge of creating types.""" From 567e3a742b9add5b8ed4fd8e6c04cf7e7c93d97b Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Thu, 22 Feb 2024 12:28:56 +0100 Subject: [PATCH 03/12] Added preprocessing stage to find function pointers --- decompiler/pipeline/pipeline.py | 2 ++ decompiler/pipeline/preprocessing/__init__.py | 1 + .../preprocessing/get_function_pointer.py | 27 +++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 decompiler/pipeline/preprocessing/get_function_pointer.py diff --git a/decompiler/pipeline/pipeline.py b/decompiler/pipeline/pipeline.py index 74e4267a3..83d82fdc3 100644 --- a/decompiler/pipeline/pipeline.py +++ b/decompiler/pipeline/pipeline.py @@ -15,6 +15,7 @@ RegisterPairHandling, RemoveStackCanary, SwitchVariableDetection, + GetFunctionPointer, ) from decompiler.pipeline.ssa.outofssatranslation import OutOfSsaTranslation from decompiler.task import DecompilerTask @@ -35,6 +36,7 @@ MemPhiConverter, InsertMissingDefinitions, PhiFunctionFixer, + GetFunctionPointer, ] POSTPROCESSING_STAGES = [OutOfSsaTranslation, PatternIndependentRestructuring] diff --git a/decompiler/pipeline/preprocessing/__init__.py b/decompiler/pipeline/preprocessing/__init__.py index 5dfe26cc0..49aab34f1 100644 --- a/decompiler/pipeline/preprocessing/__init__.py +++ b/decompiler/pipeline/preprocessing/__init__.py @@ -8,3 +8,4 @@ from .register_pair_handling import RegisterPairHandling from .remove_stack_canary import RemoveStackCanary from .switch_variable_detection import BackwardSliceSwitchVariableDetection as SwitchVariableDetection +from .get_function_pointer import GetFunctionPointer diff --git a/decompiler/pipeline/preprocessing/get_function_pointer.py b/decompiler/pipeline/preprocessing/get_function_pointer.py new file mode 100644 index 000000000..a51f44e74 --- /dev/null +++ b/decompiler/pipeline/preprocessing/get_function_pointer.py @@ -0,0 +1,27 @@ +"""Module to find and declare function pointer variables""" + +from decompiler.pipeline.stage import PipelineStage +from decompiler.structures.pseudo.instructions import Assignment, Variable +from decompiler.structures.pseudo.operations import Call +from decompiler.structures.pseudo.typing import FunctionPointer, Pointer +from decompiler.task import DecompilerTask + + +class GetFunctionPointer(PipelineStage): + name = "get-function-pointer" + + def run(self, task: DecompilerTask): + for block in task.graph: + for expression in block: + if ( + isinstance(expression, Assignment) + and isinstance(expression.value, Call) + and isinstance(expression.value.function, Variable) + ): + expression.value.function._type = Pointer( + basetype=FunctionPointer( + size=expression.value.function.type.size, + return_type=expression.value.function.type, + parameters=tuple(expression.value.parameters), + ), + ) From e05ce682ff0ed3bcff07f185cdee41cc6ef534f7 Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Thu, 22 Feb 2024 12:29:53 +0100 Subject: [PATCH 04/12] Moved Type propagation after code eleminations --- decompiler/util/default.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/decompiler/util/default.json b/decompiler/util/default.json index e2eedadac..5cc50e766 100644 --- a/decompiler/util/default.json +++ b/decompiler/util/default.json @@ -507,10 +507,10 @@ "default": [ "expression-propagation", "bit-field-comparison-unrolling", - "type-propagation", "dead-path-elimination", "dead-loop-elimination", "dead-code-elimination", + "type-propagation", "expression-propagation-memory", "expression-propagation-function-call", "expression-simplification-cfg", From adb451d84c880a4a5757eba093f770333aba9693 Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Thu, 22 Feb 2024 12:40:16 +0100 Subject: [PATCH 05/12] isort --- decompiler/pipeline/pipeline.py | 2 +- decompiler/pipeline/preprocessing/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/decompiler/pipeline/pipeline.py b/decompiler/pipeline/pipeline.py index 83d82fdc3..980b95f09 100644 --- a/decompiler/pipeline/pipeline.py +++ b/decompiler/pipeline/pipeline.py @@ -9,13 +9,13 @@ from decompiler.pipeline.preprocessing import ( Coherence, CompilerIdiomHandling, + GetFunctionPointer, InsertMissingDefinitions, MemPhiConverter, PhiFunctionFixer, RegisterPairHandling, RemoveStackCanary, SwitchVariableDetection, - GetFunctionPointer, ) from decompiler.pipeline.ssa.outofssatranslation import OutOfSsaTranslation from decompiler.task import DecompilerTask diff --git a/decompiler/pipeline/preprocessing/__init__.py b/decompiler/pipeline/preprocessing/__init__.py index 49aab34f1..a83143c8f 100644 --- a/decompiler/pipeline/preprocessing/__init__.py +++ b/decompiler/pipeline/preprocessing/__init__.py @@ -2,10 +2,10 @@ from .coherence import Coherence from .compiler_idiom_handling import CompilerIdiomHandling +from .get_function_pointer import GetFunctionPointer from .mem_phi_conversion import MemPhiConverter from .missing_definitions import InsertMissingDefinitions from .phi_predecessors import PhiFunctionFixer from .register_pair_handling import RegisterPairHandling from .remove_stack_canary import RemoveStackCanary from .switch_variable_detection import BackwardSliceSwitchVariableDetection as SwitchVariableDetection -from .get_function_pointer import GetFunctionPointer From 008fef1f57a458e6b5c410e2379f1e99e4e7f3cc Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Tue, 27 Feb 2024 13:15:28 +0100 Subject: [PATCH 06/12] Changed Type from Pointer(FunctionPointer) to FunctionPointer() --- decompiler/backend/cexpressiongenerator.py | 5 +++-- .../pipeline/preprocessing/get_function_pointer.py | 10 ++++------ decompiler/structures/pseudo/__init__.py | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/decompiler/backend/cexpressiongenerator.py b/decompiler/backend/cexpressiongenerator.py index 5f0775949..fe38c1a5b 100644 --- a/decompiler/backend/cexpressiongenerator.py +++ b/decompiler/backend/cexpressiongenerator.py @@ -2,7 +2,7 @@ from itertools import chain, repeat from decompiler.structures import pseudo as expressions -from decompiler.structures.pseudo import Float, FunctionTypeDef, Integer, OperationType, Pointer, StringSymbol, Type +from decompiler.structures.pseudo import Float, FunctionTypeDef, FunctionPointer, Integer, OperationType, Pointer, StringSymbol, Type from decompiler.structures.pseudo import instructions as instructions from decompiler.structures.pseudo import operations as operations from decompiler.structures.pseudo.operations import MemberAccess @@ -349,7 +349,8 @@ def _format_string_literal(constant: expressions.Constant) -> str: def format_variables_declaration(var_type: Type, var_names: list[str]) -> str: """Return a string representation of variable declarations.""" match var_type: - case Pointer(type=FunctionTypeDef() as fun_type): + case Pointer(type=FunctionTypeDef()) | FunctionPointer(): + fun_type = var_type.type if isinstance(var_type, Pointer) else var_type parameter_names = ", ".join(str(parameter) for parameter in fun_type.parameters) declarations_without_return_type = [f"(* {var_name})({parameter_names})" for var_name in var_names] return f"{fun_type.return_type} {', '.join(declarations_without_return_type)}" diff --git a/decompiler/pipeline/preprocessing/get_function_pointer.py b/decompiler/pipeline/preprocessing/get_function_pointer.py index a51f44e74..d1e872f54 100644 --- a/decompiler/pipeline/preprocessing/get_function_pointer.py +++ b/decompiler/pipeline/preprocessing/get_function_pointer.py @@ -18,10 +18,8 @@ def run(self, task: DecompilerTask): and isinstance(expression.value, Call) and isinstance(expression.value.function, Variable) ): - expression.value.function._type = Pointer( - basetype=FunctionPointer( - size=expression.value.function.type.size, - return_type=expression.value.function.type, - parameters=tuple(expression.value.parameters), - ), + expression.value.function._type = FunctionPointer( + return_type=expression.value.function.type, + parameters=tuple(expression.value.parameters), + size=expression.value.function.type.size, ) diff --git a/decompiler/structures/pseudo/__init__.py b/decompiler/structures/pseudo/__init__.py index 0df23d585..75936b302 100644 --- a/decompiler/structures/pseudo/__init__.py +++ b/decompiler/structures/pseudo/__init__.py @@ -34,5 +34,5 @@ Return, ) from .operations import BinaryOperation, Call, Condition, ListOperation, Operation, OperationType, TernaryExpression, UnaryOperation -from .typing import CustomType, Float, FunctionTypeDef, Integer, Pointer, Type, TypeParser, UnknownType +from .typing import CustomType, Float, FunctionTypeDef, FunctionPointer, Integer, Pointer, Type, TypeParser, UnknownType from .z3_logic import Z3Converter From 1120e3ed24c73e1b0cc15df98e4fd93a549aea1e Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Tue, 27 Feb 2024 13:21:39 +0100 Subject: [PATCH 07/12] isort --- decompiler/backend/cexpressiongenerator.py | 2 +- decompiler/structures/pseudo/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/decompiler/backend/cexpressiongenerator.py b/decompiler/backend/cexpressiongenerator.py index fe38c1a5b..c2db8f7e6 100644 --- a/decompiler/backend/cexpressiongenerator.py +++ b/decompiler/backend/cexpressiongenerator.py @@ -2,7 +2,7 @@ from itertools import chain, repeat from decompiler.structures import pseudo as expressions -from decompiler.structures.pseudo import Float, FunctionTypeDef, FunctionPointer, Integer, OperationType, Pointer, StringSymbol, Type +from decompiler.structures.pseudo import Float, FunctionPointer, FunctionTypeDef, Integer, OperationType, Pointer, StringSymbol, Type from decompiler.structures.pseudo import instructions as instructions from decompiler.structures.pseudo import operations as operations from decompiler.structures.pseudo.operations import MemberAccess diff --git a/decompiler/structures/pseudo/__init__.py b/decompiler/structures/pseudo/__init__.py index 75936b302..8963e9393 100644 --- a/decompiler/structures/pseudo/__init__.py +++ b/decompiler/structures/pseudo/__init__.py @@ -34,5 +34,5 @@ Return, ) from .operations import BinaryOperation, Call, Condition, ListOperation, Operation, OperationType, TernaryExpression, UnaryOperation -from .typing import CustomType, Float, FunctionTypeDef, FunctionPointer, Integer, Pointer, Type, TypeParser, UnknownType +from .typing import CustomType, Float, FunctionPointer, FunctionTypeDef, Integer, Pointer, Type, TypeParser, UnknownType from .z3_logic import Z3Converter From 22c64db50945c5004e9e252eb8301eb9ae6ec089 Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Wed, 28 Feb 2024 11:16:58 +0100 Subject: [PATCH 08/12] Revert "Changed Type from Pointer(FunctionPointer) to FunctionPointer()" This reverts commit 008fef1f57a458e6b5c410e2379f1e99e4e7f3cc. --- decompiler/backend/cexpressiongenerator.py | 5 ++--- .../pipeline/preprocessing/get_function_pointer.py | 10 ++++++---- decompiler/structures/pseudo/__init__.py | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/decompiler/backend/cexpressiongenerator.py b/decompiler/backend/cexpressiongenerator.py index c2db8f7e6..5f0775949 100644 --- a/decompiler/backend/cexpressiongenerator.py +++ b/decompiler/backend/cexpressiongenerator.py @@ -2,7 +2,7 @@ from itertools import chain, repeat from decompiler.structures import pseudo as expressions -from decompiler.structures.pseudo import Float, FunctionPointer, FunctionTypeDef, Integer, OperationType, Pointer, StringSymbol, Type +from decompiler.structures.pseudo import Float, FunctionTypeDef, Integer, OperationType, Pointer, StringSymbol, Type from decompiler.structures.pseudo import instructions as instructions from decompiler.structures.pseudo import operations as operations from decompiler.structures.pseudo.operations import MemberAccess @@ -349,8 +349,7 @@ def _format_string_literal(constant: expressions.Constant) -> str: def format_variables_declaration(var_type: Type, var_names: list[str]) -> str: """Return a string representation of variable declarations.""" match var_type: - case Pointer(type=FunctionTypeDef()) | FunctionPointer(): - fun_type = var_type.type if isinstance(var_type, Pointer) else var_type + case Pointer(type=FunctionTypeDef() as fun_type): parameter_names = ", ".join(str(parameter) for parameter in fun_type.parameters) declarations_without_return_type = [f"(* {var_name})({parameter_names})" for var_name in var_names] return f"{fun_type.return_type} {', '.join(declarations_without_return_type)}" diff --git a/decompiler/pipeline/preprocessing/get_function_pointer.py b/decompiler/pipeline/preprocessing/get_function_pointer.py index d1e872f54..a51f44e74 100644 --- a/decompiler/pipeline/preprocessing/get_function_pointer.py +++ b/decompiler/pipeline/preprocessing/get_function_pointer.py @@ -18,8 +18,10 @@ def run(self, task: DecompilerTask): and isinstance(expression.value, Call) and isinstance(expression.value.function, Variable) ): - expression.value.function._type = FunctionPointer( - return_type=expression.value.function.type, - parameters=tuple(expression.value.parameters), - size=expression.value.function.type.size, + expression.value.function._type = Pointer( + basetype=FunctionPointer( + size=expression.value.function.type.size, + return_type=expression.value.function.type, + parameters=tuple(expression.value.parameters), + ), ) diff --git a/decompiler/structures/pseudo/__init__.py b/decompiler/structures/pseudo/__init__.py index 8963e9393..0df23d585 100644 --- a/decompiler/structures/pseudo/__init__.py +++ b/decompiler/structures/pseudo/__init__.py @@ -34,5 +34,5 @@ Return, ) from .operations import BinaryOperation, Call, Condition, ListOperation, Operation, OperationType, TernaryExpression, UnaryOperation -from .typing import CustomType, Float, FunctionPointer, FunctionTypeDef, Integer, Pointer, Type, TypeParser, UnknownType +from .typing import CustomType, Float, FunctionTypeDef, Integer, Pointer, Type, TypeParser, UnknownType from .z3_logic import Z3Converter From 948046dea31180d86ece9ff5d92b24c137e12296 Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Wed, 28 Feb 2024 12:47:43 +0100 Subject: [PATCH 09/12] Added tests --- tests/backend/test_codegenerator.py | 6 +- .../test_get_function_pointer.py | 101 ++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tests/pipeline/preprocessing/test_get_function_pointer.py diff --git a/tests/backend/test_codegenerator.py b/tests/backend/test_codegenerator.py index 021160101..4faafb520 100644 --- a/tests/backend/test_codegenerator.py +++ b/tests/backend/test_codegenerator.py @@ -33,7 +33,7 @@ OperationType, UnaryOperation, ) -from decompiler.structures.pseudo.typing import CustomType, Float, Integer, Pointer, Type +from decompiler.structures.pseudo.typing import CustomType, Float, FunctionPointer, Integer, Pointer, Type from decompiler.task import DecompilerTask from decompiler.util.options import Options @@ -80,6 +80,8 @@ def logic_cond(name: str, context) -> LogicCondition: var_p = Variable("p", Pointer(int32)) var_fun_p = Variable("p", Pointer(FunctionTypeDef(0, int32, (int32,)))) var_fun_p0 = Variable("p0", Pointer(FunctionTypeDef(0, int32, (int32,)))) +var_fun_ptr = Variable("ptr", Pointer(FunctionPointer(0, int32, (int32,)))) +var_fun_ptr0 = Variable("ptr0", Pointer(FunctionPointer(0, int32, (int32,)))) const_0 = Constant(0, int32) const_1 = Constant(1, int32) @@ -1286,6 +1288,8 @@ class TestLocalDeclarationGenerator: (1, [var_x.copy(), var_y.copy(), var_p.copy()], "int x;\nint y;\nint * p;"), (1, [var_x.copy(), var_y.copy(), var_fun_p.copy()], "int x;\nint y;\nint (* p)(int);"), (2, [var_x.copy(), var_y.copy(), var_fun_p.copy(), var_fun_p0.copy()], "int x, y;\nint (* p)(int), (* p0)(int);"), + (1, [var_x.copy(), var_y.copy(), var_fun_ptr.copy()], "int x;\nint y;\nint (* ptr)(int);"), + (2, [var_x.copy(), var_y.copy(), var_fun_ptr.copy(), var_fun_ptr0.copy()], "int x, y;\nint (* ptr)(int), (* ptr0)(int);"), ], ) def test_variable_declaration(self, vars_per_line: int, variables: List[Variable], expected: str): diff --git a/tests/pipeline/preprocessing/test_get_function_pointer.py b/tests/pipeline/preprocessing/test_get_function_pointer.py new file mode 100644 index 000000000..97d59604c --- /dev/null +++ b/tests/pipeline/preprocessing/test_get_function_pointer.py @@ -0,0 +1,101 @@ +from decompiler.pipeline.preprocessing import GetFunctionPointer +from decompiler.structures.graphs.cfg import BasicBlock, ControlFlowGraph, FalseCase, TrueCase, UnconditionalEdge +from decompiler.structures.pseudo import ( + Assignment, + Call, + Condition, + Constant, + ImportedFunctionSymbol, + Integer, + ListOperation, + OperationType, + Variable, +) +from decompiler.structures.pseudo.instructions import Branch, Return +from decompiler.structures.pseudo.typing import FunctionPointer, Pointer +from decompiler.task import DecompilerTask + + +def test_set_variable_to_function_pointer(): + """ + Test the change of a variable type to FunctionPointer if there is a call on this variable. + + a = 0x0804c020 + b = 1 + if (a == 0) + return b + else + a() + """ + cfg = ControlFlowGraph() + var_a = Variable("a", Integer.int32_t()) + var_b = Variable("b", Integer.int32_t()) + cfg.add_nodes_from( + [ + n0 := BasicBlock(0, instructions=[Assignment(var_a, Constant(0x0804C020)), Assignment(var_b, Constant(1))]), + n1 := BasicBlock(1, instructions=[Branch(Condition(OperationType.equal, [var_a, Constant(0)]))]), + n2 := BasicBlock(2, instructions=[Return([var_b])]), + n3 := BasicBlock(3, instructions=[Assignment(ListOperation([]), Call(var_a, []))]), + ] + ) + cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) + GetFunctionPointer().run(DecompilerTask("test", cfg)) + assert var_a.type == Pointer(FunctionPointer(32, Integer.int32_t(), ())) + + +def test_set_variable_to_function_pointer_with_parameters(): + """ + Test the change of a variable type to FunctionPointer if there is a call on this variable with parameters. + + a = 0x0804c020 + b = 1 + if (a == 0) + return b + else + a(c, d) + """ + cfg = ControlFlowGraph() + var_a = Variable("a", Integer.int32_t()) + var_b = Variable("b", Integer.int32_t()) + var_c = Variable("c", Integer.int32_t()) + var_d = Variable("d", Integer.int32_t()) + cfg.add_nodes_from( + [ + n0 := BasicBlock(0, instructions=[Assignment(var_a, Constant(0x0804C020)), Assignment(var_b, Constant(1))]), + n1 := BasicBlock(1, instructions=[Branch(Condition(OperationType.equal, [var_a, Constant(0)]))]), + n2 := BasicBlock(2, instructions=[Return([var_b])]), + n3 := BasicBlock(3, instructions=[Assignment(ListOperation([]), Call(var_a, [var_c, var_d]))]), + ] + ) + cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) + GetFunctionPointer().run(DecompilerTask("test", cfg)) + assert var_a.type == Pointer(FunctionPointer(32, Integer.int32_t(), (var_c, var_d))) + + +def test_skip_set_variable_to_function_pointer(): + """ + Test the skip of a change of a variable type to FunctionPointer if there is a call without a variable. + + a = 0x0804c020 + b = 1 + if (a == 0) + return b + else + printf("%d\n", a) + """ + cfg = ControlFlowGraph() + var_a = Variable("a", Integer.int32_t()) + var_b = Variable("b", Integer.int32_t()) + cfg.add_nodes_from( + [ + n0 := BasicBlock(0, instructions=[Assignment(var_a, Constant(0x0804C020)), Assignment(var_b, Constant(1))]), + n1 := BasicBlock(1, instructions=[Branch(Condition(OperationType.equal, [var_a, Constant(0)]))]), + n2 := BasicBlock(2, instructions=[Return([var_b])]), + n3 := BasicBlock( + 3, instructions=[Assignment(ListOperation([]), Call(ImportedFunctionSymbol("printf", 0), [Constant("%d\n"), var_a]))] + ), + ] + ) + cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) + GetFunctionPointer().run(DecompilerTask("test", cfg)) + assert not any(isinstance(variable.type, Pointer) for variable in cfg.get_variables()) From 7efbfcf04e1deb4e1770e6ce47a37d339e3d8efc Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Wed, 28 Feb 2024 13:02:13 +0100 Subject: [PATCH 10/12] Rename stage --- decompiler/pipeline/pipeline.py | 4 ++-- decompiler/pipeline/preprocessing/__init__.py | 2 +- .../{get_function_pointer.py => find_function_pointer.py} | 4 ++-- ..._function_pointer.py => test_find_function_pointer.py} | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) rename decompiler/pipeline/preprocessing/{get_function_pointer.py => find_function_pointer.py} (93%) rename tests/pipeline/preprocessing/{test_get_function_pointer.py => test_find_function_pointer.py} (93%) diff --git a/decompiler/pipeline/pipeline.py b/decompiler/pipeline/pipeline.py index 980b95f09..00c0dba0f 100644 --- a/decompiler/pipeline/pipeline.py +++ b/decompiler/pipeline/pipeline.py @@ -9,7 +9,7 @@ from decompiler.pipeline.preprocessing import ( Coherence, CompilerIdiomHandling, - GetFunctionPointer, + FindFunctionPointer, InsertMissingDefinitions, MemPhiConverter, PhiFunctionFixer, @@ -36,7 +36,7 @@ MemPhiConverter, InsertMissingDefinitions, PhiFunctionFixer, - GetFunctionPointer, + FindFunctionPointer, ] POSTPROCESSING_STAGES = [OutOfSsaTranslation, PatternIndependentRestructuring] diff --git a/decompiler/pipeline/preprocessing/__init__.py b/decompiler/pipeline/preprocessing/__init__.py index a83143c8f..0b3aad3af 100644 --- a/decompiler/pipeline/preprocessing/__init__.py +++ b/decompiler/pipeline/preprocessing/__init__.py @@ -2,7 +2,7 @@ from .coherence import Coherence from .compiler_idiom_handling import CompilerIdiomHandling -from .get_function_pointer import GetFunctionPointer +from .find_function_pointer import FindFunctionPointer from .mem_phi_conversion import MemPhiConverter from .missing_definitions import InsertMissingDefinitions from .phi_predecessors import PhiFunctionFixer diff --git a/decompiler/pipeline/preprocessing/get_function_pointer.py b/decompiler/pipeline/preprocessing/find_function_pointer.py similarity index 93% rename from decompiler/pipeline/preprocessing/get_function_pointer.py rename to decompiler/pipeline/preprocessing/find_function_pointer.py index a51f44e74..3a3910ee6 100644 --- a/decompiler/pipeline/preprocessing/get_function_pointer.py +++ b/decompiler/pipeline/preprocessing/find_function_pointer.py @@ -7,8 +7,8 @@ from decompiler.task import DecompilerTask -class GetFunctionPointer(PipelineStage): - name = "get-function-pointer" +class FindFunctionPointer(PipelineStage): + name = "find-function-pointer" def run(self, task: DecompilerTask): for block in task.graph: diff --git a/tests/pipeline/preprocessing/test_get_function_pointer.py b/tests/pipeline/preprocessing/test_find_function_pointer.py similarity index 93% rename from tests/pipeline/preprocessing/test_get_function_pointer.py rename to tests/pipeline/preprocessing/test_find_function_pointer.py index 97d59604c..c39fea290 100644 --- a/tests/pipeline/preprocessing/test_get_function_pointer.py +++ b/tests/pipeline/preprocessing/test_find_function_pointer.py @@ -1,4 +1,4 @@ -from decompiler.pipeline.preprocessing import GetFunctionPointer +from decompiler.pipeline.preprocessing import FindFunctionPointer from decompiler.structures.graphs.cfg import BasicBlock, ControlFlowGraph, FalseCase, TrueCase, UnconditionalEdge from decompiler.structures.pseudo import ( Assignment, @@ -39,7 +39,7 @@ def test_set_variable_to_function_pointer(): ] ) cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) - GetFunctionPointer().run(DecompilerTask("test", cfg)) + FindFunctionPointer().run(DecompilerTask("test", cfg)) assert var_a.type == Pointer(FunctionPointer(32, Integer.int32_t(), ())) @@ -68,7 +68,7 @@ def test_set_variable_to_function_pointer_with_parameters(): ] ) cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) - GetFunctionPointer().run(DecompilerTask("test", cfg)) + FindFunctionPointer().run(DecompilerTask("test", cfg)) assert var_a.type == Pointer(FunctionPointer(32, Integer.int32_t(), (var_c, var_d))) @@ -97,5 +97,5 @@ def test_skip_set_variable_to_function_pointer(): ] ) cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) - GetFunctionPointer().run(DecompilerTask("test", cfg)) + FindFunctionPointer().run(DecompilerTask("test", cfg)) assert not any(isinstance(variable.type, Pointer) for variable in cfg.get_variables()) From 959565cb9656556c7d822388f26c53054506ecdc Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Mon, 11 Mar 2024 11:00:38 +0100 Subject: [PATCH 11/12] Added docstrings --- decompiler/pipeline/preprocessing/find_function_pointer.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/decompiler/pipeline/preprocessing/find_function_pointer.py b/decompiler/pipeline/preprocessing/find_function_pointer.py index 3a3910ee6..b76ccee38 100644 --- a/decompiler/pipeline/preprocessing/find_function_pointer.py +++ b/decompiler/pipeline/preprocessing/find_function_pointer.py @@ -8,9 +8,15 @@ class FindFunctionPointer(PipelineStage): + """Pipeline stage to identify and annotate function pointers in the decompiled code.""" + name = "find-function-pointer" def run(self, task: DecompilerTask): + """ + Run the pipeline stage in the given task, search in all expressions for a + variable that is called and adjust its type information. + """ for block in task.graph: for expression in block: if ( From f822dfd650c768e2826275e8dccdc2bf4c3a4d06 Mon Sep 17 00:00:00 2001 From: fnhartmann Date: Mon, 11 Mar 2024 11:20:58 +0100 Subject: [PATCH 12/12] Removed subclassing --- .../pipeline/preprocessing/find_function_pointer.py | 4 ++-- decompiler/structures/pseudo/typing.py | 5 ----- tests/backend/test_codegenerator.py | 6 +----- .../preprocessing/test_find_function_pointer.py | 12 ++++++------ 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/decompiler/pipeline/preprocessing/find_function_pointer.py b/decompiler/pipeline/preprocessing/find_function_pointer.py index b76ccee38..7de378d3b 100644 --- a/decompiler/pipeline/preprocessing/find_function_pointer.py +++ b/decompiler/pipeline/preprocessing/find_function_pointer.py @@ -3,7 +3,7 @@ from decompiler.pipeline.stage import PipelineStage from decompiler.structures.pseudo.instructions import Assignment, Variable from decompiler.structures.pseudo.operations import Call -from decompiler.structures.pseudo.typing import FunctionPointer, Pointer +from decompiler.structures.pseudo.typing import FunctionTypeDef, Pointer from decompiler.task import DecompilerTask @@ -25,7 +25,7 @@ def run(self, task: DecompilerTask): and isinstance(expression.value.function, Variable) ): expression.value.function._type = Pointer( - basetype=FunctionPointer( + basetype=FunctionTypeDef( size=expression.value.function.type.size, return_type=expression.value.function.type, parameters=tuple(expression.value.parameters), diff --git a/decompiler/structures/pseudo/typing.py b/decompiler/structures/pseudo/typing.py index aff8d5aca..f27086bcc 100644 --- a/decompiler/structures/pseudo/typing.py +++ b/decompiler/structures/pseudo/typing.py @@ -218,11 +218,6 @@ def __str__(self) -> str: return f"{self.return_type}({', '.join(str(x) for x in self.parameters)})" -@dataclass(frozen=True, order=True) -class FunctionPointer(FunctionTypeDef): - pass - - class TypeParser: """A type parser in charge of creating types.""" diff --git a/tests/backend/test_codegenerator.py b/tests/backend/test_codegenerator.py index 4faafb520..021160101 100644 --- a/tests/backend/test_codegenerator.py +++ b/tests/backend/test_codegenerator.py @@ -33,7 +33,7 @@ OperationType, UnaryOperation, ) -from decompiler.structures.pseudo.typing import CustomType, Float, FunctionPointer, Integer, Pointer, Type +from decompiler.structures.pseudo.typing import CustomType, Float, Integer, Pointer, Type from decompiler.task import DecompilerTask from decompiler.util.options import Options @@ -80,8 +80,6 @@ def logic_cond(name: str, context) -> LogicCondition: var_p = Variable("p", Pointer(int32)) var_fun_p = Variable("p", Pointer(FunctionTypeDef(0, int32, (int32,)))) var_fun_p0 = Variable("p0", Pointer(FunctionTypeDef(0, int32, (int32,)))) -var_fun_ptr = Variable("ptr", Pointer(FunctionPointer(0, int32, (int32,)))) -var_fun_ptr0 = Variable("ptr0", Pointer(FunctionPointer(0, int32, (int32,)))) const_0 = Constant(0, int32) const_1 = Constant(1, int32) @@ -1288,8 +1286,6 @@ class TestLocalDeclarationGenerator: (1, [var_x.copy(), var_y.copy(), var_p.copy()], "int x;\nint y;\nint * p;"), (1, [var_x.copy(), var_y.copy(), var_fun_p.copy()], "int x;\nint y;\nint (* p)(int);"), (2, [var_x.copy(), var_y.copy(), var_fun_p.copy(), var_fun_p0.copy()], "int x, y;\nint (* p)(int), (* p0)(int);"), - (1, [var_x.copy(), var_y.copy(), var_fun_ptr.copy()], "int x;\nint y;\nint (* ptr)(int);"), - (2, [var_x.copy(), var_y.copy(), var_fun_ptr.copy(), var_fun_ptr0.copy()], "int x, y;\nint (* ptr)(int), (* ptr0)(int);"), ], ) def test_variable_declaration(self, vars_per_line: int, variables: List[Variable], expected: str): diff --git a/tests/pipeline/preprocessing/test_find_function_pointer.py b/tests/pipeline/preprocessing/test_find_function_pointer.py index c39fea290..a56af525e 100644 --- a/tests/pipeline/preprocessing/test_find_function_pointer.py +++ b/tests/pipeline/preprocessing/test_find_function_pointer.py @@ -12,13 +12,13 @@ Variable, ) from decompiler.structures.pseudo.instructions import Branch, Return -from decompiler.structures.pseudo.typing import FunctionPointer, Pointer +from decompiler.structures.pseudo.typing import FunctionTypeDef, Pointer from decompiler.task import DecompilerTask def test_set_variable_to_function_pointer(): """ - Test the change of a variable type to FunctionPointer if there is a call on this variable. + Test the change of a variable type to function pointer if there is a call on this variable. a = 0x0804c020 b = 1 @@ -40,12 +40,12 @@ def test_set_variable_to_function_pointer(): ) cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) FindFunctionPointer().run(DecompilerTask("test", cfg)) - assert var_a.type == Pointer(FunctionPointer(32, Integer.int32_t(), ())) + assert var_a.type == Pointer(FunctionTypeDef(32, Integer.int32_t(), ())) def test_set_variable_to_function_pointer_with_parameters(): """ - Test the change of a variable type to FunctionPointer if there is a call on this variable with parameters. + Test the change of a variable type to function pointer if there is a call on this variable with parameters. a = 0x0804c020 b = 1 @@ -69,12 +69,12 @@ def test_set_variable_to_function_pointer_with_parameters(): ) cfg.add_edges_from([UnconditionalEdge(n0, n1), TrueCase(n1, n2), FalseCase(n1, n3)]) FindFunctionPointer().run(DecompilerTask("test", cfg)) - assert var_a.type == Pointer(FunctionPointer(32, Integer.int32_t(), (var_c, var_d))) + assert var_a.type == Pointer(FunctionTypeDef(32, Integer.int32_t(), (var_c, var_d))) def test_skip_set_variable_to_function_pointer(): """ - Test the skip of a change of a variable type to FunctionPointer if there is a call without a variable. + Test the skip of a change of a variable type to function pointer if there is a call without a variable. a = 0x0804c020 b = 1