From d626276398a3cdd3cd6432e073a8866aa91418ce Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 5 Jan 2013 13:30:19 +0000
Subject: Refined the definition of basic blocks and used them to build extra
 clusters for dot.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@317 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                        |  32 ++++++++++
 src/analysis/binary.c            |   6 +-
 src/analysis/block-int.h         |   4 ++
 src/analysis/block.c             |  21 +++++++
 src/analysis/block.h             |  16 +++++
 src/analysis/blocks/flow.c       |  62 +++++++++++++++++--
 src/analysis/blocks/flow.h       |   3 +
 src/analysis/blocks/virtual.c    |  54 +++++++++++++++++
 src/analysis/blocks/virtual.h    |   3 +
 src/analysis/decomp/decompiler.c |   2 +
 src/analysis/disass/macro.c      | 125 ++++++++++++++++++++++++++++++---------
 src/decomp/expr/immediate.c      |   1 +
 src/gtkext/graph/layout.c        | 120 ++++++++++++++++++++++++++++++++-----
 src/gtkext/graph/layout.h        |   2 +-
 src/gtkext/graph/node.c          |  78 ++++++++++++++++++++----
 src/gtkext/graph/node.h          |  13 +++-
 src/gtkext/gtkgraphview.c        |  16 +++--
 17 files changed, 486 insertions(+), 72 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9561278..59f7fc6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+13-01-05  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/binary.c:
+	Restore decompilation at this level.
+
+	* src/analysis/block.c:
+	* src/analysis/block.h:
+	* src/analysis/block-int.h:
+	* src/analysis/blocks/flow.c:
+	* src/analysis/blocks/flow.h:
+	* src/analysis/blocks/virtual.c:
+	* src/analysis/blocks/virtual.h:
+	Implement a visitor design pattern for basic blocks.
+
+	* src/analysis/decomp/decompiler.c:
+	Disable decompilation for now.
+
+	* src/analysis/disass/macro.c:
+	Refine the definition of basic blocks for easier abstract use.
+
+	* src/decomp/expr/immediate.c:
+	Avoid faults by increasing a ref counter.
+
+	* src/gtkext/graph/layout.c:
+	* src/gtkext/graph/layout.h:
+	* src/gtkext/graph/node.c:
+	* src/gtkext/graph/node.h:
+	Define new clusters using the basic blocks to group nodes.
+
+	* src/gtkext/gtkgraphview.c:
+	Update code.
+
 13-01-02  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/block.c:
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 61f826a..e3b3e9d 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * binary.c - traitement des flots de code binaire
  *
