From 7f35f8d2f211fdf087252ede7665e9c81f35cdc7 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 27 Jan 2013 00:43:59 +0000 Subject: Implemented the first steps for visiting or replacing items in decompiled instructions. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@331 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 17 +++++++ src/decomp/expr/access.c | 84 +++++++++++++++++++++++++++++++++ src/decomp/expr/arithm.c | 84 +++++++++++++++++++++++++++++++++ src/decomp/expr/array.c | 84 +++++++++++++++++++++++++++++++++ src/decomp/expr/assign.c | 84 +++++++++++++++++++++++++++++++++ src/decomp/expr/block.c | 80 ++++++++++++++++++++++++++++++++ src/decomp/expr/call.c | 80 ++++++++++++++++++++++++++++++++ src/decomp/expr/cond.c | 84 +++++++++++++++++++++++++++++++++ src/decomp/expr/return.c | 78 +++++++++++++++++++++++++++++++ src/decomp/instr/ite.c | 107 +++++++++++++++++++++++++++++++++++-------- src/decomp/instruction-int.h | 6 ++- src/decomp/instruction.c | 58 ++++++++++++++++++----- src/decomp/instruction.h | 16 +++++-- 13 files changed, 827 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index b43e967..a839cc1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +13-01-27 Cyrille Bagard + + * src/decomp/expr/access.c: + * src/decomp/expr/arithm.c: + * src/decomp/expr/array.c: + * src/decomp/expr/assign.c: + * src/decomp/expr/block.c: + * src/decomp/expr/call.c: + * src/decomp/expr/cond.c: + * src/decomp/expr/return.c: + * src/decomp/instr/ite.c: + * src/decomp/instruction.c: + * src/decomp/instruction.h: + * src/decomp/instruction-int.h: + Implement the first steps for visiting or replacing items in decompiled + instructions. + 13-01-26 Cyrille Bagard * configure.ac: diff --git a/src/decomp/expr/access.c b/src/decomp/expr/access.c index 277209a..f06c47b 100644 --- a/src/decomp/expr/access.c +++ b/src/decomp/expr/access.c @@ -54,6 +54,12 @@ static void g_access_expression_class_init(GAccessExpressionClass *); /* Initialise une instance d'accessation quelconque. */ static void g_access_expression_init(GAccessExpression *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_access_expression_visit(GAccessExpression *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_access_expression_replace(GAccessExpression *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_access_expression_print(const GAccessExpression *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -99,6 +105,8 @@ static void g_access_expression_init(GAccessExpression *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_access_expression_visit; + instr->replace = (dec_instr_replace_fc)g_access_expression_replace; instr->print = (dec_instr_print_fc)g_access_expression_print; } @@ -133,6 +141,82 @@ GDecInstruction *g_access_expression_new(GDecExpression *owner, GDecExpression * /****************************************************************************** * * +* Paramètres : expr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_access_expression_visit(GAccessExpression *expr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->owner), callback, flags, data); + + if (result) + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->target), callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_access_expression_replace(GAccessExpression *expr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + + if (expr->owner == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->owner)); + g_object_ref(G_OBJECT(new)); + expr->owner = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->owner), old, new); + + if (expr->target == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->target)); + g_object_ref(G_OBJECT(new)); + expr->target = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result |= g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->target), old, new); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : expr = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/expr/arithm.c b/src/decomp/expr/arithm.c index d91e080..3811cf4 100644 --- a/src/decomp/expr/arithm.c +++ b/src/decomp/expr/arithm.c @@ -56,6 +56,12 @@ static void g_arithm_expression_class_init(GArithmExpressionClass *); /* Initialise une instance d'opération arithmétique définie. */ static void g_arithm_expression_init(GArithmExpression *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_arithm_expression_visit(GArithmExpression *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_arithm_expression_replace(GArithmExpression *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_arithm_expression_print(const GArithmExpression *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -101,6 +107,8 @@ static void g_arithm_expression_init(GArithmExpression *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_arithm_expression_visit; + instr->replace = (dec_instr_replace_fc)g_arithm_expression_replace; instr->print = (dec_instr_print_fc)g_arithm_expression_print; } @@ -138,6 +146,82 @@ GDecInstruction *g_arithm_expression_new(GDecExpression *op1, ArithmOperationTyp /****************************************************************************** * * +* Paramètres : expr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_arithm_expression_visit(GArithmExpression *expr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->op1), callback, flags, data); + + if (result) + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->op2), callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_arithm_expression_replace(GArithmExpression *expr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + + if (expr->op1 == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->op1)); + g_object_ref(G_OBJECT(new)); + expr->op1 = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->op1), old, new); + + if (expr->op2 == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->op2)); + g_object_ref(G_OBJECT(new)); + expr->op2 = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result |= g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->op2), old, new); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : expr = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/expr/array.c b/src/decomp/expr/array.c index dc487ee..4053169 100644 --- a/src/decomp/expr/array.c +++ b/src/decomp/expr/array.c @@ -54,6 +54,12 @@ static void g_array_access_class_init(GArrayAccessClass *); /* Initialise une instance d'accès à une cellule de tableau. */ static void g_array_access_init(GArrayAccess *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_array_access_visit(GArrayAccess *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_array_access_replace(GArrayAccess *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_array_access_print(const GArrayAccess *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -99,6 +105,8 @@ static void g_array_access_init(GArrayAccess *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_array_access_visit; + instr->replace = (dec_instr_replace_fc)g_array_access_replace; instr->print = (dec_instr_print_fc)g_array_access_print; } @@ -133,6 +141,82 @@ GDecInstruction *g_array_access_new(GDecExpression *array, GDecExpression *index /****************************************************************************** * * +* Paramètres : expr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_array_access_visit(GArrayAccess *expr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->array), callback, flags, data); + + if (result) + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->index), callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_array_access_replace(GArrayAccess *expr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + + if (expr->array == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->array)); + g_object_ref(G_OBJECT(new)); + expr->array = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->array), old, new); + + if (expr->index == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->index)); + g_object_ref(G_OBJECT(new)); + expr->index = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result |= g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->index), old, new); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : expr = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/expr/assign.c b/src/decomp/expr/assign.c index fd86021..26d31f6 100644 --- a/src/decomp/expr/assign.c +++ b/src/decomp/expr/assign.c @@ -54,6 +54,12 @@ static void g_assign_expression_class_init(GAssignExpressionClass *); /* Initialise une instance d'assignation quelconque. */ static void g_assign_expression_init(GAssignExpression *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_assign_expression_visit(GAssignExpression *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_assign_expression_replace(GAssignExpression *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_assign_expression_print(const GAssignExpression *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -99,6 +105,8 @@ static void g_assign_expression_init(GAssignExpression *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_assign_expression_visit; + instr->replace = (dec_instr_replace_fc)g_assign_expression_replace; instr->print = (dec_instr_print_fc)g_assign_expression_print; } @@ -133,6 +141,82 @@ GDecInstruction *g_assign_expression_new(GDecExpression *dest, GDecExpression *s /****************************************************************************** * * +* Paramètres : expr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_assign_expression_visit(GAssignExpression *expr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->dest), callback, flags, data); + + if (result) + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->src), callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_assign_expression_replace(GAssignExpression *expr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + + if (expr->dest == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->dest)); + g_object_ref(G_OBJECT(new)); + expr->dest = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->dest), old, new); + + if (expr->src == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->src)); + g_object_ref(G_OBJECT(new)); + expr->src = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result |= g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->src), old, new); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : expr = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/expr/block.c b/src/decomp/expr/block.c index 5124204..3c56ef6 100644 --- a/src/decomp/expr/block.c +++ b/src/decomp/expr/block.c @@ -57,6 +57,12 @@ static void g_expr_block_class_init(GExprBlockClass *); /* Initialise une instance d'ensemble d'instructions. */ static void g_expr_block_init(GExprBlock *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_expr_block_visit(GExprBlock *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_expr_block_replace(GExprBlock *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_expr_block_print(const GExprBlock *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -102,6 +108,8 @@ static void g_expr_block_init(GExprBlock *block) instr = G_DEC_INSTRUCTION(block); + instr->visit = (dec_instr_visit_fc)g_expr_block_visit; + instr->replace = (dec_instr_replace_fc)g_expr_block_replace; instr->print = (dec_instr_print_fc)g_expr_block_print; } @@ -134,6 +142,78 @@ GDecInstruction *g_expr_block_new(GDecInstruction *item) /****************************************************************************** * * +* Paramètres : block = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_expr_block_visit(GExprBlock *block, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < block->count && result; i++) + result = g_dec_instruction_visit(block->list[i], callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : block = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_expr_block_replace(GExprBlock *block, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = false; + + for (i = 0; i < block->count; i++) + { + if (block->list[i] == old) + { + g_object_unref(G_OBJECT(block->list[i])); + g_object_ref(G_OBJECT(new)); + block->list[i] = new; + + result = true; + + } + else + result |= g_dec_instruction_replace(block->list[i], old, new); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : block = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/expr/call.c b/src/decomp/expr/call.c index e518c6f..ed1c43a 100644 --- a/src/decomp/expr/call.c +++ b/src/decomp/expr/call.c @@ -60,6 +60,12 @@ static void g_routine_call_class_init(GRoutineCallClass *); /* Initialise une instance d'appel à une routine quelconque. */ static void g_routine_call_init(GRoutineCall *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_routine_call_visit(GRoutineCall *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_routine_call_replace(GRoutineCall *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_routine_call_print(const GRoutineCall *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -105,6 +111,8 @@ static void g_routine_call_init(GRoutineCall *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_routine_call_visit; + instr->replace = (dec_instr_replace_fc)g_routine_call_replace; instr->print = (dec_instr_print_fc)g_routine_call_print; } @@ -137,6 +145,78 @@ GDecInstruction *g_routine_call_new(GBinRoutine *routine) /****************************************************************************** * * +* Paramètres : call = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_routine_call_visit(GRoutineCall *call, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < call->count && result; i++) + result = g_dec_instruction_visit(call->args[i], callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : call = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_routine_call_replace(GRoutineCall *call, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + result = false; + + for (i = 0; i < call->count; i++) + { + if (call->args[i] == old) + { + g_object_unref(G_OBJECT(call->args[i])); + g_object_ref(G_OBJECT(new)); + call->args[i] = new; + + result = true; + + } + else + result |= g_dec_instruction_replace(call->args[i], old, new); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : call = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/expr/cond.c b/src/decomp/expr/cond.c index 4a9b63b..d96f483 100644 --- a/src/decomp/expr/cond.c +++ b/src/decomp/expr/cond.c @@ -55,6 +55,12 @@ static void g_cond_expression_class_init(GCondExpressionClass *); /* Initialise une instance de condition binaire quelconque. */ static void g_cond_expression_init(GCondExpression *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_cond_expression_visit(GCondExpression *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_cond_expression_replace(GCondExpression *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_cond_expression_print(const GCondExpression *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -100,6 +106,8 @@ static void g_cond_expression_init(GCondExpression *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_cond_expression_visit; + instr->replace = (dec_instr_replace_fc)g_cond_expression_replace; instr->print = (dec_instr_print_fc)g_cond_expression_print; } @@ -136,6 +144,82 @@ GDecInstruction *g_cond_expression_new(GDecExpression *a, CompSignType sign, GDe /****************************************************************************** * * +* Paramètres : expr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_cond_expression_visit(GCondExpression *expr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->a), callback, flags, data); + + if (result) + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->b), callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_cond_expression_replace(GCondExpression *expr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + + if (expr->a == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->a)); + g_object_ref(G_OBJECT(new)); + expr->a = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->a), old, new); + + if (expr->b == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->b)); + g_object_ref(G_OBJECT(new)); + expr->b = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result |= g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->b), old, new); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : expr = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/expr/return.c b/src/decomp/expr/return.c index a9c10d9..d012893 100644 --- a/src/decomp/expr/return.c +++ b/src/decomp/expr/return.c @@ -53,6 +53,12 @@ static void g_return_expression_class_init(GReturnExpressionClass *); /* Initialise une instance d'ordre de retour. */ static void g_return_expression_init(GReturnExpression *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_return_expression_visit(GReturnExpression *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_return_expression_replace(GReturnExpression *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_return_expression_print(const GReturnExpression *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -98,6 +104,8 @@ static void g_return_expression_init(GReturnExpression *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_return_expression_visit; + instr->replace = (dec_instr_replace_fc)g_return_expression_replace; instr->print = (dec_instr_print_fc)g_return_expression_print; } @@ -130,6 +138,76 @@ GDecInstruction *g_return_expression_new(GDecExpression *payload) /****************************************************************************** * * +* Paramètres : expr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * +* * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_return_expression_visit(GReturnExpression *expr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + + if (expr->payload) + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->payload), callback, flags, data); + else + result = false; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_return_expression_replace(GReturnExpression *expr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + + if (expr->payload) + { + if (expr->payload == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->payload)); + g_object_ref(G_OBJECT(new)); + expr->payload = G_DEC_EXPRESSION(new); + + result = true; + + } + else + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->payload), old, new); + + } + else + result = false; + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : expr = expression à transcrire en version humaine. * * buffer = tampon où doit se réaliser l'insertion. * * line = ligne d'impression prête à emploi ou NULL. * diff --git a/src/decomp/instr/ite.c b/src/decomp/instr/ite.c index c12d314..1abf61c 100644 --- a/src/decomp/instr/ite.c +++ b/src/decomp/instr/ite.c @@ -72,6 +72,12 @@ static void g_ite_instruction_class_init(GITEInstructionClass *); /* Initialise une instance d'aiguillage du flux d'exécution. */ static void g_ite_instruction_init(GITEInstruction *); +/* Visite un ensemble hiérarchique d'instructions décompilées. */ +static bool g_ite_instruction_visit(GITEInstruction *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +static bool g_ite_instruction_replace(GITEInstruction *, GDecInstruction *, GDecInstruction *); + /* Imprime pour l'écran un version humaine d'une instruction. */ static GBufferLine *g_ite_instruction_print(const GITEInstruction *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -117,6 +123,8 @@ static void g_ite_instruction_init(GITEInstruction *expr) instr = G_DEC_INSTRUCTION(expr); + instr->visit = (dec_instr_visit_fc)g_ite_instruction_visit; + instr->replace = (dec_instr_replace_fc)g_ite_instruction_replace; instr->print = (dec_instr_print_fc)g_ite_instruction_print; } @@ -153,34 +161,62 @@ GDecInstruction *g_ite_instruction_new(GDecExpression *cond, vmpa_t if_true, vmp /****************************************************************************** * * -* Paramètres : cond = expression fixant le choix de l'aiguillage. * -* true_branch = instructions si la condition est vérifiée. * -* false_branch = instructions si la cond. n'est pas vérifiée. * +* Paramètres : instr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * * * -* Description : Détermine le corps des différentes branches possibles. * +* Description : Visite un ensemble hiérarchique d'instructions décompilées. * * * -* Retour : - * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * * * * Remarques : - * * * ******************************************************************************/ -void g_ite_instruction_set_branches(GITEInstruction *expr, GDecInstruction *true_branch, GDecInstruction *false_branch) +static bool g_ite_instruction_visit(GITEInstruction *instr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) { + bool result; /* Bilan à retourner */ - if (true_branch == NULL) - { - expr->inverse = true; + result = g_dec_instruction_visit(G_DEC_INSTRUCTION(instr->cond), callback, flags, data); - expr->true_branch = false_branch; - expr->false_branch = true_branch; + if (result) + result = g_dec_instruction_visit(instr->true_branch, callback, flags, data); - } - else - { - expr->true_branch = true_branch; - expr->false_branch = false_branch; - } + if (result && instr->false_branch != NULL) + result = g_dec_instruction_visit(instr->false_branch, callback, flags, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_ite_instruction_replace(GITEInstruction *instr, GDecInstruction *old, GDecInstruction *new) +{ + bool result; /* Bilan à retourner */ + + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(instr->cond), old, new); + + result |= g_dec_instruction_replace(instr->true_branch, old, new); + + if (instr->false_branch != NULL) + result |= g_dec_instruction_replace(instr->false_branch, old, new); + + return result; } @@ -212,8 +248,7 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->cond), buffer, line, output); - if (expr->true_branch != NULL) - result = g_dec_instruction_print(expr->true_branch, buffer, result, output); + result = g_dec_instruction_print(expr->true_branch, buffer, result, output); if (expr->false_branch != NULL) { @@ -224,3 +259,37 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu return result; } + + +/****************************************************************************** +* * +* Paramètres : cond = expression fixant le choix de l'aiguillage. * +* true_branch = instructions si la condition est vérifiée. * +* false_branch = instructions si la cond. n'est pas vérifiée. * +* * +* Description : Détermine le corps des différentes branches possibles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_ite_instruction_set_branches(GITEInstruction *expr, GDecInstruction *true_branch, GDecInstruction *false_branch) +{ + + if (true_branch == NULL) + { + expr->inverse = true; + + expr->true_branch = false_branch; + expr->false_branch = true_branch; + + } + else + { + expr->true_branch = true_branch; + expr->false_branch = false_branch; + } + +} diff --git a/src/decomp/instruction-int.h b/src/decomp/instruction-int.h index 9b29162..f0c503b 100644 --- a/src/decomp/instruction-int.h +++ b/src/decomp/instruction-int.h @@ -32,7 +32,10 @@ /* Visite un ensemble hiérarchique d'instructions décompilées. */ -typedef void (* dec_instr_visit_fc) (GDecInstruction *, process_decomp_fc, void *, bool); +typedef bool (* dec_instr_visit_fc) (GDecInstruction *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +typedef bool (* dec_instr_replace_fc) (GDecInstruction *, GDecInstruction *, GDecInstruction *); /* Imprime pour l'écran un version humaine d'une instruction. */ typedef GBufferLine * (* dec_instr_print_fc) (const GDecInstruction *, GCodeBuffer *, GBufferLine *, GLangOutput *); @@ -48,6 +51,7 @@ struct _GDecInstruction vmpa_t address; /* Position associée */ dec_instr_visit_fc visit; /* Visite des instructions */ + dec_instr_replace_fc replace; /* Remplacement à la volée */ dec_instr_print_fc print; /* Impression pour à l'écran */ }; diff --git a/src/decomp/instruction.c b/src/decomp/instruction.c index 2d42e71..3a9917a 100644 --- a/src/decomp/instruction.c +++ b/src/decomp/instruction.c @@ -79,29 +79,63 @@ static void g_dec_instruction_init(GDecInstruction *instr) /****************************************************************************** * * -* Paramètres : instr = première instruction à venir visiter. * -* process = procédure à appeler à chaque instruction visitée. * -* data = données quelconques associées au visiteur. * -* order = précise le sens de la visite. * +* Paramètres : instr = première instruction à venir visiter. * +* callback = procédure à appeler à chaque instruction visitée. * +* flags = moments des appels à réaliser en retour. * +* data = données quelconques associées au visiteur. * * * * Description : Visite un ensemble hiérarchique d'instructions décompilées. * * * -* Retour : - * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_dec_instruction_visit(GDecInstruction *instr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (flags & DVF_ENTER) + result = callback(instr, DVF_ENTER, data); + + if (result && instr->visit) + result = instr->visit(instr, callback, flags, data); + + if (result && (flags & DVF_EXIT)) + result = callback(instr, DVF_EXIT, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = première instruction à venir ausculter. * +* old = instruction décompilée à venir remplacer. * +* new = instruction décompilée à utiliser dorénavant. * +* * +* Description : Remplace une instruction décompilée par une autre. * +* * +* Retour : true si un remplacement a été effectué, false sinon. * * * * Remarques : - * * * ******************************************************************************/ -void g_dec_instruction_visit(GDecInstruction *instr, process_decomp_fc process, void *data, bool order) +bool g_dec_instruction_replace(GDecInstruction *instr, GDecInstruction *old, GDecInstruction *new) { - if (order) - process(instr, data); + bool result; /* Bilan à retourner */ - if (instr->visit) - instr->visit(instr, process, data, order); + if (instr->replace != NULL) + result = instr->replace(instr, old, new); + else + result = false; - if (!order) - process(instr, data); + return result; } diff --git a/src/decomp/instruction.h b/src/decomp/instruction.h index 810be79..ed8090d 100644 --- a/src/decomp/instruction.h +++ b/src/decomp/instruction.h @@ -47,16 +47,26 @@ typedef struct _GDecInstruction GDecInstruction; /* Définition d'une instruction décompilée (classe) */ typedef struct _GDecInstructionClass GDecInstructionClass; +/* Position au cours d'une visite */ +typedef enum _DecInstrVisitFlags +{ + DVF_ENTER, /* Entrée dans une instruction */ + DVF_EXIT /* Sortie d'une instruction */ -/* Visite un ensemble hiérarchique d'instructions décompilées. */ -typedef void (* process_decomp_fc) (GDecInstruction *, void *); +} DecInstrVisitFlags; + +/* Rappel à chaque instruction décompilée visitée */ +typedef bool (* dec_instr_visitor_cb) (GDecInstruction *, DecInstrVisitFlags, void *); /* Indique le type défini pour une instruction décompilée. */ GType g_dec_instruction_get_type(void); /* Visite un ensemble hiérarchique d'instructions décompilées. */ -void g_dec_instruction_visit(GDecInstruction *, process_decomp_fc, void *, bool); +bool g_dec_instruction_visit(GDecInstruction *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +/* Remplace une instruction décompilée par une autre. */ +bool g_dec_instruction_replace(GDecInstruction *, GDecInstruction *, GDecInstruction *); /* Imprime pour l'écran un version humaine d'une expression. */ GBufferLine *g_dec_instruction_print(const GDecInstruction *, GCodeBuffer *, GBufferLine *, GLangOutput *); -- cgit v0.11.2-87-g4458