From 5c7ea8e2137e4e5bb2887de0d1ffd8a0b277636e Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
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 <nocbos@gmail.com>
 
+	* 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 <nocbos@gmail.com>
+
 	* 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 <malloc.h>
 
 
+#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 <malloc.h>
+#include <string.h>
 
 
 #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