- * Copyright (C) 2008-2012 Cyrille Bagard
+ * Copyright (C) 2008-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -797,10 +797,10 @@ void ack_completed_disassembly(GDelayedDisassembly *disass, GLoadedBinary *binar
     if (binary->decbuf_count > 0)
     {
         binary->dec_buffers = (GCodeBuffer **)calloc(binary->decbuf_count, sizeof(GCodeBuffer *));
-        /*
+
         for (i = 0; i < binary->decbuf_count; i++)
             binary->dec_buffers[i] = decompile_all_from_file(binary, files[i]);
-        */
+
     }
 
 
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h
index e194ace..ba84fcb 100644
--- a/src/analysis/block-int.h
+++ b/src/analysis/block-int.h
@@ -29,6 +29,9 @@
 
 
 
+/* Parcours tous les blocs d'instructions dans un ordre donné. */
+typedef bool (* visit_all_blocks_fc) (GInstrBlock *, instr_block_visitor_cb, void *);
+
 /* Etablit la liste de tous les blocs présents. */
 typedef void (* list_all_blocks_fc) (const GInstrBlock *, GInstrBlock ***, size_t *);
 
@@ -42,6 +45,7 @@ struct _GInstrBlock
 {
     GObject parent;                         /* A laisser en premier        */
 
+    visit_all_blocks_fc visit_blocks;       /* Visite des différents blocs */
     list_all_blocks_fc list_blocks;         /* Liste de tous les blocs     */
     list_regs_accesses_fc list_regs;        /* Liste des accès registres   */
 
diff --git a/src/analysis/block.c b/src/analysis/block.c
index 3093a98..3b3eaf3 100644
--- a/src/analysis/block.c
+++ b/src/analysis/block.c
@@ -157,6 +157,27 @@ static void g_instr_block_finalize(GInstrBlock *block)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : block    = bloc d'instructions démarrant la visite.          *
+*                callback = ensemble de blocs à parcourir.                    *
+*                data     = donnée utilisateur à associer au parcours.        *
+*                                                                             *
+*  Description : Parcours tous les blocs d'instructions dans un ordre donné.  *
+*                                                                             *
+*  Retour      : true si le parcours a été jusqu'à son terme, false sinon.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_instr_block_visit(GInstrBlock *block, instr_block_visitor_cb callback, void *data)
+{
+    return block->visit_blocks(block, callback, data);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : block = bloc d'instructions à consulter.                     *
 *                list  = ensemble de blocs à compléter. [OUT]                 *
 *                count = nombre de blocs au total. [OUT]                      *
diff --git a/src/analysis/block.h b/src/analysis/block.h
index 9e136a3..a85e4aa 100644
--- a/src/analysis/block.h
+++ b/src/analysis/block.h
@@ -79,9 +79,25 @@ typedef struct _GInstrBlock GInstrBlock;
 typedef struct _GInstrBlockClass GInstrBlockClass;
 
 
+/* Position au cours d'une visite */
+typedef enum _BlockVisitOrder
+{
+    BVO_IN,                                 /* Entrée dans un gros bloc    */
+    BVO_PENDING,                            /* Visite d'un bloc simple     */
+    BVO_OUT                                 /* Sortie d'un gros bloc       */
+
+} BlockVisitOrder;
+
+/* Rappel à chaque bloc visité */
+typedef bool (* instr_block_visitor_cb) (GInstrBlock *, BlockVisitOrder, void *);
+
+
 /* Indique le type défini pour un bloc d'instructions. */
 GType g_instr_block_get_type(void);
 
+/* Parcours tous les blocs d'instructions dans un ordre donné. */
+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 *);
 
diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c
index f80b7c8..85d98ee 100644
--- a/src/analysis/blocks/flow.c
+++ b/src/analysis/blocks/flow.c
@@ -65,15 +65,18 @@ static void g_flow_block_dispose(GFlowBlock *);
 /* Procède à la libération totale de la mémoire. */
 static void g_flow_block_finalize(GFlowBlock *);
 
+/* Parcours le bloc d'instructions dans un ordre donné. */
+static bool g_flow_block_visit(GFlowBlock *, instr_block_visitor_cb, void *);
+
+/* Etablit la liste de tous les blocs présents. */
+static void g_flow_block_list_all_blocks(const GFlowBlock *, GInstrBlock ***, size_t *);
+
 /* Prend note de l'usage d'un registre, au besoin. */
 static void g_flow_block_memorize_access(GFlowBlock *, GArchRegister *, RegAccessType, vmpa_t);
 
 /* Note les différents accès aux registres. */
 static void g_flow_block_compute_regs_access(GFlowBlock *);
 
-/* Etablit la liste de tous les blocs présents. */
-static void g_flow_block_list_all_blocks(const GFlowBlock *, GInstrBlock ***, size_t *);
-
 /* Fournit les différents accès aux registres. */
 static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *, size_t *);
 
@@ -125,6 +128,7 @@ static void g_flow_block_init(GFlowBlock *block)
 
     parent = G_INSTR_BLOCK(block);
 
+    parent->visit_blocks = (visit_all_blocks_fc)g_flow_block_visit;
     parent->list_blocks = (list_all_blocks_fc)g_flow_block_list_all_blocks;
     parent->list_regs = (list_regs_accesses_fc)g_flow_block_list_regs_accesses;
 
@@ -199,7 +203,7 @@ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first,
 {
     GFlowBlock *result;                     /* Structure à retourner       */
 
-    vmpa_t addr;                            /* Adresse de la destination   */
+    //vmpa_t addr;                            /* Adresse de la destination   */
 
 
     result = g_object_new(G_TYPE_FLOW_BLOCK, NULL);
@@ -232,6 +236,27 @@ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first,
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : block    = bloc d'instructions concerné par la visite.       *
+*                callback = ensemble de blocs à parcourir.                    *
+*                data     = donnée utilisateur à associer au parcours.        *
+*                                                                             *
+*  Description : Parcours le bloc d'instructions dans un ordre donné.         *
+*                                                                             *
+*  Retour      : true si le parcours a été jusqu'à son terme, false sinon.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_flow_block_visit(GFlowBlock *block, instr_block_visitor_cb callback, void *data)
+{
+    return callback(G_INSTR_BLOCK(block), BVO_PENDING, data);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : block = bloc d'instructions à consulter.                     *
 *                list  = ensemble de blocs à compléter. [OUT]                 *
 *                count = nombre de blocs au total. [OUT]                      *
@@ -394,6 +419,28 @@ static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *block
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : block = bloc d'instructions à consulter.                     *
+*                first = instruction de départ du bloc. [OUT]                 *
+*                last  = dernière instruction du bloc. [OUT]                  *
+*                                                                             *
+*  Description : Fournit les instructions limites d'un bloc d'exécution.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_flow_block_get_boundary(const GFlowBlock *block, GArchInstruction **first, GArchInstruction **last)
+{
+    *first = block->first;
+    *last = block->last;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : block = bloc d'instructions à consulter.                     *
 *                start = adresse de départ du bloc. [OUT]                     *
 *                end   = dernière adresse du bloc. [OUT]                      *
 *                                                                             *
@@ -407,7 +454,10 @@ static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *block
 
 void g_flow_block_get_boundary_addresses(const GFlowBlock *block, vmpa_t *start, vmpa_t *end)
 {
-    g_arch_instruction_get_location(block->first, NULL, NULL, start);
-    g_arch_instruction_get_location(block->last, NULL, NULL, end);
+    if (start != NULL)
+        g_arch_instruction_get_location(block->first, NULL, NULL, start);
+
+    if (end != NULL)
+        g_arch_instruction_get_location(block->last, NULL, NULL, end);
 
 }
diff --git a/src/analysis/blocks/flow.h b/src/analysis/blocks/flow.h
index 14f49ec..8bd7257 100644
--- a/src/analysis/blocks/flow.h
+++ b/src/analysis/blocks/flow.h
@@ -55,6 +55,9 @@ GType g_flow_block_get_type(void);
 /* Crée un bloc d'exécution d'instructions. */
 GInstrBlock *g_flow_block_new(GArchInstruction *, GArchInstruction *, GArchInstruction *);
 
+/* Fournit les instructions limites d'un bloc d'exécution. */
+void g_flow_block_get_boundary(const GFlowBlock *, GArchInstruction **, GArchInstruction **);
+
 /* Fournit les adresses limites d'un bloc d'exécution. */
 void g_flow_block_get_boundary_addresses(const GFlowBlock *, vmpa_t *, vmpa_t *);
 
diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c
index c981ece..90bccca 100644
--- a/src/analysis/blocks/virtual.c
+++ b/src/analysis/blocks/virtual.c
@@ -69,6 +69,9 @@ static void g_virtual_block_dispose(GVirtualBlock *);
 /* Procède à la libération totale de la mémoire. */
 static void g_virtual_block_finalize(GVirtualBlock *);
 
+/* Parcours le bloc d'instructions dans un ordre donné. */
+static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void *);
+
 /* Etablit la liste de tous les blocs présents. */
 static void g_virtual_block_list_all_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *);
 
@@ -123,6 +126,7 @@ static void g_virtual_block_init(GVirtualBlock *block)
 
     parent = G_INSTR_BLOCK(block);
 
+    parent->visit_blocks = (visit_all_blocks_fc)g_virtual_block_visit;
     parent->list_blocks = (list_all_blocks_fc)g_virtual_block_list_all_blocks;
     parent->list_regs = (list_regs_accesses_fc)g_virtual_block_list_regs_accesses;
 
@@ -203,6 +207,37 @@ GInstrBlock *g_virtual_block_new(void)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : block    = bloc d'instructions concerné par la visite.       *
+*                callback = ensemble de blocs à parcourir.                    *
+*                data     = donnée utilisateur à associer au parcours.        *
+*                                                                             *
+*  Description : Parcours le bloc d'instructions dans un ordre donné.         *
+*                                                                             *
+*  Retour      : true si le parcours a été jusqu'à son terme, false sinon.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_virtual_block_visit(GVirtualBlock *block, instr_block_visitor_cb callback, void *data)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = callback(G_INSTR_BLOCK(block), BVO_IN, data);
+
+    for (i = 0; i < block->children_count && result; i++)
+        result = g_instr_block_visit(block->children[i], callback, data);
+
+    result &= callback(G_INSTR_BLOCK(block), BVO_OUT, data);
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : block = bloc d'instructions à consulter.                     *
 *                list  = ensemble de blocs à compléter. [OUT]                 *
 *                count = nombre de blocs au total. [OUT]                      *
@@ -270,3 +305,22 @@ void g_virtual_block_add_child(GVirtualBlock *block, GInstrBlock *child)
     g_object_ref(G_OBJECT(child));
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : block = bloc d'instructions à consulter.                     *
+*                                                                             *
+*  Description : Compte le nombre de blocs contenus dans le groupe courant.   *
+*                                                                             *
+*  Retour      : Quantité normalement non nulle.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_virtual_block_count_children(GVirtualBlock *block)
+{
+    return block->children_count;
+
+}
diff --git a/src/analysis/blocks/virtual.h b/src/analysis/blocks/virtual.h
index f1f559f..5e8ddcd 100644
--- a/src/analysis/blocks/virtual.h
+++ b/src/analysis/blocks/virtual.h
@@ -58,6 +58,9 @@ GInstrBlock *g_virtual_block_new(void);
 /* Ajoute un bloc au groupe courant. */
 void g_virtual_block_add_child(GVirtualBlock *, GInstrBlock *);
 
+/* Compte le nombre de blocs contenus dans le groupe courant. */
+size_t g_virtual_block_count_children(GVirtualBlock *);
+
 
 
 #endif  /* _ANALYSIS_BLOCKS_VIRTUAL_H */
diff --git a/src/analysis/decomp/decompiler.c b/src/analysis/decomp/decompiler.c
index 1ac177a..c824697 100644
--- a/src/analysis/decomp/decompiler.c
+++ b/src/analysis/decomp/decompiler.c
@@ -217,6 +217,7 @@ GCodeBuffer *decompile_all_from_file(const GLoadedBinary *binary, const char *fi
     build_decomp_prologue(result, filename);
 
 
+    /*
     prepare_all_routines_for_decomp(binary, filename);
 
 
@@ -224,6 +225,7 @@ GCodeBuffer *decompile_all_from_file(const GLoadedBinary *binary, const char *fi
 
     format = g_loaded_binary_get_format(binary);
     g_binary_format_decompile(G_BIN_FORMAT(format), result, filename);
+    */
 
     return result;
 
diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c
index 46dc0d3..2e5c0ee 100644
--- a/src/analysis/disass/macro.c
+++ b/src/analysis/disass/macro.c
@@ -277,6 +277,7 @@ static vmpa_t compute_first_common_addr_in_group(const branch_info *list, size_t
 static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t start, vmpa_t end, vmpa_t stop)
 {
     GInstrBlock *result;                    /* Regroupement à retourner    */
+    GInstrBlock *result_cached;             /* Temporisation pour unicité  */
     branch_info main_branch;                /* Flot d'exécution complet    */
     GArchInstruction *first;                /* Première instruction        */
     GArchInstruction *last;                 /* Dernière instruction        */
@@ -287,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 *group;                     /* Regroupement de blocs       */
     branch_info *cases_branches;            /* Branches d'un aiguillage    */
     size_t cases_count;                     /* Nombre d'aiguillages        */
     branch_info true_branch;                /* Branche 'condition vraie'   */
@@ -298,6 +300,32 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
     vmpa_t stop_addr;                       /* Adresse de fin de bloc      */
 
     result = NULL;
+    result_cached = NULL;
+
+    /**
+     * Procédure d'ajout de blocs : pour le premier, on conserve le bloc en mémoire
+     * et on attend. Si rien ne suit, il constitura l'unique retour. Sinon, on
+     * l'ajoute à partir de la sauvegarde, et le reste suit.
+     */
+#define DELAYED_BLOCK_ADDING(res, cache, blk)                               \
+    do                                                                      \
+    {                                                                       \
+        if (res == NULL)                                                    \
+        {                                                                   \
+            if (cache == NULL)                                              \
+                cache = blk;                                                \
+            else                                                            \
+            {                                                               \
+                res = g_virtual_block_new();                                \
+                g_virtual_block_add_child(G_VIRTUAL_BLOCK(res), cache);     \
+            }                                                               \
+        }                                                                   \
+                                                                            \
+        if (res != NULL)                                                    \
+            g_virtual_block_add_child(G_VIRTUAL_BLOCK(res), blk);           \
+                                                                            \
+    }                                                                       \
+    while (0)
 
     first = NULL;
     last = NULL;
@@ -347,14 +375,13 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
                 case ILT_EXEC_FLOW:
                 case ILT_JUMP:
 
-                    if (result == NULL)
-                        result = g_virtual_block_new();
 
                     block = g_flow_block_new(instrs, first, iter);
                     MACRO_MARK_AS_PROCESSED(first);
-                    g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
                     first = NULL;
 
+                    DELAYED_BLOCK_ADDING(result, result_cached, block);
+
                     g_arch_instruction_get_location(dests[i], NULL, NULL, &next_addr);
 
                     break;
@@ -401,15 +428,14 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
         /* Post-traitements de ILT_CASE_JUMP */
         if (cases_count > 0)
         {
-            if (result == NULL)
-                result = g_virtual_block_new();
-
             if (first != NULL)
             {
                 block = g_flow_block_new(instrs, first, iter);
                 MACRO_MARK_AS_PROCESSED(first);
-                g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
                 first = NULL;
+
+                DELAYED_BLOCK_ADDING(result, result_cached, block);
+
             }
 
             //printf(" --- cases --- start\n");
@@ -417,6 +443,8 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
             next_addr = compute_first_common_addr_in_group(cases_branches, cases_count);
             //printf("    stop :: 0x%08llx\n", next_addr);
 
+            group = g_virtual_block_new();
+
             for (j = 0; j < cases_count; j++)
             {
                 //printf(" ## %zu\n", j);
@@ -425,12 +453,17 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
 
                 if (block != NULL)
 
-                g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+                g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
 
                 free(cases_branches[j].jumps);
 
             }
 
+            if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0)
+                DELAYED_BLOCK_ADDING(result, result_cached, group);
+            else
+                g_object_unref(G_OBJECT(group));
+
             //printf(" --- cases --- end\n");
 
 
@@ -441,15 +474,14 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
         /* Post-traitements de ILT_CATCH_EXCEPTION */
         if (excep_count > 0)
         {
-            if (result == NULL)
-                result = g_virtual_block_new();
-
             if (first != NULL)
             {
                 block = g_flow_block_new(instrs, first, iter);
                 MACRO_MARK_AS_PROCESSED(first);
-                g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
                 first = NULL;
+
+                DELAYED_BLOCK_ADDING(result, result_cached, block);
+
             }
 
             for (j = 0; j < excep_count; j++)
@@ -482,28 +514,30 @@ 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 (result == NULL)
-                result = g_virtual_block_new();
-
             if (first != NULL)
             {
                 block = g_flow_block_new(instrs, first, iter);
                 MACRO_MARK_AS_PROCESSED(first);
-                g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
                 first = NULL;
-            }
 
-            block = build_instruction_block(instrs, true_branch.jumps[0], end, next_addr);
+                DELAYED_BLOCK_ADDING(result, result_cached, block);
 
-                if (block != NULL)
+            }
 
-            g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+            group = g_virtual_block_new();
 
-            block = build_instruction_block(instrs, false_branch.jumps[0], end, next_addr);
+            block = build_instruction_block(instrs, true_branch.jumps[0], end, next_addr);
+            if (block != NULL)
+                g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
 
-                if (block != NULL)
+            block = build_instruction_block(instrs, false_branch.jumps[0], end, next_addr);
+            if (block != NULL)
+                g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
 
-            g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+            if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0)
+                DELAYED_BLOCK_ADDING(result, result_cached, group);
+            else
+                g_object_unref(G_OBJECT(group));
 
             free(true_branch.jumps);
             free(false_branch.jumps);
@@ -526,21 +560,51 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
             MACRO_MARK_AS_PROCESSED(first);
             //printf("--close!--\n");
 
-            if (result == NULL)
-                result = block;
-            else
-                g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+            DELAYED_BLOCK_ADDING(result, result_cached, block);
+
         }
 
     }
 
-    if (result == NULL)
+    if ((result != NULL ? result : result_cached) == NULL)
     {
         //printf("WARNING :: null !\n");
         //exit(0);
     }
 
-    return result;
+    return (result != NULL ? result : result_cached);
+
+}
+
+
+static bool print_blocks(GInstrBlock *blk, BlockVisitOrder order, int *pad)
+{
+    int i;
+    vmpa_t start, end;
+
+    if (order != BVO_OUT)
+        for (i = 0; i < *pad; i++)
+            printf("   ");
+
+    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);
+    }
+    else
+    {
+        if (order != BVO_OUT)
+        {
+            printf(" - virtual %p\n", blk);
+            *pad += 1;
+        }
+        else *pad -= 1;
+
+    }
+
+    fflush(NULL);
+
+    return true;
 
 }
 
