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())