From f80c4c6ee0479070f7319a5ce7e30e05406cdb8f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 3 Apr 2016 14:48:41 +0200
Subject: Reorganized the whole disassembling process and displayed the
 relative progression.

---
 ChangeLog                          |  44 ++++
 src/analysis/disass/Makefile.am    |   1 +
 src/analysis/disass/area.c         |  34 +--
 src/analysis/disass/area.h         |   6 +-
 src/analysis/disass/disassembler.c | 421 ++++++++++++++-----------------------
 src/analysis/disass/fetch.c        |  49 ++---
 src/analysis/disass/fetch.h        |   4 +-
 src/analysis/disass/instructions.c | 312 +++++++++++++++++++++++++++
 src/analysis/disass/instructions.h |  68 ++++++
 src/analysis/disass/limit.c        | 355 +++----------------------------
 src/analysis/disass/limit.h        |   9 +-
 src/analysis/disass/links.c        |  54 +----
 src/analysis/disass/links.h        |  15 +-
 src/analysis/disass/routines.c     |  89 +++++---
 src/analysis/disass/routines.h     |  12 +-
 src/arch/arm/v7/post.c             |  12 ++
 src/arch/instruction.h             |   3 +-
 src/arch/processor.c               |  52 +++++
 src/arch/processor.h               |   6 +
 src/gtkext/gtkstatusstack.c        |  49 +++--
 src/gtkext/gtkstatusstack.h        |   6 +-
 src/main.c                         |  21 +-
 22 files changed, 866 insertions(+), 756 deletions(-)
 create mode 100644 src/analysis/disass/instructions.c
 create mode 100644 src/analysis/disass/instructions.h

diff --git a/ChangeLog b/ChangeLog
index 6b45152..067a186 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+16-04-03  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/disass/Makefile.am:
+	Add the 'instructions.[ch]' files to libanalysisdisass_la_SOURCES.
+
+	* src/analysis/disass/area.c:
+	* src/analysis/disass/area.h:
+	Update code.
+
+	* src/analysis/disass/disassembler.c:
+	Update code. Reorganize the whole disassembling process and display
+	the relative progression.
+
+	* src/analysis/disass/fetch.c:
+	* src/analysis/disass/fetch.h:
+	Update code.
+
+	* src/analysis/disass/instructions.c:
+	* src/analysis/disass/instructions.h:
+	New entries: handle all instructions disassembling processing in one place.
+
+	* src/analysis/disass/limit.c:
+	* src/analysis/disass/limit.h:
+	* src/analysis/disass/links.c:
+	* src/analysis/disass/links.h:
+	* src/analysis/disass/routines.c:
+	* src/analysis/disass/routines.h:
+	Update code.
+
+	* src/arch/instruction.h:
+	The g_arch_instruction_find_by_address() function is slow and should not
+	be used anymore.
+
+	* src/arch/processor.c:
+	* src/arch/processor.h:
+	Provide direct access to collected instructions.
+
+	* src/gtkext/gtkstatusstack.c:
+	* src/gtkext/gtkstatusstack.h:
+	Track the progression of an activity in a more clever way.
+
+	* src/main.c:
+	Ensure the main window is shown as soon as possible.
+
 16-04-02  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/blocks/flow.c:
diff --git a/src/analysis/disass/Makefile.am b/src/analysis/disass/Makefile.am
index e901570..7223e5a 100644
--- a/src/analysis/disass/Makefile.am
+++ b/src/analysis/disass/Makefile.am
@@ -6,6 +6,7 @@ libanalysisdisass_la_SOURCES =			\
 	disassembler.h disassembler.c		\
 	dragon.h dragon.c					\
 	fetch.h fetch.c						\
+	instructions.h instructions.c		\
 	limit.h limit.c						\
 	links.h links.c						\
 	loop.h loop.c						\
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c
index 5f63c82..c1807b7 100644
--- a/src/analysis/disass/area.c
+++ b/src/analysis/disass/area.c
@@ -77,10 +77,10 @@ static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *, GArchInstructi
 
 
 /* Procède au désassemblage d'un contenu binaire non exécutable. */
-static void load_data_from_mem_area_v2(mem_area_v2 *, GProcContext *, const vmpa2t *, status_blob_info *);
+static void load_data_from_mem_area_v2(mem_area_v2 *, GProcContext *, const vmpa2t *, GtkStatusStack *, activity_id_t);
 
 /* S'assure qu'une aire contient toutes ses instructions. */
-static void fill_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, status_blob_info *);
+static void fill_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, GtkStatusStack *, activity_id_t);
 
 /* Rassemble les instructions conservées dans une zone donnée. */
 static GArchInstruction *get_instructions_from_mem_area_v2(const mem_area_v2 *);
@@ -280,7 +280,8 @@ static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *area, GArchInstr
 *                binary = représentation de binaire chargé.                   *
 *                ctx    = contexte offert en soutien à un désassemblage.      *
 *                start  = démarrage de l'exécution au sein de la zone.        *
-*                info   = indications quant à la progression à afficher.      *
+*                status = barre de statut à actualiser.                       *
+*                id     = identifiant du groupe de progression à l'affichage. *
 *                                                                             *
 *  Description : Procède au désassemblage d'un contenu binaire exécutable.    *
 *                                                                             *
@@ -290,7 +291,7 @@ static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *area, GArchInstr
 *                                                                             *
 ******************************************************************************/
 
-void load_code_from_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, const vmpa2t *start, status_blob_info *info)
+void load_code_from_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, const vmpa2t *start, GtkStatusStack *status, activity_id_t id)
 {
 
 
@@ -381,7 +382,7 @@ void load_code_from_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t cou
             break;
         }
 
-        inc_progessive_status(info, diff);
+        gtk_status_stack_update_activity_value(status, id, diff);
 
         assert(!is_range_blank_in_mem_area_v2(area, i, diff));
 
@@ -421,7 +422,8 @@ void load_code_from_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t cou
 *  Paramètres  : area   = aire représentant à contenu à parcourir.            *
 *                ctx    = contexte offert en soutien à un désassemblage.      *
 *                start  = démarrage de l'exécution au sein de la zone.        *
-*                info   = indications quant à la progression à afficher.      *
+*                status = barre de statut à actualiser.                       *
+*                id     = identifiant du groupe de progression à l'affichage. *
 *                                                                             *
 *  Description : Procède au désassemblage d'un contenu binaire non exécutable.*
 *                                                                             *
@@ -431,7 +433,7 @@ void load_code_from_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t cou
 *                                                                             *
 ******************************************************************************/
 
-static void load_data_from_mem_area_v2(mem_area_v2 *area, GProcContext *ctx, const vmpa2t *start, status_blob_info *info)
+static void load_data_from_mem_area_v2(mem_area_v2 *area, GProcContext *ctx, const vmpa2t *start, GtkStatusStack *status, activity_id_t id)
 {
     GBinContent *content;                   /* Données binaires à lire     */
     SourceEndian endianness;                /* Boutisme de cette machine   */
@@ -511,7 +513,7 @@ static void load_data_from_mem_area_v2(mem_area_v2 *area, GProcContext *ctx, con
             break;
         }
 
-        inc_progessive_status(info, diff);
+        gtk_status_stack_update_activity_value(status, id, diff);
 
         assert(!is_range_blank_in_mem_area_v2(area, i, diff));
 
@@ -531,7 +533,8 @@ static void load_data_from_mem_area_v2(mem_area_v2 *area, GProcContext *ctx, con
 *                count  = nombre de zones à disposition.                      *
 *                binary = représentation de binaire chargé.                   *
 *                ctx    = contexte offert en soutien à un désassemblage.      *
-*                info   = indications quant à la progression à afficher.      *
+*                status = barre de statut à actualiser.                       *
+*                id     = identifiant du groupe de progression à l'affichage. *
 *                                                                             *
 *  Description : S'assure qu'une aire contient toutes ses instructions.       *
 *                                                                             *
@@ -541,7 +544,7 @@ static void load_data_from_mem_area_v2(mem_area_v2 *area, GProcContext *ctx, con
 *                                                                             *
 ******************************************************************************/
 
-static void fill_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, status_blob_info *info)
+static void fill_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, GtkStatusStack *status, activity_id_t id)
 {
     const vmpa2t *addr;                     /* Début de la zone à traiter  */
     phys_t len;                             /* Taille de la zone à remplir */
@@ -559,10 +562,10 @@ static void fill_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count,
             advance_vmpa(&start, i);
 
             if (area->is_exec && get_virt_addr(&start) % area->packing_size == 0)
-                load_code_from_mem_area_v2(area, list, count, ctx, &start, info);
+                load_code_from_mem_area_v2(area, list, count, ctx, &start, status, id);
 
             if (is_range_blank_in_mem_area_v2(area, i, 1))
-                load_data_from_mem_area_v2(area, ctx, &start, info);
+                load_data_from_mem_area_v2(area, ctx, &start, status, id);
 
         }
 
@@ -1039,7 +1042,8 @@ void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *areas, size_t count, con
 *                count  = nombre de zones à disposition.                      *
 *                binary = représentation de binaire chargé.                   *
 *                ctx    = contexte offert en soutien à un désassemblage.      *
-*                info   = indications quant à la progression à afficher.      *
+*                status = barre de statut à actualiser.                       *
+*                id     = identifiant du groupe de progression à l'affichage. *
 *                                                                             *
 *  Description : S'assure que l'ensemble des aires est entièrement décodé.    *
 *                                                                             *
@@ -1049,12 +1053,12 @@ void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *areas, size_t count, con
 *                                                                             *
 ******************************************************************************/
 
-void ensure_all_mem_areas_are_filled(mem_area_v2 *list, size_t count, GProcContext *ctx, status_blob_info *info)
+void ensure_all_mem_areas_are_filled(mem_area_v2 *list, size_t count, GProcContext *ctx, GtkStatusStack *status, activity_id_t id)
 {
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < count; i++)
-        fill_mem_area_v2(&list[i], list, count, ctx, info);
+        fill_mem_area_v2(&list[i], list, count, ctx, status, id);
 
 }
 
diff --git a/src/analysis/disass/area.h b/src/analysis/disass/area.h
index aa26da0..3ffdbc5 100644
--- a/src/analysis/disass/area.h
+++ b/src/analysis/disass/area.h
@@ -27,7 +27,7 @@
 
 #include "../binary.h"
 #include "../../arch/instruction.h"
