From 221bcaeeb06415d501f9abbb9bc4b7d8339af1fe Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 10 Jan 2013 22:47:37 +0000
Subject: Simplified the decompilation process by using links between basic
 blocks.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@322 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                     |  19 +++++++
 src/analysis/block-int.h      |   2 +
 src/analysis/block.c          |  46 ++++++++++++++++
 src/analysis/block.h          |   6 +++
 src/analysis/blocks/virtual.c |   3 +-
 src/analysis/decomp/il.c      |  30 +++++------
 src/analysis/disass/macro.c   | 121 ++++++++++++++++++++++++------------------
 src/decomp/instr/ite.c        |  21 +++++++-
 8 files changed, 175 insertions(+), 73 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b081ee7..74e3608 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+13-01-10  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/block.c:
+	* src/analysis/block.h:
+	* src/analysis/block-int.h:
+	Create a link between basic blocks.
+
+	* src/analysis/blocks/virtual.c:
+	Return the first [parent] block found, not the final one.
+
+	* src/analysis/decomp/il.c:
+	Simplify the decompilation process by using links between basic blocks.
+
+	* src/analysis/disass/macro.c:
+	Attach the conditional blocks with their origin. Fix a bug for exceptions.
+
+	* src/decomp/instr/ite.c:
+	Inverse the condition if the 'true' branch is empty.
+
 13-01-09  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/decomp/decompiler.c:
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h
index 355c1ee..f016e35 100644
--- a/src/analysis/block-int.h
+++ b/src/analysis/block-int.h
@@ -53,6 +53,8 @@ struct _GInstrBlock
     list_all_blocks_fc list_blocks;         /* Liste de tous les blocs     */
     list_regs_accesses_fc list_regs;        /* Liste des accès registres   */
 
+    GInstrBlock *links_block;               /* Lieu des blocs attachés     */
+
 };
 
 /* Description d'un bloc d'instructions (classe) */
diff --git a/src/analysis/block.c b/src/analysis/block.c
index 62b56ab..1ec9804 100644
--- a/src/analysis/block.c
+++ b/src/analysis/block.c
@@ -131,6 +131,9 @@ static void g_instr_block_init(GInstrBlock *block)
 
 static void g_instr_block_dispose(GInstrBlock *block)
 {
+    if (block->links_block != NULL)
+        g_object_unref(G_OBJECT(block->links_block));
+
     G_OBJECT_CLASS(g_instr_block_parent_class)->dispose(G_OBJECT(block));
 
 }