@@ -580,6 +644,9 @@ void group_routines_instructions(GArchInstruction *list, GBinRoutine **routines,
         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 });
+
         gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
 
     }
diff --git a/src/decomp/expr/immediate.c b/src/decomp/expr/immediate.c
index a17b2a1..18af422 100644
--- a/src/decomp/expr/immediate.c
+++ b/src/decomp/expr/immediate.c
@@ -122,6 +122,7 @@ GDecInstruction *g_imm_expression_new(GImmOperand *operand)
     result = g_object_new(G_TYPE_IMM_EXPRESSION, NULL);
 
     result->operand = operand;
+    g_object_ref(G_OBJECT(operand));
 
     return G_DEC_INSTRUCTION(result);
 
diff --git a/src/gtkext/graph/layout.c b/src/gtkext/graph/layout.c
index 45e3a82..2cf4a36 100644
--- a/src/gtkext/graph/layout.c
+++ b/src/gtkext/graph/layout.c
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * layout.c - mise en place de graphique
  *
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -33,14 +33,33 @@
 #include "node.h"
 #include "../gtkbufferview.h"
 #include "../../analysis/binary.h"
+#include "../../analysis/blocks/flow.h"
 #include "../../common/extstr.h"
 
 
 
+/* Taille maximale des introductions aux clusters */
+#define CLUSTER_DESC_LEN 128
+
 /* Taille maximale des descriptions de liens */
 #define LINKS_DESC_LEN 128
 
 