-#include "../../gtkext/gtkextstatusbar.h"
+#include "../../gtkext/gtkstatusstack.h"
 
 
 
@@ -40,7 +40,7 @@ typedef struct _mem_area_v2 mem_area_v2;
 
 
 /* Procède au désassemblage d'un contenu binaire exécutable. */
-void load_code_from_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, const vmpa2t *, status_blob_info *);
+void load_code_from_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, const vmpa2t *, GtkStatusStack *, activity_id_t);
 
 
 
@@ -57,7 +57,7 @@ mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *, phys_t, size_t *);
 void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *, size_t, const GBinSymbol *);
 
 /* S'assure que l'ensemble des aires est entièrement décodé. */
-void ensure_all_mem_areas_are_filled(mem_area_v2 *, size_t, GProcContext *, status_blob_info *);
+void ensure_all_mem_areas_are_filled(mem_area_v2 *, size_t, GProcContext *, GtkStatusStack *, activity_id_t);
 
 /* Rassemble les instructions conservées dans des zones données. */
 GArchInstruction *collect_instructions_from_mem_areas_v2(const mem_area_v2 *, size_t);
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index 4e6a13c..5bd9d43 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -33,12 +33,9 @@
 
 
 #include "fetch.h"
-#include "limit.h"
-#include "links.h"
-#include "loop.h"
-#include "macro.h"
 #include "output.h"
-#include "rank.h"
+
+#include "instructions.h"
 #include "routines.h"
 #include "../../decomp/lang/asm.h"
 #include "../../format/format.h"
@@ -81,8 +78,14 @@ static void g_delayed_disassembly_init(GDelayedDisassembly *);
 /* Crée une tâche de désassemblage différé. */
 static GDelayedDisassembly *g_delayed_disassembly_new(GLoadedBinary *, GArchInstruction **, GCodeBuffer *);
 
+/* Opère sur toutes les instructions. */
+static void process_all_instructions(wgroup_id_t, GtkStatusStack *, const char *, ins_fallback_cb, GArchProcessor *, GExeFormat *);
+
+/* Opère sur toutes les routines. */
+static void process_all_routines(wgroup_id_t, GtkStatusStack *, const char *, rtn_fallback_cb, GArchProcessor *, GExeFormat *);
+
 /* Assure le désassemblage en différé. */
-static void g_delayed_disassembly_process(GDelayedDisassembly *, GtkExtStatusBar *);
+static void g_delayed_disassembly_process(GDelayedDisassembly *, GtkStatusStack *);
 
 
 
@@ -178,10 +181,14 @@ static GDelayedDisassembly *g_delayed_disassembly_new(GLoadedBinary *binary, GAr
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : disass    = analyse à mener.                                 *
-*                statusbar = barre de statut à tenir informée.                *
+*  Paramètres  : gid      = groupe de travail impliqué.                       *
+                 status   = barre de statut à tenir informée.                 *
+*                msg      = message à faire paraître pour la patience.        *
+*                fallback = routine de traitements particuliers.              *
+*                proc     = ensemble d'instructions désassemblées.            *
+*                format   = accès aux données du binaire d'origine.           *
 *                                                                             *
-*  Description : Assure le désassemblage en différé.                          *
+*  Description : Opère sur toutes les instructions.                           *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -189,129 +196,204 @@ static GDelayedDisassembly *g_delayed_disassembly_new(GLoadedBinary *binary, GAr
 *                                                                             *
 ******************************************************************************/
 
-static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtStatusBar *statusbar)
+static void process_all_instructions(wgroup_id_t gid, GtkStatusStack *status, const char *msg, ins_fallback_cb fallback, GArchProcessor *proc, GExeFormat *format)
 {
-    wgroup_id_t gid;                        /* Identifiant pour les tâches */
+    guint runs_count;                       /* Qté d'exécutions parallèles */
+    size_t ins_count;                       /* Quantité d'instructions     */
+    size_t run_size;                        /* Volume réparti par exécution*/
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    activity_id_t id;                       /* Identifiant de progression  */
+    guint i;                                /* Boucle de parcours          */
+    size_t begin;                           /* Début de bloc de traitement */
+    size_t end;                             /* Fin d'un bloc de traitement */
+    GInstructionsStudy *study;              /* Tâche d'étude à programmer  */
 
-    //GBinFormat *format;                     /* Format du fichier binaire   */
-    GArchProcessor *proc;                   /* Architecture du binaire     */
+    runs_count = g_get_num_processors();
 
+    ins_count = g_arch_processor_count_disassembled_instructions(proc);
 
-    //size_t i;                               /* Boucle de parcours          */
+    run_size = ins_count / runs_count;
 
-    GBinRoutine **routines;                 /* Liste des routines trouvées */
-    size_t routines_count;                  /* Nombre de ces routines      */
-    activity_id_t id;                        /* Identifiant de statut       */
+    queue = get_work_queue();
 
+    id = gtk_status_stack_add_activity(status, msg, ins_count);
 
-    //GArchProcessor *proc;                   /* Architecture du binaire     */
+    for (i = 0; i < runs_count; i++)
+    {
+        begin = i * run_size;
 
+        if ((i + 1) == runs_count)
+            end = ins_count;
+        else
+            end = begin + run_size;
 
+        study = g_instructions_study_new(proc, G_BIN_FORMAT(format), begin, end, id, fallback);
 
-    gid = g_work_queue_define_work_group(get_work_queue());
+        g_work_queue_schedule_work(queue, G_DELAYED_WORK(study), gid);
 
+    }
 
+    g_work_queue_wait_for_completion(queue, gid);
 
+    gtk_status_stack_remove_activity(status, id);
 
+}
 
-    //format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
-    proc = g_loaded_binary_get_processor(disass->binary);
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : gid      = groupe de travail impliqué.                       *
+                 status   = barre de statut à tenir informée.                 *
+*                msg      = message à faire paraître pour la patience.        *
+*                fallback = routine de traitements particuliers.              *
+*                proc     = ensemble d'instructions désassemblées.            *
+*                format   = accès aux données du binaire d'origine.           *
+*                                                                             *
+*  Description : Opère sur toutes les routines.                               *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->format), &routines_count);
+static void process_all_routines(wgroup_id_t gid, GtkStatusStack *status, const char *msg, rtn_fallback_cb fallback, GArchProcessor *proc, GExeFormat *format)
+{
+    mrange_t *exe_ranges;                   /* Liste de zones exécutables  */
+    size_t exe_count;                       /* Nombre de ces zones         */
+    GBinRoutine **routines;                 /* Liste des routines trouvées */
+    size_t routines_count;                  /* Nombre de ces routines      */
+    guint runs_count;                       /* Qté d'exécutions parallèles */
+    size_t run_size;                        /* Volume réparti par exécution*/
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    activity_id_t id;                       /* Identifiant de progression  */
+    guint i;                                /* Boucle de parcours          */
+    size_t begin;                           /* Début de bloc de traitement */
+    size_t end;                             /* Fin d'un bloc de traitement */
+    GRoutinesStudy *study;                  /* Tâche d'étude à programmer  */
 
+    exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);
 
-    /* Première étape */
+    routines = g_binary_format_get_routines(G_BIN_FORMAT(format), &routines_count);
 
-    //id = gtk_extended_status_bar_push(statusbar, _("Disassembling..."), true);
+    runs_count = g_get_num_processors();
 
+    run_size = routines_count / runs_count;
 
+    queue = get_work_queue();
 
-    process_disassembly_event(PGA_DISASSEMBLY_STARTED, disass->binary);
+    id = gtk_status_stack_add_activity(status, msg, routines_count);
 
+    for (i = 0; i < runs_count; i++)
+    {
+        begin = i * run_size;
 
+        if ((i + 1) == runs_count)
+            end = routines_count;
+        else
+            end = begin + run_size;
 
-    *disass->instrs = disassemble_binary_content(disass->binary, gid, statusbar);
+        study = g_routines_study_new(proc, exe_ranges, exe_count, routines, routines_count,
+                                     begin, end, id, fallback);
 
+        g_work_queue_schedule_work(queue, G_DELAYED_WORK(study), gid);
 
-    g_arch_processor_set_disassembled_instructions(proc, *disass->instrs);
+    }
 
+    g_work_queue_wait_for_completion(queue, gid);
 
-    // plugins //////////////////////////
-    process_disassembly_event(PGA_DISASSEMBLY_RAW, disass->binary);
+    gtk_status_stack_remove_activity(status, id);
 
+    if (exe_ranges != NULL)
+        free(exe_ranges);
 
+}
 
-    /*
-    *disass->instrs = disassemble_binary_parts(disass->binary, disass->parts, disass->count,
-                                               statusbar, id);
-    */
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : disass = analyse à mener.                                    *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Assure le désassemblage en différé.                          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
+static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkStatusStack *status)
+{
+    wgroup_id_t gid;                        /* Identifiant pour les tâches */
 
+    //GBinFormat *format;                     /* Format du fichier binaire   */
+    GArchProcessor *proc;                   /* Architecture du binaire     */
 
 
-    do
-    {
-        GBinFormat *format;                     /* Format du fichier binaire   */
-        GArchInstruction *iter;                 /* Boucle de parcours          */
+    //size_t i;                               /* Boucle de parcours          */
+
+    GBinRoutine **routines;                 /* Liste des routines trouvées */
+    size_t routines_count;                  /* Nombre de ces routines      */
+
 
 
 
-        format = G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary));
 
-        for (iter = *disass->instrs;
-             iter != NULL;
-             iter = g_arch_instruction_get_next_iter(*disass->instrs, iter, 0))
-        {
 
-            g_arch_instruction_call_hook(iter, IPH_LINK, proc, /*ctx*/NULL, format);
+    gid = g_work_queue_define_work_group(get_work_queue());
 
 
 
-        }
 
 
+    //format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+    proc = g_loaded_binary_get_processor(disass->binary);
 
-    } while (0);
 
+    routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->format), &routines_count);
 
 
-    // plugins //////////////////////////
-    process_disassembly_event(PGA_DISASSEMBLY_HOOKED_LINK, disass->binary);
+    /* Première étape */
 
+    //id = gtk_extended_status_bar_push(statusbar, _("Disassembling..."), true);
 
 
-    //gtk_extended_status_bar_remove(statusbar, id);
 
+    process_disassembly_event(PGA_DISASSEMBLY_STARTED, disass->binary);
 