@@ -215,3 +218,46 @@ void g_instr_block_list_all_blocks(const GInstrBlock *block, GInstrBlock ***list
     block->list_blocks(block, list, count);
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : block = bloc d'instructions à mettre à jour.                 *
+*                links = bloc contenant les blocs liés au bloc.               *
+*                                                                             *
+*  Description : Définit l'ensemble contenant les blocs liés.                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_instr_block_set_links_block(GInstrBlock *block, GInstrBlock *links)
+{
+    if (block->links_block != NULL)
+        g_object_unref(G_OBJECT(block->links_block));
+
+    g_object_ref(G_OBJECT(links));
+    block->links_block = links;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : block = bloc d'instructions à mettre à jour.                 *
+*                                                                             *
+*  Description : Fournit l'ensemble contenant les blocs liés.                 *
+*                                                                             *
+*  Retour      : Bloc contenant les blocs liés au bloc.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GInstrBlock *g_instr_block_get_links_block(const GInstrBlock *block)
+{
+    return block->links_block;
+
+}
diff --git a/src/analysis/block.h b/src/analysis/block.h
index 1574dc1..125ff0e 100644
--- a/src/analysis/block.h
+++ b/src/analysis/block.h
@@ -104,6 +104,12 @@ bool g_instr_block_visit(GInstrBlock *, instr_block_visitor_cb, void *);
 /* Etablit la liste de tous les blocs présents. */
 void g_instr_block_list_all_blocks(const GInstrBlock *, GInstrBlock ***, size_t *);
 
+/* Définit l'ensemble contenant les blocs liés. */
+void g_instr_block_set_links_block(GInstrBlock *, GInstrBlock *);
+
+/* Fournit l'ensemble contenant les blocs liés. */
+GInstrBlock *g_instr_block_get_links_block(const GInstrBlock *);
+
 
 
 #endif  /* _ANALYSIS_BLOCK_H */
diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c
index 71a6d06..2385f67 100644
--- a/src/analysis/blocks/virtual.c
+++ b/src/analysis/blocks/virtual.c
@@ -230,7 +230,8 @@ static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *block, vmp
     result = NULL;
 
     for (i = 0; i < block->children_count && result == NULL; i++)
-        result = g_instr_block_find_by_addr(block->children[i], addr);
+        if (g_instr_block_find_by_addr(block->children[i], addr))
+            result = block->children[i];
 
     return result;
 
diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c
index c2bc0be..f3c2265 100644
--- a/src/analysis/decomp/il.c
+++ b/src/analysis/decomp/il.c
@@ -46,7 +46,7 @@
 static GDecInstruction *merge_decompiled_instructions(GDecInstruction *, GDecInstruction *);
 
 /* Procède à la décompilation d'un bloc déterminé. */
-static GDecInstruction *decompiled_instructions_block(GFlowBlock *, GVirtualBlock *, GDecContext *);
+static GDecInstruction *decompiled_instructions_block(GFlowBlock *, GDecContext *);
 
 /* Procède à la décompilation d'un ensemble de blocs déterminé. */
 static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *, GDecContext *);
@@ -111,9 +111,8 @@ static GDecInstruction *merge_decompiled_instructions(GDecInstruction *group, GD
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : block  = ensemble des instructions d'assemblage à traiter.   *
-*                parent = groupe de blocs d'appartenance.                     *
-*                ctx    = contexte de soutien à associer à l'opération.       *
+*  Paramètres  : block = ensemble des instructions d'assemblage à traiter.    *
+*                ctx   = contexte de soutien à associer à l'opération.        *
 *                                                                             *
 *  Description : Procède à la décompilation d'un bloc déterminé.              *
 *                                                                             *
@@ -123,7 +122,7 @@ static GDecInstruction *merge_decompiled_instructions(GDecInstruction *group, GD
 *                                                                             *
 ******************************************************************************/
 
-static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtualBlock *parent, GDecContext *ctx)
+static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecContext *ctx)
 {
     GDecInstruction *res;
 
@@ -137,7 +136,8 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtua
     GDecInstruction *false_dinstr;          /* Décompilation 'cond fausse' */
     GArchInstruction *next;                 /* Instruction de branchement  */
     vmpa_t next_addr;                       /* Adresse de cette instruct°  */
-    GInstrBlock *next_block;                /* Bloc basique correspondant  */
+    GInstrBlock *next_parent;               /* Bloc basique correspondant  */
+    GInstrBlock *next_block;                /* Sous-bloc basique direct    */
 
     instrs = g_flow_block_get_all_instructions_list(block);
     g_flow_block_get_boundary(block, &first, &last);
@@ -172,13 +172,10 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtua
         if (next != NULL)
         {
             g_arch_instruction_get_location(next, NULL, NULL, &next_addr);
-            next_block = g_instr_block_find_by_addr(G_INSTR_BLOCK(parent), next_addr);
+            next_block = g_instr_block_find_by_addr(g_instr_block_get_links_block(block), next_addr);
 
             if (next_block != NULL)
-            {
-                next_block = g_instr_block_find_by_addr(next_block, next_addr);
                 true_dinstr = decompiled_basic_block(next_block, ctx);
-            }
 
         }
 
@@ -191,21 +188,18 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtua
         if (next != NULL)
         {
             g_arch_instruction_get_location(next, NULL, NULL, &next_addr);
-            next_block = g_instr_block_find_by_addr(G_INSTR_BLOCK(parent), next_addr);
+            next_block = g_instr_block_find_by_addr(g_instr_block_get_links_block(block), next_addr);
 
             if (next_block != NULL)
-            {
-                next_block = g_instr_block_find_by_addr(next_block, next_addr);
                 false_dinstr = decompiled_basic_block(next_block, ctx);
-            }
 
         }
 
         printf(" -> ite : %p + %p\n", true_dinstr, false_dinstr);
 
         printf(" -> ite : %s + %s\n",
-               g_type_name(G_TYPE_FROM_INSTANCE(true_dinstr)),
-               g_type_name(G_TYPE_FROM_INSTANCE(false_dinstr)));
+               true_dinstr ? g_type_name(G_TYPE_FROM_INSTANCE(true_dinstr)) : "none",
+               false_dinstr ? g_type_name(G_TYPE_FROM_INSTANCE(false_dinstr)) : "none");
 
 
         g_ite_instruction_set_branches(G_ITE_INSTRUCTION(decomp), true_dinstr, false_dinstr);
@@ -259,7 +253,7 @@ static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *block, GDe
         /* FIXME */
         g_dec_context_set_decomp_instrs(ctx, NULL);
 
-        dinstrs = decompiled_instructions_block(G_FLOW_BLOCK(sub_block), block, ctx);
+        dinstrs = decompiled_instructions_block(G_FLOW_BLOCK(sub_block), ctx);
         result = merge_decompiled_instructions(result, dinstrs);
 
     }
