From 9f9041e11efa71cb043425cd5e89daea0247e76c Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 29 Dec 2016 11:30:28 +0100
Subject: Cut binary data into several areas using all the available CPUs and
 less memory.

---
 ChangeLog                          |  54 +++
 plugins/mobicore/mclf.c            |  42 +--
 plugins/ropgadgets/finder.c        |  31 +-
 src/analysis/disass/area.c         | 637 +++++++++++++++++++++------------
 src/analysis/disass/area.h         |   6 +-
 src/analysis/disass/disassembler.c |  10 +-
 src/analysis/disass/fetch.c        |   4 +-
 src/analysis/disass/fetch.h        |   2 +-
 src/analysis/disass/limit.c        |  55 +--
 src/analysis/disass/limit.h        |   2 +-
 src/analysis/disass/output.c       |  26 +-
 src/analysis/disass/routines.c     |  14 +-
 src/analysis/disass/routines.h     |   2 +-
 src/format/dex/class.c             |   9 +-
 src/format/dex/class.h             |   2 +-
 src/format/dex/dex.c               |  16 +-
 src/format/dex/method.c            |  18 +-
 src/format/dex/method.h            |   2 +-
 src/format/elf/elf.c               | 155 ++------
 src/format/executable-int.h        |   8 +-
 src/format/executable.c            | 167 +++++----
 src/format/executable.h            |   6 +-
 src/format/format.c                |   1 -
 src/format/symbol.c                |  31 ++
 src/format/symbol.h                |   3 +
 src/glibext/gbinportion.c          | 708 +++++++++++--------------------------
 src/glibext/gbinportion.h          |  67 ++--
 src/gtkext/gtkbinarystrip.c        |  42 +--
 src/gtkext/gtkstatusstack.c        |  10 +-
 src/gui/panels/strings.c           |   9 +-
 30 files changed, 1009 insertions(+), 1130 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 91bc161..2ace970 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,57 @@
+16-12-29  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/mobicore/mclf.c:
+	Register portions using the new way.
+
+	* plugins/ropgadgets/finder.c:
+	Collect all executable ranges using the new visitor.
+
+	* src/analysis/disass/area.c:
+	* src/analysis/disass/area.h:
+	Cut binary data into several areas using all the available CPUs and less
+	memory.
+
+	* src/analysis/disass/disassembler.c:
+	* src/analysis/disass/fetch.c:
+	* src/analysis/disass/fetch.h:
+	Update code.
+
+	* src/analysis/disass/limit.c:
+	* src/analysis/disass/limit.h:
+	Save memory by relying on portions only.
+
+	* src/analysis/disass/output.c:
+	* src/analysis/disass/routines.c:
+	* src/analysis/disass/routines.h:
+	Update code.
+
+	* src/format/dex/class.c:
+	* src/format/dex/class.h:
+	* src/format/dex/dex.c:
+	* src/format/dex/method.c:
+	* src/format/dex/method.h:
+	* src/format/elf/elf.c:
+	* src/format/executable-int.h:
+	* src/format/executable.c:
+	* src/format/executable.h:
+	Register portions using the new way.
+
+	* src/format/format.c:
+	Typo.
+
+	* src/format/symbol.c:
+	* src/format/symbol.h:
+	Provide an extra method to compare symbols.
+
+	* src/glibext/gbinportion.c:
+	* src/glibext/gbinportion.h:
+	Remove all layer definitions and introduce trees of binary portions.
+
+	* src/gtkext/gtkbinarystrip.c:
+	* src/gtkext/gtkstatusstack.c:
+	* src/gui/panels/strings.c:
+	Update code.
+
 16-12-23  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gui/panels/welcome.c:
diff --git a/plugins/mobicore/mclf.c b/plugins/mobicore/mclf.c
index edb6a4a..3cab4a6 100644
--- a/plugins/mobicore/mclf.c
+++ b/plugins/mobicore/mclf.c
@@ -54,7 +54,7 @@ static void g_mclf_format_finalize(GMCLFFormat *);
 static const char *g_mclf_format_get_target_machine(const GMCLFFormat *);
 
 /* Etend la définition des portions au sein d'un binaire. */
-static void g_mclf_format_refine_portions(const GMCLFFormat *, GPortionLayer *);
+static void g_mclf_format_refine_portions(GMCLFFormat *);
 
 
 