-    //run_plugins_on_binary(disass->binary, PGA_BINARY_DISASSEMBLED, true);
 
 
-    do
-    {
-        GBinFormat *format;                     /* Format du fichier binaire   */
-        GArchInstruction *iter;                 /* Boucle de parcours          */
+    *disass->instrs = disassemble_binary_content(disass->binary, gid, status);
 
 
+    g_arch_processor_set_disassembled_instructions(proc, *disass->instrs);
 
-        format = G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary));
 
-        for (iter = *disass->instrs;
-             iter != NULL;
-             iter = g_arch_instruction_get_next_iter(*disass->instrs, iter, 0))
-        {
+    // plugins //////////////////////////
+    process_disassembly_event(PGA_DISASSEMBLY_RAW, disass->binary);
 
-            g_arch_instruction_call_hook(iter, IPH_POST, proc, /*ctx*/NULL, format);
 
 
+    process_all_instructions(gid, status, _("Calling 'link' hook on all instructions..."),
+                             g_instructions_study_do_link_operation,
+                             proc, disass->format);
 
-        }
+
+    // plugins //////////////////////////
+    process_disassembly_event(PGA_DISASSEMBLY_HOOKED_LINK, disass->binary);
+
+
+
+    //gtk_extended_status_bar_remove(statusbar, id);
 
 
+    //run_plugins_on_binary(disass->binary, PGA_BINARY_DISASSEMBLED, true);
 
-    } while (0);
 
+    process_all_instructions(gid, status, _("Calling 'post' hook on all instructions..."),
+                             g_instructions_study_do_post_operation,
+                             proc, disass->format);
 
 
 
@@ -332,17 +414,13 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta
     routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->format), &routines_count);
 
 
-
-
-    id = gtk_extended_status_bar_push(statusbar, _("Finding remaining limits..."), true);
-
     //qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare);
 
-    limit_all_routines(disass->format, proc, routines, routines_count, gid, 0/*id*/);
 
-    gtk_extended_status_bar_remove(statusbar, 0/*id*/);
 
-    //run_plugins_on_binary(disass->binary, PGA_BINARY_BOUNDED, true);
+    process_all_routines(gid, status,
+                         _("Finding remaining limits..."),
+                         g_routines_study_compute_limits, proc, disass->format);
 
 
 
@@ -353,24 +431,9 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta
 
     /* Troisième étape */
 
-    id = gtk_extended_status_bar_push(statusbar, _("Establishing links..."), true);
-
-
-    /**
-     *
-     * Lequel choisir ???
-
-G_BIN_FORMAT(disass->format)
-G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
-
-     */
-
-
-    establish_links_between_instructions(*disass->instrs, G_BIN_FORMAT(disass->format), statusbar, 0/*id*/);
-
-    gtk_extended_status_bar_remove(statusbar, 0/*id*/);
-
-    //run_plugins_on_binary(disass->binary, PGA_BINARY_LINKED, true);
+    process_all_instructions(gid, status, _("Establishing links betweek all instructions..."),
+                             g_instructions_study_do_link_operation,
+                             proc, disass->format);
 
 
 
@@ -408,58 +471,11 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
 
     // Control-flow analysis...
 
-
-
-
-
-
-
-
-    mrange_t *exe_ranges;                   /* Liste de zones exécutables  */
-    size_t exe_count;                       /* Nombre de ces zones         */
-    guint runs_count;                       /* Qté d'exécutions parallèles */
-    size_t run_size;                        /* Volume réparti par exécution*/
-    GWorkQueue *queue;                      /* Gestionnaire de différés    */
-    guint i;                                /* Boucle de parcours          */
-    size_t begin;                           /* Début de bloc de traitement */
-    size_t end;                             /* Fin d'un bloc de traitement */
-    GRoutinesStudy *study;                  /* Tâche d'étude à programmer  */
-
-    exe_ranges = g_exe_format_get_x_ranges(disass->format, &exe_count);
-
-    runs_count = g_get_num_processors();
-
-    run_size = routines_count / runs_count;
-
-    queue = get_work_queue();
-
-    for (i = 0; i < runs_count; i++)
-    {
-        begin = i * run_size;
-
-        if ((i + 1) < runs_count)
-            end = routines_count - begin;
-        else
-            end = begin + run_size;
-
-        study = g_routines_study_new(proc, exe_ranges, exe_count, routines, routines_count, begin, end, id);
-
-        g_work_queue_schedule_work(queue, G_DELAYED_WORK(study), gid);
-
-    }
-
-    g_work_queue_wait_for_completion(queue, gid);
-
-    if (exe_ranges != NULL)
-        free(exe_ranges);
-
-
-
-
-
-
-
-
+    /*
+    process_all_routines(gid, status,
+                         _("Control-flow analysis for routines..."),
+                         g_routines_study_handle_blocks, proc, disass->format);
+    */
 
 
 
@@ -510,7 +526,7 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
     proc = g_loaded_binary_get_processor(disass->binary);
 
     print_disassembled_instructions(disass->buffer, disass->format, proc, *disass->instrs,
-                                    routines, routines_count, statusbar, 0/*id*/);
+                                    routines, routines_count, status, 0/*id*/);
 
     g_object_unref(G_OBJECT(proc));
 
@@ -532,133 +548,6 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
 
 }
 
-#if 0
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : disass    = analyse à mener.                                 *
-*                statusbar = barre de statut à tenir informée.                *
-*                                                                             *
-*  Description : Assure le désassemblage en différé.                          *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_delayed_disassembly_process_old(GDelayedDisassembly *disass, GtkExtStatusBar *statusbar)
-{
-#ifdef DEBUG
-    unsigned int valid;                     /* Instructions traduites      */
-    unsigned int db;                        /* Instructions non décodées   */
-    unsigned int valid_sum;                 /* Instructions traduites      */
-    unsigned int instr_sum;                 /* Instructions totales        */
-    size_t i;                               /* Boucle de parcours          */
-#endif
-    GBinRoutine **routines;                 /* Liste des routines trouvées */
-    size_t routines_count;                  /* Nombre de ces routines      */
-    bstatus_id_t id;                        /* Identifiant de statut       */
-
-    routines = g_binary_format_get_routines(G_BIN_FORMAT(disass->format), &routines_count);
-
-    /* Première étape */
-
-    id = gtk_extended_status_bar_push(statusbar, _("Disassembling..."), true);
-
-    *disass->instrs = disassemble_binary_parts(disass->binary, disass->parts, disass->count,
-                                               statusbar, id);
-
-    gtk_extended_status_bar_remove(statusbar, id);
-
-#ifdef DEBUG
-
-    valid_sum = 0;
-    instr_sum = 0;
-
-    for (i = 0; i < disass->count; i++)
-    {
-        g_binary_part_get_checkup(disass->parts[i], &valid, &db);
-        valid_sum += valid;
-        instr_sum += (valid + db);
-    }
-
-    log_variadic_message(LMT_WARNING, _("Disassembled instructions : %u %% (%u / %d)"),
-                         (valid_sum * 100) / instr_sum,
-                         valid_sum, instr_sum);
-
-#endif
-
-    run_plugins_on_binary(disass->binary, PGA_BINARY_DISASSEMBLED, true);
-
-    /* Seconde étape */
-
-    id = gtk_extended_status_bar_push(statusbar, _("Establishing links..."), true);
-
-    establish_links_between_lines(*disass->instrs, routines, routines_count, statusbar, id);
-
-    gtk_extended_status_bar_remove(statusbar, id);
-
-    run_plugins_on_binary(disass->binary, PGA_BINARY_LINKED, true);
-
-    /* Troisième  étape */
-
-    id = gtk_extended_status_bar_push(statusbar, _("Finding remaining limits..."), true);
-
-    qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare);
-
-    limit_all_routines(*disass->instrs, routines, routines_count, statusbar, id);
-
-    gtk_extended_status_bar_remove(statusbar, id);
-
-    run_plugins_on_binary(disass->binary, PGA_BINARY_BOUNDED, true);
-
-    /* Quatrième étape */
-
-    id = gtk_extended_status_bar_push(statusbar, _("Detecting loops..."), true);
-
-    detect_loops_in_code(*disass->instrs, routines, routines_count, statusbar, id);
-
-    gtk_extended_status_bar_remove(statusbar, id);
-
-    /* Cinquième étape */
-
-    id = gtk_extended_status_bar_push(statusbar, _("Grouping routines instructions..."), true);
-
-    qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare);
-
-    group_routines_instructions(*disass->instrs, routines, routines_count, statusbar, id);
-
-    gtk_extended_status_bar_remove(statusbar, id);
-
-    run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true);
-
-    /* Sixième étape */
-
-    id = gtk_extended_status_bar_push(statusbar, _("Ranking each instructions block..."), true);
-
-    qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare);
-
-    rank_routines_blocks(routines, routines_count, statusbar, id);
-
-    gtk_extended_status_bar_remove(statusbar, id);
-
-    run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true);
-
-    /* Septième étape */
-
-    id = gtk_extended_status_bar_push(statusbar, _("Printing disassembled code..."), true);
-
-    qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_compare);
-
-    print_disassembled_instructions(disass->buffer, disass->format, *disass->instrs,
-                                    routines, routines_count, statusbar, id);
-
-    gtk_extended_status_bar_remove(statusbar, id);
-
-    run_plugins_on_binary(disass->binary, PGA_BINARY_PRINTED, true);
-
-}
-#endif
 
 
 /* ---------------------------------------------------------------------------------- */
diff --git a/src/analysis/disass/fetch.c b/src/analysis/disass/fetch.c
index 4813111..f484f05 100644
--- a/src/analysis/disass/fetch.c
+++ b/src/analysis/disass/fetch.c
@@ -64,7 +64,9 @@ typedef struct _GDelayedFetching
     GProcContext *ctx;                      /* Contexte de désassemblage   */
     mem_area_v2 *areas;                        /* Zone de productions         */
     size_t count;                           /* Nombre de ces zones         */
-    status_blob_info *info;                 /* Informations de progression */
+
+    GtkStatusStack *status;                 /* Barre de statut             */
+    activity_id_t id;                       /* Groupe de progression       */
 
     virt_t virt;                            /* Adresse de départ dépilée   */
 
@@ -205,6 +207,8 @@ static void g_delayed_fetching_dispose(GDelayedFetching *fetching)
 
     g_object_unref(G_OBJECT(fetching->ctx));
 
+    g_object_unref(G_OBJECT(fetching->status));
+
     G_OBJECT_CLASS(g_delayed_fetching_parent_class)->dispose(G_OBJECT(fetching));
 
 }