@@ -294,7 +288,7 @@ static GDecInstruction *decompiled_basic_block(GInstrBlock *block, GDecContext *
 
     else
     {
-        result = decompiled_instructions_block(G_FLOW_BLOCK(block), NULL, ctx);
+        result = decompiled_instructions_block(G_FLOW_BLOCK(block), ctx);
 
         if (!G_IS_EXPR_BLOCK(result))
             result = merge_decompiled_instructions(NULL, result);
diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c
index 2e5c0ee..8652b27 100644
--- a/src/analysis/disass/macro.c
+++ b/src/analysis/disass/macro.c
@@ -288,6 +288,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
     size_t dcount;                          /* Nombre de liens de dest.    */
     size_t i;                               /* Boucle de parcours #1       */
     GInstrBlock *block;                     /* Nouveau bloc mis en place   */
+    GInstrBlock *parent;                    /* Mémorisation pour les liens */
     GInstrBlock *group;                     /* Regroupement de blocs       */
     branch_info *cases_branches;            /* Branches d'un aiguillage    */
     size_t cases_count;                     /* Nombre d'aiguillages        */
@@ -375,7 +376,6 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
                 case ILT_EXEC_FLOW:
                 case ILT_JUMP:
 
-
                     block = g_flow_block_new(instrs, first, iter);
                     MACRO_MARK_AS_PROCESSED(first);
                     first = NULL;
@@ -428,21 +428,23 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
         /* Post-traitements de ILT_CASE_JUMP */
         if (cases_count > 0)
         {
-            if (first != NULL)
-            {
-                block = g_flow_block_new(instrs, first, iter);
-                MACRO_MARK_AS_PROCESSED(first);
-                first = NULL;
-
-                DELAYED_BLOCK_ADDING(result, result_cached, block);
+            /**
+             * On doit clôturer le bloc renvoyant vers les branches de cas ici.
+             * Les sauts conditionnels sont normalement présents de façon exclusive,
+             * sauf pour les exceptions, qui sont traitées après.
+             */
+            block = g_flow_block_new(instrs, first, iter);
+            MACRO_MARK_AS_PROCESSED(first);
+            first = NULL;
 
-            }
+            DELAYED_BLOCK_ADDING(result, result_cached, block);
 
             //printf(" --- cases --- start\n");
 
             next_addr = compute_first_common_addr_in_group(cases_branches, cases_count);
             //printf("    stop :: 0x%08llx\n", next_addr);
 
+            parent = block;
             group = g_virtual_block_new();
 
             for (j = 0; j < cases_count; j++)
@@ -460,7 +462,10 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
             }
 
             if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0)
+            {
                 DELAYED_BLOCK_ADDING(result, result_cached, group);
+                g_instr_block_set_links_block(parent, group);
+            }
             else
                 g_object_unref(G_OBJECT(group));
 
@@ -471,38 +476,6 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
 
         }
 
-        /* Post-traitements de ILT_CATCH_EXCEPTION */
-        if (excep_count > 0)
-        {
-            if (first != NULL)
-            {
-                block = g_flow_block_new(instrs, first, iter);
-                MACRO_MARK_AS_PROCESSED(first);
-                first = NULL;
-
-                DELAYED_BLOCK_ADDING(result, result_cached, block);
-
-            }
-
-            for (j = 0; j < excep_count; j++)
-            {
-                stop_addr = compute_first_common_addr(&main_branch, &excep_branches[j]);
-                //next_addr = MIN(next_addr, end);
-
-                block = build_instruction_block(instrs, excep_branches[j].jumps[0], end, stop_addr);
-
-                if (block != NULL)
-
-                g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
-
-                free(excep_branches[j].jumps);
-
-            }
-
-            free(excep_branches);
-
-        }
-
         if (next_addr == VMPA_MAX)
         {
             iter = g_arch_instruction_get_next_iter(instrs, iter, end);
@@ -514,16 +487,18 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
             next_addr = compute_first_common_addr(&true_branch, &false_branch);
             next_addr = MIN(next_addr, end);
 
-            if (first != NULL)
-            {
-                block = g_flow_block_new(instrs, first, iter);
-                MACRO_MARK_AS_PROCESSED(first);
-                first = NULL;
-
-                DELAYED_BLOCK_ADDING(result, result_cached, block);
+            /**
+             * On doit clôturer le bloc renvoyant vers les branches 'true' et 'false' ici.
+             * Les sauts conditionnels sont normalement présents de façon exclusive,
+             * sauf pour les exceptions, qui sont traitées après.
+             */
+            block = g_flow_block_new(instrs, first, iter);
+            MACRO_MARK_AS_PROCESSED(first);
+            first = NULL;
 
-            }
+            DELAYED_BLOCK_ADDING(result, result_cached, block);
 
+            parent = block;
             group = g_virtual_block_new();
 
             block = build_instruction_block(instrs, true_branch.jumps[0], end, next_addr);
@@ -535,7 +510,10 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
                 g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
 
             if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0)