@@ -262,7 +262,6 @@ static const char *g_mclf_format_get_target_machine(const GMCLFFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = informations chargées à consulter.                  *
-*                main   = couche de portions principale à raffiner.           *
 *                                                                             *
 *  Description : Etend la définition des portions au sein d'un binaire.       *
 *                                                                             *
@@ -272,59 +271,54 @@ static const char *g_mclf_format_get_target_machine(const GMCLFFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-static void g_mclf_format_refine_portions(const GMCLFFormat *format, GPortionLayer *main)
+static void g_mclf_format_refine_portions(GMCLFFormat *format)
 {
-    GPortionLayer *layer;                   /* Couche à mettre en place    */
+    GExeFormat *exe_format;                 /* Autre version du format     */
+    vmpa2t addr;                            /* Emplacement dans le binaire */
     GBinPortion *new;                       /* Nouvelle portion définie    */
     char desc[MAX_PORTION_DESC];            /* Description d'une portion   */
     phys_t length;                          /* Taille de portion globale   */
-    vmpa2t addr;                            /* Emplacement dans le binaire */
- 
-    layer = g_portion_layer_new(NO_LENGTH_YET, _("Segment"));
 
-    g_portion_layer_attach_sub(main, layer);
+    exe_format = G_EXE_FORMAT(format);
 
     /* Segment de code */
 
-    new = g_binary_portion_new(BPC_CODE);
+    init_vmpa(&addr, 0, format->header.v1.text.start);
+
+    new = g_binary_portion_new(BPC_CODE, &addr, format->header.v1.text.len);
 
     sprintf(desc, "%s \"%s\"", _("Segment"), "text");
     g_binary_portion_set_desc(new, desc);
 
-    init_vmpa(&addr, 0, format->header.v1.text.start);
-    g_binary_portion_set_values(new, &addr, format->header.v1.text.len);
-
     g_binary_portion_set_rights(new, PAC_WRITE | PAC_EXEC);
 
-    g_portion_layer_include(layer, new);
+    g_exe_format_include_portion(exe_format, new);
 
     /* Segment de données */
 
-    new = g_binary_portion_new(BPC_DATA);
+    init_vmpa(&addr, format->header.v1.text.len, format->header.v1.data.start);
+
+    new = g_binary_portion_new(BPC_DATA, &addr, format->header.v1.data.len);
 
     sprintf(desc, "%s \"%s\"", _("Segment"), "data");
     g_binary_portion_set_desc(new, desc);
 
-    init_vmpa(&addr, format->header.v1.text.len, format->header.v1.data.start);
-    g_binary_portion_set_values(new, &addr, format->header.v1.data.len);
-
     g_binary_portion_set_rights(new, PAC_READ | PAC_WRITE);
 
-    g_portion_layer_include(layer, new);
+    g_exe_format_include_portion(exe_format, new);
 
     /* Signature finale */
 
-    new = g_binary_portion_new(BPC_DATA);
+    length = g_binary_content_compute_size(G_BIN_FORMAT(format)->content);
+    init_vmpa(&addr, length - 521, VMPA_NO_VIRTUAL);  /* FIXME */
+
+    new = g_binary_portion_new(BPC_DATA, &addr, 521);
 
     sprintf(desc, "%s \"%s\"", _("Segment"), "sig");
     g_binary_portion_set_desc(new, desc);
 
-    length = g_binary_content_compute_size(G_BIN_FORMAT(format)->content);
-    init_vmpa(&addr, length - 521, VMPA_NO_VIRTUAL);  /* FIXME */
-    g_binary_portion_set_values(new, &addr, 521);
-
     g_binary_portion_set_rights(new, PAC_READ | PAC_WRITE);
 
-    g_portion_layer_include(layer, new);
+    g_exe_format_include_portion(exe_format, new);
 
 }
diff --git a/plugins/ropgadgets/finder.c b/plugins/ropgadgets/finder.c
index 6a2283c..98871b5 100644
--- a/plugins/ropgadgets/finder.c
+++ b/plugins/ropgadgets/finder.c
@@ -323,6 +323,7 @@ found_rop_list *list_all_gadgets(GExeFormat *format, unsigned int max_depth, upd
     found_rop_list *result;                 /* Liste de listes à renvoyer  */
     const char *target;                     /* Sous-traitance requise      */
     search_domain domain;                   /* Outils pour la recherche    */
+    GBinPortion *portions;                  /* Couche première de portions */
     GProcContext **contexts;                /* Contextes pour recherches   */
     char **names;                           /* Désignations humaines liées */
     size_t i;                               /* Boucle de parcours          */
@@ -337,7 +338,35 @@ found_rop_list *list_all_gadgets(GExeFormat *format, unsigned int max_depth, upd
     target = g_exe_format_get_target_machine(format);
     domain.proc = get_arch_processor_for_type(target);
 
-    domain.exe_ranges = g_exe_format_get_x_ranges(format, &domain.exe_count);
+    bool collect_x_ranges(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, void *unused)
+    {
+        const mrange_t *range;
+
+        if (visit == BPV_SHOW)
+        {
+            if (g_binary_portion_get_rights(portion) & PAC_EXEC)
+            {
+                range = g_binary_portion_get_range(portion);
+
+                domain.exe_ranges = (mrange_t *)realloc(domain.exe_ranges, ++domain.exe_count * sizeof(mrange_t));
+                copy_mrange(&domain.exe_ranges[domain.exe_count - 1], range);
+
+            }
+
+        }
+
+        return true;
+
+    }
+
+    domain.exe_ranges = NULL;
+    domain.exe_count = 0;
+
+    portions = g_exe_format_get_portions(format);
+
+    g_binary_portion_visit(portions, (visit_portion_fc)collect_x_ranges, NULL);
+
+    g_object_unref(G_OBJECT(portions));
 
     /* Récupération des différents contextes */
 
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c
index 71e2784..2bc7a53 100644
--- a/src/analysis/disass/area.c
+++ b/src/analysis/disass/area.c
@@ -35,6 +35,7 @@
 #include "../../analysis/contents/restricted.h"
 #include "../../arch/raw.h"
 #include "../../common/bits.h"
+#include "../../common/sort.h"
 #include "../../format/format.h"
 #include "../../glibext/delayed-int.h"
 #include "../../gui/panels/log.h"
@@ -115,11 +116,32 @@ typedef struct _GAreaCollector
 
     mem_area *areas;                        /* Zone de productions         */
 
-    size_t begin;                           /* Début du parcours à mener   */
-    size_t end;                             /* Fin de ce même parcours     */
+    union
+    {
+        struct
+        {
+            size_t acount;                  /* Nombre de zones créées      */
+
+            GLoadedBinary *binary;          /* Binaire à associer aux zones*/
 
-    GArchInstruction **collected;           /* Instructions collectées     */
-    size_t count;                           /* Quantité de ces instructions*/
+            phys_t first;                   /* Début de traitement         */
+            phys_t last;                    /* Fin de traitement           */
+
+            bool closing;                   /* Tâche clôturant le parcours */
+
+        };
+
+        struct
+        {
+            size_t begin;                   /* Début du parcours à mener   */
+            size_t end;                     /* Fin de ce même parcours     */
+
+            GArchInstruction **collected;   /* Instructions collectées     */
+            size_t ccount;                  /* Quantité de ces instructions*/
+
+        };
+
+    };
 
 } GAreaCollector;
 
@@ -149,6 +171,12 @@ static void g_area_collector_finalize(GAreaCollector *);
 /* Assure un traitement particulier concernant les zones. */
 static void g_area_collector_process(GAreaCollector *, GtkStatusStack *);
 
+/* Crée une tâche de calcul des zones binaires à désassembler. */
+static GAreaCollector *g_area_collector_new_intro(activity_id_t, GLoadedBinary *, phys_t, phys_t, bool);
+
+/* Construit une liste bornée de zones contigües. */
+static void g_area_collector_do_compute(GAreaCollector *, GtkStatusStack *);
+
 /* Crée une tâche de récupération d'instructions différée. */
 static GAreaCollector *g_area_collector_new_outro(activity_id_t, mem_area *, size_t, size_t);
 
@@ -779,230 +807,6 @@ static GArchInstruction **get_instructions_from_mem_area(const mem_area *area, G
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : binary     = binaire analysé contenant quantités d'infos.    *
-*                bin_length = quantité d'octets à traiter au total.           *
-*                count      = nombre de zones mises en place. [OUT]           *
-*                                                                             *
-*  Description : Détermine une liste de zones contigües à traiter.            *
-*                                                                             *
-*  Retour      : Liste de zones mémoire à libérer après usage.                *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-mem_area *compute_memory_areas(const GLoadedBinary *binary, phys_t bin_length, size_t *count)
-{
-    mem_area *result;                       /* Liste à renvoyer            */
-    GExeFormat *format;                     /* Format de fichier associé   */
-    mrange_t *exe_ranges;                   /* Liste de zones exécutables  */
-    size_t exe_count;                       /* Nombre de ces zones         */
-    GBinSymbol **symbols;                   /* Symboles à représenter      */
-    size_t sym_count;                       /* Qté de symboles présents    */
-    vmpa2t last;                            /* Dernière bordure rencontrée */
-    bool status;                            /* Bilan d'une conversion      */
-    size_t i;                               /* Boucle de parcours #1       */
-    const vmpa2t *border;                   /* Nouvelle bordure rencontrée */
-    mem_area *area;                         /* Zone avec valeurs à éditer  */
-    vmpa2t tmp;                             /* Stockage temporaire         */
-    GPortionLayer *layer;                   /* Couche première de portions */
-    GBinPortion **portions;                 /* Morceaux d'encadrement      */
-    size_t portions_count;                  /* Taille de cette liste       */
-    const vmpa2t *portion_start;            /* Point de départ de portion  */
-    const vmpa2t *portion_next;             /* Départ de portion suivante  */
-    size_t j;                               /* Boucle de parcours #2       */
-    SymbolType type;                        /* Nature d'un symbole         */
-    const mrange_t *range;                  /* Couverture d'un symbole     */
-    phys_t length;                          /* Taille de ce même symbole   */
-    phys_t new_length;                      /* Nouvelle taille déterminée  */
-
-    result = NULL;
-    *count = 0;
-
-    /**
-     * Le parcours n'est valide que si les zones exécutables sont triées !
-     */
-
-    format = g_loaded_binary_get_format(binary);
-
-    exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);
-
-    symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
-
-    /* Première étape : on comble les trous ! */
-
-    status = g_exe_format_translate_offset_into_vmpa(format, 0, &last);
-    assert(status);
-
-    for (i = 0; i < exe_count; i++)
-    {
-        border = get_mrange_addr(&exe_ranges[i]);
-
-        /* Zone tampon à constituer */
-
-        if (cmp_vmpa(&last, border) < 0)
-        {
-            result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
-            area = &result[*count - 1];
-
-            init_mem_area_from_addr(area, &last, compute_vmpa_diff(&last, border), binary);
-            area->is_exec = false;
-
-        }
-
-        /* Insertion d'une zone exécutable déjà définie */
-
-        result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
-        area = &result[*count - 1];
-
-        init_mem_area_from_addr(area, get_mrange_addr(&exe_ranges[i]),
-                                   get_mrange_length(&exe_ranges[i]), binary);
-        area->is_exec = true;
-
-        /* Avancée du curseur */
-
-        compute_mrange_end_addr(&exe_ranges[i], &last);
-
-    }
-
-    /* Extension finale complémentaire ? */
-
-    area = &result[*count - 1];
-
-    copy_vmpa(&tmp, get_mrange_addr(&area->range));
-    advance_vmpa(&tmp, get_mrange_length(&area->range));
-
-    if (get_phy_addr(&tmp) < bin_length)
-    {
-        result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
-        area = &result[*count - 1];
-
-        init_mem_area_from_addr(area, &tmp, bin_length - get_phy_addr(&tmp), binary);
-        area->is_exec = false;
-
-    }
-
-    /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */
-
-    layer = g_exe_format_get_main_layer(format);
-
-    portions = g_portion_layer_collect_all_portions(layer, &portions_count);
-
-    for (i = 1; i < portions_count; i++)
-    {
-        portion_start = get_mrange_addr(g_binary_portion_get_range(portions[i]));
-
-        /**
-         * Si plusieurs portions débutent au même endroit, il ne sert
-         * à rien de découper plusieurs fois.
-         */
-        if ((i + 1) < portions_count)
-        {
-            portion_next = get_mrange_addr(g_binary_portion_get_range(portions[i + 1]));
-
-            if (cmp_vmpa(portion_start, portion_next) == 0)
-                continue;
-
-        }
-
-        for (j = 0; j < *count; j++)
-        {
-            area = &result[j];
-
-            if (!mrange_contains_addr(&area->range, portion_start))
-                continue;
-
-            /* Si le déccoupage actuel ne correspond pas au besoin des portions... */
-            if (cmp_vmpa(get_mrange_addr(&area->range), portion_start) != 0)
-            {
-                fini_mem_area(&result[j]);
-
-                result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
-                memmove(&result[j + 2], &result[j + 1], (*count - j - 2) * sizeof(mem_area));
-
-                status = result[j].is_exec;
-
-                /* Première moitié */
-
-                area = &result[j];
-
-                copy_vmpa(&tmp, get_mrange_addr(&area->range));
-                length = get_mrange_length(&area->range);
-
-                new_length = compute_vmpa_diff(&tmp, portion_start);
-
-                init_mem_area_from_addr(area, &tmp, new_length, binary);
-                area->is_exec = status;
-
-                /* Seconde moitié */
-
-                length -= get_mrange_length(&area->range);
-
-                area = &result[j + 1];
-
-                init_mem_area_from_addr(area, portion_start, length, binary);
-                area->is_exec = status;
-
-            }
-
-            j = *count;
-
-        }
-
-    }
-
-    if (portions != NULL)
-        free(portions);
-
-    g_object_unref(G_OBJECT(layer));
-
-    /* Troisième étape : on insère les symboles existants */
-
-    for (i = 0; i < sym_count; i++)
-    {
-        type = g_binary_symbol_get_target_type(symbols[i]);
-
-        /**
-         * On ne garde que les symboles renvoyant directement une ou
-         * plusieurs instructions, c'est à dire les symboles valides
-         * pour un appel à g_binary_symbol_get_instruction().
-         *
-         * Les instructions des autres symboles sont obtenues et mises
-         * en place durant la procédure de désassemblage.
-         */
-
-        if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL)
-            continue;
-
-        range = g_binary_symbol_get_range(symbols[i]);
-
-        length = get_mrange_length(range);
-
-        if (length == 0)
-            continue;
-
-        insert_extra_symbol_into_mem_areas(result, *count, symbols[i]);
-
-    }
-
-    /* Nettoyage final */
-
-    if (exe_ranges != NULL)
-        free(exe_ranges);
-
-    g_object_unref(G_OBJECT(format));
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : list  = listes de zones utable à consulter.                  *
 *                count = nombre de zones mises en place.                      *
 *                addr  = adresse à retrouver dans les aires présentes.        *
@@ -1212,6 +1016,9 @@ static void g_area_collector_init(GAreaCollector *collector)
 
 static void g_area_collector_dispose(GAreaCollector *collector)
 {
+    if (collector->run == (run_task_fc)g_area_collector_do_compute)
+        g_object_unref(G_OBJECT(collector->binary));
+
     G_OBJECT_CLASS(g_area_collector_parent_class)->dispose(G_OBJECT(collector));
 
 }
@@ -1258,6 +1065,366 @@ static void g_area_collector_process(GAreaCollector *collector, GtkStatusStack *
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : id      = identifiant pour signaler la progression courante. *
+*                binary  = binaire chargé à conserver dans les zones définies.*
+*                first   = localisation du début de la portion à traiter.     *
+*                last    = localisation de la fin de la portion à traiter.    *
+*                closing = indique si la tâche doit terminer l'analyse.       *
+*                                                                             *
+*  Description : Crée une tâche de calcul des zones binaires à désassembler.  *
+*                                                                             *
+*  Retour      : Tâche créée.                                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GAreaCollector *g_area_collector_new_intro(activity_id_t id, GLoadedBinary *binary, phys_t first, phys_t last, bool closing)
+{
+    GAreaCollector *result;            /* Tâche à retourner           */
+
+    result = g_object_new(G_TYPE_AREA_COLLECTOR, NULL);
+
+    result->id = id;
+    result->run = (run_task_fc)g_area_collector_do_compute;
+
+    result->areas = NULL;
+
+    result->acount = 0;
+
+    result->binary = binary;
+    g_object_ref(G_OBJECT(binary));
+
+    result->first = first;
+    result->last = last;
+
+    result->closing = closing;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : fetching = récupération à mener.                             *
+*                status   = barre de statut à tenir informée.                 *
+*                                                                             *
+*  Description : Construit une liste bornée de zones contigües.               *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_area_collector_do_compute(GAreaCollector *collector, GtkStatusStack *status)
+{
+    mem_area **list;                        /* Liste de zones à constituer */
+    size_t *count;                          /* Nombre d'éléments intégrés  */
+    vmpa2t first;                           /* Point de départ             */
+    vmpa2t last;                            /* Point d'arrivée             */
+    GExeFormat *format;                     /* Format du binaire           */
+    vmpa2t prev;                            /* Dernière bordure rencontrée */
+    bool state;                             /* Bilan d'une conversion      */
+    GBinSymbol **symbols;                   /* Symboles à représenter      */
+    size_t sym_count;                       /* Qté de symboles présents    */
+    bool has_sym_index;                     /* Détermine une validité      */
+    size_t sym_index;                       /* Prochain symbole non traité */
+    GBinPortion *portions;                  /* Couche première de portions */
+
+    void populate_with_symbols(const vmpa2t *limit)
+    {
+        GBinSymbol *symbol;                 /* Symbole en cours d'analyse  */
+        SymbolType type;                    /* Nature d'un symbole         */
+        const mrange_t *range;              /* Couverture d'un symbole     */
+        vmpa2t end;                         /* Adresse de fin du symbole   */
+
+        for (; sym_index < sym_count; sym_index++)
+        {
+            symbol = symbols[sym_index];
+
+            type = g_binary_symbol_get_target_type(symbol);
+
+            /**
+             * On ne garde que les symboles renvoyant directement une ou
+             * plusieurs instructions, c'est à dire les symboles valides
+             * pour un appel à g_binary_symbol_get_instruction().
+             *
+             * Les instructions des autres symboles sont obtenues et mises
+             * en place durant la procédure de désassemblage.
+             */
+
+            if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL)
+                continue;
+
+            range = g_binary_symbol_get_range(symbol);
+
+            if (get_mrange_length(range) == 0)
+                continue;
+
+            if (cmp_vmpa(get_mrange_addr(range), limit) >= 0)
+                break;
+
+            compute_mrange_end_addr(range, &end);
+
+            /**
+             * Si un symbole est à cheval entre deux zones, tant pis pour lui !
+             */
+
+            if (cmp_vmpa(&end, limit) > 0)
+                break;
+
+            insert_extra_symbol_into_mem_areas(*list, *count, symbol);
+
+        }
+
+    }
+
+    void fill_gap(vmpa2t *old, vmpa2t *new, bool exec)
+    {
+        phys_t diff;                        /* Espace entre bordures       */
+        mem_area *area;                     /* Zone avec valeurs à éditer  */
+
+        diff = compute_vmpa_diff(old, new);
+
+        /**
+         * S'il existe un écart entre la dernière bordure ajoutée et
+         * l'extréminité de la portion courante, on le comble !
+         */
+
+        if (diff > 0)
+        {
+            /* Zone tampon à constituer */
+
+            *list = (mem_area *)realloc(*list, ++(*count) * sizeof(mem_area));
+
+            area = &(*list)[*count - 1];
+
+            init_mem_area_from_addr(area, old, diff, collector->binary);
+            area->is_exec = exec;
+
+            /* Insertion des symboles existants */
+
+            if (!has_sym_index)
+            {
+                int cmp_vmpa_with_symbol(const vmpa2t *a, const GBinSymbol **s)
+                {
+                    return g_binary_symbol_cmp_with_vmpa(*s, a);
+                }
+
+                bsearch_index(old, symbols, sym_count, sizeof(GBinSymbol *),
+                              (__compar_fn_t)cmp_vmpa_with_symbol, &sym_index);
+
+                has_sym_index = true;
+
+            }
+
+            populate_with_symbols(new);
+
+            /* Avancée du curseur */
+
+            copy_vmpa(old, new);
+
+            gtk_status_stack_update_activity_value(status, collector->id, diff);
+
+        }
+
+    }
+
+    bool build_area_from_portion(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, void *unused)
+    {
+        const mrange_t *range;              /* Espace de portion à traiter */
+        vmpa2t border;                      /* Nouvelle bordure rencontrée */
+        bool on_track;                      /* Le tronçon courant est bon ?*/
+        PortionAccessRights rights;         /* Droits d'accès à analyser   */
+
+        range = g_binary_portion_get_range(portion);
+
+        if (visit == BPV_ENTER)
+        {
+            copy_vmpa(&border, get_mrange_addr(range));
+
+            on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0;
+
+            if (on_track)
+            {
+                rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE);
+                fill_gap(&prev, &border, rights & PAC_EXEC);
+            }
+            else
+                copy_vmpa(&prev, &border);
+
+        }
+
+        else if (visit == BPV_SHOW)
+        {
+            copy_vmpa(&border, get_mrange_addr(range));
+
+            on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0;
+
+            if (on_track)
+            {
+                rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE);
+                fill_gap(&prev, &border, rights & PAC_EXEC);
+
+                compute_mrange_end_addr(range, &border);
+
+                rights = g_binary_portion_get_rights(portion);
+                fill_gap(&prev, &border, rights & PAC_EXEC);
+
+            }
+            else
+                compute_mrange_end_addr(range, &prev);
+
+        }
+
+        else if (visit == BPV_EXIT)
+        {
+            compute_mrange_end_addr(range, &border);
+
+            if (collector->closing)
+                on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) <= 0;
+            else
+                on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0;
+
+            if (on_track)
+            {
+                rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE);
+                fill_gap(&prev, &border, rights & PAC_EXEC);
+            }
+            else
+                copy_vmpa(&prev, &border);
+
+        }
+
+#ifndef NDEBUG
+        else
+            assert(false);
+#endif
+
+        return (cmp_vmpa(&prev, &last) < 0);
+
+    }
+
+    list = &collector->areas;
+    count = &collector->acount;
+
+    init_vmpa(&first, collector->first, VMPA_NO_VIRTUAL);
+    init_vmpa(&last, collector->last, VMPA_NO_VIRTUAL);
+
+    format = g_loaded_binary_get_format(collector->binary);
+
+#ifndef NDEBUG
+    state = g_exe_format_translate_offset_into_vmpa(format, 0, &prev);
+    assert(state);
+#else
+    g_exe_format_translate_offset_into_vmpa(format, 0, &prev);
+#endif
+
+    symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
+
+    has_sym_index = false;
+
+    portions = g_exe_format_get_portions(format);
+
+    g_binary_portion_visit(portions, (visit_portion_fc)build_area_from_portion, NULL);
+
+    g_object_unref(G_OBJECT(portions));
+
+    g_object_unref(G_OBJECT(format));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : gid    = groupe de travail impliqué.                         *
+*                status = barre de statut à tenir informée.                   *
+*                binary = binaire analysé contenant quantités d'infos.        *
+*                length = quantité d'octets à traiter au total.               *
+*                count  = nombre de zones mises en place. [OUT]               *
+*                                                                             *
+*  Description : Détermine une liste de zones contigües à traiter.            *
+*                                                                             *
+*  Retour      : Liste de zones mémoire à libérer après usage.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+mem_area *collect_memory_areas(wgroup_id_t gid, GtkStatusStack *status, GLoadedBinary *binary, phys_t length, size_t *count)
+{
+    mem_area *result;                       /* Liste finale à retourner    */
+    guint runs_count;                       /* Qté d'exécutions parallèles */
+    GAreaCollector **collectors;            /* Collecteurs à suivre        */
+    phys_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          */
+    phys_t first;                           /* Début de zone de traitement */
+    bool closing;                           /* Détection de fin en amont   */
+    phys_t last;                            /* Fin de zone de traitement   */
+
+    runs_count = g_get_num_processors();
+
+    collectors = (GAreaCollector **)calloc(runs_count, sizeof(GAreaCollector *));
+
+    run_size = length / runs_count;
+
+    queue = get_work_queue();
+
+    id = gtk_status_stack_add_activity(status, _("Computing memory areas to disassemble"), length);
+
+    for (i = 0; i < runs_count; i++)
+    {
+        first = i * run_size;
+
+        closing = ((i + 1) == runs_count);
+
+        if (closing)
+            last = length;
+        else
+            last = first + run_size;
+
+        collectors[i] = g_area_collector_new_intro(id, binary, first, last, closing);
+
+        g_object_ref(G_OBJECT(collectors[i]));
+        g_work_queue_schedule_work(queue, G_DELAYED_WORK(collectors[i]), gid);
+
+    }
+
+    g_work_queue_wait_for_completion(queue, gid);
+
+    /* Récupération des aires */
+
+    result = NULL;
+    *count = 0;
+
+    for (i = 0; i < runs_count; i++)
+    {
+        result = (mem_area *)realloc(result, (*count + collectors[i]->acount) * sizeof(mem_area));
+
+        memcpy(&result[*count], collectors[i]->areas, collectors[i]->acount * sizeof(mem_area));
+        *count += collectors[i]->acount;
+
+        g_object_unref(G_OBJECT(collectors[i]));
+
+    }
+
+    /* Fin */
+
+    free(collectors);
+
+    gtk_status_stack_remove_activity(status, id);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : id    = identifiant pour signaler la progression courante.   *
 *                list  = liste des zones en place à parcourir.                *
 *                begin = indice de la première zone à traiter.                *
@@ -1286,7 +1453,7 @@ static GAreaCollector *g_area_collector_new_outro(activity_id_t id, mem_area *li
     result->end = end;
 
     result->collected = NULL;
-    result->count = 0;
+    result->ccount = 0;
 
     return result;
 
@@ -1313,7 +1480,7 @@ static void g_area_collector_do_collect(GAreaCollector *collector, GtkStatusStac
     for (i = collector->begin; i < collector->end; i++)
     {
         collector->collected = get_instructions_from_mem_area(&collector->areas[i],
-                                                              collector->collected, &collector->count);
+                                                              collector->collected, &collector->ccount);
 
         fini_mem_area(&collector->areas[i]);
 
@@ -1326,8 +1493,8 @@ static void g_area_collector_do_collect(GAreaCollector *collector, GtkStatusStac
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : gid      = groupe de travail impliqué.                       *
-*                status   = barre de statut à tenir informée.                 *
+*  Paramètres  : gid    = groupe de travail impliqué.                         *
+*                status = barre de statut à tenir informée.                   *
 *                list   = liste des zones de données à relire puis libérer.   *
 *                acount = taille de cette liste de zones.                     *
 *                icount = nombre d'instructions récupérées. [OUT]             *
@@ -1388,10 +1555,10 @@ GArchInstruction **collect_disassembled_instructions(wgroup_id_t gid, GtkStatusS
     for (i = 0; i < runs_count; i++)
     {
         result = (GArchInstruction **)realloc(result,
-                                              (*icount + collectors[i]->count) * sizeof(GArchInstruction *));
+                                              (*icount + collectors[i]->ccount) * sizeof(GArchInstruction *));
 
-        memcpy(&result[*icount], collectors[i]->collected, collectors[i]->count * sizeof(GArchInstruction *));
-        *icount += collectors[i]->count;
+        memcpy(&result[*icount], collectors[i]->collected, collectors[i]->ccount * sizeof(GArchInstruction *));
+        *icount += collectors[i]->ccount;
 
         g_object_unref(G_OBJECT(collectors[i]));
 
diff --git a/src/analysis/disass/area.h b/src/analysis/disass/area.h
index 725b9a8..d5f910b 100644
--- a/src/analysis/disass/area.h
+++ b/src/analysis/disass/area.h
@@ -43,9 +43,6 @@ typedef struct _mem_area mem_area;
 void load_code_from_mem_area(mem_area *, mem_area *, size_t, GProcContext *, const vmpa2t *, bool, GtkStatusStack *, activity_id_t);
 
 /* Détermine une liste de zones contigües à traiter. */
-mem_area *compute_memory_areas(const GLoadedBinary *, phys_t, size_t *);
-
-/* Détermine une liste de zones contigües à traiter. */
 mem_area *find_memory_area_by_addr(mem_area *, size_t, const vmpa2t *);
 
 /* Insère un symbole dans un découpage en aires. */
@@ -58,6 +55,9 @@ void ensure_all_mem_areas_are_filled(mem_area *, size_t, GProcContext *, GtkStat
 /* ----------------------- MANIPULATIONS PARALLELES DES ZONES ----------------------- */
 
 
+/* Détermine une liste de zones contigües à traiter. */
+mem_area *collect_memory_areas(wgroup_id_t, GtkStatusStack *, GLoadedBinary *, phys_t, size_t *);
+
 /* Rassemble les instructions conservées dans des zones données. */
 GArchInstruction **collect_disassembled_instructions(wgroup_id_t, GtkStatusStack *, mem_area *, size_t, size_t *);
 
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index 172ee1c..5326c36 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -312,8 +312,7 @@ static void process_all_instructions(wgroup_id_t gid, GtkStatusStack *status, co
 
 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         */
+    GBinPortion *portions;                  /* Couche première de portions */
     GBinRoutine **routines;                 /* Liste des routines trouvées */
     size_t routines_count;                  /* Nombre de ces routines      */
     guint runs_count;                       /* Qté d'exécutions parallèles */
@@ -325,7 +324,7 @@ static void process_all_routines(wgroup_id_t gid, GtkStatusStack *status, const
     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);
+    portions = g_exe_format_get_portions(format);
 
     routines = g_binary_format_get_routines(G_BIN_FORMAT(format), &routines_count);
 
@@ -346,7 +345,7 @@ static void process_all_routines(wgroup_id_t gid, GtkStatusStack *status, const
         else
             end = begin + run_size;
 
-        study = g_routines_study_new(proc, exe_ranges, exe_count, routines, routines_count,
+        study = g_routines_study_new(proc, portions, routines, routines_count,
                                      begin, end, id, fallback);
 
         g_work_queue_schedule_work(queue, G_DELAYED_WORK(study), gid);
@@ -357,8 +356,7 @@ static void process_all_routines(wgroup_id_t gid, GtkStatusStack *status, const
 
     gtk_status_stack_remove_activity(status, id);
 
-    if (exe_ranges != NULL)
-        free(exe_ranges);
+    g_object_unref(G_OBJECT(portions));
 
 }
 
diff --git a/src/analysis/disass/fetch.c b/src/analysis/disass/fetch.c
index 784e103..ee0916b 100644
--- a/src/analysis/disass/fetch.c
+++ b/src/analysis/disass/fetch.c
@@ -392,7 +392,7 @@ static bool check_if_extra_wait_is_needed(GWorkQueue *queue, wgroup_id_t id, GPr
 *                                                                             *
 ******************************************************************************/
 
-GArchInstruction **disassemble_binary_content(const GLoadedBinary *binary, GProcContext *ctx, wgroup_id_t gid, GtkStatusStack *status, size_t *count)
+GArchInstruction **disassemble_binary_content(GLoadedBinary *binary, GProcContext *ctx, wgroup_id_t gid, GtkStatusStack *status, size_t *count)
 {
     GArchInstruction **result;               /* Instruction désassemblées   */
     GDelayedFetching template;              /* Patron des tâches à venir   */
@@ -415,7 +415,7 @@ GArchInstruction **disassemble_binary_content(const GLoadedBinary *binary, GProc
     length = g_binary_content_compute_size(content);
     g_object_unref(G_OBJECT(content));
 
-    template.areas = compute_memory_areas(binary, length, &template.count);
+    template.areas = collect_memory_areas(gid, status, binary, length, &template.count);
 
     template.status = status;
 
diff --git a/src/analysis/disass/fetch.h b/src/analysis/disass/fetch.h
index bf2b52f..b36a999 100644
--- a/src/analysis/disass/fetch.h
+++ b/src/analysis/disass/fetch.h
@@ -32,7 +32,7 @@
 
 
 /* Procède au désassemblage basique d'un contenu binaire. */
-GArchInstruction **disassemble_binary_content(const GLoadedBinary *, GProcContext *, wgroup_id_t, GtkStatusStack *, size_t *);
+GArchInstruction **disassemble_binary_content(GLoadedBinary *, GProcContext *, wgroup_id_t, GtkStatusStack *, size_t *);
 
 
 
diff --git a/src/analysis/disass/limit.c b/src/analysis/disass/limit.c
index 28a8264..18d089a 100644
--- a/src/analysis/disass/limit.c
+++ b/src/analysis/disass/limit.c
@@ -25,48 +25,12 @@
 
 
 
-/* Recherche la zone correspond à une adresse donnée. */
-static const mrange_t *find_x_range_for_addr(const mrange_t *, size_t, const vmpa2t *);
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : ranges = liste de zones offrant une exécution et disponibles.*
-*                count  = taille de cette liste.                              *
-*                                                                             *
-*  Description : Recherche la zone correspond à une adresse donnée.           *
-*                                                                             *
-*  Retour      : Zone trouvée ou NULL si aucune ne correspond.                *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static const mrange_t *find_x_range_for_addr(const mrange_t *ranges, size_t count, const vmpa2t *addr)
-{
-    const mrange_t *result;                 /* Zone à retourner            */
-    size_t i;                               /* Boucle de parcours          */
-
-    result = NULL;
-
-    for (i = 0; i < count && result == NULL; i++)
-        if (mrange_contains_addr(&ranges[i], addr))
-            result = &ranges[i];
-
-    return result;
-
-}
-
-
 /******************************************************************************
 *                                                                             *
-*  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.   *
+*  Paramètres  : routine  = routine dont les frontières sont à fixer.         *
+*                prev     = routine précédente dans les traitements.          *
+*                proc     = ensemble d'instructions désassemblées.            *
+*                portions = ensemble de couches binaires bornées.             *
 *                                                                             *
 *  Description : S'assure qu'une routine est bien bornée.                     *
 *                                                                             *
@@ -76,12 +40,13 @@ static const mrange_t *find_x_range_for_addr(const mrange_t *ranges, size_t coun
 *                                                                             *
 ******************************************************************************/
 
-void compute_routine_limit(GBinRoutine *routine, GBinRoutine *prev, GArchProcessor *proc, mrange_t *exe_ranges, size_t exe_count)
+void compute_routine_limit(GBinRoutine *routine, GBinRoutine *prev, GArchProcessor *proc, GBinPortion *portions)
 {
     const mrange_t *range;                  /* Emplacement courant         */
     vmpa2t addr;                            /* Adresse à conserver         */
     GArchInstruction *start;                /* Première instruction        */
     phys_t diff;                            /* Taille définie par déduction*/
+    GBinPortion *portion;                   /* Conteneur avec limites      */
     mrange_t new;                           /* Nouvel emplacement taillé   */
 
     range = g_binary_routine_get_range(routine);
@@ -114,12 +79,16 @@ void compute_routine_limit(GBinRoutine *routine, GBinRoutine *prev, GArchProcess
     /* Sinon on va jusqu'à la fin de la zone ! */
     else
     {
-        range = find_x_range_for_addr(exe_ranges, exe_count, &addr);
-        if (range == NULL) goto crl_skip;
+        portion = g_binary_portion_find_at_addr(portions, &addr, (GdkRectangle []) { });
+        if (portion == NULL) goto crl_skip;
+
+        range = g_binary_portion_get_range(portion);
 
         diff = compute_vmpa_diff(&addr, get_mrange_addr(range));
         diff = get_mrange_length(range) - diff;
 
+        g_object_unref(G_OBJECT(portion));
+
     }
 
     init_mrange(&new, &addr, diff);
diff --git a/src/analysis/disass/limit.h b/src/analysis/disass/limit.h
index 7aba8a6..ed53325 100644
--- a/src/analysis/disass/limit.h
+++ b/src/analysis/disass/limit.h
@@ -32,7 +32,7 @@
 
 
 /* S'assure qu'une routine est bien bornée. */
-void compute_routine_limit(GBinRoutine *, GBinRoutine *, GArchProcessor *, mrange_t *, size_t);
+void compute_routine_limit(GBinRoutine *, GBinRoutine *, GArchProcessor *, GBinPortion *);
 
 
 
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index 0d85870..fe4d705 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -59,7 +59,7 @@
 
 void print_disassembled_instructions(GCodeBuffer *buffer, GExeFormat *format, GArchProcessor *proc, GtkStatusStack *status)
 {
-    GPortionLayer *layer;                   /* Couche première de portions */
+    GBinPortion *root;                      /* Couche première de portions */
     GBinPortion **portions;                 /* Morceaux d'encadrement      */
     size_t portions_count;                  /* Taille de cette liste       */
     size_t portion_index;                   /* Prochaine portion à traiter */
@@ -99,12 +99,29 @@ void print_disassembled_instructions(GCodeBuffer *buffer, GExeFormat *format, GA
 
 
 
+    bool collect_all_portions(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, void *unused)
+    {
+        if (visit == BPV_ENTER || visit == BPV_SHOW)
+        {
+            portions = (GBinPortion **)realloc(portions, ++portions_count * sizeof(GBinPortion *));
+            portions[portions_count - 1] = portion;
+        }
+
+        return true;
+
+    }
 
-    layer = g_exe_format_get_main_layer(format);
+    portions = NULL;
+    portions_count = 0;
 
-    portions = g_portion_layer_collect_all_portions(layer, &portions_count);
     portion_index = 0;
 
+    root = g_exe_format_get_portions(format);
+
+    g_binary_portion_visit(root, (visit_portion_fc)collect_all_portions, NULL);
+
+    g_object_unref(G_OBJECT(root));
+
     symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
     sym_index = 0;
 
@@ -339,9 +356,6 @@ void print_disassembled_instructions(GCodeBuffer *buffer, GExeFormat *format, GA
     if (portions != NULL)
         free(portions);
 
-    g_object_unref(G_OBJECT(layer));
-
-
     fprintf(stderr, "MISSING :: %u symbols\n", _missing);
 
 
diff --git a/src/analysis/disass/routines.c b/src/analysis/disass/routines.c
index a9414fc..6fd9279 100644
--- a/src/analysis/disass/routines.c
+++ b/src/analysis/disass/routines.c
@@ -40,8 +40,7 @@ struct _GRoutinesStudy
 
     GArchProcessor *proc;                   /* Processeurs avec ses instr. */
 
-    mrange_t *exe_ranges;                   /* Liste de zones exécutables  */
-    size_t exe_count;                       /* Nombre de ces zones         */
+    GBinPortion *portions;                  /* Couches de binaire bornées  */
 
     GBinRoutine **routines;                 /* Liste de routines à traiter */
     size_t count;                           /* Taille de cette liste       */
@@ -147,6 +146,8 @@ static void g_routines_study_init(GRoutinesStudy *study)
 
 static void g_routines_study_dispose(GRoutinesStudy *study)
 {
+    g_object_unref(G_OBJECT(study->portions));
+
     G_OBJECT_CLASS(g_routines_study_parent_class)->dispose(G_OBJECT(study));
 
 }
@@ -174,6 +175,7 @@ static void g_routines_study_finalize(GRoutinesStudy *study)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : proc     = ensemble d'instructions désassemblées.            *
+*                portions = ensemble de couches binaires bornées.             *
 *                routines = prototypes existants à insérer.                   *
 *                count    = quantité de ces prototypes.                       *
 *                begin    = point de départ du parcours de liste.             *
@@ -189,7 +191,7 @@ static void g_routines_study_finalize(GRoutinesStudy *study)
 *                                                                             *
 ******************************************************************************/
 
-GRoutinesStudy *g_routines_study_new(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 *g_routines_study_new(GArchProcessor *proc, GBinPortion *portions, GBinRoutine **routines, size_t count, size_t begin, size_t end, activity_id_t id, rtn_fallback_cb fallback)
 {
     GRoutinesStudy *result;                /* Tâche à retourner           */
 
@@ -197,8 +199,8 @@ GRoutinesStudy *g_routines_study_new(GArchProcessor *proc, mrange_t *exe_ranges,
 
     result->proc = proc;
 
-    result->exe_ranges = exe_ranges;
-    result->exe_count = exe_count;
+    result->portions = portions;
+    g_object_ref(G_OBJECT(portions));
 
     result->routines = routines;
     result->count = count;
@@ -267,7 +269,7 @@ void g_routines_study_compute_limits(GRoutinesStudy *study, size_t index)
     else
         next = NULL;
 
-    compute_routine_limit(routine, next, study->proc, study->exe_ranges, study->exe_count);
+    compute_routine_limit(routine, next, study->proc, study->portions);
 
 }
 
diff --git a/src/analysis/disass/routines.h b/src/analysis/disass/routines.h
index 72df309..b89f69a 100644
--- a/src/analysis/disass/routines.h
+++ b/src/analysis/disass/routines.h
@@ -52,7 +52,7 @@ 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(GArchProcessor *, mrange_t *, size_t, GBinRoutine **, size_t, size_t, size_t, activity_id_t, rtn_fallback_cb);
+GRoutinesStudy *g_routines_study_new(GArchProcessor *, GBinPortion *, 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);
diff --git a/src/format/dex/class.c b/src/format/dex/class.c
index 26907ed..c1ff62a 100644
--- a/src/format/dex/class.c
+++ b/src/format/dex/class.c
@@ -401,9 +401,8 @@ GDexMethod *g_dex_class_get_method(const GDexClass *class, bool virtual, size_t
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : class = informations chargées à consulter.                   *
+*  Paramètres  : class  = informations chargées à consulter.                  *
 *                format = format permettant d'obtenir une adresse complète.   *
-*                layer = couche de portions à raffiner.                       *
 *                                                                             *
 *  Description : Intègre la méthode en tant que portion de code.              *
 *                                                                             *
@@ -413,15 +412,15 @@ GDexMethod *g_dex_class_get_method(const GDexClass *class, bool virtual, size_t
 *                                                                             *
 ******************************************************************************/
 
-void g_dex_class_include_as_portion(const GDexClass *class, const GDexFormat *format, GPortionLayer *layer)
+void g_dex_class_include_as_portion(const GDexClass *class, GExeFormat *format)
 {
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < class->dmethods_count; i++)
-        g_dex_method_include_as_portion(class->direct_methods[i], format, layer);
+        g_dex_method_include_as_portion(class->direct_methods[i], format);
 
     for (i = 0; i < class->vmethods_count; i++)
-        g_dex_method_include_as_portion(class->virtual_methods[i], format, layer);
+        g_dex_method_include_as_portion(class->virtual_methods[i], format);
 
 }
 
diff --git a/src/format/dex/class.h b/src/format/dex/class.h
index 46529c3..ec2fa24 100644
--- a/src/format/dex/class.h
+++ b/src/format/dex/class.h
@@ -69,7 +69,7 @@ size_t g_dex_class_count_methods(const GDexClass *, bool);
 GDexMethod *g_dex_class_get_method(const GDexClass *, bool, size_t);
 
 /* Intègre la méthode en tant que portion de code. */
-void g_dex_class_include_as_portion(const GDexClass *, const GDexFormat *, GPortionLayer *);
+void g_dex_class_include_as_portion(const GDexClass *, GExeFormat *);
 
 /* Retrouve si possible la méthode associée à une adresse. */
 GDexMethod *g_dex_class_find_method_by_address(const GDexClass *, vmpa_t);
diff --git a/src/format/dex/dex.c b/src/format/dex/dex.c
index c550375..df920b2 100755
--- a/src/format/dex/dex.c
+++ b/src/format/dex/dex.c
@@ -58,7 +58,7 @@ static void g_dex_format_finalize(GDexFormat *);
 static const char *g_dex_format_get_target_machine(const GDexFormat *);
 
 /* Etend la définition des portions au sein d'un binaire. */
-static void g_dex_format_refine_portions(const GDexFormat *, GPortionLayer *);
+static void g_dex_format_refine_portions(GDexFormat *);
 
 /* Fournit l'emplacement d'une section donnée. */
 static bool g_dex_format_get_section_range_by_name(const GDexFormat *, const char *, mrange_t *);
@@ -247,12 +247,14 @@ GBinFormat *g_dex_format_new(GBinContent *content, GExeFormat *parent, GtkStatus
 {
     GDexFormat *result;                     /* Structure à retourner       */
     GBinFormat *base;                       /* Version basique du format   */
+    GExeFormat *exe_format;                 /* Autre version du format     */
     vmpa2t pos;                             /* Position de tête de lecture */
     wgroup_id_t gid;                        /* Identifiant pour les tâches */
 
     result = g_object_new(G_TYPE_DEX_FORMAT, NULL);
 
     base = G_BIN_FORMAT(result);
+    exe_format = G_EXE_FORMAT(result);
 
     g_binary_format_set_content(base, content);
 
@@ -277,7 +279,7 @@ GBinFormat *g_dex_format_new(GBinContent *content, GExeFormat *parent, GtkStatus
     if (!load_all_dex_classes(result, gid, status))
         goto gdfn_error;
 
-    if (!g_binary_format_complete_loading(base, status))
+    if (!g_executable_format_complete_loading(exe_format, status))
         goto gdfn_error;
 
     return base;
@@ -322,20 +324,18 @@ static const char *g_dex_format_get_target_machine(const GDexFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-static void g_dex_format_refine_portions(const GDexFormat *format, GPortionLayer *main)
+static void g_dex_format_refine_portions(GDexFormat *format)
 {
-    GPortionLayer *layer;                   /* Couche à mettre en place    */
+    GExeFormat *exe_format;                 /* Autre version du format     */
     size_t max;                             /* Nombre d'itérations prévues */
     size_t i;                               /* Boucle de parcours          */
 
-    layer = g_portion_layer_new(NO_LENGTH_YET, _("Code"));
-
-    g_portion_layer_attach_sub(main, layer);
+    exe_format = G_EXE_FORMAT(format);
 
     max = g_dex_format_count_classes(format);
 
     for (i = 0; i < max; i++)
-        g_dex_class_include_as_portion(format->classes[i], format, layer);
+        g_dex_class_include_as_portion(format->classes[i], exe_format);
 
 }
 
diff --git a/src/format/dex/method.c b/src/format/dex/method.c
index 1223eb9..8659a73 100644
--- a/src/format/dex/method.c
+++ b/src/format/dex/method.c
@@ -338,7 +338,6 @@ GBinRoutine *g_dex_method_get_routine(const GDexMethod *method)
 *                                                                             *
 *  Paramètres  : method = représentation interne du format DEX à consulter.   *
 *                format = format permettant d'obtenir une adresse complète.   *
-*                layer  = couche de portions à raffiner.                      *
 *                                                                             *
 *  Description : Intègre la méthode en tant que portion de code.              *
 *                                                                             *
@@ -348,11 +347,10 @@ GBinRoutine *g_dex_method_get_routine(const GDexMethod *method)
 *                                                                             *
 ******************************************************************************/
 
-void g_dex_method_include_as_portion(const GDexMethod *method, const GDexFormat *format, GPortionLayer *layer)
+void g_dex_method_include_as_portion(const GDexMethod *method, GExeFormat *format)
 {
     vmpa2t addr;                            /* Emplacement dans le binaire */
     GBinPortion *new;                       /* Nouvelle portion définie    */
-    char *desc;                             /* Description d'une portion   */
 
     /* Si la taille est nulle, on ne fait rien */
     if (method->info.access_flags & ACC_NATIVE)
@@ -361,22 +359,16 @@ void g_dex_method_include_as_portion(const GDexMethod *method, const GDexFormat
     if (!method->has_body)
         return;
 
-    if (!g_exe_format_translate_offset_into_vmpa(G_EXE_FORMAT(format), method->offset, &addr))
+    if (!g_exe_format_translate_offset_into_vmpa(format, method->offset, &addr))
         return;
 
-    new = g_binary_portion_new(BPC_CODE);
+    new = g_binary_portion_new(BPC_CODE, &addr, method->body.insns_size * sizeof(uint16_t));
 
-    asprintf(&desc, _("Dalvik code"));
-
-    g_binary_portion_set_desc(new, desc);
-
-    free(desc);
-
-    g_binary_portion_set_values(new, &addr, method->body.insns_size * sizeof(uint16_t));
+    g_binary_portion_set_desc(new, _("Dalvik code"));
 
     g_binary_portion_set_rights(new, PAC_READ | PAC_EXEC);
 
-    g_portion_layer_include(layer, new);
+    g_exe_format_include_portion(format, new);
 
 }
 
diff --git a/src/format/dex/method.h b/src/format/dex/method.h
index 41ddb4c..8836abb 100644
--- a/src/format/dex/method.h
+++ b/src/format/dex/method.h
@@ -82,7 +82,7 @@ const code_item *g_dex_method_get_dex_body(const GDexMethod *);
 GBinRoutine *g_dex_method_get_routine(const GDexMethod *);
 
 /* Intègre la méthode en tant que portion de code. */
-void g_dex_method_include_as_portion(const GDexMethod *, const GDexFormat *, GPortionLayer *);
+void g_dex_method_include_as_portion(const GDexMethod *, GExeFormat *);
 
 /* Indique la position de la méthode au sein du binaire. */
 bool g_dex_method_get_offset(const GDexMethod *method, phys_t *);
diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c
index 2dd41e1..a51fe33 100644
--- a/src/format/elf/elf.c
+++ b/src/format/elf/elf.c
@@ -69,7 +69,7 @@ static SourceEndian g_elf_format_get_endianness(const GElfFormat *);
 static const char *g_elf_format_get_target_machine(const GElfFormat *);
 
 /* Etend la définition des portions au sein d'un binaire. */
-static void g_elf_format_refine_portions(const GElfFormat *, GPortionLayer *);
+static void g_elf_format_refine_portions(GElfFormat *);
 
 /* Fournit l'emplacement correspondant à une position physique. */
 static bool g_elf_format_translate_offset_into_vmpa(const GElfFormat *, phys_t, vmpa2t *);
@@ -244,10 +244,12 @@ GBinFormat *g_elf_format_new(GBinContent *content, GExeFormat *parent, GtkStatus
 {
     GElfFormat *result;                     /* Structure à retourner       */
     GBinFormat *base;                       /* Version basique du format   */
+    GExeFormat *exe_format;                 /* Autre version du format     */
 
     result = g_object_new(G_TYPE_ELF_FORMAT, NULL);
 
     base = G_BIN_FORMAT(result);
+    exe_format = G_EXE_FORMAT(result);
 
     g_binary_format_set_content(base, content);
 
@@ -305,7 +307,7 @@ GBinFormat *g_elf_format_new(GBinContent *content, GExeFormat *parent, GtkStatus
     }
 
 
-    if (!g_binary_format_complete_loading(base, status))
+    if (!g_executable_format_complete_loading(exe_format, status))
         goto gefn_error;
 
     return base;
@@ -383,7 +385,6 @@ static const char *g_elf_format_get_target_machine(const GElfFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = informations chargées à consulter.                  *
-*                main   = couche de portions principale à raffiner.           *
 *                                                                             *
 *  Description : Etend la définition des portions au sein d'un binaire.       *
 *                                                                             *
@@ -393,14 +394,13 @@ static const char *g_elf_format_get_target_machine(const GElfFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer *main)
+static void g_elf_format_refine_portions(GElfFormat *format)
 {
-    GPortionLayer *layer;                   /* Couche à mettre en place    */
+    GExeFormat *exe_format;                 /* Autre version du format     */
     uint16_t max;                           /* Décompte d'éléments traités */
-    elf_phdr *sorted_phdrs;                 /* Liste de segments triée     */
     uint16_t i;                             /* Boucle de parcours          */
     off_t offset;                           /* Début de part de programme  */
-    elf_phdr *phdr;                         /* En-tête de programme ELF    */
+    elf_phdr phdr;                          /* En-tête de programme ELF    */
     uint32_t p_flags;                       /* Droits associés à une partie*/
     const char *background;                 /* Fond signigicatif           */
     GBinPortion *new;                       /* Nouvelle portion définie    */
@@ -409,11 +409,12 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
     PortionAccessRights rights;             /* Droits d'une portion        */
     elf_shdr strings;                       /* Section des descriptions    */
     bool has_strings;                       /* Section trouvée ?           */
-    elf_shdr *sorted_shdrs;                 /* Liste de sections triée     */
-    elf_shdr *section;                      /* En-tête de section ELF      */
+    elf_shdr shdr;                          /* En-tête de section ELF      */
     uint64_t sh_flags;                      /* Droits associés à une partie*/
     const char *name;                       /* Nom trouvé ou NULL          */
 
+    exe_format = G_EXE_FORMAT(format);
+
     /**
      * La copie des différents en-têtes cherche à reproduire l'inclusion native
      * du format :
@@ -429,83 +430,35 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
      * Côté segments basiques.
      */
 
-    layer = g_portion_layer_new(NO_LENGTH_YET, _("Segment"));
-
-    g_portion_layer_attach_sub(main, layer);
-
-    /* Constitution d'une liste de travail */
-
     max = ELF_HDR(format, format->header, e_phnum);
 
-    sorted_phdrs = (elf_phdr *)calloc(max, sizeof(elf_phdr));
-
     for (i = 0; i < max; i++)
     {
         offset = ELF_HDR(format, format->header, e_phoff)
             + ELF_HDR(format, format->header, e_phentsize) * i;
 
-        if (!read_elf_program_header(format, offset, &sorted_phdrs[i]))
-        {
-            if (format->is_32b)
-                sorted_phdrs[i].phdr32.p_type = PT_NULL;
-            else
-                sorted_phdrs[i].phdr64.p_type = PT_NULL;
-        }
-
-    }
-
-    /* Tri de cette liste */
-
-    int sort_phdr(elf_phdr *a, elf_phdr *b)
-    {
-        uint64_t filesz_a;                  /* Taille de l'en-tête 'a'     */
-        uint64_t filesz_b;                  /* Taille de l'en-tête 'b'     */
-        int status;                         /* Bilan d'une comparaison     */
-
-        filesz_a = ELF_PHDR(format, *a, p_filesz);
-        filesz_b = ELF_PHDR(format, *b, p_filesz);
-
-        if (filesz_a < filesz_b)
-            status = 1;
-
-        else if (filesz_a > filesz_b)
-            status = -1;
-
-        else
-            status = 0;
-
-        return status;
-
-    }
-
-    qsort(sorted_phdrs, max, sizeof(elf_phdr), (__compar_fn_t)sort_phdr);
-
-    /* Inclusion de ces en-têtes */
-
-    for (i = 0; i < max; i++)
-    {
-        phdr = &sorted_phdrs[i];
+        if (!read_elf_program_header(format, offset, &phdr))
+            continue;
 
-        if (ELF_PHDR(format, *phdr, p_type) == PT_NULL)
+        if (ELF_PHDR(format, phdr, p_type) == PT_NULL)
             continue;
 
-        p_flags = ELF_PHDR(format, *phdr, p_flags);
+        p_flags = ELF_PHDR(format, phdr, p_flags);
 
         if (p_flags & PF_X) background = BPC_CODE;
         else if (p_flags & PF_W) background = BPC_DATA;
         else background = BPC_DATA_RO;
 
-        new = g_binary_portion_new(background);
+        init_vmpa(&addr, ELF_PHDR(format, phdr, p_offset), ELF_PHDR(format, phdr, p_vaddr));
+
+        new = g_binary_portion_new(background, &addr, ELF_PHDR(format, phdr, p_filesz));
 
         snprintf(desc, MAX_PORTION_DESC, "%s \"%s\"",
                  _("Segment"),
-                 get_elf_program_type_desc(ELF_PHDR(format, *phdr, p_type)));
+                 get_elf_program_type_desc(ELF_PHDR(format, phdr, p_type)));
 
         g_binary_portion_set_desc(new, desc);
 
-        init_vmpa(&addr, ELF_PHDR(format, *phdr, p_offset), ELF_PHDR(format, *phdr, p_vaddr));
-        g_binary_portion_set_values(new, &addr, ELF_PHDR(format, *phdr, p_filesz));
-
         rights = PAC_NONE;
         if (p_flags & PF_R) rights |= PAC_READ;
         if (p_flags & PF_W) rights |= PAC_WRITE;
@@ -513,12 +466,10 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
 
         g_binary_portion_set_rights(new, rights);
 
-        g_portion_layer_include(layer, new);
+        g_exe_format_include_portion(exe_format, new);
 
     }
 
-    free(sorted_phdrs);
-
     /**
      * Inclusion des sections, si possible...
      */
@@ -527,64 +478,17 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
                                             ELF_HDR(format, format->header, e_shstrndx),
                                             &strings);
 
-    layer = g_portion_layer_new(NO_LENGTH_YET, _("Section"));
-
-    g_portion_layer_attach_sub(main, layer);
-
-    /* Constitution d'une liste de travail */
-
     max = ELF_HDR(format, format->header, e_shnum);
 
-    sorted_shdrs = (elf_shdr *)calloc(max, sizeof(elf_shdr));
-
-    for (i = 0; i < max; i++)
-    {
-        if (!find_elf_section_by_index(format, i, &sorted_shdrs[i]))
-        {
-            if (format->is_32b)
-                sorted_shdrs[i].shdr32.sh_offset = 0;
-            else
-                sorted_shdrs[i].shdr64.sh_offset = 0;
-        }
-
-    }
-
-    /* Tri de cette liste */
-
-    int sort_shdr(elf_shdr *a, elf_shdr *b)
-    {
-        uint64_t size_a;                    /* Taille de l'en-tête 'a'     */
-        uint64_t size_b;                    /* Taille de l'en-tête 'b'     */
-        int status;                         /* Bilan d'une comparaison     */
-
-        size_a = ELF_SHDR(format, *a, sh_size);
-        size_b = ELF_SHDR(format, *b, sh_size);
-
-        if (size_a < size_b)
-            status = 1;
-
-        else if (size_a > size_b)
-            status = -1;
-
-        else
-            status = 0;
-
-        return status;
-
-    }
-
-    qsort(sorted_shdrs, max, sizeof(elf_shdr), (__compar_fn_t)sort_shdr);
-
-    /* Inclusion de ces en-têtes */
-
     for (i = 0; i < max; i++)
     {
-        section = &sorted_shdrs[i];
+        if (!find_elf_section_by_index(format, i, &shdr))
+            continue;
 
-        if (ELF_SHDR(format, *section, sh_offset) == 0)
+        if (ELF_SHDR(format, shdr, sh_offset) == 0)
             continue;
 
-        sh_flags = ELF_SHDR(format, *section, sh_flags);
+        sh_flags = ELF_SHDR(format, shdr, sh_flags);
 
         if ((sh_flags & SHF_ALLOC) == 0)
             continue;
@@ -593,11 +497,13 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
         else if (sh_flags & SHF_WRITE) background = BPC_DATA;
         else background = BPC_DATA_RO;
 
-        new = g_binary_portion_new(background);
+        init_vmpa(&addr, ELF_SHDR(format, shdr, sh_offset), ELF_SHDR(format, shdr, sh_addr));
+
+        new = g_binary_portion_new(background, &addr, ELF_SHDR(format, shdr, sh_size));
 
         if (has_strings)
             name = extract_name_from_elf_string_section(format, &strings,
-                                                        ELF_SHDR(format, *section, sh_name));
+                                                        ELF_SHDR(format, shdr, sh_name));
         else name = NULL;
 
         if (name != NULL)
@@ -607,9 +513,6 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
 
         g_binary_portion_set_desc(new, desc);
 
-        init_vmpa(&addr, ELF_SHDR(format, *section, sh_offset), ELF_SHDR(format, *section, sh_addr));
-        g_binary_portion_set_values(new, &addr, ELF_SHDR(format, *section, sh_size));
-
         rights = PAC_NONE;
         if (sh_flags & SHF_ALLOC) rights |= PAC_READ;
         if (sh_flags & SHF_WRITE) rights |= PAC_WRITE;
@@ -617,12 +520,10 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer
 
         g_binary_portion_set_rights(new, rights);
 
-        g_portion_layer_include(layer, new);
+        g_exe_format_include_portion(exe_format, new);
 
     }
 
-    free(sorted_shdrs);
-
 }
 
 
diff --git a/src/format/executable-int.h b/src/format/executable-int.h
index a4d4b35..88527a5 100644
--- a/src/format/executable-int.h
+++ b/src/format/executable-int.h
@@ -36,7 +36,7 @@
 typedef const char * (* get_target_machine_fc) (const GExeFormat *);
 
 /* Etend la définition des portions au sein d'un binaire. */
-typedef void (* refine_portions_fc) (const GExeFormat *, GPortionLayer *);
+typedef void (* refine_portions_fc) (GExeFormat *);
 
 /* Fournit l'emplacement correspondant à une position physique. */
 typedef bool (* translate_phys_fc) (const GExeFormat *, phys_t, vmpa2t *);
@@ -57,7 +57,8 @@ struct _GExeFormat
     GDbgFormat **debugs;                    /* Informations de débogage    */
     size_t debugs_count;                    /* Nombre de ces informations  */
 
-    GPortionLayer *layers;                  /* Couches de morceaux binaires*/
+    GBinPortion *portions;                  /* Couches de morceaux binaires*/
+    GMutex mutex;                           /* Accès à l'arborescence      */
 
 };
 
@@ -77,6 +78,9 @@ struct _GExeFormatClass
 };
 
 
+/* Effectue les ultimes opérations de chargement d'un binaire. */
+bool g_executable_format_complete_loading(GExeFormat *, GtkStatusStack *);
+
 /* Fournit l'emplacement correspondant à une position physique. */
 bool g_exe_format_without_virt_translate_offset_into_vmpa(const GExeFormat *, phys_t, vmpa2t *);
 
diff --git a/src/format/executable.c b/src/format/executable.c
index c1ff940..3e902cf 100644
--- a/src/format/executable.c
+++ b/src/format/executable.c
@@ -24,6 +24,7 @@
 #include "executable.h"
 
 
+#include <assert.h>
 #include <malloc.h>
 #include <stdlib.h>
 
@@ -39,6 +40,12 @@ static void g_executable_format_class_init(GExeFormatClass *);
 /* Initialise une instance de format d'exécutable générique. */
 static void g_executable_format_init(GExeFormat *);
 
+/* Supprime toutes les références externes. */
+static void g_executable_format_dispose(GExeFormat *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_executable_format_finalize(GExeFormat *);
+
 
 
 /* Indique le type défini pour un format d'exécutable générique. */
@@ -59,6 +66,12 @@ G_DEFINE_TYPE(GExeFormat, g_executable_format, G_TYPE_BIN_FORMAT);
 
 static void g_executable_format_class_init(GExeFormatClass *klass)
 {
+    GObjectClass *object;                   /* Autre version de la classe  */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_executable_format_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_executable_format_finalize;
 
 }
 
@@ -77,11 +90,57 @@ static void g_executable_format_class_init(GExeFormatClass *klass)
 
 static void g_executable_format_init(GExeFormat *format)
 {
+    g_mutex_init(&format->mutex);
 
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_executable_format_dispose(GExeFormat *format)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < format->debugs_count; i++)
+        g_object_unref(G_OBJECT(format->debugs[i]));
+
+    if (format->portions != NULL)
+        g_object_unref(G_OBJECT(format->portions));
+
+    g_mutex_clear(&format->mutex);
 
+    G_OBJECT_CLASS(g_executable_format_parent_class)->dispose(G_OBJECT(format));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_executable_format_finalize(GExeFormat *format)
+{
+    G_OBJECT_CLASS(g_executable_format_parent_class)->finalize(G_OBJECT(format));
+
+}
 
 
 /******************************************************************************
@@ -184,109 +243,95 @@ const char *g_exe_format_get_target_machine(const GExeFormat *format)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : format = description de l'exécutable à consulter.            *
+*  Paramètres  : format = instance à traiter.                                 *
+*                status = barre de statut à tenir informée.                   *
 *                                                                             *
-*  Description : Fournit la première couche des portions composent le binaire.*
+*  Description : Effectue les ultimes opérations de chargement d'un binaire.  *
 *                                                                             *
-*  Retour      : Couche brute des différentes portions.                       *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
-*  Remarques   : Le compteur de références de l'instance renvoyée doit être   *
-*                décrémenté après usage.                                      *
+*  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GPortionLayer *g_exe_format_get_main_layer(GExeFormat *format)
+bool g_executable_format_complete_loading(GExeFormat *format, GtkStatusStack *status)
 {
-    GBinPortion *portion;                   /* Portion brute globale       */
+    bool result;                            /* Bilan à faire remonter      */
+    GBinFormat *base;                       /* Version basique du format   */
     vmpa2t addr;                            /* Emplacement vide de sens    */
     phys_t length;                          /* Taille de portion globale   */
-    GPortionLayer *layer;                   /* Couche à mettre en place    */
-
-    if (format->layers == NULL)
-    {
-        /* Création d'une portion globale */
-
-        portion = g_binary_portion_new(BPC_RAW);
 
-        init_vmpa(&addr, 0, VMPA_NO_VIRTUAL);
-        length = g_binary_content_compute_size(G_BIN_FORMAT(format)->content);
+    base = G_BIN_FORMAT(format);
 
-        g_binary_portion_set_values(portion, &addr, length);
+    result = g_binary_format_complete_loading(base, status);
 
-        /* Création d'une couche de base brute */
-
-        layer = g_portion_layer_new(length, NULL);
-
-        g_portion_layer_include(layer, portion);
+    if (result)
+    {
+        result = g_exe_format_translate_offset_into_vmpa(format, 0, &addr);
+        assert(result);
 
-        /* Remplissage */
+        length = g_binary_content_compute_size(base->content);
 
-        G_EXE_FORMAT_GET_CLASS(format)->refine_portions(format, layer);
+        format->portions = g_binary_portion_new(BPC_RAW, &addr, length);
 
-        format->layers = layer;
+        G_EXE_FORMAT_GET_CLASS(format)->refine_portions(format);
 
     }
 
-    g_object_ref(G_OBJECT(format->layers));
-
-    return format->layers;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : format = informations chargées à consulter.                  *
-*                count  = quantité de zones listées. [OUT]                    *
+*  Paramètres  : format  = description de l'exécutable à modifier.            *
+*                portion = portion à inclure dans les définitions du format.  *
 *                                                                             *
-*  Description : Fournit les espaces mémoires des portions exécutables.       *
+*  Description : Procède à l'enregistrement d'une portion dans un format.     *
 *                                                                             *
-*  Retour      : Liste de zones binaires exécutables à libérer après usage.   *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-mrange_t *g_exe_format_get_x_ranges(GExeFormat *format, size_t *count)
+void g_exe_format_include_portion(GExeFormat *format, GBinPortion *portion)
 {
-    mrange_t *result;                       /* Liste à retourner           */
-
-    typedef struct _x_ranges
-    {
-        mrange_t *list;
-        size_t length;
+    g_mutex_lock(&format->mutex);
 
-    } x_ranges;
+    g_binary_portion_include(format->portions, portion);
 
-    x_ranges tmp;                           /* Sauvegarde de la liste      */
-    GPortionLayer *layer;                   /* Couche première de portions */
+    g_mutex_unlock(&format->mutex);
 
-    bool visit_for_x(GBinPortion *portion, x_ranges *ranges)
-    {
-        const mrange_t *range;
-
-        if (g_binary_portion_get_rights(portion) & PAC_EXEC)
-        {
-            range = g_binary_portion_get_range(portion);
+}
 
-            ranges->list = (mrange_t *)realloc(ranges->list, ++ranges->length * sizeof(mrange_t));
-            copy_mrange(&ranges->list[ranges->length - 1], range);
 
-        }
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = description de l'exécutable à consulter.            *
+*                                                                             *
+*  Description : Fournit la première couche des portions composent le binaire.*
+*                                                                             *
+*  Retour      : Arborescence des différentes portions binaires.              *
+*                                                                             *
+*  Remarques   : Le compteur de références de l'instance renvoyée doit être   *
+*                décrémenté après usage.                                      *
+*                                                                             *
+******************************************************************************/
 
-        return true;
+GBinPortion *g_exe_format_get_portions(GExeFormat *format)
+{
+    GBinPortion *result;                    /* Instance à retourner        */
 
-    }
+    g_mutex_lock(&format->mutex);
 
-    tmp.list = NULL;
-    tmp.length = 0;
+    result = format->portions;
 
-    layer = g_exe_format_get_main_layer(format);
-    g_portion_layer_visit(format->layers, (visit_portion_fc)visit_for_x, &tmp);
-    g_object_unref(G_OBJECT(layer));
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
 
-    result = tmp.list;
-    *count = tmp.length;
+    g_mutex_unlock(&format->mutex);
 
     return result;
 
diff --git a/src/format/executable.h b/src/format/executable.h
index ad89948..6384851 100644
--- a/src/format/executable.h
+++ b/src/format/executable.h
@@ -52,7 +52,6 @@ typedef struct _GExeFormatClass GExeFormatClass;
 /* Indique le type défini pour un format d'exécutable générique. */
 GType g_executable_format_get_type(void);
 
-
 /* Rajoute des informations de débogage à un exécutable. */
 void g_exe_format_add_debug_info(GExeFormat *, GDbgFormat *);
 
@@ -65,8 +64,11 @@ GDbgFormat *g_exe_format_get_debug_info(const GExeFormat *, size_t);
 /* Indique le type d'architecture visée par le format. */
 const char *g_exe_format_get_target_machine(const GExeFormat *);
 
+/* Procède à l'enregistrement d'une portion dans un format. */
+void g_exe_format_include_portion(GExeFormat *, GBinPortion *);
+
 /* Fournit la première couche des portions composent le binaire. */
-GPortionLayer *g_exe_format_get_main_layer(GExeFormat *);
+GBinPortion *g_exe_format_get_portions(GExeFormat *);
 
 /* Fournit les espaces mémoires des portions exécutables. */
 mrange_t *g_exe_format_get_x_ranges(GExeFormat *format, size_t *count);
diff --git a/src/format/format.c b/src/format/format.c
index bf4a0e1..516f882 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -137,7 +137,6 @@ bool g_binary_format_complete_loading(GBinFormat *format, GtkStatusStack *status
 *                                                                             *
 *  Paramètres  : format  = description de l'exécutable à consulter.           *
 *                content = contenu binaire à parcourir.                       *
-*                length  = taille du contenu fourni.                          *
 *                                                                             *
 *  Description : Définit le contenu binaire à analyser.                       *
 *                                                                             *
diff --git a/src/format/symbol.c b/src/format/symbol.c
index 48f3dbb..97ff114 100644
--- a/src/format/symbol.c
+++ b/src/format/symbol.c
@@ -226,6 +226,37 @@ int g_binary_symbol_cmp(const GBinSymbol **a, const GBinSymbol **b)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : symbol = symbole à analyser.                                 *
+*                addr   = localisation à venir comparer à celle du symbole.   *
+*                                                                             *
+*  Description : Compare un symbole et une localisation.                      *
+*                                                                             *
+*  Retour      : Bilan de la comparaison : -1, 0 ou 1 (-1 par défaut).        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int g_binary_symbol_cmp_with_vmpa(const GBinSymbol *symbol, const vmpa2t *addr)
+{
+    int result;                             /* Bilan à retourner           */
+    const mrange_t *range;                  /* Emplacement du symbole      */
+
+    range = g_binary_symbol_get_range(symbol);
+
+    if (range == NULL)
+        result = 1;
+
+    else
+        result = cmp_mrange_with_vmpa(range, addr);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : symbol = symbole à venir consulter.                          *
 *                                                                             *
 *  Description : Fournit le type du symbole.                                  *
diff --git a/src/format/symbol.h b/src/format/symbol.h
index 8432d8d..78741cb 100644
--- a/src/format/symbol.h
+++ b/src/format/symbol.h
@@ -80,6 +80,9 @@ GBinSymbol *g_binary_symbol_new(SymbolType);
 /* Compare deux symboles d'exécutable selon leurs propriétés. */
 int g_binary_symbol_cmp(const GBinSymbol **, const GBinSymbol **);
 
+/* Compare un symbole et une localisation. */
+int g_binary_symbol_cmp_with_vmpa(const GBinSymbol *, const vmpa2t *);
+
 /* Fournit le type du symbole. */
 SymbolType g_binary_symbol_get_target_type(const GBinSymbol *);
 
diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c
index 8fc7805..4137763 100644
--- a/src/glibext/gbinportion.c
+++ b/src/glibext/gbinportion.c
@@ -34,6 +34,7 @@
 
 
 #include "../common/extstr.h"
+#include "../common/sort.h"
 
 
 
@@ -45,8 +46,6 @@ struct _GBinPortion
 {
     GObject parent;                         /* A laisser en premier        */
 
-    const unsigned int *level;              /* Profondeur de la portion    */
-
     char *code;                             /* Code de la couleur de fond  */
 
     char *desc;                             /* Désignation humaine         */
@@ -55,6 +54,9 @@ struct _GBinPortion
 
     PortionAccessRights rights;             /* Droits d'accès              */
 
+    GBinPortion **subs;                     /* Portions incluses           */
+    size_t count;                           /* Quantité d'inclusions       */
+
 };
 
 /* Portion de données binaires quelconques (classe) */
@@ -77,58 +79,16 @@ static void g_binary_portion_dispose(GBinPortion *);
 /* Procède à la libération totale de la mémoire. */
 static void g_binary_portion_finalize(GBinPortion *);
 
-/* Définit le niveau de profondeur pour une branche de portions. */
-static void g_binary_portion_set_level(GBinPortion *, const unsigned int *);
-
 /* Détermine l'aire d'une sous-portion. */
 static bool g_binary_portion_compute_sub_area(const GBinPortion *, phys_t, const GdkRectangle *, GdkRectangle *);
 
-/* Détermine si une portion contient une adresse donnée. */
-static bool g_portion_layer_contains_addr(const GBinPortion *, const vmpa2t *);
-
-
-
-/* -------------------------- COUCHES DE PORTIONS BINAIRES -------------------------- */
-
-
-/* Couche de portions binaires quelconques (instance) */
-struct _GPortionLayer
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    phys_t length;                          /* Taille de portion globale   */
-    const char *name;                       /* Désignation de la couche    */
-
-    unsigned int level;                     /* Profondeur de la portion    */
-
-    GPortionLayer *sub_layer;               /* Eventuelle couche inférieure*/
-
-    GBinPortion **portions;                 /* Portions incluses           */
-    size_t count;                           /* Quantité d'inclusions       */
-
-};
-
-/* Couche de portions binaires quelconques (classe) */
-struct _GPortionLayerClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-};
-
-
-/* Initialise la classe des couches de portions binaires. */
-static void g_portion_layer_class_init(GPortionLayerClass *);
 
-/* Initialise une instance de couche de portions binaires. */
-static void g_portion_layer_init(GPortionLayer *);
 
-/* Supprime toutes les références externes. */
-static void g_portion_layer_dispose(GPortionLayer *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_portion_layer_finalize(GPortionLayer *);
+/* ------------------------ PARCOURS D'ENSEMBLES DE PORTIONS ------------------------ */
 
 
+/* Détermine si une portion contient une adresse donnée. */
+static bool g_portion_layer_contains_addr(const GBinPortion *, const vmpa2t *);
 
 
 
@@ -180,7 +140,6 @@ static void g_binary_portion_class_init(GBinPortionClass *klass)
 
 static void g_binary_portion_init(GBinPortion *portion)
 {
-    portion->level = NULL;
 
 }
 
@@ -231,6 +190,8 @@ static void g_binary_portion_finalize(GBinPortion *portion)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : code = désignation humaine de la couleur de fond.            *
+*                addr = emplacement de la section à conserver.                *
+*                size = taille de la section à conserver.                     *
 *                                                                             *
 *  Description : Crée une description de partie de code vierge.               *
 *                                                                             *
@@ -240,7 +201,7 @@ static void g_binary_portion_finalize(GBinPortion *portion)
 *                                                                             *
 ******************************************************************************/
 
-GBinPortion *g_binary_portion_new(const char *code)
+GBinPortion *g_binary_portion_new(const char *code, const vmpa2t *addr, phys_t size)
 {
     GBinPortion *result;                    /* Structure à retourner       */
 
@@ -248,27 +209,9 @@ GBinPortion *g_binary_portion_new(const char *code)
 
     result->code = strdup(code);
 
-    return result;
-
-}
+    init_mrange(&result->range, addr, size);
 
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
-*                level   = niveau de profondeur à associer.                   *
-*                                                                             *
-*  Description : Définit le niveau de profondeur pour une branche de portions.*
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_binary_portion_set_level(GBinPortion *portion, const unsigned int *level)
-{
-    portion->level = level;
+    return result;
 
 }
 
@@ -291,31 +234,12 @@ int g_binary_portion_compare(const GBinPortion **a, const GBinPortion **b)
     int result;                             /* Bilan à retourner           */
     const vmpa2t *addr_a;                   /* Adresse de la portion 'a'   */
     const vmpa2t *addr_b;                   /* Adresse de la portion 'b'   */
-    const unsigned int *level_a;            /* Niveau de la portion 'a'    */
-    const unsigned int *level_b;            /* Niveau de la portion 'b'    */
 
     addr_a = get_mrange_addr(&(*a)->range);
     addr_b = get_mrange_addr(&(*b)->range);
 
     result = cmp_vmpa(addr_a, addr_b);
 
-    if (result == 0)
-    {
-        level_a = (*a)->level;
-        level_b = (*b)->level;
-
-        if (level_a != NULL && level_b != NULL)
-        {
-            if (*level_a < *level_b)
-                result = -1;
-
-            else if (*level_a > *level_b)
-                result = 1;
-
-        }
-
-    }
-
     return result;
 
 }
@@ -365,27 +289,6 @@ const char *g_binary_portion_get_desc(const GBinPortion *portion)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : portion = description de partie à mettre à jour.             *
-*                addr    = emplacement de la section à conserver.             *
-*                size    = taille de la section à conserver.                  *
-*                                                                             *
-*  Description : Définit les valeurs utiles d'une partie de code binaire.     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_binary_portion_set_values(GBinPortion *portion, const vmpa2t *addr, phys_t size)
-{
-    init_mrange(&portion->range, addr, size);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
 *                                                                             *
 *  Description : Fournit l'emplacement d'une partie de code binaire.          *
 *                                                                             *
@@ -443,76 +346,6 @@ PortionAccessRights g_binary_portion_get_rights(const GBinPortion *portion)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : portion  = portion mère à consulter.                         *
-*                full     = taille totale de la couche parente.               *
-*                area     = étendue de représentation de la portion mère.     *
-*                sub_area = étendue de représentation de la portion fille.    *
-*                                                                             *
-*  Description : Détermine l'aire d'une sous-portion.                         *
-*                                                                             *
-*  Retour      : true si la sous-surface a été calculée correctement.         *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_binary_portion_compute_sub_area(const GBinPortion *portion, phys_t full, const GdkRectangle *area, GdkRectangle *sub_area)
-{
-    phys_t length;                          /* Taille de la portion        */
-    phys_t start;                           /* Position de départ          */
-
-    length = get_mrange_length(&portion->range);
-
-    /* On saute les portions comme le segment GNU_STACK... */
-    if (length == 0) return false;
-
-    start = get_phy_addr(get_mrange_addr(&portion->range));
-
-    sub_area->y = area->y;
-    sub_area->height = area->height;
-
-    sub_area->x = area->x + (start * area->width) / full;
-    sub_area->width = (length * area->width) / full;
-
-    return true;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : portion = portion mère à consulter.                          *
-*                addr    = adresse du point de recherche.                     *
-*                                                                             *
-*  Description : Détermine si une portion contient une adresse donnée.        *
-*                                                                             *
-*  Retour      : true ou false selon le résultat.                             *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_portion_layer_contains_addr(const GBinPortion *portion, const vmpa2t *addr)
-{
-    bool result;                            /* Bilan à retourner           */
-
-    result = false;
-
-    /* Portion non allouée en mémoire -> adresse nulle ; on écarte */
-    if (get_virt_addr(get_mrange_addr(&portion->range)) == 0)
-        goto not_found;
-
-    result = mrange_contains_addr(&portion->range, addr);
-
- not_found:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : portion = description de partie à consulter.                 *
 *                buffer  = espace où placer ledit contenu.                    *
 *                msize   = taille idéale des positions et adresses;           *
@@ -686,52 +519,50 @@ void g_binary_portion_query_tooltip(GBinPortion *portion, GtkTooltip *tooltip)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : portion = description de partie à consulter.                 *
-*                cr      = contexte graphique pour le dessin.                 *
-*                area    = étendue mise à disposition.                        *
+*  Paramètres  : portion  = portion mère à consulter.                         *
+*                full     = taille totale de la couche parente.               *
+*                area     = étendue de représentation de la portion mère.     *
+*                sub_area = étendue de représentation de la portion fille.    *
 *                                                                             *
-*  Description : Représente la portion sur une bande dédiée.                  *
+*  Description : Détermine l'aire d'une sous-portion.                         *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : true si la sous-surface a été calculée correctement.         *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_binary_portion_draw(const GBinPortion *portion, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area)
+static bool g_binary_portion_compute_sub_area(const GBinPortion *portion, phys_t full, const GdkRectangle *area, GdkRectangle *sub_area)
 {
-    //cairo_set_line_width(cr, 1.0);
+    phys_t length;                          /* Taille de la portion        */
+    phys_t start;                           /* Position de départ          */
 
-    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+    length = get_mrange_length(&portion->range);
 
-    gtk_style_context_save(context);
+    /* On saute les portions comme le segment GNU_STACK... */
+    if (length == 0) return false;
 
-    gtk_style_context_add_class(context, portion->code);
+    start = get_phy_addr(get_mrange_addr(&portion->range));
 
-    gtk_render_background(context, cr, area->x, area->y, area->width, area->height);
+    sub_area->y = area->y;
+    sub_area->height = area->height;
 
-    gtk_render_frame(context, cr, area->x, area->y, area->width, area->height);
+    sub_area->x = area->x + (start * area->width) / full;
+    sub_area->width = (length * area->width) / full;
 
-    gtk_style_context_restore(context);
+    return true;
 
 }
 
 
-
-/* ---------------------------------------------------------------------------------- */
-/*                            COUCHES DE PORTIONS BINAIRES                            */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini par la GLib pour les couches de portions binaires. */
-G_DEFINE_TYPE(GPortionLayer, g_portion_layer, G_TYPE_OBJECT);
-
-
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : klass = classe à initialiser.                                *
+*  Paramètres  : portion = description de partie à consulter.                 *
+*                context = contexte graphique associé à la procédure.         *
+*                cr      = contexte graphique pour le dessin.                 *
+*                area    = étendue mise à disposition.                        *
 *                                                                             *
-*  Description : Initialise la classe des couches de portions binaires.       *
+*  Description : Représente la portion sur une bande dédiée.                  *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -739,70 +570,51 @@ G_DEFINE_TYPE(GPortionLayer, g_portion_layer, G_TYPE_OBJECT);
 *                                                                             *
 ******************************************************************************/
 
-static void g_portion_layer_class_init(GPortionLayerClass *klass)
+void g_binary_portion_draw(const GBinPortion *portion, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area)
 {
-    GObjectClass *object;                   /* Autre version de la classe  */
-
-    object = G_OBJECT_CLASS(klass);
+    phys_t full;                            /* Espace total représenté     */
+    size_t i;                               /* Boucle de parcours          */
+    GBinPortion *sub;                       /* Portion incluse à montrer   */
+    GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
 
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_portion_layer_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_portion_layer_finalize;
+    /* Dessin de la portion courante */
 
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
 
-}
+    gtk_style_context_save(context);
 
+    gtk_style_context_add_class(context, portion->code);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : layer = instance à initialiser.                              *
-*                                                                             *
-*  Description : Initialise une instance de couche de portions binaires.      *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    gtk_render_background(context, cr, area->x, area->y, area->width, area->height);
 
-static void g_portion_layer_init(GPortionLayer *layer)
-{
-    layer->level = 0;
+    gtk_render_frame(context, cr, area->x, area->y, area->width, area->height);
 
-}
+    gtk_style_context_restore(context);
 
+    /* Dessin des portions contenues */
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : layer = instance d'objet GLib à traiter.                     *
-*                                                                             *
-*  Description : Supprime toutes les références externes.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    full = get_mrange_length(&portion->range);
 
-static void g_portion_layer_dispose(GPortionLayer *layer)
-{
-    size_t i;                               /* Boucle de parcours          */
+    for (i = 0; i < portion->count; i++)
+    {
+        sub = portion->subs[i];
 
-    if (layer->sub_layer != NULL)
-        g_object_unref(G_OBJECT(layer->sub_layer));
+        if (!g_binary_portion_compute_sub_area(sub, full, area, &sub_area))
+            continue;
 
-    for (i = 0; i < layer->count; i++)
-        g_object_unref(G_OBJECT(layer->portions[i]));
+        g_binary_portion_draw(sub, context, cr, &sub_area);
 
-    G_OBJECT_CLASS(g_portion_layer_parent_class)->dispose(G_OBJECT(layer));
+    }
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : layer = instance d'objet GLib à traiter.                     *
+*  Paramètres  : portion = portion principale à compléter.                    *
+*                sub     = portion à inclure dans la définition courante.     *
 *                                                                             *
-*  Description : Procède à la libération totale de la mémoire.                *
+*  Description : Procède à l'inclusion d'une portion dans une autre.          *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -810,204 +622,161 @@ static void g_portion_layer_dispose(GPortionLayer *layer)
 *                                                                             *
 ******************************************************************************/
 
-static void g_portion_layer_finalize(GPortionLayer *layer)
+void g_binary_portion_include(GBinPortion *portion, GBinPortion *sub)
 {
-    if (layer->portions != NULL)
-        free(layer->portions);
-
-    G_OBJECT_CLASS(g_portion_layer_parent_class)->finalize(G_OBJECT(layer));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : length = 
-*                name   = désignation pouvant servir de suffixe aux portions. *
-*                                                                             *
-*  Description : Crée une nouvelle couche de portions binaires.               *
-*                                                                             *
-*  Retour      : Instance mise en place.                                      *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GPortionLayer *g_portion_layer_new(phys_t length, const char *name)
-{
-    GPortionLayer *result;                  /* Structure à retourner       */
-
-    result = g_object_new(G_TYPE_BIN_PORTION, NULL);
-
-    result->length = length;
-    result->name = name;
-
-    return result;
-
-}
+    bool found;                             /* Zone d'accueil trouvée ?    */
+    size_t best;                            /* Meilleur point d'insertion  */
+    const mrange_t *prange;                 /* Emplacement de portion #1   */
+    const mrange_t *srange;                 /* Emplacement de portion #2   */
+    GBinPortion tmp;                        /* Sauvegarde temporaire       */
 
+    found = bsearch_index(sub, portion->subs, portion->count, sizeof(GBinPortion *),
+                          (__compar_fn_t)g_binary_portion_compare, &best);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : layer = couche rassemblant des portions à modifier.          *
-*  Paramètres  : sub   = couche inférieure à rattacher à la couche courante.  *
-*                                                                             *
-*  Description : Attache une couche à une autre en tant que couche inférieure.*
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    if (!found)
+        portion->subs = qinsert(portion->subs, &portion->count, sizeof(GBinPortion *),
+                                (__compar_fn_t)g_binary_portion_compare, &sub);
 
-void g_portion_layer_attach_sub(GPortionLayer *layer, GPortionLayer *sub)
-{
-    void set_layers_length(GPortionLayer *parent, GPortionLayer *child)
+    else
     {
-        if (child->length == NO_LENGTH_YET)
+        /**
+         * On prend ici en compte le genre de situations suivantes :
+         *
+         *  [21] .bss                NOBITS          00088240 07823c 0018c8 00  WA  0   0  8
+         *  [22] __libc_freeres_ptrs NOBITS          00089b08 07823c 000018 00  WA  0   0  4
+         *  [23] .comment            PROGBITS        00000000 07823c 000022 01  MS  0   0  1
+         *
+         * Pendant le désassemblage, la procédure n'aime pas trop les intersections
+         * de zones mémoire.
+         */
+
+        prange = g_binary_portion_get_range(portion->subs[best]);
+        srange = g_binary_portion_get_range(sub);
+
+        if (mrange_contains_mrange(prange, srange))
+            g_binary_portion_include(portion->subs[best], sub);
+
+        else
         {
-            assert(parent->length != NO_LENGTH_YET);
+            assert(mrange_contains_mrange(srange, prange));
 
-            child->length = parent->length;
+            memcpy(&tmp, portion->subs[best], sizeof(GBinPortion));
+            memcpy(portion->subs[best], sub, sizeof(GBinPortion));
+            memcpy(sub, &tmp, sizeof(GBinPortion));
 
-            if (child->sub_layer != NULL)
-                set_layers_length(child, child->sub_layer);
+            g_binary_portion_include(portion->subs[best], sub);
 
         }
 
     }
 
-    void set_layers_depth(GPortionLayer *parent, GPortionLayer *child)
-    {
-        child->level = parent->level + 1;
-
-        if (child->sub_layer != NULL)
-            set_layers_length(child, child->sub_layer);
-
-    }
-
-    set_layers_length(layer, sub);
-
-    set_layers_depth(layer, sub);
-
-    layer->sub_layer = sub;
-
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : layer   = couche rassemblant les portions d'un même niveau.  *
-*                portion = portion à inclure dans la définition courante.     *
+*  Paramètres  : portion = première couche amorçant la visite.                *
+*                visitor = fonction à appeler à chaque étape de la descente.  *
+*                data    = adresse pointant vers des données de l'utilisateur.*
 *                                                                             *
-*  Description : Procède à l'inclusion d'une portion dans une couche.         *
+*  Description : Parcourt un ensemble de portions binaires.                   *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : true si la visite a été jusqu'à son terme, false sinon.      *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_portion_layer_include(GPortionLayer *layer, GBinPortion *portion)
+bool g_binary_portion_visit(GBinPortion *portion, visit_portion_fc visitor, void *data)
 {
-    GPortionLayer *sub;                     /* Sous couche indispensable   */
-    bool conflict;                          /* Conflit dû aux débordements */
-    const mrange_t *range;                  /* Emplacement de la portion   */
-    size_t i;                               /* Boucle de parcours          */
-    const mrange_t *other;                  /* Emplacements déjà occupés   */
-
-    /**
-     * On prend ici en compte le genre de situations suivantes :
-     *
-     *  [21] .bss                NOBITS          00088240 07823c 0018c8 00  WA  0   0  8
-     *  [22] __libc_freeres_ptrs NOBITS          00089b08 07823c 000018 00  WA  0   0  4
-     *  [23] .comment            PROGBITS        00000000 07823c 000022 01  MS  0   0  1
-     *
-     * Pendant le désassemblage, la procédure n'aime pas trop les intersections
-     * de zones mémoire.
-     */
+    bool result;                            /* Etat à retourner            */
 
-    conflict = false;
+    bool visit_portion(GBinPortion *p, GBinPortion *pp)
+    {
+        bool ret;                           /* Etat à retourner            */
+        size_t i;                           /* Boucle de parcours          */
 
-    range = g_binary_portion_get_range(portion);
+        if (p->count == 0)
+            ret = visitor(p, pp, BPV_SHOW, data);
 
-    for (i = 0; i < layer->count && !conflict; i++)
-    {
-        other = g_binary_portion_get_range(layer->portions[i]);
+        else
+        {
+            ret = visitor(p, pp, BPV_ENTER, data);
 
-        conflict = mrange_intersects_mrange(range, other);
+            for (i = 0; i < p->count && ret; i++)
+                ret = visit_portion(p->subs[i], p);
 
-    }
+            if (ret)
+                ret = visitor(p, pp, BPV_EXIT, data);
 
-    /* La portion recouvre-t-elle une portion déjà existante ? */
-    if (conflict)
-    {
-        if (layer->sub_layer == NULL)
-        {
-            sub = g_portion_layer_new(layer->length, layer->name);
-            g_portion_layer_attach_sub(layer, sub);
         }
 
-        g_portion_layer_include(layer->sub_layer, portion);
+        return ret;
 
     }
 
-    /* Sinon on l'intègre dans la couche courante */
-    else
-    {
-        layer->portions = (GBinPortion **)realloc(layer->portions,
-                                                  ++layer->count * sizeof(GBinPortion *));
+    result = visit_portion(portion, NULL);
 
-        layer->portions[layer->count - 1] = portion;
+    return result;
 
-        g_binary_portion_set_level(portion, &layer->level);
+}
 
-        qsort(layer->portions, layer->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);
 
-    }
 
-}
+/* ---------------------------------------------------------------------------------- */
+/*                          PARCOURS D'ENSEMBLES DE PORTIONS                          */
+/* ---------------------------------------------------------------------------------- */
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : layer = couche première à parcourir intégralement.           *
-*                count = nombre de portions trouvées et renvoyées. [OUT]      *
+*  Paramètres  : portion = couche de portions à parcourir pour les recherches.*
+*                x       = abscisse du point de recherche.                    *
+*                area    = étendue de portion mère, puis celle trouvée. [OUT] *
 *                                                                             *
-*  Description : Fournit une liste triée de portions d'un binaire.            *
+*  Description : Recherche la portion présente à un point donné.              *
 *                                                                             *
-*  Retour      : Liste de définitions de zones à libérer après usage.         *
+*  Retour      : Portion trouvée à l'endroit indiqué.                         *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBinPortion **g_portion_layer_collect_all_portions(const GPortionLayer *layer, size_t *count)
+GBinPortion *g_binary_portion_find_at_pos(GBinPortion *portion, gint x, GdkRectangle *area)
 {
-    GBinPortion **result;                   /* Liste construite à renvoyer */
+    GBinPortion *result;                    /* Portion à retourner         */
+    phys_t full;                            /* Espace total représenté     */
+    size_t i;                               /* Boucle de parcours          */
+    GBinPortion *sub;                       /* Portion incluse à traiter   */
+    GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
 
-    GBinPortion **do_collect(const GPortionLayer *l, GBinPortion **lst, size_t *c)
-    {
-        size_t start;                       /* Indice de départ des ajouts */
-        size_t i;                           /* Boucle de parcours          */
+    result = NULL;
 
-        start = *c;
-        *c += l->count;
+    full = get_mrange_length(&portion->range);
 
-        lst = (GBinPortion **)realloc(lst, *c * sizeof(GBinPortion *));
+    for (i = 0; i < portion->count && result == NULL; i++)
+    {
+        sub = portion->subs[i];
 
-        for (i = 0; i < l->count; i++)
-            lst[start + i] = l->portions[i];
+        if (!g_binary_portion_compute_sub_area(sub, full, area, &sub_area))
+            continue;
 
-        return lst;
+        if (sub_area.x <= x && x < (sub_area.x + sub_area.width))
+        {
+            result = g_binary_portion_find_at_pos(sub, x, &sub_area);
 
-    }
+            if (result != NULL)
+                *area = sub_area;
 
-    *count = 0;
+        }
 
-    result = do_collect(layer, NULL, count);
+    }
 
-    qsort(result, *count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);
+    if (result == NULL)
+    {
+        result = portion;
+        g_object_ref(G_OBJECT(result));
+    }
 
     return result;
 
@@ -1016,44 +785,30 @@ GBinPortion **g_portion_layer_collect_all_portions(const GPortionLayer *layer, s
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : layer = couche de portions à parcourir pour les recherches.  *
-*                x     = abscisse du point de recherche.                      *
-*                area  = étendue de portion mère, puis celle trouvée. [OUT]   *
+*  Paramètres  : portion = portion mère à consulter.                          *
+*                addr    = adresse du point de recherche.                     *
 *                                                                             *
-*  Description : Recherche la portion présente à un point donné.              *
+*  Description : Détermine si une portion contient une adresse donnée.        *
 *                                                                             *
-*  Retour      : Portion trouvée à l'endroit indiqué.                         *
+*  Retour      : true ou false selon le résultat.                             *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBinPortion *g_portion_layer_find_portion_at_pos(const GPortionLayer *layer, gint x, GdkRectangle *area)
+static bool g_portion_layer_contains_addr(const GBinPortion *portion, const vmpa2t *addr)
 {
-    GBinPortion *result;                    /* Portion à retourner         */
-    size_t i;                               /* Boucle de parcours          */
-    GBinPortion *sub;                       /* Portion incluse à traiter   */
-    GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
-
-    if (layer->sub_layer != NULL)
-        result = g_portion_layer_find_portion_at_pos(layer->sub_layer, x, area);
-    else
-        result = NULL;
+    bool result;                            /* Bilan à retourner           */
 
-    for (i = 0; i < layer->count && result == NULL; i++)
-    {
-        sub = layer->portions[i];
+    result = false;
 
-        if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area))
-            continue;
+    /* Portion non allouée en mémoire -> adresse nulle ; on écarte */
+    if (get_virt_addr(get_mrange_addr(&portion->range)) == 0)
+        goto not_found;
 
-        if (sub_area.x <= x && x < (sub_area.x + sub_area.width))
-        {
-            result = sub;
-            *area = sub_area;
-        }
+    result = mrange_contains_addr(&portion->range, addr);
 
-    }
+ not_found:
 
     return result;
 
@@ -1062,9 +817,9 @@ GBinPortion *g_portion_layer_find_portion_at_pos(const GPortionLayer *layer, gin
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : layer = couche de portions à parcourir pour les recherches.  *
-*                addr  = adresse du point de recherche.                       *
-*                area  = étendue de portion mère, puis celle trouvée. [OUT]   *
+*  Paramètres  : portion = couche de portions à parcourir pour les recherches.*
+*                addr    = adresse du point de recherche.                     *
+*                area    = étendue de portion mère, puis celle trouvée. [OUT] *
 *                                                                             *
 *  Description : Recherche la portion présente à une adresse donnée.          *
 *                                                                             *
@@ -1074,31 +829,39 @@ GBinPortion *g_portion_layer_find_portion_at_pos(const GPortionLayer *layer, gin
 *                                                                             *
 ******************************************************************************/
 
-GBinPortion *g_portion_layer_find_portion_at_addr(const GPortionLayer *layer, const vmpa2t *addr, GdkRectangle *area)
+GBinPortion *g_binary_portion_find_at_addr(GBinPortion *portion, const vmpa2t *addr, GdkRectangle *area)
 {
     GBinPortion *result;                    /* Portion à retourner         */
+    phys_t full;                            /* Espace total représenté     */
     size_t i;                               /* Boucle de parcours #1       */
     GBinPortion *sub;                       /* Portion incluse à traiter   */
     GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
 
-    if (layer->sub_layer != NULL)
-        result = g_portion_layer_find_portion_at_addr(layer->sub_layer, addr, area);
-    else
-        result = NULL;
+    result = NULL;
+
+    full = get_mrange_length(&portion->range);
 
-    for (i = 0; i < layer->count && result == NULL; i++)
+    for (i = 0; i < portion->count && result == NULL; i++)
     {
-        sub = layer->portions[i];
+        sub = portion->subs[i];
 
         if (!g_portion_layer_contains_addr(sub, addr))
             continue;
 
-        if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area))
+        if (!g_binary_portion_compute_sub_area(sub, full, area, &sub_area))
             continue;
 
-        result = sub;
-        *area = sub_area;
+        result = g_binary_portion_find_at_addr(sub, addr, &sub_area);
+
+        if (result != NULL)
+            *area = sub_area;
+
+    }
 
+    if (result == NULL)
+    {
+        result = portion;
+        g_object_ref(G_OBJECT(result));
     }
 
     return result;
@@ -1108,10 +871,10 @@ GBinPortion *g_portion_layer_find_portion_at_addr(const GPortionLayer *layer, co
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : layer = couche de portions à parcourir pour les recherches.  *
-*                x     = abscisse du point de recherche.                      *
-*                area  = étendue de représentation de la portion mère.        *
-*                addr  = adresse correspondante. [OUT]                        *
+*  Paramètres  : root = couche de portions à parcourir pour les recherches.   *
+*                x    = abscisse du point de recherche.                       *
+*                area = étendue de représentation de la portion mère.         *
+*                addr = adresse correspondante. [OUT]                         *
 *                                                                             *
 *  Description : Fournit la position correspondant à une adresse donnée.      *
 *                                                                             *
@@ -1121,20 +884,22 @@ GBinPortion *g_portion_layer_find_portion_at_addr(const GPortionLayer *layer, co
 *                                                                             *
 ******************************************************************************/
 
-bool g_portion_layer_get_addr_from_pos(GPortionLayer *layer, gint x, const GdkRectangle *area, vmpa2t *addr)
+bool get_binary_portion_addr_from_pos(GBinPortion *root, gint x, const GdkRectangle *area, vmpa2t *addr)
 {
     GdkRectangle owner_area;                /* Aire de contenance          */
     GBinPortion *owner;                     /* Conteneur propriétaire      */
 
     owner_area = *area;
 
-    owner = g_portion_layer_find_portion_at_pos(layer, x, &owner_area);
+    owner = g_binary_portion_find_at_pos(root, x, &owner_area);
     if (owner == NULL) return false;
 
     copy_vmpa(addr, get_mrange_addr(&owner->range));
 
     advance_vmpa(addr, (get_mrange_length(&owner->range) * (x - owner_area.x)) / owner_area.width);
 
+    g_object_unref(G_OBJECT(owner));
+
     return true;
 
 }
@@ -1142,10 +907,10 @@ bool g_portion_layer_get_addr_from_pos(GPortionLayer *layer, gint x, const GdkRe
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : layer = couche de portions à parcourir pour les recherches.  *
-*                addr  = adresse du point de recherche.                       *
-*                area  = étendue de représentation de la portion mère.        *
-*                x     = position correspondante. [OUT]                       *
+*  Paramètres  : root = couche de portions à parcourir pour les recherches.   *
+*                addr = adresse du point de recherche.                        *
+*                area = étendue de représentation de la portion mère.         *
+*                x    = position correspondante. [OUT]                        *
 *                                                                             *
 *  Description : Fournit l'adresse correspondant à une position donnée.       *
 *                                                                             *
@@ -1155,7 +920,7 @@ bool g_portion_layer_get_addr_from_pos(GPortionLayer *layer, gint x, const GdkRe
 *                                                                             *
 ******************************************************************************/
 
-bool g_portion_layer_get_pos_from_addr(GPortionLayer *layer, const vmpa2t *addr, const GdkRectangle *area, gint *x)
+bool get_binary_portion_pos_from_addr(GBinPortion *root, const vmpa2t *addr, const GdkRectangle *area, gint *x)
 {
     GdkRectangle owner_area;                /* Aire de contenance          */
     GBinPortion *owner;                     /* Conteneur propriétaire      */
@@ -1163,46 +928,16 @@ bool g_portion_layer_get_pos_from_addr(GPortionLayer *layer, const vmpa2t *addr,
 
     owner_area = *area;
 
-    owner = g_portion_layer_find_portion_at_addr(layer, addr, &owner_area);
+    owner = g_binary_portion_find_at_addr(root, addr, &owner_area);
     if (owner == NULL) return false;
 
     diff = compute_vmpa_diff(addr, get_mrange_addr(&owner->range));
 
     *x = owner_area.x + (diff * owner_area.width) / get_mrange_length(&owner->range);
 
-    return true;
-
-}
-
+    g_object_unref(G_OBJECT(owner));
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : layer   = première couche amorçant la visite.                *
-*                visitor = fonction à appeler à chaque étape de la descente.  *
-*                data    = adresse pointant vers des données de l'utilisateur.*
-*                                                                             *
-*  Description : Parcours un ensemble de portions binaires.                   *
-*                                                                             *
-*  Retour      : true si la visite a été jusqu'à son terme, false sinon.      *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool g_portion_layer_visit(const GPortionLayer *layer, visit_portion_fc visitor, void *data)
-{
-    bool result;                            /* Etat à retourner            */
-    size_t i;                               /* Boucle de parcours          */
-
-    if (layer->sub_layer != NULL)
-        result = g_portion_layer_visit(layer->sub_layer, visitor, data);
-    else
-        result = true;
-
-    for (i = 0; i < layer->count && result; i++)
-        result = visitor(layer->portions[i], data);
-
-    return result;
+    return true;
 
 }
 
@@ -1223,52 +958,17 @@ bool g_portion_layer_visit(const GPortionLayer *layer, visit_portion_fc visitor,
 *                                                                             *
 ******************************************************************************/
 
-gboolean g_portion_layer_query_tooltip(const GPortionLayer *layer, gint x, gint y, const GdkRectangle *area, GtkTooltip *tooltip)
+gboolean query_tooltip_for_binary_portion(GBinPortion *root, gint x, gint y, const GdkRectangle *area, GtkTooltip *tooltip)
 {
     GBinPortion *selected;                  /* Portion à décrire ici       */
 
-    selected = g_portion_layer_find_portion_at_pos(layer, x, (GdkRectangle []) { *area });
+    selected = g_binary_portion_find_at_pos(root, x, (GdkRectangle []) { *area });
     if (selected == NULL) return FALSE;
 
     g_binary_portion_query_tooltip(selected, tooltip);
 
-    return TRUE;
-
-}
-
+    g_object_unref(G_OBJECT(selected));
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : layer = couche de portions à consulter.                      *
-*                cr    = contexte graphique pour le dessin.                   *
-*                area  = étendue mise à disposition.                          *
-*                                                                             *
-*  Description : Représente une couche de portions sur une bande dédiée.      *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_portion_layer_draw(const GPortionLayer *layer, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area)
-{
-    size_t i;                               /* Boucle de parcours          */
-    GBinPortion *sub;                       /* Portion incluse à montrer   */
-    GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
-
-    for (i = 0; i < layer->count; i++)
-    {
-        sub = layer->portions[i];
-
-        if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area))
-            continue;
-
-        g_binary_portion_draw(sub, context, cr, &sub_area);
-
-    }
-
-    if (layer->sub_layer != NULL)
-        g_portion_layer_draw(layer->sub_layer, context, cr, area);
+    return TRUE;
 
 }
diff --git a/src/glibext/gbinportion.h b/src/glibext/gbinportion.h
index b91af05..2aa5e1a 100644
--- a/src/glibext/gbinportion.h
+++ b/src/glibext/gbinportion.h
@@ -80,7 +80,7 @@ typedef enum _PortionAccessRights
 GType g_binary_portion_get_type(void);
 
 /* Crée une description de partie de code vierge. */
-GBinPortion *g_binary_portion_new(const char *);
+GBinPortion *g_binary_portion_new(const char *, const vmpa2t *, phys_t);
 
 /* Etablit la comparaison ascendante entre deux portions. */
 int g_binary_portion_compare(const GBinPortion **, const GBinPortion **);
@@ -91,9 +91,6 @@ void g_binary_portion_set_desc(GBinPortion *, const char *);
 /* Fournit la description attribuée à une partie de code. */
 const char *g_binary_portion_get_desc(const GBinPortion *);
 
-/* Définit les valeurs utiles d'une partie de code. */
-void g_binary_portion_set_values(GBinPortion *, const vmpa2t *, phys_t);
-
 /* Fournit l'emplacement d'une partie de code binaire. */
 const mrange_t *g_binary_portion_get_range(const GBinPortion *);
 
@@ -112,68 +109,44 @@ void g_binary_portion_query_tooltip(GBinPortion *, GtkTooltip *);
 /* Représente la portion sur une bande dédiée. */
 void g_binary_portion_draw(const GBinPortion *, GtkStyleContext *, cairo_t *, const GdkRectangle *);
 
+/* Procède à l'inclusion d'une portion dans une autre. */
+void g_binary_portion_include(GBinPortion *, GBinPortion *);
 
+/* Sens des visites */
+typedef enum _BinaryPortionVisit
+{
+    BPV_ENTER,                              /* Arrivée sur une branche     */
+    BPV_SHOW,                               /* Visite d'une feuille        */
+    BPV_EXIT                                /* Départ d'une branche        */
 
-/* -------------------------- COUCHES DE PORTIONS BINAIRES -------------------------- */
-
-
-#define G_TYPE_PORTION_LAYER                (g_portion_layer_get_type())
-#define G_PORTION_LAYER(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PORTION_LAYER, GPortionLayer))
-#define G_IS_PORTION_LAYER(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PORTION_LAYER))
-#define G_PORTION_LAYER_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PORTION_LAYER, GPortionLayerClass))
-#define G_IS_PORTION_LAYER_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PORTION_LAYER))
-#define G_PORTION_LAYER_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PORTION_LAYER, GPortionLayerClass))
-
-
-/* Couche de portions binaires quelconques (instance) */
-typedef struct _GPortionLayer GPortionLayer;
-
-/* Couche de portions binaires quelconques (classe) */
-typedef struct _GPortionLayerClass GPortionLayerClass;
-
+} BinaryPortionVisit;
 
-/* Taille à définir lors d'un rattachement */
-#define NO_LENGTH_YET VMPA_NO_PHYSICAL
 
+/* Fonction appelée à chaque visite de portion.*/
+typedef bool (* visit_portion_fc) (GBinPortion *, GBinPortion *, BinaryPortionVisit, void *);
 
-/* Indique le type défini par la GLib pour les couches de portions binaires. */
-GType g_portion_layer_get_type(void);
+/* Parcourt un ensemble de portions binaires. */
+bool g_binary_portion_visit(GBinPortion *, visit_portion_fc, void *);
 
-/* Crée une nouvelle couche de portions binaires. */
-GPortionLayer *g_portion_layer_new(phys_t, const char *);
 
-/* Attache une couche à une autre en tant que couche inférieure. */
-void g_portion_layer_attach_sub(GPortionLayer *, GPortionLayer *);
 
-/* Procède à l'inclusion d'une portion dans une couche. */
-void g_portion_layer_include(GPortionLayer *, GBinPortion *);
+/* ------------------------ PARCOURS D'ENSEMBLES DE PORTIONS ------------------------ */
 
-/* Fournit une liste triée de portions d'un binaire. */
-GBinPortion **g_portion_layer_collect_all_portions(const GPortionLayer *, size_t *);
 
 /* Recherche la portion présente à un point donné. */
-GBinPortion *g_portion_layer_find_portion_at_pos(const GPortionLayer *, gint, GdkRectangle *);
+GBinPortion *g_binary_portion_find_at_pos(GBinPortion *, gint, GdkRectangle *);
 
 /* Recherche la portion présente à une adresse donnée. */
-GBinPortion *g_portion_layer_find_portion_at_addr(const GPortionLayer *, const vmpa2t *, GdkRectangle *);
+GBinPortion *g_binary_portion_find_at_addr(GBinPortion *, const vmpa2t *, GdkRectangle *);
 
 /* Fournit la position correspondant à une adresse donnée. */
-bool g_portion_layer_get_addr_from_pos(GPortionLayer *, gint, const GdkRectangle *, vmpa2t *);
+bool get_binary_portion_addr_from_pos(GBinPortion *, gint, const GdkRectangle *, vmpa2t *);
 
 /* Fournit l'adresse correspondant à une position donnée. */
-bool g_portion_layer_get_pos_from_addr(GPortionLayer *, const vmpa2t *, const GdkRectangle *, gint *);
-
-/* Fonction appelée à chaque visite de portion.*/
-typedef bool (* visit_portion_fc) (GBinPortion *, void *);
-
-/* Parcours un ensemble de portions binaires. */
-bool g_portion_layer_visit(const GPortionLayer *, visit_portion_fc, void *);
+bool get_binary_portion_pos_from_addr(GBinPortion *, const vmpa2t *, const GdkRectangle *, gint *);
 
 /* Prépare une astuce concernant une portion pour son affichage. */
-gboolean g_portion_layer_query_tooltip(const GPortionLayer *, gint, gint, const GdkRectangle *, GtkTooltip *);
-
-/* Représente une couche de portions sur une bande dédiée. */
-void g_portion_layer_draw(const GPortionLayer *, GtkStyleContext *, cairo_t *, const GdkRectangle *);
+gboolean query_tooltip_for_binary_portion(GBinPortion *, gint, gint, const GdkRectangle *, GtkTooltip *);
 
 
 
diff --git a/src/gtkext/gtkbinarystrip.c b/src/gtkext/gtkbinarystrip.c
index fff6a78..d1638ed 100644
--- a/src/gtkext/gtkbinarystrip.c
+++ b/src/gtkext/gtkbinarystrip.c
@@ -211,7 +211,7 @@ static void gtk_binary_strip_size_allocate(GtkWidget *widget, GtkAllocation *all
 {
     GtkBinaryStrip *strip;                  /* Autre version du composant  */
     GExeFormat *format;                     /* Format du binaire           */
-    GPortionLayer *layer;                   /* Couche première de portions */
+    GBinPortion *portions;                  /* Couche première de portions */
     GdkRectangle area;                      /* Surface du composant        */
 
     GTK_WIDGET_CLASS(gtk_binary_strip_parent_class)->size_allocate(widget, allocation);
@@ -222,17 +222,17 @@ static void gtk_binary_strip_size_allocate(GtkWidget *widget, GtkAllocation *all
         return;
 
     format = g_loaded_binary_get_format(strip->binary);
-    layer = g_exe_format_get_main_layer(format);
+    portions = g_exe_format_get_portions(format);
 
     area.x = 0;
     area.y = 0;
     area.width = allocation->width;
     area.height = allocation->height;
 
-    if (!g_portion_layer_get_pos_from_addr(layer, &strip->cursor_addr, &area, &strip->cursor_pos))
+    if (!get_binary_portion_pos_from_addr(portions, &strip->cursor_addr, &area, &strip->cursor_pos))
         strip->cursor_pos = 0;
 
-    g_object_unref(G_OBJECT(layer));
+    g_object_unref(G_OBJECT(portions));
     g_object_unref(G_OBJECT(format));
 
 }
@@ -257,7 +257,7 @@ static gboolean gtk_binary_strip_button_release(GtkWidget *widget, GdkEventButto
     gint height;                            /* Hauteur du composant        */
     GtkBinaryStrip *strip;                  /* Autre version du composant  */
     GExeFormat *format;                     /* Format du binaire           */
-    GPortionLayer *layer;                   /* Couche première de portions */
+    GBinPortion *portions;                  /* Couche première de portions */
     GdkRectangle area;                      /* Surface du composant        */
     vmpa2t addr;                            /* Adresse à sélectionner      */
 
@@ -272,14 +272,14 @@ static gboolean gtk_binary_strip_button_release(GtkWidget *widget, GdkEventButto
 
     strip = GTK_BINARY_STRIP(widget);
     format = g_loaded_binary_get_format(strip->binary);
-    layer = g_exe_format_get_main_layer(format);
+    portions = g_exe_format_get_portions(format);
 
     area.x = 0;
     area.y = 0;
     area.width = width;
     area.height = height;
 
-    if (g_portion_layer_get_addr_from_pos(layer, event->x, &area, &addr))
+    if (get_binary_portion_addr_from_pos(portions, event->x, &area, &addr))
     {
         copy_vmpa(&strip->cursor_addr, &addr);
         strip->cursor_pos = event->x;
@@ -290,7 +290,7 @@ static gboolean gtk_binary_strip_button_release(GtkWidget *widget, GdkEventButto
 
     }
 
-    g_object_unref(G_OBJECT(layer));
+    g_object_unref(G_OBJECT(portions));
     g_object_unref(G_OBJECT(format));
 
     return FALSE;
@@ -314,10 +314,10 @@ static gboolean gtk_binary_strip_button_release(GtkWidget *widget, GdkEventButto
 static gboolean gtk_binary_strip_draw(GtkWidget *widget, cairo_t *cr)
 {
     GtkBinaryStrip *strip;                  /* Autre vision du composant   */
+    GtkStyleContext *context;               /* Contexte du thème actuel    */
     GExeFormat *format;                     /* Format du binaire           */
-    GPortionLayer *layer;                   /* Couche première de portions */
+    GBinPortion *portions;                  /* Portions de binaire         */
     GdkRectangle full;                      /* Taille totale de la surface */
-    GtkStyleContext *context;               /* Contexte du thème actuel    */
     GdkRGBA *color;                         /* Couleur du curseur          */
 
     strip = GTK_BINARY_STRIP(widget);
@@ -325,21 +325,21 @@ static gboolean gtk_binary_strip_draw(GtkWidget *widget, cairo_t *cr)
     if (strip->binary == NULL)
         return FALSE;
 
+    context = gtk_widget_get_style_context(widget);
+
     /* Dessin des portions de binaire */
 
     format = g_loaded_binary_get_format(strip->binary);
-    layer = g_exe_format_get_main_layer(format);
+    portions = g_exe_format_get_portions(format);
 
     full.x = 0;
     full.y = 1;
     full.width = gtk_widget_get_allocated_width(widget);
     full.height = gtk_widget_get_allocated_height(widget) - 1;
 
-    context = gtk_widget_get_style_context(widget);
-
-    g_portion_layer_draw(layer, context, cr, &full);
+    g_binary_portion_draw(portions, context, cr, &full);
 
-    g_object_unref(G_OBJECT(layer));
+    g_object_unref(G_OBJECT(portions));
     g_object_unref(G_OBJECT(format));
 
     /* Dessin de la position */
@@ -348,8 +348,8 @@ static gboolean gtk_binary_strip_draw(GtkWidget *widget, cairo_t *cr)
     {
         cairo_set_line_width(cr, 1);
 
-        gtk_style_context_get(gtk_widget_get_style_context(widget), GTK_STATE_FLAG_NORMAL,
-                       GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &color, NULL);
+        gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL,
+                              GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &color, NULL);
 
         cairo_set_source_rgb(cr, color->red, color->green, color->blue);
 
@@ -395,7 +395,7 @@ static gboolean gtk_binary_strip_query_tooltip(GtkWidget *widget, gint x, gint y
     gboolean result;                        /* Bilan à retourner           */
     GtkBinaryStrip *strip;                  /* Autre version du composant  */
     GExeFormat *format;                     /* Format du binaire           */
-    GPortionLayer *layer;                   /* Couches binaires à consulter*/
+    GBinPortion *portions;                  /* Couches binaires à consulter*/
     GdkRectangle area;                      /* Surface du composant        */
 
     if (keyboard) return FALSE;
@@ -405,16 +405,16 @@ static gboolean gtk_binary_strip_query_tooltip(GtkWidget *widget, gint x, gint y
     if (strip->binary != NULL)
     {
         format = g_loaded_binary_get_format(strip->binary);
-        layer = g_exe_format_get_main_layer(format);
+        portions = g_exe_format_get_portions(format);
 
         area.x = 0;
         area.y = 0;
         area.width = gtk_widget_get_allocated_width(widget);
         area.height = gtk_widget_get_allocated_height(widget);
 
-        result = g_portion_layer_query_tooltip(layer, x, y, &area, tooltip);
+        result = query_tooltip_for_binary_portion(portions, x, y, &area, tooltip);
 
-        g_object_unref(G_OBJECT(layer));
+        g_object_unref(G_OBJECT(portions));
         g_object_unref(G_OBJECT(format));
 
     }
diff --git a/src/gtkext/gtkstatusstack.c b/src/gtkext/gtkstatusstack.c
index b5dc0e1..dba5145 100644
--- a/src/gtkext/gtkstatusstack.c
+++ b/src/gtkext/gtkstatusstack.c
@@ -527,7 +527,7 @@ void gtk_status_stack_update_current_instruction(GtkStatusStack *stack, const GL
     GExeFormat *format;                     /* Format de binaire à traiter */
     const mrange_t *range;                  /* Emplacement d'instruction   */
     const vmpa2t *addr;                     /* Localisation de départ      */
-    GPortionLayer *layer;                   /* Couche première de portions */
+    GBinPortion *portions;                  /* Couche première de portions */
     GBinPortion *portion;                   /* Zone mémoire d'appartenance */
     const char *text;                       /* Texte au contenu à copier   */
     GBinSymbol *symbol;                     /* Symbole présent à l'adresse */
@@ -556,9 +556,9 @@ void gtk_status_stack_update_current_instruction(GtkStatusStack *stack, const GL
 
     /* Zone d'appartenance */
 
-    layer = g_exe_format_get_main_layer(format);
+    portions = g_exe_format_get_portions(format);
 
-    portion = g_portion_layer_find_portion_at_addr(layer, addr, (GdkRectangle []) { });
+    portion = g_binary_portion_find_at_addr(portions, addr, (GdkRectangle []) { });
 
     text = g_binary_portion_get_desc(portion);
 
@@ -567,7 +567,9 @@ void gtk_status_stack_update_current_instruction(GtkStatusStack *stack, const GL
     else
         info->segment = strdup(_("Binary"));
 
-    g_object_unref(G_OBJECT(layer));
+    g_object_unref(G_OBJECT(portion));
+
+    g_object_unref(G_OBJECT(portions));
 
     /* Adresses de base */
 
diff --git a/src/gui/panels/strings.c b/src/gui/panels/strings.c
index b8631b6..38a17a2 100644
--- a/src/gui/panels/strings.c
+++ b/src/gui/panels/strings.c
@@ -465,7 +465,7 @@ static void change_strings_panel_current_binary(GStringsPanel *panel, GLoadedBin
     GArchProcessor *proc;                   /* Architecture du binaire     */
     MemoryDataSize msize;                   /* Taille par défaut           */
     GExeFormat *format;                     /* Format de travail           */
-    GPortionLayer *layer;                   /* Couche première de portions */
+    GBinPortion *portions;                  /* Couche première de portions */
     GBinContent *content;                   /* Contenu binaire en mémoire  */
     size_t count;                           /* Nombre des chaînes          */
     GBinSymbol **symbols;                   /* Liste des chaînes trouvées  */
@@ -505,7 +505,7 @@ static void change_strings_panel_current_binary(GStringsPanel *panel, GLoadedBin
     g_object_unref(G_OBJECT(proc));
 
     format = g_loaded_binary_get_format(binary);
-    layer = g_exe_format_get_main_layer(format);
+    portions = g_exe_format_get_portions(format);
     content = g_binary_format_get_content(G_BIN_FORMAT(format));
 
     symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &count);
@@ -520,8 +520,9 @@ static void change_strings_panel_current_binary(GStringsPanel *panel, GLoadedBin
         vmpa2_phys_to_string(addr, msize, phys, NULL);
         vmpa2_virt_to_string(addr, msize, virt, NULL);
 
-        portion = g_portion_layer_find_portion_at_addr(layer, addr, (GdkRectangle []) { });
+        portion = g_binary_portion_find_at_addr(portions, addr, (GdkRectangle []) { });
         area = g_binary_portion_get_desc(portion);
+        g_object_unref(G_OBJECT(portion));
 
         label = g_binary_symbol_get_label(symbols[i]);
 
@@ -562,7 +563,7 @@ static void change_strings_panel_current_binary(GStringsPanel *panel, GLoadedBin
     }
 
     g_object_unref(G_OBJECT(content));
-    g_object_unref(G_OBJECT(layer));
+    g_object_unref(G_OBJECT(portions));
     g_object_unref(G_OBJECT(format));
 
 }
-- 
cgit v0.11.2-87-g4458