@@ -258,7 +262,11 @@ static GDelayedFetching *g_delayed_fetching_new(const GDelayedFetching *template
 
     result->areas = template->areas;
     result->count = template->count;
-    result->info = template->info;
+
+    result->status = template->status;
+    g_object_ref(G_OBJECT(result->status));
+
+    result->id = template->id;
 
     result->virt = virt;
 
@@ -293,7 +301,7 @@ static void g_delayed_fetching_process(GDelayedFetching *fetching, GtkExtStatusB
 
     if (area != NULL)
         load_code_from_mem_area_v2(area, fetching->areas, fetching->count,
-                                   fetching->ctx, &addr, fetching->info);
+                                   fetching->ctx, &addr, fetching->status, fetching->id);
 
 }
 
@@ -467,9 +475,9 @@ static GDelayedFetching template;              /* Patron des tâches à venir
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : binary    = représentation de binaire chargé.                *
-*                gid       = identifiant du groupe de travail à utiliser.     *
-*                statusbar = barre de statut avec progression à mettre à jour.*
+*  Paramètres  : binary = représentation de binaire chargé.                   *
+*                gid    = identifiant du groupe de travail à utiliser.        *
+*                status = barre de statut avec progression à mettre à jour.   *
 *                                                                             *
 *  Description : Procède au désassemblage basique d'un contenu binaire.       *
 *                                                                             *
@@ -479,7 +487,7 @@ static GDelayedFetching template;              /* Patron des tâches à venir
 *                                                                             *
 ******************************************************************************/
 
-GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup_id_t gid, GtkExtStatusBar *statusbar)
+GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup_id_t gid, GtkStatusStack *status)
 {
     GArchInstruction *result;               /* Instruction désassemblées   */
     //GDelayedFetching template;              /* Patron des tâches à venir   */
@@ -489,7 +497,6 @@ GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup
     phys_t length;                          /* Taille des données à lire   */
     GWorkQueue *queue;                      /* Gestionnaire de différés    */
     gint remaining_counter;                 /* Quantité de points restants */
-    double done;                            /* Portion de travail accompli */
 
     /* Constitution du modèle de référence */
 
@@ -508,6 +515,8 @@ GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup
 
     template.areas = compute_memory_areas_v2(binary, length, &template.count);
 
+    template.status = status;
+
     /* Amorce des traitements */
 
     queue = get_work_queue();
@@ -528,27 +537,21 @@ GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup
 
     g_signal_connect(template.ctx, "drop-point-pushed", G_CALLBACK(follow_execution_flow_v2), &template);
 
-    template.info = init_progessive_status(statusbar,
-                                           _("Disassembling following the execution flow..."),
-                                           0, length);
+    template.id = gtk_status_stack_add_activity(status,
+                                                _("Disassembling following the execution flow..."),
+                                                length);
 
     g_binary_format_setup_disassembling_context(format, template.ctx);
 
     g_work_queue_wait_for_completion(queue, gid);
 
-    done = get_current_progessive_status(template.info);
-
-    fini_progessive_status(template.info);
-
     /**
      * Seconde phase : on comble les trous laissés.
      */
 
-    template.info = init_progessive_status(statusbar,
-                                           _("Disassembling the remaining instructions..."),
-                                           done, length);
+    gtk_status_stack_update_activity(status, template.id, _("Disassembling the remaining instructions..."));
 
-    ensure_all_mem_areas_are_filled(template.areas, template.count, template.ctx, template.info);
+    ensure_all_mem_areas_are_filled(template.areas, template.count, template.ctx, status, template.id);
 
     g_work_queue_wait_for_completion(queue, gid);
 
@@ -556,20 +559,14 @@ GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, wgroup
 
     g_object_set_data(G_OBJECT(template.ctx), "remaining_counter", NULL);
 
-    fini_progessive_status(template.info);
-
     /**
      * Troisième et dernière phase : récolte des fruits.
      */
 
-    template.info = init_progessive_status(statusbar,
-                                           _("Collecting disassembled instructions..."),
-                                           0, length);
+    gtk_status_stack_update_activity(status, template.id, _("Collecting disassembled instructions..."));
 
     result = collect_instructions_from_mem_areas_v2(template.areas, template.count);
 
-    fini_progessive_status(template.info);
-
     /* Libérations finales */
 
     //g_object_unref(G_OBJECT(template.format));
diff --git a/src/analysis/disass/fetch.h b/src/analysis/disass/fetch.h
index 37dac80..3ebb4d8 100644
--- a/src/analysis/disass/fetch.h
+++ b/src/analysis/disass/fetch.h
@@ -27,12 +27,12 @@
 
 #include "../binary.h"
 #include "../../glibext/delayed.h"
-#include "../../gtkext/gtkextstatusbar.h"
+#include "../../gtkext/gtkstatusstack.h"
 
 
 
 /* Procède au désassemblage basique d'un contenu binaire. */
-GArchInstruction *disassemble_binary_content(const GLoadedBinary *, wgroup_id_t, GtkExtStatusBar *);
+GArchInstruction *disassemble_binary_content(const GLoadedBinary *, wgroup_id_t, GtkStatusStack *);
 
 
 
diff --git a/src/analysis/disass/instructions.c b/src/analysis/disass/instructions.c
new file mode 100644
index 0000000..7e76a5d
--- /dev/null
+++ b/src/analysis/disass/instructions.c
@@ -0,0 +1,312 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instructions.c - étude complémentaire des instructions désassemblées
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "instructions.h"
+
+
+#include "dragon.h"
+#include "links.h"
+#include "loop.h"
+#include "macro.h"
+#include "rank.h"
+#include "../../glibext/delayed-int.h"
+
+
+
+/* Fraction d'instructions à limiter (instance) */
+struct _GInstructionsStudy
+{
+    GDelayedWork parent;                    /* A laisser en premier        */
+
+    GArchProcessor *proc;                   /* Processeurs avec ses instr. */
+    GBinFormat *format;                     /* Format binaire à manipuler  */
+
+    ins_fallback_cb fallback;               /* Routine de traitement finale*/
+    size_t begin;                           /* Point de départ du parcours */
+    size_t end;                             /* Point d'arrivée exclu       */
+
+    activity_id_t id;                       /* Identifiant pour messages   */
+
+};
+
+/* Fraction d'instructions à limiter (classe) */
+struct _GInstructionsStudyClass
+{
+    GDelayedWorkClass parent;               /* A laisser en premier        */
+
+};
+
+
+/* Indique le type défini pour les tâches d'étude d'instructions. */
+GType g_instructions_study_get_type(void);
+
+/* Initialise la classe des tâches d'étude d'instructions. */
+static void g_instructions_study_class_init(GInstructionsStudyClass *);
+
+/* Initialise une tâche d'étude d'instructions. */
+static void g_instructions_study_init(GInstructionsStudy *);
+
+/* Supprime toutes les références externes. */
+static void g_instructions_study_dispose(GInstructionsStudy *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_instructions_study_finalize(GInstructionsStudy *);
+
+/* Assure l'étude des instructions en différé. */
+static void g_instructions_study_process(GInstructionsStudy *, GtkStatusStack *);
+
+
+
+/* Indique le type défini pour les tâches d'étude d'instructions. */
+G_DEFINE_TYPE(GInstructionsStudy, g_instructions_study, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des tâches d'étude d'instructions.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_instructions_study_class_init(GInstructionsStudyClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GDelayedWorkClass *work;                /* Version en classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_instructions_study_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_instructions_study_finalize;
+
+    work = G_DELAYED_WORK_CLASS(klass);
+
+    work->run = (run_task_fc)g_instructions_study_process;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : computing = instance à initialiser.                          *
+*                                                                             *
+*  Description : Initialise une tâche d'étude d'instructions.                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_instructions_study_init(GInstructionsStudy *study)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_instructions_study_dispose(GInstructionsStudy *computing)
+{
+    G_OBJECT_CLASS(g_instructions_study_parent_class)->dispose(G_OBJECT(computing));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_instructions_study_finalize(GInstructionsStudy *computing)
+{
+    G_OBJECT_CLASS(g_instructions_study_parent_class)->finalize(G_OBJECT(computing));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc     = ensemble d'instructions désassemblées.            *
+*                format   = accès aux données du binaire d'origine.           *
+*                begin    = point de départ du parcours de liste.             *
+*                end      = point d'arrivée exclu du parcours.                *
+*                id       = identifiant du message affiché à l'utilisateur.   *
+*                fallback = routine de traitements particuliers.              *
+*                                                                             *
+*  Description : Crée une tâche d'étude d'instructions différée.              *
+*                                                                             *
+*  Retour      : Tâche créée.                                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GInstructionsStudy *g_instructions_study_new(GArchProcessor *proc, GBinFormat *format, size_t begin, size_t end, activity_id_t id, ins_fallback_cb fallback)
+{
+    GInstructionsStudy *result;                /* Tâche à retourner           */
+
+    result = g_object_new(G_TYPE_INSTRUCTIONS_STUDY, NULL);
+
+    result->proc = proc;
+    result->format = format;
+
+    result->fallback = fallback;
+    result->begin = begin;
+    result->end = end;
+
+    result->id = id;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : study  = étude d'instructions à mener.                       *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Assure l'étude des instructions en différé.                  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_instructions_study_process(GInstructionsStudy *study, GtkStatusStack *status)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = study->begin; i < study->end; i++)
+    {
+        study->fallback(study, i);
+
+        gtk_status_stack_update_activity_value(status, study->id, 1);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : study = étude d'instructions à mener.                        *
+*                index = indice de l'insruction visée.                        *
+*                                                                             *
+*  Description : Réalise l'appel de type IPH_LINK sur une instruction.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_instructions_study_do_link_operation(GInstructionsStudy *study, size_t index)
+{
+    GArchInstruction *instr;                /* Instruction en traitement   */
+
+    instr = g_arch_processor_get_disassembled_instruction(study->proc, index);
+
+    g_arch_instruction_call_hook(instr, IPH_LINK, study->proc, NULL, study->format);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : study = étude d'instructions à mener.                        *
+*                index = indice de l'insruction visée.                        *
+*                                                                             *
+*  Description : Réalise l'appel de type IPH_POST sur une instruction.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_instructions_study_do_post_operation(GInstructionsStudy *study, size_t index)
+{
+    GArchInstruction *instr;                /* Instruction en traitement   */
+
+    instr = g_arch_processor_get_disassembled_instruction(study->proc, index);
+
+    g_arch_instruction_call_hook(instr, IPH_POST, study->proc, NULL, study->format);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : study = étude d'instructions à mener.                        *
+*                index = indice de l'insruction visée.                        *
+*                                                                             *
+*  Description : Etablit les liens entres les différentes instructions.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_instructions_study_establish_links(GInstructionsStudy *study, size_t index)
+{
+    GArchInstruction *instr;                /* Instruction en traitement   */
+    GArchInstruction *prev;                 /* Instruction précédente      */
+
+    instr = g_arch_processor_get_disassembled_instruction(study->proc, index);
+
+    if (index > 0)
+    {
+        prev = g_arch_processor_get_disassembled_instruction(study->proc, index - 1);
+
+        establish_natural_link(instr, prev);
+
+    }
+
+    establish_links_for_instruction(instr, study->format, study->proc);
+
+}
diff --git a/src/analysis/disass/instructions.h b/src/analysis/disass/instructions.h
new file mode 100644
index 0000000..20b853d
--- /dev/null
+++ b/src/analysis/disass/instructions.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instructions.h - prototypes pour l'étude complémentaire des instructions désassemblées
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_DISASS_INSTRUCTIONS_H
+#define _ANALYSIS_DISASS_INSTRUCTIONS_H
+
+
+#include "../routine.h"
+#include "../../arch/processor.h"
+#include "../../format/executable.h"
+#include "../../gtkext/gtkstatusstack.h"
+
+
+
+#define G_TYPE_INSTRUCTIONS_STUDY               g_instructions_study_get_type()
+#define G_INSTRUCTIONS_STUDY(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_instructions_study_get_type(), GInstructionsStudy))
+#define G_IS_INSTRUCTIONS_STUDY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_instructions_study_get_type()))
+#define G_INSTRUCTIONS_STUDY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_INSTRUCTIONS_STUDY, GInstructionsStudyClass))
+#define G_IS_INSTRUCTIONS_STUDY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_INSTRUCTIONS_STUDY))
+#define G_INSTRUCTIONS_STUDY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_INSTRUCTIONS_STUDY, GInstructionsStudyClass))
+
+
+/* Fraction d'instructions à limiter (instance) */
+typedef struct _GInstructionsStudy GInstructionsStudy;
+
+/* Fraction d'instructions à limiter (classe) */
+typedef struct _GInstructionsStudyClass GInstructionsStudyClass;
+
+
+/* Assure l'étude d'instructions en différé. */
+typedef void (* ins_fallback_cb) (GInstructionsStudy *, size_t);
+
+
+/* Crée une tâche d'étude de instructions différée. */
+GInstructionsStudy *g_instructions_study_new(GArchProcessor *, GBinFormat *, size_t, size_t, activity_id_t, ins_fallback_cb);
+
+/* Réalise l'appel de type IPH_LINK sur une instruction. */
+void g_instructions_study_do_link_operation(GInstructionsStudy *, size_t);
+
+/* Réalise l'appel de type IPH_POST sur une instruction. */
+void g_instructions_study_do_post_operation(GInstructionsStudy *, size_t);
+
+/* Etablit les liens entres les différentes instructions. */
+void g_instructions_study_establish_links(GInstructionsStudy *, size_t);
+
+
+
+#endif  /* _ANALYSIS_DISASS_INSTRUCTIONS_H */
diff --git a/src/analysis/disass/limit.c b/src/analysis/disass/limit.c
index 4fd931d..dba62cc 100644
--- a/src/analysis/disass/limit.c
+++ b/src/analysis/disass/limit.c
@@ -24,209 +24,10 @@
 #include "limit.h"
 
 
-#include <malloc.h>
-
-
-#include "../../glibext/delayed-int.h"
-
-
-
-/* ------------------------- CALCULS DE LIMITES DE ROUTINES ------------------------- */
-
-
-#define G_TYPE_LIMIT_COMPUTING               g_limit_computing_get_type()
-#define G_LIMIT_COMPUTING(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_limit_computing_get_type(), GLimitComputing))
-#define G_IS_LIMIT_COMPUTING(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_limit_computing_get_type()))
-#define G_LIMIT_COMPUTING_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LIMIT_COMPUTING, GLimitComputingClass))
-#define G_IS_LIMIT_COMPUTING_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LIMIT_COMPUTING))
-#define G_LIMIT_COMPUTING_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LIMIT_COMPUTING, GLimitComputingClass))
-
-
-/* Fraction de routines à limiter (instance) */
-typedef struct _GLimitComputing
-{
-    GDelayedWork parent;                    /* A laisser en premier        */
-
-    const GArchProcessor *proc;             /* Processeurs avec ses instr. */
-
-    mrange_t *exe_ranges;                   /* Liste de zones exécutables  */
-    size_t exe_count;                       /* Nombre de ces zones         */
-
-    GBinRoutine **routines;                 /* Liste de routines à traiter */
-    size_t count;                           /* Taille de cette liste       */
-    size_t begin;                           /* Point de départ du parcours */
-    size_t end;                             /* Point d'arrivée exclu       */
-
-    bstatus_id_t id;                        /* Identifiant pour messages   */
-
-} GLimitComputing;
-
-/* Fraction de routines à limiter (classe) */
-typedef struct _GLimitComputingClass
-{
-    GDelayedWorkClass parent;               /* A laisser en premier        */
-
-} GLimitComputingClass;
-
-
-/* Indique le type défini pour les tâches de calculs de limites. */
-GType g_limit_computing_get_type(void);
-
-/* Initialise la classe des tâches de calculs de limites. */
-static void g_limit_computing_class_init(GLimitComputingClass *);
-
-/* Initialise une tâche de calculs de limites. */
-static void g_limit_computing_init(GLimitComputing *);
-
-/* Supprime toutes les références externes. */
-static void g_limit_computing_dispose(GLimitComputing *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_limit_computing_finalize(GLimitComputing *);
-
-/* Crée une tâche de calculs de limites différée. */
-static GLimitComputing *g_limit_computing_new(const GArchProcessor *, mrange_t *, size_t, GBinRoutine **, size_t, size_t, size_t, bstatus_id_t);
 
 /* Recherche la zone correspond à une adresse donnée. */
 static const mrange_t *find_x_range_for_addr(const mrange_t *, size_t, const vmpa2t *);
 
-/* Assure le calcul de limites de routines en différé. */
-static void g_limit_computing_process(GLimitComputing *, GtkExtStatusBar *);
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                           CALCULS DE LIMITES DE ROUTINES                           */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour les tâches de calculs de limites. */
-G_DEFINE_TYPE(GLimitComputing, g_limit_computing, G_TYPE_DELAYED_WORK);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : klass = classe à initialiser.                                *
-*                                                                             *
-*  Description : Initialise la classe des tâches de calculs de limites.       *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_limit_computing_class_init(GLimitComputingClass *klass)
-{
-    GObjectClass *object;                   /* Autre version de la classe  */
-    GDelayedWorkClass *work;                /* Version en classe parente   */
-
-    object = G_OBJECT_CLASS(klass);
-
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_limit_computing_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_limit_computing_finalize;
-
-    work = G_DELAYED_WORK_CLASS(klass);
-
-    work->run = (run_task_fc)g_limit_computing_process;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : computing = instance à initialiser.                          *
-*                                                                             *
-*  Description : Initialise une tâche de calculs de limites.                  *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_limit_computing_init(GLimitComputing *computing)
-{
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
-*                                                                             *
-*  Description : Supprime toutes les références externes.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_limit_computing_dispose(GLimitComputing *computing)
-{
-    G_OBJECT_CLASS(g_limit_computing_parent_class)->dispose(G_OBJECT(computing));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
-*                                                                             *
-*  Description : Procède à la libération totale de la mémoire.                *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_limit_computing_finalize(GLimitComputing *computing)
-{
-    G_OBJECT_CLASS(g_limit_computing_parent_class)->finalize(G_OBJECT(computing));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : proc     = ensemble d'instructions désassemblées.            *
-*                routines = prototypes existants à insérer.                   *
-*                count    = quantité de ces prototypes.                       *
-*                begin    = point de départ du parcours de liste.             *
-*                end      = point d'arrivée exclu du parcours.                *
-*                id       = identifiant du message affiché à l'utilisateur.   *
-*                                                                             *
-*  Description : Crée une tâche de calculs de limites différée.               *
-*                                                                             *
-*  Retour      : Tâche créée.                                                 *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static GLimitComputing *g_limit_computing_new(const GArchProcessor *proc, mrange_t *exe_ranges, size_t exe_count, GBinRoutine **routines, size_t count, size_t begin, size_t end, bstatus_id_t id)
-{
-    GLimitComputing *result;                /* Tâche à retourner           */
-
-    result = g_object_new(G_TYPE_LIMIT_COMPUTING, NULL);
-
-    result->proc = proc;
-
-    result->exe_ranges = exe_ranges;
-    result->exe_count = exe_count;
-
-    result->routines = routines;
-    result->count = count;
-    result->begin = begin;
-    result->end = end;
-
-    result->id = id;
-
-    return result;
-
-}
 
 
 /******************************************************************************
@@ -260,163 +61,71 @@ static const mrange_t *find_x_range_for_addr(const mrange_t *ranges, size_t coun
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : computing  = récupération à mener.                           *
-*                statusbar = barre de statut à tenir informée.                *
+*  Paramètres  : proc     = ensemble d'instructions désassemblées.            *
+*                routines = prototypes existants à insérer.                   *
+*                count    = quantité de ces prototypes.                       *
+*                begin    = point de départ du parcours de liste.             *
+*                end      = point d'arrivée exclu du parcours.                *
+*                id       = identifiant du message affiché à l'utilisateur.   *
 *                                                                             *
-*  Description : Assure le calcul de limites de routines en différé.          *
+*  Description : S'assure qu'une routine est bien bornée.                     *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Tâche créée.                                                 *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void g_limit_computing_process(GLimitComputing *computing, GtkExtStatusBar *statusbar)
+void compute_routine_limit(GBinRoutine *routine, GBinRoutine *prev, const GArchProcessor *proc, mrange_t *exe_ranges, size_t exe_count)
 {
-    size_t i;                               /* Boucle de parcours          */
-    GBinRoutine *routine;                   /* Routine en traitement       */
     const mrange_t *range;                  /* Emplacement courant         */
     vmpa2t addr;                            /* Adresse à conserver         */
     GArchInstruction *start;                /* Première instruction        */
     phys_t diff;                            /* Taille définie par déduction*/
     mrange_t new;                           /* Nouvel emplacement taillé   */
 
-    for (i = computing->begin; i < computing->end; i++)
-    {
-        //gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
-
-        routine = computing->routines[i];
-
-        range = g_binary_routine_get_range(routine);
-        if (get_mrange_length(range) > 0) continue;
+    range = g_binary_routine_get_range(routine);
+    if (get_mrange_length(range) > 0) goto crl_skip;
 
-        copy_vmpa(&addr, get_mrange_addr(range));
+    copy_vmpa(&addr, get_mrange_addr(range));
 
-        /* Marquage de la première instruction */
+    /* Marquage de la première instruction */
 
-        start = g_arch_processor_find_instr_by_address(computing->proc, &addr);
+    start = g_arch_processor_find_instr_by_address(proc, &addr);
 
 
-        if (start == NULL) continue;
+    /* FIXME ? */
+    if (start == NULL) goto crl_skip;
 
 
-        g_arch_instruction_set_flag(start, AIF_ROUTINE_START);
+    g_arch_instruction_set_flag(start, AIF_ROUTINE_START);
 
-        /* Si on peut se raccrocher à la routine suivante... */
-        if ((i + 1) < computing->count)
-        {
-            range = g_binary_routine_get_range(computing->routines[i + 1]);
-
-            diff = compute_vmpa_diff(&addr, get_mrange_addr(range));
-
-        }
-
-        /* Sinon on va jusqu'à la fin de la zone ! */
-        else
-        {
-            range = find_x_range_for_addr(computing->exe_ranges, computing->exe_count, &addr);
-            if (range == NULL) continue;
-
-            diff = compute_vmpa_diff(&addr, get_mrange_addr(range));
-            diff = get_mrange_length(range) - diff;
-
-        }
-
-        init_mrange(&new, &addr, diff);
-
-        g_binary_routine_set_range(routine, &new);
-
-    }
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                            POINT D'ENTREE ET DECOUPAGES                            */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : format   = format du binaire concerné par la procédure.      *
-*                proc     = ensemble d'instructions désassemblées.            *
-*                routines = prototypes existants à insérer.                   *
-*                count    = quantité de ces prototypes.                       *
-*                gid      = identifiant du groupe de travail à utiliser.      *
-*                id       = identifiant du message affiché à l'utilisateur.   *
-*                                                                             *
-*  Description : S'assure que toutes les routines ont une taille définie.     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void limit_all_routines(GExeFormat *format, const GArchProcessor *proc, GBinRoutine **routines, size_t count, wgroup_id_t gid, bstatus_id_t id)
-{
-    mrange_t *exe_ranges;                   /* Liste de zones exécutables  */
-    size_t exe_count;                       /* Nombre de ces zones         */
-    guint runs_count;                       /* Qté d'exécutions parallèles */
-    size_t run_size;                        /* Volume réparti par exécution*/
-    GWorkQueue *queue;                      /* Gestionnaire de différés    */
-    guint i;                                /* Boucle de parcours          */
-    size_t begin;                           /* Début de bloc de traitement */
-    size_t end;                             /* Fin d'un bloc de traitement */
-    GLimitComputing *computing;             /* Tâche de calcul à programmer*/
-
-    exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);
-
-    runs_count = g_get_num_processors();
-
-    run_size = count / runs_count;
-
-    queue = get_work_queue();
-
-    for (i = 0; i < runs_count; i++)
+    /* Si on peut se raccrocher à la routine suivante... */
+    if (prev != NULL)
     {
-        begin = i * run_size;
-
-        if ((i + 1) < runs_count)
-            end = count - begin;
-        else
-            end = begin + run_size;
+        range = g_binary_routine_get_range(prev);
 
-        computing = g_limit_computing_new(proc, exe_ranges, exe_count, routines, count, begin, end, id);
-
-        g_work_queue_schedule_work(queue, G_DELAYED_WORK(computing), gid);
+        diff = compute_vmpa_diff(&addr, get_mrange_addr(range));
 
     }
 
-    g_work_queue_wait_for_completion(queue, gid);
-
-    if (exe_ranges != NULL)
-        free(exe_ranges);
-
-
-
-
-    do
+    /* Sinon on va jusqu'à la fin de la zone ! */
+    else
     {
-        const mrange_t *_range;
-        vmpa2t _end;
+        range = find_x_range_for_addr(exe_ranges, exe_count, &addr);
+        if (range == NULL) goto crl_skip;
 
-        printf("LIMIT == %zu routines\n", count);
+        diff = compute_vmpa_diff(&addr, get_mrange_addr(range));
+        diff = get_mrange_length(range) - diff;
 
-        for (i = 0; i < count; i++)
-        {
-            _range = g_binary_routine_get_range(routines[i]);
-            compute_mrange_end_addr(_range, &_end);
+    }
 
-            printf(" <LIMIT> 0x%08x <-> 0x%08x '%s'\n",
-                   (unsigned int)((get_mrange_addr(_range))->virtual),
-                   (unsigned int)_end.virtual,
-                   g_binary_routine_to_string(routines[i]));
+    init_mrange(&new, &addr, diff);
 
-        }
+    g_binary_routine_set_range(routine, &new);
 
-    } while (0);
+ crl_skip:
 
+    ;
 
 }
diff --git a/src/analysis/disass/limit.h b/src/analysis/disass/limit.h
index 2fa3303..434d4e8 100644
--- a/src/analysis/disass/limit.h
+++ b/src/analysis/disass/limit.h
@@ -28,16 +28,11 @@
 #include "../routine.h"
 #include "../../arch/processor.h"
 #include "../../format/executable.h"
-#include "../../glibext/delayed.h"
-#include "../../gtkext/gtkextstatusbar.h"
 
 
 
-/* -------------------------- POINT D'ENTREE ET DECOUPAGES -------------------------- */
-
-
-/* S'assure que toutes les routines ont une taille définie. */
-void limit_all_routines(GExeFormat *, const GArchProcessor *, GBinRoutine **, size_t, wgroup_id_t, bstatus_id_t);
+/* S'assure qu'une routine est bien bornée. */
+void compute_routine_limit(GBinRoutine *, GBinRoutine *, const GArchProcessor *, mrange_t *, size_t);
 
 
 
diff --git a/src/analysis/disass/links.c b/src/analysis/disass/links.c
index 5e1e483..86663cc 100644
--- a/src/analysis/disass/links.c
+++ b/src/analysis/disass/links.c
@@ -31,11 +31,8 @@
 
 
 
-/* Rétablit un lien naturel coupé par un autre lien. */
-static void establish_natural_link(GArchInstruction *, GArchInstruction *);
-
 /* Complète un désassemblage accompli pour une instruction. */
-static void convert_immediate_into_target(GArchInstruction *, size_t, GBinFormat *);
+static void convert_immediate_into_target(GArchInstruction *, size_t, const GBinFormat *);
 
 
 
@@ -52,7 +49,7 @@ static void convert_immediate_into_target(GArchInstruction *, size_t, GBinFormat
 *                                                                             *
 ******************************************************************************/
 
-static void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
+void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
 {
     GArchInstruction **others;              /* Instructions diverses liées */
     InstructionLinkType *types;             /* Types de lien existants     */
@@ -126,7 +123,7 @@ static void establish_natural_link(GArchInstruction *instr, GArchInstruction *pr
 *                                                                             *
 ******************************************************************************/
 
-static void convert_immediate_into_target(GArchInstruction *instr, size_t index, GBinFormat *format)
+static void convert_immediate_into_target(GArchInstruction *instr, size_t index, const GBinFormat *format)
 {
     GArchOperand *op;                       /* Opérande numérique en place */
     GImmOperand *imm;                       /* Version native de l'opérande*/
@@ -160,8 +157,8 @@ static void convert_immediate_into_target(GArchInstruction *instr, size_t index,
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : instr  = instruction désassemblée à traiter.                 *
-*                list   = ensemble d'instructions à relier.                   *
 *                format = accès aux données du binaire d'origine.             *
+*                proc   = ensemble d'instructions à relier.                   *
 *                                                                             *
 *  Description : Complète un désassemblage accompli pour une instruction.     *
 *                                                                             *
@@ -171,7 +168,7 @@ static void convert_immediate_into_target(GArchInstruction *instr, size_t index,
 *                                                                             *
 ******************************************************************************/
 
-static void establish_links_for_instruction(GArchInstruction *instr, GArchInstruction *list, GBinFormat *format)
+void establish_links_for_instruction(GArchInstruction *instr, const GBinFormat *format, const GArchProcessor *proc)
 {
     bool skip;                              /* Saut des conversions        */
     size_t count;                           /* Nombre d'opérandes présents */
@@ -199,7 +196,7 @@ static void establish_links_for_instruction(GArchInstruction *instr, GArchInstru
         virt = g_target_operand_get_addr(G_TARGET_OPERAND(op));
         init_vmpa(&addr, VMPA_NO_PHYSICAL, virt);
 
-        target = g_arch_instruction_find_by_address(list, &addr, true);
+        target = g_arch_processor_find_instr_by_address(proc, &addr);
 
         if (target != NULL)
             g_arch_instruction_link_with(instr, target, ILT_REF);
@@ -207,42 +204,3 @@ static void establish_links_for_instruction(GArchInstruction *instr, GArchInstru
     }
 
 }
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : list      = ensemble d'instructions à relier.                *
-*                format    = accès aux données du binaire d'origine.          *
-*                statusbar = barre de statut avec progression à mettre à jour.*
-*                id        = identifiant du message affiché à l'utilisateur.  *
-*                                                                             *
-*  Description : Etablit les liens entres les différentes lignes de code.     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void establish_links_between_instructions(GArchInstruction *list, GBinFormat *format, GtkExtStatusBar *statusbar, bstatus_id_t id)
-{
-    GArchInstruction *prev;                 /* Itération précédente        */
-    GArchInstruction *iter;                 /* Boucle de parcours          */
-
-    prev = NULL;
-
-    for (iter = list;
-         iter != NULL;
-         iter = g_arch_instruction_get_next_iter(list, iter, ~0/* FIXME */))
-    {
-        if (prev != NULL)
-            establish_natural_link(iter, prev);
-
-        prev = iter;
-
-        establish_links_for_instruction(iter, list, format);
-
-
-    }
-
-}
diff --git a/src/analysis/disass/links.h b/src/analysis/disass/links.h
index f4092f9..b1f5a71 100644
--- a/src/analysis/disass/links.h
+++ b/src/analysis/disass/links.h
@@ -25,22 +25,17 @@
 #define _ANALYSIS_DISASS_LINKS_H
 
 
-//#include "../routine.h"
 #include "../../arch/instruction.h"
+#include "../../arch/processor.h"
 #include "../../format/format.h"
-#include "../../gtkext/gtkextstatusbar.h"
 
 
 
+/* Rétablit un lien naturel coupé par un autre lien. */
+void establish_natural_link(GArchInstruction *, GArchInstruction *);
 
-/* Etablit les liens entres les différentes lignes de code. */
-void establish_links_between_instructions(GArchInstruction *, GBinFormat *, GtkExtStatusBar *, bstatus_id_t);
-
-
-
-
-/* Etablit les liens entres les différentes lignes de code. */
-//void establish_links_between_lines(GArchInstruction *, GBinRoutine **, size_t, GtkExtStatusBar *, bstatus_id_t);
+/* Complète un désassemblage accompli pour une instruction. */
+void establish_links_for_instruction(GArchInstruction *, const GBinFormat *, const GArchProcessor *);
 
 
 
diff --git a/src/analysis/disass/routines.c b/src/analysis/disass/routines.c
index 280757a..3e0aa71 100644
--- a/src/analysis/disass/routines.c
+++ b/src/analysis/disass/routines.c
@@ -25,6 +25,7 @@
 
 
 #include "dragon.h"
+#include "limit.h"
 #include "loop.h"
 #include "macro.h"
 #include "rank.h"
@@ -44,6 +45,8 @@ struct _GRoutinesStudy
 
     GBinRoutine **routines;                 /* Liste de routines à traiter */
     size_t count;                           /* Taille de cette liste       */
+
+    rtn_fallback_cb fallback;               /* Routine de traitement finale*/
     size_t begin;                           /* Point de départ du parcours */
     size_t end;                             /* Point d'arrivée exclu       */
 
@@ -176,6 +179,7 @@ static void g_routines_study_finalize(GRoutinesStudy *computing)
 *                begin    = point de départ du parcours de liste.             *
 *                end      = point d'arrivée exclu du parcours.                *
 *                id       = identifiant du message affiché à l'utilisateur.   *
+*                fallback = routine de traitements particuliers.              *
 *                                                                             *
 *  Description : Crée une tâche d'étude de routines différée.                 *
 *                                                                             *
@@ -185,7 +189,7 @@ static void g_routines_study_finalize(GRoutinesStudy *computing)
 *                                                                             *
 ******************************************************************************/
 
-GRoutinesStudy *g_routines_study_new(const GArchProcessor *proc, mrange_t *exe_ranges, size_t exe_count, GBinRoutine **routines, size_t count, size_t begin, size_t end, activity_id_t id)
+GRoutinesStudy *g_routines_study_new(const GArchProcessor *proc, mrange_t *exe_ranges, size_t exe_count, GBinRoutine **routines, size_t count, size_t begin, size_t end, activity_id_t id, rtn_fallback_cb fallback)
 {
     GRoutinesStudy *result;                /* Tâche à retourner           */
 
@@ -198,6 +202,8 @@ GRoutinesStudy *g_routines_study_new(const GArchProcessor *proc, mrange_t *exe_r
 
     result->routines = routines;
     result->count = count;
+
+    result->fallback = fallback;
     result->begin = begin;
     result->end = end;
 
@@ -224,55 +230,90 @@ GRoutinesStudy *g_routines_study_new(const GArchProcessor *proc, mrange_t *exe_r
 static void g_routines_study_process(GRoutinesStudy *study, GtkStatusStack *status)
 {
     size_t i;                               /* Boucle de parcours          */
-    GBinRoutine *routine;                   /* Routine en traitement       */
-    const mrange_t *range;                  /* Couverture d'une routine    */
-    const vmpa2t *start;                    /* Adresse de départ           */
-    const instr_coverage *coverage;         /* Instructions couvertes      */
-    dragon_knight *knight;                  /* Complexité de code posée    */
-    //dragon_node *nodes;                     /* Liste des noeuds détectés   */
-    //size_t count;                           /* Taille de cette liste       */
 
     for (i = study->begin; i < study->end; i++)
     {
-        //gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
-
-        routine = study->routines[i];
+        study->fallback(study, i);
 
-        /* Préparatifs communs */
+        gtk_status_stack_update_activity_value(status, study->id, 1);
 
-        range = g_binary_routine_get_range(routine);
-        start = get_mrange_addr(range);
-
-        coverage = g_arch_processor_find_coverage_by_address(study->proc, start);
+    }
 
-        knight = begin_dragon_knight(study->proc, coverage, range, start);
+}
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : study = étude de routines à mener.                           *
+*                index = indice de l'insruction visée.                        *
+*                                                                             *
+*  Description : Détermine si besoin est les bornes des routines.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
+void g_routines_study_compute_limits(GRoutinesStudy *study, size_t index)
+{
+    GBinRoutine *routine;                   /* Routine à traiter           */
+    GBinRoutine *next;                      /* Routine suivante éventuelle */
 
-        detect_loops_in_code(knight);
+    routine = study->routines[index];
 
+    if ((index + 1) < study->count)
+        next = study->routines[index + 1];
+    else
+        next = NULL;
 
+    compute_routine_limit(routine, next, study->proc, study->exe_ranges, study->exe_count);
 
-        /* Phase AAAA : regroupement des instructions par blocs */
+}
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : study = étude de routines à mener.                           *
+*                index = indice de l'insruction visée.                        *
+*                                                                             *
+*  Description : Procède au traitement des blocs de routines.                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
+void g_routines_study_handle_blocks(GRoutinesStudy *study, size_t index)
+{
+    GBinRoutine *routine;                   /* Routine à traiter           */
+    const mrange_t *range;                  /* Couverture d'une routine    */
+    const vmpa2t *start;                    /* Adresse de départ           */
+    const instr_coverage *coverage;         /* Instructions couvertes      */
+    dragon_knight *knight;                  /* Complexité de code posée    */
 
-        group_routine_instructions(routine, knight);
+    routine = study->routines[index];
 
+    /* Préparatifs communs */
 
+    range = g_binary_routine_get_range(routine);
+    start = get_mrange_addr(range);
 
+    coverage = g_arch_processor_find_coverage_by_address(study->proc, start);
 
+    knight = begin_dragon_knight(study->proc, coverage, range, start);
 
-        rank_routine_blocks(routine);
+    /* Traitement par blocs */
 
+    detect_loops_in_code(knight);
 
+    group_routine_instructions(routine, knight);
 
-        /* Nettoyage final */
+    rank_routine_blocks(routine);
 
-        end_dragon_knight(knight);
+    /* Nettoyage final */
 
-    }
+    end_dragon_knight(knight);
 
 }
diff --git a/src/analysis/disass/routines.h b/src/analysis/disass/routines.h
index 7e01928..f85affe 100644
--- a/src/analysis/disass/routines.h
+++ b/src/analysis/disass/routines.h
@@ -47,8 +47,18 @@ typedef struct _GRoutinesStudy GRoutinesStudy;
 typedef struct _GRoutinesStudyClass GRoutinesStudyClass;
 
 
+/* Assure l'étude des routines en différé. */
+typedef void (* rtn_fallback_cb) (GRoutinesStudy *, size_t);
+
+
 /* Crée une tâche d'étude de routines différée. */
-GRoutinesStudy *g_routines_study_new(const GArchProcessor *, mrange_t *, size_t, GBinRoutine **, size_t, size_t, size_t, activity_id_t);
+GRoutinesStudy *g_routines_study_new(const GArchProcessor *, mrange_t *, size_t, GBinRoutine **, size_t, size_t, size_t, activity_id_t, rtn_fallback_cb);
+
+/* Détermine si besoin est les bornes des routines. */
+void g_routines_study_compute_limits(GRoutinesStudy *, size_t);
+
+/* Procède au traitement des blocs de routines. */
+void g_routines_study_handle_blocks(GRoutinesStudy *, size_t);
 
 
 
diff --git a/src/arch/arm/v7/post.c b/src/arch/arm/v7/post.c
index e066bb0..0692cea 100644
--- a/src/arch/arm/v7/post.c
+++ b/src/arch/arm/v7/post.c
@@ -57,6 +57,10 @@ void post_process_branch_instructions(GArchInstruction *instr, GArchProcessor *p
 
     op = g_arch_instruction_get_operand(instr, 0);
 
+
+    if (!G_IS_IMM_OPERAND(op)) return;
+
+
     if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, &addr)
         && g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), addr, &target))
     {
@@ -121,6 +125,10 @@ void post_process_branch_and_link_instructions(GArchInstruction *instr, GArchPro
 
     op = g_arch_instruction_get_operand(instr, 0);
 
+
+    if (!G_IS_IMM_OPERAND(op)) return;
+
+
     if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, &addr)
         && g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), addr, &target))
     {
@@ -195,6 +203,10 @@ void post_process_comp_and_branch_instructions(GArchInstruction *instr, GArchPro
 
     op = g_arch_instruction_get_operand(instr, 1);
 
+
+    if (!G_IS_IMM_OPERAND(op)) return;
+
+
     if (g_imm_operand_get_value(G_IMM_OPERAND(op), MDS_32_BITS_UNSIGNED, &addr)
         && g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), addr, &target))
     {
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index 0db68c7..d75cf54 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -248,7 +248,8 @@ GArchInstruction *g_arch_instruction_get_next_iter(const GArchInstruction *, con
 GArchInstruction *g_arch_instruction_find_by_range(GArchInstruction *, const mrange_t *);
 
 /* Recherche une instruction d'après son adresse. */
-GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *, const vmpa2t *, bool);
+GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *, const vmpa2t *, bool) __attribute__ ((deprecated));
+/* -> g_arch_processor_find_instr_by_address */
 
 
 
diff --git a/src/arch/processor.c b/src/arch/processor.c
index 21db869..da5ddce 100644
--- a/src/arch/processor.c
+++ b/src/arch/processor.c
@@ -520,6 +520,58 @@ GArchInstruction *g_arch_processor_get_disassembled_instructions(const GArchProc
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : proc = architecture visée par la procédure.                  *
+*                index = indice de l'instruction visée.                       *
+*                                                                             *
+*  Description : Fournit une instruction désassemblée pour une architecture.  *
+*                                                                             *
+*  Retour      : Instructions désassemblée trouvée ou NULL si aucune.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GArchInstruction *g_arch_processor_get_disassembled_instruction(const GArchProcessor *proc, size_t index)
+{
+    GArchInstruction *result;               /* Instruction à retourner     */
+
+    if (proc->instr_count == 0)
+        result = NULL;
+
+    else
+    {
+        assert(index < proc->instr_count);
+
+        result = proc->instructions[index];
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc = architecture visée par la procédure.                  *
+*                                                                             *
+*  Description : Compte le nombre d'instructions représentées.                *
+*                                                                             *
+*  Retour      : Nombre d'instructions présentes.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_arch_processor_count_disassembled_instructions(const GArchProcessor *proc)
+{
+    return proc->instr_count;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : proc   = processeur recensant diverses instructions.         *
 *                addr   = position en mémoire ou physique à chercher.         *
 *                nearby = la recherche s'effectue-t-elle de façon stricte ?   *
diff --git a/src/arch/processor.h b/src/arch/processor.h
index 82c4f18..9dee9f6 100644
--- a/src/arch/processor.h
+++ b/src/arch/processor.h
@@ -91,6 +91,12 @@ void g_arch_processor_set_disassembled_instructions(GArchProcessor *, GArchInstr
 /* Fournit les instructions désassemblées pour une architecture. */
 GArchInstruction *g_arch_processor_get_disassembled_instructions(const GArchProcessor *);
 
+/* Fournit une instruction désassemblée pour une architecture. */
+GArchInstruction *g_arch_processor_get_disassembled_instruction(const GArchProcessor *, size_t);
+
+/* Compte le nombre d'instructions représentées. */
+size_t g_arch_processor_count_disassembled_instructions(const GArchProcessor *);
+
 /* Recherche un groupe d'instruction d'après son adresse. */
 const instr_coverage *g_arch_processor_find_coverage_by_address(const GArchProcessor *, const vmpa2t *);
 
diff --git a/src/gtkext/gtkstatusstack.c b/src/gtkext/gtkstatusstack.c
index 9177399..880f4ed 100644
--- a/src/gtkext/gtkstatusstack.c
+++ b/src/gtkext/gtkstatusstack.c
@@ -134,7 +134,11 @@ typedef struct _progress_status
     activity_id_t id;                       /* Identifiant unique          */
 
     char *message;                          /* Indication à faire valoir   */
-    double value;                           /* Centième de pourcentage     */
+
+    unsigned long current;                  /* Position courante           */
+    unsigned long max;                      /* Couverture à parcourir      */
+
+    double last_updated;                    /* Dernière valeur poussée     */
 
 } progress_status;
 
@@ -802,6 +806,7 @@ static GtkWidget *build_progress_status_stack(GtkStatusStack *stack)
     progress = gtk_progress_bar_new();
     g_object_set_data(ref, "progress", progress);
     gtk_widget_set_size_request(progress, 200, -1);
+    gtk_widget_set_valign(progress, GTK_ALIGN_CENTER);
     gtk_widget_show(progress);
     gtk_box_pack_start(GTK_BOX(result), progress, FALSE, TRUE, 8);
 
@@ -817,7 +822,7 @@ static GtkWidget *build_progress_status_stack(GtkStatusStack *stack)
 *                                                                             *
 *  Paramètres  : stack = barre de statut à actualiser.                        *
 *                msg   = nouveau message de statut à copier.                  *
-*                value = nouvelle valeur pour une progression donnée.         *
+*                max   = taille de la plage à parcourir.                      *
 *                                                                             *
 *  Description : Démarre le suivi d'une nouvelle activité.                    *
 *                                                                             *
@@ -827,7 +832,7 @@ static GtkWidget *build_progress_status_stack(GtkStatusStack *stack)
 *                                                                             *
 ******************************************************************************/
 
-activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *msg, double value)
+activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *msg, unsigned long max)
 {
     activity_id_t result;                   /* Numéro unique à renvoyer    */
     progress_info *info;                    /* Informations à consulter    */
@@ -844,7 +849,7 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
     info->statuses = (progress_status *)realloc(info->statuses,
                                                 info->count * sizeof(progress_status));
 
-    info->statuses[new].id = new;
+    info->statuses[new].id = result;
 
     /* Intitulé */
 
@@ -855,7 +860,8 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
 
     /* Valeur */
 
-    info->statuses[new].value = value;
+    info->statuses[new].current = 0;
+    info->statuses[new].max = max;
 
     /* Actualisation */
 
@@ -876,7 +882,6 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
 *  Paramètres  : stack = barre de statut à actualiser.                        *
 *                id    = identifiant de l'activité à cibler.                  *
 *                msg   = nouveau message de statut à copier.                  *
-*                value = nouvelle valeur pour une progression donnée.         *
 *                                                                             *
 *  Description : Actualise les informations concernant une activité.          *
 *                                                                             *
@@ -886,7 +891,7 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
 *                                                                             *
 ******************************************************************************/
 
-void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, const char *msg, double value)
+void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, const char *msg)
 {
     progress_info *info;                    /* Informations à consulter    */
     size_t i;                               /* Boucle de parcours          */
@@ -923,15 +928,9 @@ void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, c
         else
             info->statuses[i].message = strdup(msg);
 
-        /* Valeur */
-
-        old = info->statuses[i].value;
-
-        info->statuses[i].value = value;
-
         /* On n'actualise que le sommet de la pile */
 
-        if ((i + 1) == info->count && (msg_changed || (value - old) > 1.0))
+        if ((i + 1) == info->count)
         {
             if (info->tag != 0)
                 g_source_remove(info->tag);
@@ -951,7 +950,7 @@ void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, c
 *                                                                             *
 *  Paramètres  : stack = barre de statut à actualiser.                        *
 *                id    = identifiant de l'activité à cibler.                  *
-*                value = nouvelle valeur pour une progression donnée.         *
+*                inc   = nouvelle valeur pour une progression donnée.         *
 *                                                                             *
 *  Description : Actualise la progression d'une activité.                     *
 *                                                                             *
@@ -961,11 +960,13 @@ void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, c
 *                                                                             *
 ******************************************************************************/
 
-void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t id, double value)
+void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t id, unsigned long inc)
 {
     progress_info *info;                    /* Informations à consulter    */
     size_t i;                               /* Boucle de parcours          */
-    double old;                             /* Conservation pour la diff.  */
+    progress_status *status;                /* Raccourci de confort        */
+    double old;                             /* Ancienne progression        */
+    double new;                             /* Nouvelle progression        */
 
     info = stack->prog_info;
 
@@ -977,15 +978,21 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t
 
     if (i < info->count)
     {
+        status = &info->statuses[i];
+
         /* Valeur */
 
-        old = info->statuses[i].value;
+        status->current += inc;
 
-        info->statuses[i].value = value;
+        new = (status->current * 1.0) / status->max;
 
         /* On n'actualise que le sommet de la pile */
 
-        if ((i + 1) == info->count && (value - old) > 1.0)
+
+        //fprintf(stderr, "PROG %g -> %g <=> %g ==> %d\n", old, new, new - old, (new - old) > 0.1);
+
+
+        if ((i + 1) == info->count && (new - status->last_updated) > 0.1)
         {
             if (info->tag != 0)
                 g_source_remove(info->tag);
@@ -1099,7 +1106,7 @@ static gboolean gtk_status_stack_show_current_activity(GtkStatusStack *stack)
             last = &info->statuses[info->count - 1];
 
             progress = GTK_PROGRESS_BAR(g_object_get_data(ref, "progress"));
-            gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), last->value);
+            gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), (last->current * 1.0) / last->max);
 
             label = GTK_LABEL(g_object_get_data(ref, "message"));
             gtk_label_set_text(label, last->message);
diff --git a/src/gtkext/gtkstatusstack.h b/src/gtkext/gtkstatusstack.h
index afc3213..590f562 100644
--- a/src/gtkext/gtkstatusstack.h
+++ b/src/gtkext/gtkstatusstack.h
@@ -77,13 +77,13 @@ typedef unsigned long activity_id_t;
 
 
 /* Démarre le suivi d'une nouvelle activité. */
-activity_id_t gtk_status_stack_add_activity(GtkStatusStack *, const char *, double);
+activity_id_t gtk_status_stack_add_activity(GtkStatusStack *, const char *, unsigned long);
 
 /* Actualise les informations concernant une activité. */
-void gtk_status_stack_update_activity(GtkStatusStack *, activity_id_t, const char *, double);
+void gtk_status_stack_update_activity(GtkStatusStack *, activity_id_t, const char *);
 
 /* Actualise la progression d'une activité. */
-void gtk_status_stack_update_activity_value(GtkStatusStack *, activity_id_t, double);
+void gtk_status_stack_update_activity_value(GtkStatusStack *, activity_id_t, unsigned long);
 
 /* Met fin au suivi d'une activité donnée. */
 void gtk_status_stack_remove_activity(GtkStatusStack *, activity_id_t);
diff --git a/src/main.c b/src/main.c
index 2de2379..bd98b32 100644
--- a/src/main.c
+++ b/src/main.c
@@ -165,7 +165,7 @@ int main(int argc, char **argv)
 
 
     editor = create_editor();
-    gtk_widget_show(editor);
+    gtk_widget_show_now(editor);
 
     init_work_queue(G_OBJECT(editor));
 
@@ -181,13 +181,22 @@ int main(int argc, char **argv)
 
     /* Charge le dernier projet */
 
-    if (!g_generic_config_get_value(config, MPK_LAST_PROJECT, &filename))
-        filename = NULL;
+    gboolean load_last_project(GGenConfig *cfg)
+    {
+
+        if (!g_generic_config_get_value(cfg, MPK_LAST_PROJECT, &filename))
+            filename = NULL;
+
+        if (filename == NULL) project = g_study_project_new(G_OBJECT(editor));
+        else project = g_study_project_open(G_OBJECT(editor), filename);
 
-    if (filename == NULL) project = g_study_project_new(G_OBJECT(editor));
-    else project = g_study_project_open(G_OBJECT(editor), filename);
+        set_current_project(project);
+
+        return G_SOURCE_REMOVE;
+
+    }
 
-    set_current_project(project);
+    g_idle_add((GSourceFunc)load_last_project, config);
 
     /* Exécution du programme */
 
-- 
cgit v0.11.2-87-g4458