+            {
                 DELAYED_BLOCK_ADDING(result, result_cached, group);
+                g_instr_block_set_links_block(parent, group);
+            }
             else
                 g_object_unref(G_OBJECT(group));
 
@@ -546,6 +524,38 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
 
         }
 
+        /* Post-traitements de ILT_CATCH_EXCEPTION */
+        if (excep_count > 0)
+        {
+            if (first != NULL)
+            {
+                block = g_flow_block_new(instrs, first, iter);
+                MACRO_MARK_AS_PROCESSED(first);
+                first = NULL;
+
+                DELAYED_BLOCK_ADDING(result, result_cached, block);
+
+            }
+
+            for (j = 0; j < excep_count; j++)
+            {
+                stop_addr = compute_first_common_addr(&main_branch, &excep_branches[j]);
+                //next_addr = MIN(next_addr, end);
+
+                block = build_instruction_block(instrs, excep_branches[j].jumps[0], end, stop_addr);
+
+                if (block != NULL)
+
+                DELAYED_BLOCK_ADDING(result, result_cached, block);
+
+                free(excep_branches[j].jumps);
+
+            }
+
+            free(excep_branches);
+
+        }
+
         /* Détermination du prochain point de chute */
         iter = g_arch_instruction_find_by_address(instrs, next_addr, true);
 
@@ -581,6 +591,7 @@ static bool print_blocks(GInstrBlock *blk, BlockVisitOrder order, int *pad)
 {
     int i;
     vmpa_t start, end;
+    GInstrBlock *links;
 
     if (order != BVO_OUT)
         for (i = 0; i < *pad; i++)
@@ -589,7 +600,13 @@ static bool print_blocks(GInstrBlock *blk, BlockVisitOrder order, int *pad)
     if (G_IS_FLOW_BLOCK(blk))
     {
         g_flow_block_get_boundary_addresses(G_FLOW_BLOCK(blk), &start, &end);
-        printf(" - flow %p : 0x%08lx -> 0x%08lx\n", blk, start, end);
+        links = g_instr_block_get_links_block(blk);
+
+        if (links != NULL)
+            printf(" - flow %p : 0x%08lx -> 0x%08lx (links = %p)\n", blk, start, end, links);
+        else
+            printf(" - flow %p : 0x%08lx -> 0x%08lx\n", blk, start, end);
+
     }
     else
     {
@@ -638,14 +655,14 @@ void group_routines_instructions(GArchInstruction *list, GBinRoutine **routines,
         end = start + g_binary_routine_get_size(routines[i]);
 
 
-        //printf("==== %s ====\n", g_binary_routine_to_string(routines[i]));
+        printf("==== %s ====\n", g_binary_routine_to_string(routines[i]));
 
 
         block = build_instruction_block(list, start, end, VMPA_MAX);
         g_binary_routine_set_basic_blocks(routines[i], block);
 
 
-        //g_instr_block_visit(block, (instr_block_visitor_cb)print_blocks, (int []){ 0 });
+        g_instr_block_visit(block, (instr_block_visitor_cb)print_blocks, (int []){ 0 });
 
         gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
 
diff --git a/src/decomp/instr/ite.c b/src/decomp/instr/ite.c
index 7c68031..c12d314 100644
--- a/src/decomp/instr/ite.c
+++ b/src/decomp/instr/ite.c
@@ -33,6 +33,8 @@ struct _GITEInstruction
 {
     GDecInstruction parent;                 /* A laisser en premier        */
 
+    bool inverse;                           /* Condition inversée          */
+
     GDecExpression *cond;                   /* Condition prise en compte   */
 
     GDecInstruction *true_branch;           /* Condition vérifiée          */
@@ -165,8 +167,20 @@ GDecInstruction *g_ite_instruction_new(GDecExpression *cond, vmpa_t if_true, vmp
 
 void g_ite_instruction_set_branches(GITEInstruction *expr, GDecInstruction *true_branch, GDecInstruction *false_branch)
 {
-    expr->true_branch = true_branch;
-    expr->false_branch = 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;
+    }
 
 }
 
@@ -192,6 +206,9 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu
 
     g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "if ", 3, RTT_KEY_WORD);
 
+    if (expr->inverse)
+        g_buffer_line_insert_text(line /* FIXME */, BLC_ASSEMBLY_HEAD, "!", 1, RTT_KEY_WORD);
+
     result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->cond),
                                      buffer, line, output);
 
-- 
cgit v0.11.2-87-g4458