From 5c7ea8e2137e4e5bb2887de0d1ffd8a0b277636e Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 27 Jan 2013 22:03:31 +0000 Subject: Reduced the quantity of used variables in decompiled code. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@332 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 36 ++++ src/analysis/decomp/decompiler.c | 2 + src/analysis/decomp/reduce.c | 395 +++++++++++++++++++++++++++++++++++++-- src/analysis/decomp/reduce.h | 9 +- src/arch/dalvik/context.c | 6 +- src/arch/dalvik/decomp/iget.c | 2 +- src/arch/dalvik/decomp/iput.c | 2 +- src/decomp/expr/access.c | 6 +- src/decomp/expr/arithm.c | 6 +- src/decomp/expr/array.c | 6 +- src/decomp/expr/assign.c | 10 +- src/decomp/expr/assign.h | 4 +- src/decomp/expr/block.c | 41 +++- src/decomp/expr/block.h | 3 + src/decomp/expr/call.c | 3 +- src/decomp/expr/cond.c | 6 +- src/decomp/expr/pseudo.c | 27 ++- src/decomp/expr/pseudo.h | 16 +- src/decomp/expr/return.c | 3 +- src/decomp/instr/ite.c | 9 +- src/decomp/instruction.c | 7 +- src/decomp/instruction.h | 10 +- 22 files changed, 560 insertions(+), 49 deletions(-) diff --git a/ChangeLog b/ChangeLog index a839cc1..ae76a19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,41 @@ 13-01-27 Cyrille Bagard + * src/analysis/decomp/decompiler.c: + * src/analysis/decomp/reduce.c: + * src/analysis/decomp/reduce.h: + Reduce the quantity of used variables in decompiled code. + + * src/arch/dalvik/context.c: + * src/arch/dalvik/decomp/iget.c: + * src/arch/dalvik/decomp/iput.c: + Update code when creating pseudo registers. + + * src/decomp/expr/access.c: + * src/decomp/expr/arithm.c: + * src/decomp/expr/array.c: + * src/decomp/expr/assign.c: + * src/decomp/expr/assign.h: + * src/decomp/expr/block.c: + * src/decomp/expr/block.h: + * src/decomp/expr/call.c: + * src/decomp/expr/cond.c: + Provide the parent instruction to visited children. + + * src/decomp/expr/pseudo.c: + * src/decomp/expr/pseudo.h: + Store the expected usage of a pseudo register. + + * src/decomp/expr/return.c: + * src/decomp/instr/ite.c: + Provide the parent instruction to visited children. + + * src/decomp/instruction.c: + * src/decomp/instruction.h: + Provide the parent instruction to visited children. Fix the value of the + flags used to visit decompiled instructions. + +13-01-27 Cyrille Bagard + * src/decomp/expr/access.c: * src/decomp/expr/arithm.c: * src/decomp/expr/array.c: diff --git a/src/analysis/decomp/decompiler.c b/src/analysis/decomp/decompiler.c index a61e7c7..67583bb 100644 --- a/src/analysis/decomp/decompiler.c +++ b/src/analysis/decomp/decompiler.c @@ -33,6 +33,7 @@ #include "il.h" +#include "reduce.h" #include "../../decomp/output.h" #include "../../decomp/expr/block.h" #include "../../decomp/lang/java.h" /* FIXME : remme ! */ @@ -183,6 +184,7 @@ static void prepare_all_routines_for_decomp(const GLoadedBinary *binary, const c //instr = g_binary_format_decompile_routine(G_BIN_FORMAT(format), routines[i], context); + reduce_used_variables(dinstrs); g_binary_routine_set_decomp_instructions(routines[i], dinstrs); diff --git a/src/analysis/decomp/reduce.c b/src/analysis/decomp/reduce.c index 926650d..2d6fce3 100644 --- a/src/analysis/decomp/reduce.c +++ b/src/analysis/decomp/reduce.c @@ -2,7 +2,7 @@ /* OpenIDA - Outil d'analyse de fichiers binaires * reduce.c - réduction de l'usage des [pseudo]-registres * - * Copyright (C) 2012 Cyrille Bagard + * Copyright (C) 2012-2013 Cyrille Bagard * * This file is part of OpenIDA. * @@ -24,30 +24,399 @@ #include "reduce.h" -#if 0 +#include +#include "../../decomp/expr/assign.h" +#include "../../decomp/expr/block.h" +#include "../../decomp/expr/immediate.h" +#include "../../decomp/expr/pseudo.h" -/* Mémorisation de l'usage de chaque variable */ -typedef struct _var_usage + + +/* ------------------------ DECOMPTE DES USAGES DE VARIABLES ------------------------ */ + + +/* Mémorisation de l'usage d'une variable */ +typedef struct _assigned_value +{ + GDecInstruction *value; /* Valeur de cette variable */ + + GDecInstruction *assign; /* Lieu d'assignation */ + GDecInstruction *parent; /* Zone à nettoyer au besoin */ + + size_t used_counter; /* Décompte des utilisations */ + size_t shared_counter; /* Partage entre tables */ + +} assigned_value; + + +/* Conserve tous les éléments concernant une assignation. */ +static assigned_value *memorize_assigned_value(GDecInstruction *, GDecInstruction *, GDecInstruction *); + +/* Met (éventuellement) fin à un suivi d'assignation. */ +static void forget_assigned_value(assigned_value *); + +/* Constitue un lieu de conservation d'associations pour bloc. */ +static GHashTable *create_tracking_table(GHashTable *); + +/* Met à jour les décomptes des différentes assignations. */ +static void merge_usages(GHashTable *, GHashTable *); + +/* Prend notre d'une assignation d'une valeur à une variable. */ +static void note_new_variable(GHashTable *, GDecInstruction *, assigned_value *); + + + +/* ---------------------- VISITES DES INSTRUCTIONS DECOMPILEES ---------------------- */ + + +/* Prend note de tous les accès aux différentes variables. */ +static void collect_used_variables(GDecInstruction *, GDecInstruction *, GHashTable *); + +/* Procède au remplacement de variables à rejeter. */ +static void replace_useless_variable(GDecInstruction *, GHashTable *); + +/* Visite un groupe d'instructions décompilées. */ +static bool visit_instructions_block(GDecInstruction *, GDecInstruction *, DecInstrVisitFlags, GHashTable **); + + + +/* ---------------------------------------------------------------------------------- */ +/* DECOMPTE DES USAGES DE VARIABLES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : value = nouvelle valeur assignée à suivre. * +* assign = instruction où la valeur est assignée. * +* parent = bloc d'instructions à soulager en cas d'effacement. * +* table = mémorisation des usages de variables. * +* * +* Description : Conserve tous les éléments concernant une assignation. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static assigned_value *memorize_assigned_value(GDecInstruction *value, GDecInstruction *assign, GDecInstruction *parent) +{ + assigned_value *result; /* Mémorisation à retourner */ + + result = (assigned_value *)calloc(1, sizeof(assigned_value)); + + g_object_ref(G_OBJECT(value)); + result->value = value; + + g_object_ref(G_OBJECT(assign)); + g_object_ref(G_OBJECT(parent)); + result->assign = assign; + result->parent = parent; + + result->used_counter = 0; + result->shared_counter = 0; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : val = structure à libérer de la mémoire. * +* * +* Description : Met (éventuellement) fin à un suivi d'assignation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void forget_assigned_value(assigned_value *val) +{ + if (--val->shared_counter == 0) + { + g_object_unref(G_OBJECT(val->value)); + + g_object_unref(G_OBJECT(val->assign)); + g_object_unref(G_OBJECT(val->parent)); + + free(val); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : parent = éventuel bloc d'instructions parent ou NULL. * +* * +* Description : Constitue un lieu de conservation d'associations pour bloc. * +* * +* Retour : Table prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GHashTable *create_tracking_table(GHashTable *parent) +{ + GHashTable *result; /* Création à retourner */ + GHashTableIter iter; /* Boucle de parcours */ + GDecInstruction *var; /* Variable assignée */ + assigned_value *val; /* Valeur assignée */ + + result = g_hash_table_new_full(NULL, NULL, g_object_unref, + (GDestroyNotify)forget_assigned_value); + + if (parent != NULL) + { + g_hash_table_iter_init(&iter, parent); + + while (g_hash_table_iter_next(&iter, (gpointer *)&var, (gpointer *)&val)) + note_new_variable(result, var, val); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : table = conservation des associations variable <-> valeur. * +* sub = conservation issue d'un sous bloc. * +* * +* Description : Met à jour les décomptes des différentes assignations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void merge_usages(GHashTable *table, GHashTable *sub) +{ + GHashTableIter iter; /* Boucle de parcours */ + GDecInstruction *var; /* Variable assignée */ + assigned_value *val; /* Valeur assignée */ + assigned_value *update; /* Même valeur, mise à jour */ + + g_hash_table_iter_init(&iter, table); + + while (g_hash_table_iter_next(&iter, (gpointer *)&var, (gpointer *)&val)) + { + update = (assigned_value *)g_hash_table_lookup(sub, var); + + val->used_counter = update->used_counter; + + g_hash_table_remove(sub, var); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : table = conservation des associations variable <-> valeur. * +* var = variable en place à suivre. * +* val = valeur associée. * +* * +* Description : Prend notre d'une assignation d'une valeur à une variable. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void note_new_variable(GHashTable *table, GDecInstruction *var, assigned_value *val) +{ + g_object_ref(G_OBJECT(var)); + val->shared_counter++; + + g_hash_table_insert(table, var, val); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* VISITES DES INSTRUCTIONS DECOMPILEES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : instr = instruction visitée. * +* parent = instruction parente. * +* table = mémorisation des usages de variables. * +* * +* Description : Prend note de tous les accès aux différentes variables. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void collect_used_variables(GDecInstruction *instr, GDecInstruction *parent, GHashTable *table) +{ + GAssignExpression *assign; /* Instruction d'assignation */ + GDecInstruction *dest; /* Variable de destination */ + bool valid; /* Destination valide ? */ + GDecInstruction *src; /* Valeur de source */ + assigned_value *value; /* Valeur et ses informations */ + + if (G_IS_ASSIGN_EXPRESSION(instr)) + { + assign = G_ASSIGN_EXPRESSION(instr); + + dest = G_DEC_INSTRUCTION(g_assign_expression_get_dest(assign)); + + if (G_IS_PSEUDO_REGISTER(dest)) + valid = (g_pseudo_register_get_usage(G_PSEUDO_REGISTER(dest)) == PRU_LOCAL); + else + valid = true; + + if (valid) + { + src = G_DEC_INSTRUCTION(g_assign_expression_get_src(assign)); + + value = memorize_assigned_value(src, instr, parent); + note_new_variable(table, dest, value); + + } + + } + else + { + value = (assigned_value *)g_hash_table_lookup(table, instr); + + if (value != NULL) + value->used_counter++; + + } + +} + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions décompilées à traiter. * +* table = mémorisation des usages de variables. * +* * +* Description : Procède au remplacement de variables à rejeter. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void replace_useless_variable(GDecInstruction *block, GHashTable *table) { - GDecInstruction *var; /* Variable manipulée */ + GHashTableIter iter; /* Boucle de parcours */ + GDecInstruction *var; /* Variable assignée */ + assigned_value *val; /* Valeur assignée */ + bool replace; /* Ordre de remplacement */ + + g_hash_table_iter_init(&iter, table); + + while (g_hash_table_iter_next(&iter, (gpointer *)&var, (gpointer *)&val)) + { + replace = G_IS_IMM_EXPRESSION(val->value); + replace |= (val->used_counter == 2); /* 1 assign. + 1 usage */ + + if (!replace) continue; - size_t ref_counter; /* Décompte des utilisations */ - GDecInstruction *creation; /* Emplacement de la création */ - GDecInstruction *usage; /* Lieu de dernère utilisation */ + g_expr_block_delete_item(G_EXPR_BLOCK(val->parent), val->assign); -} var_usage; + g_dec_instruction_replace(block, var, val->value); -/* Réduction des usages */ -typedef struct _usage_reduc + } + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction visitée. * +* parent = instruction parente. * +* flags = moments des appels réalisés en retour. * +* table = mémorisation des usages de variables. * +* * +* Description : Visite un groupe d'instructions décompilées. * +* * +* Retour : true afin d'aller jusqu'au terme du parcours. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool visit_instructions_block(GDecInstruction *instr, GDecInstruction *parent, DecInstrVisitFlags flags, GHashTable **table) { + GHashTable *sub; /* Associations pour sous-bloc */ + + if (G_IS_EXPR_BLOCK(instr)) + { + /* Entrée dans un bloc : on crée un contexte propre au bloc ! */ + if (flags == DVF_ENTER) + { + g_object_set_data(G_OBJECT(instr), "var_collect", *table); + *table = create_tracking_table(*table); + } + + /* Sortie du bloc : actions locales + purge ! */ + else if (flags == DVF_EXIT) + { + sub = *table; + *table = (GHashTable *)g_object_get_data(G_OBJECT(instr), "var_collect"); + + if (*table != NULL) + merge_usages(*table, sub); + replace_useless_variable(instr, sub); + g_hash_table_unref(sub); + } -} usage_reduc; + } + else if (flags == DVF_ENTER) + collect_used_variables(instr, parent, *table); + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instructions à traiter. * +* * +* Description : Réduit le nombre de variables utilisées, via propagations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reduce_used_variables(GDecInstruction *instr) +{ + GHashTable *table; -#endif + table = NULL; + g_dec_instruction_visit(instr, (dec_instr_visitor_cb)visit_instructions_block, + DVF_ENTER | DVF_EXIT, &table); +} diff --git a/src/analysis/decomp/reduce.h b/src/analysis/decomp/reduce.h index aa13d7f..1b62a06 100644 --- a/src/analysis/decomp/reduce.h +++ b/src/analysis/decomp/reduce.h @@ -2,7 +2,7 @@ /* OpenIDA - Outil d'analyse de fichiers binaires * reduce.h - prototypes pour la réduction de l'usage des [pseudo]-registres * - * Copyright (C) 2012 Cyrille Bagard + * Copyright (C) 2012-2013 Cyrille Bagard * * This file is part of OpenIDA. * @@ -25,6 +25,13 @@ #define _ANALYSIS_DECOMP_REDUCE_H +#include "../../decomp/instruction.h" + + + +/* Réduit le nombre de variables utilisées, via propagations. */ +void reduce_used_variables(GDecInstruction *instr); + #endif /* _ANALYSIS_DECOMP_REDUCE_H */ diff --git a/src/arch/dalvik/context.c b/src/arch/dalvik/context.c index 7918467..a21f8e9 100644 --- a/src/arch/dalvik/context.c +++ b/src/arch/dalvik/context.c @@ -526,7 +526,7 @@ static GDecInstruction *g_dalvik_dcontext_convert_register(GDalvikDContext *ctx, this = g_binary_variable_new(/* FIXME */g_basic_type_new(BTP_OTHER) /* FIXME */); g_binary_variable_set_name(this, "this"); - ctx->this = g_pseudo_register_new(); + ctx->this = g_pseudo_register_new(PRU_THIS); g_pseudo_register_set_variable(G_PSEUDO_REGISTER(ctx->this), this); } @@ -548,7 +548,7 @@ static GDecInstruction *g_dalvik_dcontext_convert_register(GDalvikDContext *ctx, } else { - result = g_pseudo_register_new(); + result = g_pseudo_register_new(PRU_ARG); g_pseudo_register_set_basename(G_PSEUDO_REGISTER(result), "arg"); g_pseudo_register_set_index(G_PSEUDO_REGISTER(result), DVI_INDEX(info)); @@ -582,7 +582,7 @@ static GDecInstruction *g_dalvik_dcontext_convert_register(GDalvikDContext *ctx, if (result == NULL) { - result = g_pseudo_register_new(); + result = g_pseudo_register_new(PRU_LOCAL); g_pseudo_register_set_basename(G_PSEUDO_REGISTER(result), "var"); g_pseudo_register_set_index(G_PSEUDO_REGISTER(result), ctx->locals_count); diff --git a/src/arch/dalvik/decomp/iget.c b/src/arch/dalvik/decomp/iget.c index 9cf603d..6d2ce30 100644 --- a/src/arch/dalvik/decomp/iget.c +++ b/src/arch/dalvik/decomp/iget.c @@ -65,7 +65,7 @@ GDecInstruction *dalvik_decomp_instr_iget(const GArchInstruction *instr, GDecCon index = g_dalvik_pool_operand_get_index(G_DALVIK_POOL_OPERAND(operand)); var = get_field_from_dex_pool(G_DEX_FORMAT(g_dec_context_get_format(ctx)), index); - field = g_pseudo_register_new(); + field = g_pseudo_register_new(PRU_FIXED); g_pseudo_register_set_variable(G_PSEUDO_REGISTER(field), var); operand = g_arch_instruction_get_operand(instr, 0); diff --git a/src/arch/dalvik/decomp/iput.c b/src/arch/dalvik/decomp/iput.c index ed0830c..68ad4f0 100644 --- a/src/arch/dalvik/decomp/iput.c +++ b/src/arch/dalvik/decomp/iput.c @@ -68,7 +68,7 @@ GDecInstruction *dalvik_decomp_instr_iput(const GArchInstruction *instr, GDecCon index = g_dalvik_pool_operand_get_index(G_DALVIK_POOL_OPERAND(operand)); var = get_field_from_dex_pool(G_DEX_FORMAT(g_dec_context_get_format(ctx)), index); - field = g_pseudo_register_new(); + field = g_pseudo_register_new(PRU_FIXED); g_pseudo_register_set_variable(G_PSEUDO_REGISTER(field), var); access = g_access_expression_new(G_DEC_EXPRESSION(dest), G_DEC_EXPRESSION(field)); diff --git a/src/decomp/expr/access.c b/src/decomp/expr/access.c index f06c47b..8afe635 100644 --- a/src/decomp/expr/access.c +++ b/src/decomp/expr/access.c @@ -158,10 +158,12 @@ static bool g_access_expression_visit(GAccessExpression *expr, dec_instr_visitor { bool result; /* Bilan à retourner */ - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->owner), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->owner), G_DEC_INSTRUCTION(expr), + callback, flags, data); if (result) - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->target), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->target), G_DEC_INSTRUCTION(expr), + callback, flags, data); return result; diff --git a/src/decomp/expr/arithm.c b/src/decomp/expr/arithm.c index 3811cf4..e8a4c30 100644 --- a/src/decomp/expr/arithm.c +++ b/src/decomp/expr/arithm.c @@ -163,10 +163,12 @@ static bool g_arithm_expression_visit(GArithmExpression *expr, dec_instr_visitor { bool result; /* Bilan à retourner */ - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->op1), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->op1), G_DEC_INSTRUCTION(expr), + callback, flags, data); if (result) - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->op2), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->op2), G_DEC_INSTRUCTION(expr), + callback, flags, data); return result; diff --git a/src/decomp/expr/array.c b/src/decomp/expr/array.c index 4053169..b2bb2f1 100644 --- a/src/decomp/expr/array.c +++ b/src/decomp/expr/array.c @@ -158,10 +158,12 @@ static bool g_array_access_visit(GArrayAccess *expr, dec_instr_visitor_cb callba { bool result; /* Bilan à retourner */ - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->array), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->array), G_DEC_INSTRUCTION(expr), + callback, flags, data); if (result) - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->index), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->index), G_DEC_INSTRUCTION(expr), + callback, flags, data); return result; diff --git a/src/decomp/expr/assign.c b/src/decomp/expr/assign.c index 26d31f6..939407d 100644 --- a/src/decomp/expr/assign.c +++ b/src/decomp/expr/assign.c @@ -158,10 +158,12 @@ static bool g_assign_expression_visit(GAssignExpression *expr, dec_instr_visitor { bool result; /* Bilan à retourner */ - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->dest), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->dest), G_DEC_INSTRUCTION(expr), + callback, flags, data); if (result) - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->src), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->src), G_DEC_INSTRUCTION(expr), + callback, flags, data); return result; @@ -259,7 +261,7 @@ static GBufferLine *g_assign_expression_print(const GAssignExpression *expr, GCo * * ******************************************************************************/ -GDecInstruction *g_assign_expression_get_dest(const GAssignExpression *assign) +GDecExpression *g_assign_expression_get_dest(const GAssignExpression *assign) { return assign->dest; @@ -278,7 +280,7 @@ GDecInstruction *g_assign_expression_get_dest(const GAssignExpression *assign) * * ******************************************************************************/ -GDecInstruction *g_assign_expression_get_src(const GAssignExpression *assign) +GDecExpression *g_assign_expression_get_src(const GAssignExpression *assign) { return assign->src; diff --git a/src/decomp/expr/assign.h b/src/decomp/expr/assign.h index ce441f6..b55853e 100644 --- a/src/decomp/expr/assign.h +++ b/src/decomp/expr/assign.h @@ -56,10 +56,10 @@ GType g_assign_expression_get_type(void); GDecInstruction *g_assign_expression_new(GDecExpression *, GDecExpression *); /* Indique la destination d'une assignation. */ -GDecInstruction *g_assign_expression_get_dest(const GAssignExpression *); +GDecExpression *g_assign_expression_get_dest(const GAssignExpression *); /* Indique la source d'une assignation. */ -GDecInstruction *g_assign_expression_get_src(const GAssignExpression *); +GDecExpression *g_assign_expression_get_src(const GAssignExpression *); diff --git a/src/decomp/expr/block.c b/src/decomp/expr/block.c index 3c56ef6..b58972d 100644 --- a/src/decomp/expr/block.c +++ b/src/decomp/expr/block.c @@ -25,6 +25,7 @@ #include +#include #include "../expression-int.h" @@ -163,7 +164,8 @@ static bool g_expr_block_visit(GExprBlock *block, dec_instr_visitor_cb callback, result = true; for (i = 0; i < block->count && result; i++) - result = g_dec_instruction_visit(block->list[i], callback, flags, data); + result = _g_dec_instruction_visit(block->list[i], G_DEC_INSTRUCTION(block), + callback, flags, data); return result; @@ -270,3 +272,40 @@ void g_expr_block_add_item(GExprBlock *block, GDecInstruction *item) block->list[block->count - 1] = item; } + + +/****************************************************************************** +* * +* Paramètres : block = ensemble à faire évoluer. * +* item = nouvel élément à retirer de l'ensemble. * +* * +* Description : Supprime une instruction décompilée du conteneur existant. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_expr_block_delete_item(GExprBlock *block, GDecInstruction *item) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < block->count; i++) + if (block->list[i] == item) + break; + + if (i < block->count) + { + if ((i + 1) < block->count) + memmove(&block->list[i], &block->list[i + 1], + (block->count - i - 1) * sizeof(GDecInstruction *)); + + block->list = (GDecInstruction **)realloc(block->list, + --block->count * sizeof(GDecInstruction *)); + + g_object_unref(G_OBJECT(item)); + + } + +} diff --git a/src/decomp/expr/block.h b/src/decomp/expr/block.h index 4ae4ff1..b0c2baa 100644 --- a/src/decomp/expr/block.h +++ b/src/decomp/expr/block.h @@ -57,6 +57,9 @@ GDecInstruction *g_expr_block_new(GDecInstruction *); /* Ajoute une instruction décompilée au conteneur existant. */ void g_expr_block_add_item(GExprBlock *, GDecInstruction *); +/* Supprime une instruction décompilée du conteneur existant. */ +void g_expr_block_delete_item(GExprBlock *, GDecInstruction *); + #endif /* _DECOMP_EXPR_BLOCK_H */ diff --git a/src/decomp/expr/call.c b/src/decomp/expr/call.c index ed1c43a..9aad9c0 100644 --- a/src/decomp/expr/call.c +++ b/src/decomp/expr/call.c @@ -166,7 +166,8 @@ static bool g_routine_call_visit(GRoutineCall *call, dec_instr_visitor_cb callba result = true; for (i = 0; i < call->count && result; i++) - result = g_dec_instruction_visit(call->args[i], callback, flags, data); + result = _g_dec_instruction_visit(call->args[i], G_DEC_INSTRUCTION(call), + callback, flags, data); return result; diff --git a/src/decomp/expr/cond.c b/src/decomp/expr/cond.c index d96f483..fab2c17 100644 --- a/src/decomp/expr/cond.c +++ b/src/decomp/expr/cond.c @@ -161,10 +161,12 @@ static bool g_cond_expression_visit(GCondExpression *expr, dec_instr_visitor_cb { bool result; /* Bilan à retourner */ - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->a), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->a), G_DEC_INSTRUCTION(expr), + callback, flags, data); if (result) - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->b), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->b), G_DEC_INSTRUCTION(expr), + callback, flags, data); return result; diff --git a/src/decomp/expr/pseudo.c b/src/decomp/expr/pseudo.c index 9da76e7..7c7ba71 100644 --- a/src/decomp/expr/pseudo.c +++ b/src/decomp/expr/pseudo.c @@ -38,6 +38,8 @@ struct _GPseudoRegister { GDecExpression parent; /* A laisser en premier */ + PseudoRegUsage usage; /* Type d'utilisation attendue */ + char *name; /* Désignation générale */ size_t index; /* Position dans l'ensemble */ GBinVariable *var; /* Variable plus précise */ @@ -112,7 +114,7 @@ static void g_pseudo_register_init(GPseudoRegister *reg) /****************************************************************************** * * -* Paramètres : - * +* Paramètres : usage = précision quant à l'usage du pseudo-registre à créer.* * * * Description : Assigne le contenu d'une expression dans une autre. * * * @@ -122,12 +124,14 @@ static void g_pseudo_register_init(GPseudoRegister *reg) * * ******************************************************************************/ -GDecInstruction *g_pseudo_register_new(void) +GDecInstruction *g_pseudo_register_new(PseudoRegUsage usage) { GPseudoRegister *result; /* Pseudo-registre à renvoyer */ result = g_object_new(G_TYPE_PSEUDO_REGISTER, NULL); + result->usage = usage; + return G_DEC_INSTRUCTION(result); } @@ -135,6 +139,25 @@ GDecInstruction *g_pseudo_register_new(void) /****************************************************************************** * * +* Paramètres : reg = pseudo-registre à venir consulter. * +* * +* Description : Indique l'usage attendu du pseudo-registre consulté. * +* * +* Retour : Utilité du pseudo-registre en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PseudoRegUsage g_pseudo_register_get_usage(const GPseudoRegister *reg) +{ + return reg->usage; + +} + + +/****************************************************************************** +* * * Paramètres : reg = 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/pseudo.h b/src/decomp/expr/pseudo.h index a465b41..e7f3b00 100644 --- a/src/decomp/expr/pseudo.h +++ b/src/decomp/expr/pseudo.h @@ -42,6 +42,17 @@ +/* Types de pseudo-registre */ +typedef enum _PseudoRegUsage +{ + PRU_THIS, /* "this" pour les objets */ + PRU_ARG, /* Argument de fonction */ + PRU_LOCAL, /* Variable locale */ + PRU_FIXED /* Variable type champ */ + +} PseudoRegUsage; + + /* Définition d'un pseudo-registre (instance) */ typedef struct _GPseudoRegister GPseudoRegister; @@ -53,7 +64,10 @@ typedef struct _GPseudoRegisterClass GPseudoRegisterClass; GType g_pseudo_register_get_type(void); /* Assigne le contenu d'une expression dans une autre. */ -GDecInstruction *g_pseudo_register_new(void); +GDecInstruction *g_pseudo_register_new(PseudoRegUsage); + +/* Indique l'usage attendu du pseudo-registre consulté. */ +PseudoRegUsage g_pseudo_register_get_usage(const GPseudoRegister *); /* Définit un nom général pour un pseudo-registre donné. */ void g_pseudo_register_set_basename(GPseudoRegister *, const char *); diff --git a/src/decomp/expr/return.c b/src/decomp/expr/return.c index d012893..65fd641 100644 --- a/src/decomp/expr/return.c +++ b/src/decomp/expr/return.c @@ -156,7 +156,8 @@ static bool g_return_expression_visit(GReturnExpression *expr, dec_instr_visitor bool result; /* Bilan à retourner */ if (expr->payload) - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->payload), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->payload), G_DEC_INSTRUCTION(expr), + callback, flags, data); else result = false; diff --git a/src/decomp/instr/ite.c b/src/decomp/instr/ite.c index 1abf61c..d78bb31 100644 --- a/src/decomp/instr/ite.c +++ b/src/decomp/instr/ite.c @@ -178,13 +178,16 @@ static bool g_ite_instruction_visit(GITEInstruction *instr, dec_instr_visitor_cb { bool result; /* Bilan à retourner */ - result = g_dec_instruction_visit(G_DEC_INSTRUCTION(instr->cond), callback, flags, data); + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(instr->cond), G_DEC_INSTRUCTION(instr), + callback, flags, data); if (result) - result = g_dec_instruction_visit(instr->true_branch, callback, flags, data); + result = _g_dec_instruction_visit(instr->true_branch, G_DEC_INSTRUCTION(instr), + callback, flags, data); if (result && instr->false_branch != NULL) - result = g_dec_instruction_visit(instr->false_branch, callback, flags, data); + result = _g_dec_instruction_visit(instr->false_branch, G_DEC_INSTRUCTION(instr), + callback, flags, data); return result; diff --git a/src/decomp/instruction.c b/src/decomp/instruction.c index 3a9917a..92388fc 100644 --- a/src/decomp/instruction.c +++ b/src/decomp/instruction.c @@ -80,6 +80,7 @@ static void g_dec_instruction_init(GDecInstruction *instr) /****************************************************************************** * * * Paramètres : instr = première instruction à venir visiter. * +* parent = instruction parente. * * callback = procédure à appeler à chaque instruction visitée. * * flags = moments des appels à réaliser en retour. * * data = données quelconques associées au visiteur. * @@ -92,20 +93,20 @@ static void g_dec_instruction_init(GDecInstruction *instr) * * ******************************************************************************/ -bool g_dec_instruction_visit(GDecInstruction *instr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) +bool _g_dec_instruction_visit(GDecInstruction *instr, GDecInstruction *parent, 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); + result = callback(instr, parent, 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); + result = callback(instr, parent, DVF_EXIT, data); return result; diff --git a/src/decomp/instruction.h b/src/decomp/instruction.h index ed8090d..3c8657b 100644 --- a/src/decomp/instruction.h +++ b/src/decomp/instruction.h @@ -50,20 +50,22 @@ 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 */ + DVF_ENTER = (1 << 0), /* Entrée dans une instruction */ + DVF_EXIT = (1 << 1) /* Sortie d'une instruction */ } DecInstrVisitFlags; /* Rappel à chaque instruction décompilée visitée */ -typedef bool (* dec_instr_visitor_cb) (GDecInstruction *, DecInstrVisitFlags, void *); +typedef bool (* dec_instr_visitor_cb) (GDecInstruction *, 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. */ -bool g_dec_instruction_visit(GDecInstruction *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); +bool _g_dec_instruction_visit(GDecInstruction *, GDecInstruction *, dec_instr_visitor_cb, DecInstrVisitFlags, void *); + +#define g_dec_instruction_visit(instr, callback, flags, data) _g_dec_instruction_visit(instr, NULL, callback, flags, data) /* Remplace une instruction décompilée par une autre. */ bool g_dec_instruction_replace(GDecInstruction *, GDecInstruction *, GDecInstruction *); -- cgit v0.11.2-87-g4458