+/* Paramètres de construction des commandes */
+typedef struct _visitor_dot_params
+{
+    GGraphNode **nodes;                     /* Intermédiaires en place     */
+    size_t count;                           /* Quantité de noeuds en place */
+
+    unsigned int level;                     /* Profondeur de la visite     */
+    char *cmds;                             /* Description à envoyer à dot */
+
+} visitor_dot_params;
+
+
+/* Construit les commandes pour dot en parcourant les noeuds. */
+static bool register_graph_nodes(GInstrBlock *, BlockVisitOrder, visitor_dot_params *);
+
 /* Etablit tous les liens entre les différents morceaux de code. */
 static char *complete_graph_links(const GtkGraphView *, GtkViewPanel **, size_t, char *);
 
@@ -60,47 +79,118 @@ static char *complete_graph_links(const GtkGraphView *, GtkViewPanel **, size_t,
 *                                                                             *
 ******************************************************************************/
 
-bool build_graph_view(GtkGraphView *view, GtkViewPanel **views, size_t count)
+bool build_graph_view(GtkGraphView *view, GInstrBlock *blocks, GtkViewPanel **views, size_t count)
 {
-    GGraphNode **nodes;                     /* Intermédiaires en place     */
+    visitor_dot_params params;              /* Paramètres de construction  */
     size_t i;                               /* Boucle de parcours          */
-    char *cmds;                             /* Description à envoyer à dot */
     graph_layout *layout;                   /* Graphique construit         */
     GtkLinkRenderer **links;                /* Liens graphiques construits */
     size_t links_count;                     /* Quantité de ces liens       */
 
     /* Création de la glue */
 
-    nodes = (GGraphNode **)calloc(count, sizeof(GGraphNode *));
+    params.nodes = (GGraphNode **)calloc(count, sizeof(GGraphNode *));
+    params.count = count;
 
     for (i = 0; i < count; i++)
-        nodes[i] = g_graph_node_new(GTK_WIDGET(views[i]));
+        params.nodes[i] = g_graph_node_new(GTK_WIDGET(views[i]));
  
     /* Définition du graphique */
 
-    cmds = strdup("digraph G {\n  overlap=false;\n  splines=ortho;\n  compound=true;\n");
+    params.level = 1;
+    params.cmds = strdup("digraph G {\n  overlap=false;\n  splines=ortho;\n  compound=true;\n");
 
-    for (i = 0; i < count; i++)
-        cmds = g_graph_node_register_for_dot(nodes[i], cmds);
+    g_instr_block_visit(blocks, (instr_block_visitor_cb)register_graph_nodes, &params);
 
-    cmds = complete_graph_links(view, views, count, cmds);
+    params.cmds = complete_graph_links(view, views, count, params.cmds);
 
-    cmds = stradd(cmds, "}");
+    params.cmds = stradd(params.cmds, "}");
 
-    layout = create_graph_layout(cmds);
+    layout = create_graph_layout(params.cmds);
 
     /* Affichage du graphique */
 
-    place_nodes_of_graph_layout(layout, view,  nodes, count);
+    place_nodes_of_graph_layout(layout, view,  params.nodes, count);
 
-    links = create_links_from_graph_layout(layout, &links_count,  nodes, count);
+    links = create_links_from_graph_layout(layout, &links_count,  params.nodes, count);
     gtk_graph_view_attach_links(view, links, links_count);
 
     gtk_widget_queue_draw(GTK_WIDGET(view));
 
     delete_graph_layout(layout);
 
-    /* TODO : free nodes */
+    for (i = 0; i < count; i++)
+        g_object_unref(params.nodes[i]);
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : block  = bloc d'instructions concerné par la visite.         *
+*                order  = position dans la visite.                            *
+*                params = informations à mettre à jour pour dot.              *
+*                                                                             *
+*  Description : Construit les commandes pour dot en parcourant les noeuds.   *
+*                                                                             *
+*  Retour      : true si le parcours a été jusqu'à son terme, false sinon.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool register_graph_nodes(GInstrBlock *block, BlockVisitOrder order, visitor_dot_params *params)
+{
+    char *cmds;                             /* Raccourci d'usage pratique  */
+    vmpa_t start;                           /* Adresse de départ d'un bloc */
+    GGraphNode *node;                       /* Noeud rattaché              */
+    unsigned int i;                         /* Boucle de parcours          */
+    char buffer[CLUSTER_DESC_LEN];          /* Tampon pour les commandes   */
+
+    cmds = params->cmds;
+
+    if (G_IS_FLOW_BLOCK(block))
+    {
+        g_flow_block_get_boundary_addresses(G_FLOW_BLOCK(block), &start, NULL);
+        node = find_graph_node_by_start_address(params->nodes, params->count, start);
+
+        cmds = g_graph_node_register_for_dot(node, cmds, params->level);
+
+    }
+    else
+    {
+        if (order == BVO_IN)
+        {
+            for (i = 0; i < params->level; i++)
+                cmds = stradd(cmds, DOT_IDENT);
+
+            snprintf(buffer, CLUSTER_DESC_LEN, "subgraph cluster_v%p {\n", block);
+            cmds = stradd(cmds, buffer);
+
+            params->level++;
+
+            for (i = 0; i < params->level; i++)
+                cmds = stradd(cmds, DOT_IDENT);
+
+            cmds = stradd(cmds, "style=invisible;\n");
+
+        }
+        else if (order == BVO_OUT)
+        {
+            params->level--;
+
+            for (i = 0; i < params->level; i++)
+                cmds = stradd(cmds, DOT_IDENT);
+
+            cmds = stradd(cmds, "}\n");
+
+        }
+
+    }
+
+    params->cmds = cmds;
 
     return true;
 
diff --git a/src/gtkext/graph/layout.h b/src/gtkext/graph/layout.h
index ffb227f..7a3bf1e 100644
--- a/src/gtkext/graph/layout.h
+++ b/src/gtkext/graph/layout.h
@@ -34,7 +34,7 @@
 
 
 /* Dispose une série de morceaux d'affichage en graphique. */
-bool build_graph_view(GtkGraphView *, GtkViewPanel **, size_t);
+bool build_graph_view(GtkGraphView *, GInstrBlock *, GtkViewPanel **, size_t);
 
 
 
diff --git a/src/gtkext/graph/node.c b/src/gtkext/graph/node.c
index 0d746e2..d9b0eca 100644
--- a/src/gtkext/graph/node.c
+++ b/src/gtkext/graph/node.c
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * node.c - éléments de graphiques chez dot
  *
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -29,6 +29,7 @@
 #include <string.h>
 
 
+#include "../gtkbufferview.h"
 #include "../../common/extstr.h"
 
 
@@ -60,6 +61,10 @@ struct _GGraphNodeClass
 };
 
 
+/* Taille maximale des lignes de description de noeud */
+#define NODE_DESC_LEN 128
+
+
 /* Initialise la classe des intermédiaires avec les noeuds dot. */
 static void g_graph_node_class_init(GGraphNodeClass *);
 
@@ -184,8 +189,9 @@ GGraphNode *g_graph_node_new(GtkWidget *view)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node = intermédiaire à consulter.                            *
-*                cmds = description pour dot à compléter.                     *
+*  Paramètres  : node  = intermédiaire à consulter.                           *
+*                cmds  = description pour dot à compléter.                    *
+*                level = profondeur du noeud pour l'indentation.              *
 *                                                                             *
 *  Description : Déclare l'intermédiaire en tant que noeud pour dot.          *
 *                                                                             *
@@ -195,33 +201,45 @@ GGraphNode *g_graph_node_new(GtkWidget *view)
 *                                                                             *
 ******************************************************************************/
 
-char *g_graph_node_register_for_dot(const GGraphNode *node, char *cmds)
+char *g_graph_node_register_for_dot(const GGraphNode *node, char *cmds, unsigned int level)
 {
     GtkRequisition requisition;             /* Taille à l'écran requise    */
-    char buffer[128];
+    unsigned int i;                         /* Boucle de parcours          */
+    char buffer[NODE_DESC_LEN];             /* Tampon pour les commandes   */
 
     gtk_widget_size_request(node->view, &requisition);
 
-    snprintf(buffer, 128, "  subgraph cluster%s {\n", node->name);
+    for (i = 0; i < level; i++)
+        cmds = stradd(cmds, DOT_IDENT);
+
+    snprintf(buffer, NODE_DESC_LEN, "subgraph cluster%s {\n", node->name);
     cmds = stradd(cmds, buffer);
 
-    cmds = stradd(cmds, "    style=invisible;\n");
+    for (i = 0; i < (level + 1); i++)
+        cmds = stradd(cmds, DOT_IDENT);
+
+    cmds = stradd(cmds, "style=invisible;\n");
+
+    for (i = 0; i < (level + 1); i++)
+        cmds = stradd(cmds, DOT_IDENT);
 
-    cmds = stradd(cmds, "    ");
     cmds = stradd(cmds, node->name);
     cmds = stradd(cmds, " [shape=box, fixedsize ");
 
-    snprintf(buffer, 128, ", width=\"%g\"",
+    snprintf(buffer, NODE_DESC_LEN, ", width=\"%g\"",
              requisition.width / G_GRAPH_NODE_GET_CLASS(node)->dpi_x);
     cmds = stradd(cmds, buffer);
 
-    snprintf(buffer, 128, ", height=\"%g\"",
+    snprintf(buffer, NODE_DESC_LEN, ", height=\"%g\"",
              requisition.height / G_GRAPH_NODE_GET_CLASS(node)->dpi_y);
     cmds = stradd(cmds, buffer);
 
     cmds = stradd(cmds, "];\n");
 
-    cmds = stradd(cmds, "  }\n");
+    for (i = 0; i < level; i++)
+        cmds = stradd(cmds, DOT_IDENT);
+
+    cmds = stradd(cmds, "}\n");
 
     return cmds;
 
@@ -327,6 +345,44 @@ void g_graph_node_connect(const GGraphNode *node, gint x, gint y, GdkPoint **poi
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : nodes = liste de noeuds à parcourir.                         *
+*                count = taille de la liste.                                  *
+*                addrt = adresse de début du noeud recherché.                 *
+*                                                                             *
+*  Description : Recherche un noeud donné dans une série de noeuds.           *
+*                                                                             *
+*  Retour      : Noeud trouvé ou NULL si aucun.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GGraphNode *find_graph_node_by_start_address(GGraphNode **nodes, size_t count, vmpa_t addr)
+{
+    GGraphNode *result;                     /* Trouvaille à remonter       */
+    size_t i;                               /* Boucle de parcours          */
+    GBufferView *buffer;                    /* Tampon d'une partie de code */
+    vmpa_t start;                           /* Adresse de départ du tampon */
+
+    result = NULL;
+
+    for (i = 0; i < count && result == NULL; i++)
+    {
+        buffer = gtk_buffer_view_get_buffer(GTK_BUFFER_VIEW(nodes[i]->view));
+        g_buffer_view_get_restrictions(buffer, &start, NULL);
+
+        if (start == addr)
+            result = nodes[i];
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : nodes  = liste de noeuds à parcourir.                        *
 *                count  = taille de la liste.                                 *
 *                target = nom du noeud recherché.                             *
diff --git a/src/gtkext/graph/node.h b/src/gtkext/graph/node.h
index 515c92b..57d0932 100644
--- a/src/gtkext/graph/node.h
+++ b/src/gtkext/graph/node.h
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * node.h - prototypes pour les éléments de graphiques chez dot
  *
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -26,6 +26,12 @@
 
 
 #include "../gtkgraphview.h"
+#include "../../arch/archbase.h"
+
+
+
+/* Indentation pour l'édition des commandes */
+#define DOT_IDENT "   "
 
 
 
@@ -53,7 +59,7 @@ GType g_graph_node_get_type(void);
 GGraphNode *g_graph_node_new(GtkWidget *);
 
 /* Déclare l'intermédiaire en tant que noeud pour dot. */
-char *g_graph_node_register_for_dot(const GGraphNode *, char *);
+char *g_graph_node_register_for_dot(const GGraphNode *, char *, unsigned int);
 
 /* Place le morceau de code de l'intermédiaire à l'écran. */
 void g_graph_node_place(GGraphNode *, GtkGraphView *, gint , gint);
@@ -67,6 +73,9 @@ void g_graph_node_connect(const GGraphNode *, gint, gint, GdkPoint **, size_t *)
 
 
 /* Recherche un noeud donné dans une série de noeuds. */
+GGraphNode *find_graph_node_by_start_address(GGraphNode **, size_t, vmpa_t);
+
+/* Recherche un noeud donné dans une série de noeuds. */
 GGraphNode *find_graph_node_by_name(GGraphNode **, size_t, const char *);
 
 
diff --git a/src/gtkext/gtkgraphview.c b/src/gtkext/gtkgraphview.c
index 67fb577..6aedf26 100644
--- a/src/gtkext/gtkgraphview.c
+++ b/src/gtkext/gtkgraphview.c
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * gtkgraphview.c - affichage de morceaux de code sous forme graphique
  *
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -39,8 +39,9 @@ struct _GtkGraphView
     GtkViewPanel parent;                    /* A laisser en premier        */
     GtkFixed *support;                      /* Support des vues en bloc    */
 
-    vmpa_t start;                           /* Début de la portion vue     */
-    vmpa_t end;                             /* Fin de la portion affichée  */
+    GBinRoutine *routine;                   /* Routine en cours d'affichage*/
+    vmpa_t start;                           /* Début de la portion vue     */ /* FIXME : à garder ? */
+    vmpa_t end;                             /* Fin de la portion affichée  */ /* FIXME : à garder ? */
 
     GtkViewPanel **children;                /* Liste des sous-blocs        */
     GtkAllocation *allocs;                  /* Emplacements prévisibles    */
@@ -380,6 +381,9 @@ static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr)
 
             if (start <= addr && addr < end)
             {
+                view->routine = routines[i];
+                g_object_ref(G_OBJECT(view->routine));
+
                 view->start = start;
                 view->end = end;
 
@@ -389,7 +393,8 @@ static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr)
                 view->allocs = (GtkAllocation *)calloc(view->children_count,
                                                        sizeof(GtkAllocation));
 
-                build_graph_view(view, view->children, view->children_count);
+                build_graph_view(view, g_binary_routine_get_basic_blocks(view->routine),
+                                 view->children, view->children_count);
 
                 break;
 
@@ -425,7 +430,8 @@ static void gtk_graph_view_prepare_resize(GtkGraphView *view)
         for (i = 0; i < view->children_count; i++)
             gtk_widget_queue_resize(GTK_WIDGET(view->children[i]));
 
-        build_graph_view(view, view->children, view->children_count);
+        build_graph_view(view, g_binary_routine_get_basic_blocks(view->routine),
+                         view->children, view->children_count);
 
         change_editor_items_current_view_content(GTK_VIEW_PANEL(view));
 
-- 
cgit v0.11.2-87-g4458