From b57e8ef5522dcbe126157fc2c50fcf879aa7d743 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 29 Dec 2015 00:27:12 +0100
Subject: Defined layers to register all kinds of binary portions.

---
 ChangeLog                    |   24 +
 plugins/mobicore/mclf.c      |   17 +-
 src/analysis/disass/area.c   |   28 +-
 src/analysis/disass/output.c |   26 +-
 src/format/dex/class.c       |    8 +-
 src/format/dex/class.h       |    2 +-
 src/format/dex/dex.c         |   16 +-
 src/format/dex/method.c      |    6 +-
 src/format/dex/method.h      |    2 +-
 src/format/elf/elf.c         |   24 +-
 src/format/executable-int.h  |    4 +-
 src/format/executable.c      |   89 +---
 src/format/executable.h      |    8 +-
 src/glibext/gbinportion.c    | 1010 +++++++++++++++++++++++++++---------------
 src/glibext/gbinportion.h    |   81 +++-
 src/gtkext/gtkbinarystrip.c  |   39 +-
 src/gtkext/gtkstatusstack.c  |    8 +-
 17 files changed, 878 insertions(+), 514 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f1936bb..5d253fc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+15-12-29  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/mobicore/mclf.c:
+	* src/analysis/disass/area.c:
+	* src/analysis/disass/output.c:
+	* 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:
+	Update code.
+
+	* src/glibext/gbinportion.c:
+	* src/glibext/gbinportion.h:
+	Clean code. Define layers to register all kinds of binary portions.
+
+	* src/gtkext/gtkbinarystrip.c:
+	* src/gtkext/gtkstatusstack.c:
+	Update code.
+
 15-12-28  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/arch/vmpa.c:
diff --git a/plugins/mobicore/mclf.c b/plugins/mobicore/mclf.c
index 7b1249c..8e99fc7 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 *, GBinPortion *);
+static void g_mclf_format_refine_portions(const GMCLFFormat *, GPortionLayer *);
 
 
 
@@ -261,7 +261,7 @@ static const char *g_mclf_format_get_target_machine(const GMCLFFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = informations chargées à consulter.                  *
-*                raw    = portion de binaire brut à raffiner.                 *
+*                main   = couche de portions principale à raffiner.           *
 *                                                                             *
 *  Description : Etend la définition des portions au sein d'un binaire.       *
 *                                                                             *
@@ -271,13 +271,18 @@ static const char *g_mclf_format_get_target_machine(const GMCLFFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-static void g_mclf_format_refine_portions(const GMCLFFormat *format, GBinPortion *raw)
+static void g_mclf_format_refine_portions(const GMCLFFormat *format, GPortionLayer *main)
 {
+    GPortionLayer *layer;                   /* Couche à mettre en place    */
     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);
+
     /* Segment de code */
 
     new = g_binary_portion_new(BPC_CODE);
@@ -290,7 +295,7 @@ static void g_mclf_format_refine_portions(const GMCLFFormat *format, GBinPortion
 
     g_binary_portion_set_rights(new, PAC_WRITE | PAC_EXEC);
 
-    g_binary_portion_include(raw, new);
+    g_portion_layer_include(layer, new);
 
     /* Segment de données */
 
@@ -304,7 +309,7 @@ static void g_mclf_format_refine_portions(const GMCLFFormat *format, GBinPortion
 
     g_binary_portion_set_rights(new, PAC_READ | PAC_WRITE);
 
-    g_binary_portion_include(raw, new);
+    g_portion_layer_include(layer, new);
 
     /* Signature finale */
 
@@ -319,6 +324,6 @@ static void g_mclf_format_refine_portions(const GMCLFFormat *format, GBinPortion
 
     g_binary_portion_set_rights(new, PAC_READ | PAC_WRITE);
 
-    g_binary_portion_include(raw, new);
+    g_portion_layer_include(layer, new);
 
 }
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c
index d2a03c6..c79b293 100644
--- a/src/analysis/disass/area.c
+++ b/src/analysis/disass/area.c
@@ -707,9 +707,11 @@ mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_len
     const vmpa2t *border;                   /* Nouvelle bordure rencontrée */
     mem_area_v2 *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     */
@@ -813,7 +815,9 @@ mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_len
 
     /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */
 
-    portions = g_exe_format_get_portions_at_level(format, -1, &portions_count);
+    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++)
     {
@@ -824,6 +828,20 @@ mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_len
                (unsigned int)get_phy_addr(portion_start),
                (unsigned int)get_virt_addr(portion_start));
 
+
+        /**
+         * 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];
@@ -871,7 +889,10 @@ mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_len
 
     }
 
+    if (portions != NULL)
+        free(portions);
 
+    g_object_unref(G_OBJECT(layer));
 
 
 
@@ -928,9 +949,6 @@ mem_area_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_len
 
     /* Nettoyage final */
 
-    if (portions != NULL)
-        free(portions);
-
     if (exe_ranges != NULL)
         free(exe_ranges);
 
@@ -2193,7 +2211,7 @@ mem_area *compute_memory_areas(GExeFormat *format, phys_t bin_length, size_t *co
 
     printf("--------------------\n");
 
-    portions = g_exe_format_get_portions_at_level(format, -1, &portions_count);
+    portions = NULL;//g_exe_format_get_portions_at_level(format, -1, &portions_count);
 
 
     for (i = 1; i < portions_count; i++)
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index 727c34f..67a3ce8 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -56,6 +56,14 @@
 void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *format, GArchProcessor *proc, const GArchInstruction *instrs, GBinRoutine * const *routines, size_t count, GtkExtStatusBar *statusbar, bstatus_id_t id)
 {
     GLangOutput *output;                    /* Modèle de sortie adéquat    */
+    GPortionLayer *layer;                   /* 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 */
+    GBinSymbol **symbols;                   /* Symboles à représenter      */
+    size_t sym_count;                       /* Qté de symboles présents    */
+    size_t sym_index;                       /* Prochain symbole non traité */
+
     //GArchProcessor *proc;                   /* Architecture du binaire     */
     MemoryDataSize msize;                   /* Taille du bus d'adresses    */
     const GBinContent *content;             /* Contenu binaire global      */
@@ -74,13 +82,6 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form
 
     GBufferLine *line;
 
-    GBinPortion **portions;                 /* Morceaux d'encadrement      */
-    size_t portions_count;                  /* Taille de cette liste       */
-    size_t portion_index;                   /* Prochaine portion à traiter */
-
-    GBinSymbol **symbols;                   /* Symboles à représenter      */
-    size_t sym_count;                       /* Qté de symboles présents    */
-    size_t sym_index;                       /* Prochain symbole non traité */
 
     const vmpa2t *paddr;                    /* Adresse de portion          */
 
@@ -100,12 +101,12 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form
 
     output = g_asm_output_new();
 
+    layer = g_exe_format_get_main_layer(format);
 
-    
-    portions = g_exe_format_get_portions_at_level(format, -1, &portions_count);
+    portions = g_portion_layer_collect_all_portions(layer, &portions_count);
     portion_index = 0;
 
-    symbols = g_binary_format_get_symbols(format, &sym_count);
+    symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
     sym_index = 0;
 
 #if 0
@@ -294,7 +295,10 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form
 
     g_object_unref(G_OBJECT(content));
 
-    /* free portions... */
+    if (portions != NULL)
+        free(portions);
+
+    g_object_unref(G_OBJECT(layer));
 
     g_object_unref(G_OBJECT(output));
 
diff --git a/src/format/dex/class.c b/src/format/dex/class.c
index 657461f..1dc3a40 100644
--- a/src/format/dex/class.c
+++ b/src/format/dex/class.c
@@ -309,7 +309,7 @@ GDexMethod *g_dex_class_get_method(const GDexClass *class, bool virtual, size_t
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : class = informations chargées à consulter.                   *
-*                raw   = portion de binaire brut à raffiner.                  *
+*                layer = couche de portions à raffiner.                       *
 *                                                                             *
 *  Description : Intègre la méthode en tant que portion de code.              *
 *                                                                             *
@@ -319,15 +319,15 @@ GDexMethod *g_dex_class_get_method(const GDexClass *class, bool virtual, size_t
 *                                                                             *
 ******************************************************************************/
 
-void g_dex_class_include_as_portion(const GDexClass *class, GBinPortion *raw)
+void g_dex_class_include_as_portion(const GDexClass *class, GPortionLayer *layer)
 {
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < class->dmethods_count; i++)
-        g_dex_method_include_as_portion(class->direct_methods[i], raw);
+        g_dex_method_include_as_portion(class->direct_methods[i], layer);
 
     for (i = 0; i < class->vmethods_count; i++)
-        g_dex_method_include_as_portion(class->virtual_methods[i], raw);
+        g_dex_method_include_as_portion(class->virtual_methods[i], layer);
 
 }
 
diff --git a/src/format/dex/class.h b/src/format/dex/class.h
index 77fa6ba..fb7cada 100644
--- a/src/format/dex/class.h
+++ b/src/format/dex/class.h
@@ -64,7 +64,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 *, GBinPortion *);
+void g_dex_class_include_as_portion(const GDexClass *, GPortionLayer *);
 
 /* 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 afd9db1..ed2565f 100755
--- a/src/format/dex/dex.c
+++ b/src/format/dex/dex.c
@@ -27,6 +27,9 @@
 #include <string.h>
 
 
+#include <i18n.h>
+
+
 #include "dex-int.h"
 #include "pool.h"
 
@@ -55,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 *, GBinPortion *);
+static void g_dex_format_refine_portions(const GDexFormat *, GPortionLayer *);
 
 /* Fournit l'emplacement d'une section donnée. */
 static bool g_dex_format_get_section_range_by_name(const GDexFormat *, const char *, mrange_t *);
@@ -302,7 +305,7 @@ static const char *g_dex_format_get_target_machine(const GDexFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = informations chargées à consulter.                  *
-*                raw    = portion de binaire brut à raffiner.                 *
+*                main   = couche de portions principale à raffiner.           *
 *                                                                             *
 *  Description : Etend la définition des portions au sein d'un binaire.       *
 *                                                                             *
@@ -312,15 +315,20 @@ static const char *g_dex_format_get_target_machine(const GDexFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-static void g_dex_format_refine_portions(const GDexFormat *format, GBinPortion *raw)
+static void g_dex_format_refine_portions(const GDexFormat *format, GPortionLayer *main)
 {
+    GPortionLayer *layer;                   /* Couche à mettre en place    */
     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);
+
     max = g_dex_format_count_classes(format);
 
     for (i = 0; i < max; i++)
-        g_dex_class_include_as_portion(format->classes[i], raw);
+        g_dex_class_include_as_portion(format->classes[i], layer);
 
 }
 
diff --git a/src/format/dex/method.c b/src/format/dex/method.c
index c68e9e1..9c911d1 100644
--- a/src/format/dex/method.c
+++ b/src/format/dex/method.c
@@ -294,7 +294,7 @@ GBinRoutine *g_dex_method_get_routine(const GDexMethod *method)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : method = représentation interne du format DEX à consulter.   *
-*                raw    = portion de binaire brut à raffiner.                 *
+*                layer  = couche de portions à raffiner.                      *
 *                                                                             *
 *  Description : Intègre la méthode en tant que portion de code.              *
 *                                                                             *
@@ -304,7 +304,7 @@ GBinRoutine *g_dex_method_get_routine(const GDexMethod *method)
 *                                                                             *
 ******************************************************************************/
 
-void g_dex_method_include_as_portion(const GDexMethod *method, GBinPortion *raw)
+void g_dex_method_include_as_portion(const GDexMethod *method, GPortionLayer *layer)
 {
     GBinPortion *new;                       /* Nouvelle portion définie    */
     char *desc;                             /* Description d'une portion   */
@@ -327,7 +327,7 @@ void g_dex_method_include_as_portion(const GDexMethod *method, GBinPortion *raw)
 
     g_binary_portion_set_rights(new, PAC_READ | PAC_EXEC);
 
-    g_binary_portion_include(raw, new);
+    g_portion_layer_include(layer, new);
 
 }
 
diff --git a/src/format/dex/method.h b/src/format/dex/method.h
index dee33cb..4d29bac 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 *, GBinPortion *);
+void g_dex_method_include_as_portion(const GDexMethod *, GPortionLayer *);
 
 /* Indique la position de la méthode au sein du binaire. */
 off_t g_dex_method_get_offset(const GDexMethod *);
diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c
index 3dc5d64..3491c71 100644
--- a/src/format/elf/elf.c
+++ b/src/format/elf/elf.c
@@ -67,7 +67,7 @@ static void g_elf_format_finalize(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 *, GBinPortion *);
+static void g_elf_format_refine_portions(const GElfFormat *, GPortionLayer *);
 
 /* Fournit l'emplacement correspondant à une position physique. */
 static bool g_elf_format_translate_offset_into_vmpa(const GElfFormat *, phys_t, vmpa2t *);
@@ -352,7 +352,7 @@ static const char *g_elf_format_get_target_machine(const GElfFormat *format)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = informations chargées à consulter.                  *
-*                raw    = portion de binaire brut à raffiner.                 *
+*                main   = couche de portions principale à raffiner.           *
 *                                                                             *
 *  Description : Etend la définition des portions au sein d'un binaire.       *
 *                                                                             *
@@ -362,8 +362,9 @@ static const char *g_elf_format_get_target_machine(const GElfFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion *raw)
+static void g_elf_format_refine_portions(const GElfFormat *format, GPortionLayer *main)
 {
+    GPortionLayer *layer;                   /* Couche à mettre en place    */
     uint16_t i;                             /* Boucle de parcours          */
     off_t offset;                           /* Début de part de programme  */
     elf_phdr phdr;                          /* En-tête de programme ELF    */
@@ -381,7 +382,10 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion *
 
     /* Côté segments basiques */
 
-#if 0
+    layer = g_portion_layer_new(NO_LENGTH_YET, _("Segment"));
+
+    g_portion_layer_attach_sub(main, layer);
+
     for (i = 0; i < ELF_HDR(format, format->header, e_phnum); i++)
     {
         offset = ELF_HDR(format, format->header, e_phoff)
@@ -414,10 +418,9 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion *
 
         g_binary_portion_set_rights(new, rights);
 
-        g_binary_portion_include(raw, new);
+        g_portion_layer_include(layer, new);
 
     }
-#endif
 
     /* Inclusion des sections, si possible... */
 
@@ -425,6 +428,10 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion *
                                             ELF_HDR(format, format->header, e_shstrndx),
                                             &strings);
 
+    layer = g_portion_layer_new(NO_LENGTH_YET, _("Section"));
+
+    g_portion_layer_attach_sub(main, layer);
+
     for (i = 0; i < ELF_HDR(format, format->header, e_shnum); i++)
     {
         if (!find_elf_section_by_index(format, i, &section))
@@ -432,9 +439,6 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion *
 
         sh_flags = ELF_SHDR(format, section, sh_flags);
 
-        printf("[section % 2hu] 0x%08x -> %x -> %d\n", i, sh_flags,
-               sh_flags & SHF_ALLOC, (sh_flags & SHF_ALLOC) == 0);
-
         if ((sh_flags & SHF_ALLOC) == 0)
             continue;
 
@@ -466,7 +470,7 @@ static void g_elf_format_refine_portions(const GElfFormat *format, GBinPortion *
 
         g_binary_portion_set_rights(new, rights);
 
-        g_binary_portion_include(raw, new);
+        g_portion_layer_include(layer, new);
 
     }
 
diff --git a/src/format/executable-int.h b/src/format/executable-int.h
index 4b86092..5e57133 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 *, GBinPortion *);
+typedef void (* refine_portions_fc) (const GExeFormat *, GPortionLayer *);
 
 /* Fournit l'emplacement correspondant à une position physique. */
 typedef bool (* translate_phys_fc) (const GExeFormat *, phys_t, vmpa2t *);
@@ -57,7 +57,7 @@ struct _GExeFormat
     GDbgFormat **debugs;                    /* Informations de débogage    */
     size_t debugs_count;                    /* Nombre de ces informations  */
 
-    GBinPortion *portions;                  /* Morceaux binaires distincts */
+    GPortionLayer *layers;                  /* Couches de morceaux binaires*/
 
 };
 
diff --git a/src/format/executable.c b/src/format/executable.c
index 325dc8b..fc34fa0 100644
--- a/src/format/executable.c
+++ b/src/format/executable.c
@@ -163,11 +163,6 @@ GDbgFormat *g_exe_format_get_debug_info(const GExeFormat *format, size_t index)
 }
 
 
-
-
-
-
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = informations chargées à consulter.                  *
@@ -191,89 +186,50 @@ const char *g_exe_format_get_target_machine(const GExeFormat *format)
 *                                                                             *
 *  Paramètres  : format = description de l'exécutable à consulter.            *
 *                                                                             *
-*  Description : Décrit les différentes portions qui composent le binaire.    *
+*  Description : Fournit la première couche des portions composent le binaire.*
 *                                                                             *
-*  Retour      : Défintions de zones.                                         *
+*  Retour      : Couche brute des différentes portions.                       *
 *                                                                             *
-*  Remarques   : -                                                            *
+*  Remarques   : Le compteur de références de l'instance renvoyée doit être   *
+*                décrémenté après usage.                                      *
 *                                                                             *
 ******************************************************************************/
 
-GBinPortion *g_exe_format_get_portions(GExeFormat *format)
+GPortionLayer *g_exe_format_get_main_layer(GExeFormat *format)
 {
+    GBinPortion *portion;                   /* Portion brute globale       */
     vmpa2t addr;                            /* Emplacement vide de sens    */
     phys_t length;                          /* Taille de portion globale   */
+    GPortionLayer *layer;                   /* Couche à mettre en place    */
 
-    if (format->portions == NULL)
+    if (format->layers == NULL)
     {
-        format->portions = g_binary_portion_new(BPC_RAW);
+        /* 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);
 
-        g_binary_portion_set_values(format->portions, &addr, length);
+        g_binary_portion_set_values(portion, &addr, length);
 
-        G_EXE_FORMAT_GET_CLASS(format)->refine_portions(format, format->portions);
+        /* Création d'une couche de base brute */
 
-    }
+        layer = g_portion_layer_new(length, NULL);
 
-    return format->portions;
+        g_portion_layer_include(layer, portion);
 
-}
+        /* Remplissage */
 
+        G_EXE_FORMAT_GET_CLASS(format)->refine_portions(format, layer);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : format = description de l'exécutable à consulter.            *
-*                level  = étage des portions à considérer ou -1 pour tous.    *
-*                count  = nombre de portions trouvées et renvoyées. [OUT]     *
-*                                                                             *
-*  Description : Fournit une liste choisie de portions d'un binaire.          *
-*                                                                             *
-*  Retour      : Liste de définitins de zones à libérer après usage.          *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GBinPortion **g_exe_format_get_portions_at_level(GExeFormat *format, unsigned int level, size_t *count)
-{
-    GBinPortion **result;                   /* Liste à retourner           */
-
-    typedef struct _portions_list
-    {
-        unsigned int required;
-        GBinPortion **portions;
-        size_t length;
-
-    } portions_list;
-
-    portions_list list;                     /* Sauvegarde de la liste      */
-
-    bool visit_for_level(GBinPortion *portion, portions_list *list)
-    {
-        if (list->required == -1 || g_binary_portion_get_level(portion) == list->required)
-        {
-            list->portions = (GBinPortion **)realloc(list->portions, ++list->length * sizeof(GBinPortion *));
-            list->portions[list->length - 1] = portion;
-        }
-
-        return true;
+        format->layers = layer;
 
     }
 
-    list.required = level;
-    list.portions = NULL;
-    list.length = 0;
+    g_object_ref(G_OBJECT(format->layers));
 
-    g_binary_portion_visit(g_exe_format_get_portions(format), (visit_portion_fc)visit_for_level, &list);
-
-    result = list.portions;
-    *count = list.length;
-
-    qsort(result, *count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);
-
-    return result;
+    return format->layers;
 
 }
 
@@ -303,6 +259,7 @@ mrange_t *g_exe_format_get_x_ranges(GExeFormat *format, size_t *count)
     } x_ranges;
 
     x_ranges tmp;                           /* Sauvegarde de la liste      */
+    GPortionLayer *layer;                   /* Couche première de portions */
 
     bool visit_for_x(GBinPortion *portion, x_ranges *ranges)
     {
@@ -324,7 +281,9 @@ mrange_t *g_exe_format_get_x_ranges(GExeFormat *format, size_t *count)
     tmp.list = NULL;
     tmp.length = 0;
 
-    g_binary_portion_visit(g_exe_format_get_portions(format), (visit_portion_fc)visit_for_x, &tmp);
+    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));
 
     result = tmp.list;
     *count = tmp.length;
diff --git a/src/format/executable.h b/src/format/executable.h
index 48a8139..4ca0194 100644
--- a/src/format/executable.h
+++ b/src/format/executable.h
@@ -62,15 +62,11 @@ size_t g_exe_format_count_debug_info(const GExeFormat *);
 /* Fournit un format de débogage attaché à l'exécutable. */
 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 *);
 
-/* Décrit les différentes portions qui composent le binaire. */
-GBinPortion *g_exe_format_get_portions(GExeFormat *);
-
-/* Fournit une liste choisie de portions d'un binaire. */
-GBinPortion **g_exe_format_get_portions_at_level(GExeFormat *, unsigned int, size_t *);
+/* Fournit la première couche des portions composent le binaire. */
+GPortionLayer *g_exe_format_get_main_layer(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/glibext/gbinportion.c b/src/glibext/gbinportion.c
index 920fcfe..790614a 100644
--- a/src/glibext/gbinportion.c
+++ b/src/glibext/gbinportion.c
@@ -24,6 +24,7 @@
 #include "gbinportion.h"
 
 
+#include <assert.h>
 #include <malloc.h>
 #include <stdlib.h>
 #include <string.h>
@@ -44,27 +45,16 @@ struct _GBinPortion
 {
     GObject parent;                         /* A laisser en premier        */
 
-    unsigned int level;                     /* Profondeur de la portion    */
-    GBinPortion *container;                 /* Portion parente ou racine   */
+    const unsigned int *level;              /* Profondeur de la portion    */
 
     char *code;                             /* Code de la couleur de fond  */
 
     char *desc;                             /* Désignation humaine         */
 
     mrange_t range;                         /* Emplacement dans le code    */
-    vmpa2t addr;                            /* Emplacement dans le code    */ /* TODO : clean */
-    off_t size;                             /* Taille de la partie         */ /* TODO : clean */
 
     PortionAccessRights rights;             /* Droits d'accès              */
 
-    GBinPortion **sub_portions;             /* Portions incluses           */
-    size_t sub_count;                       /* Quantité d'inclusions       */
-
-#ifdef DEBUG
-    unsigned int valid;                     /* Instructions reconnues      */
-    unsigned int db;                        /* Instructions non traduites  */
-#endif
-
 };
 
 /* Portion de données binaires quelconques (classe) */
@@ -75,10 +65,10 @@ struct _GBinPortionClass
 };
 
 
-/* Initialise la classe des blocs de données binaires. */
+/* Initialise la classe des portions de données binaires. */
 static void g_binary_portion_class_init(GBinPortionClass *);
 
-/* Initialise une instance de bloc de données binaires. */
+/* Initialise une instance de portion de données binaires. */
 static void g_binary_portion_init(GBinPortion *);
 
 /* Supprime toutes les références externes. */
@@ -88,10 +78,57 @@ static void g_binary_portion_dispose(GBinPortion *);
 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 *, unsigned int);
+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(GBinPortion *, GBinPortion *, const GdkRectangle *, GdkRectangle *);
+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 *);
+
+
 
 
 
@@ -100,7 +137,7 @@ static bool g_binary_portion_compute_sub_area(GBinPortion *, GBinPortion *, cons
 /* ---------------------------------------------------------------------------------- */
 
 
-/* Indique le type défini par la GLib pour les blocs de données. */
+/* Indique le type défini par la GLib pour les portions de données binaires. */
 G_DEFINE_TYPE(GBinPortion, g_binary_portion, G_TYPE_OBJECT);
 
 
@@ -108,7 +145,7 @@ G_DEFINE_TYPE(GBinPortion, g_binary_portion, G_TYPE_OBJECT);
 *                                                                             *
 *  Paramètres  : klass = classe à initialiser.                                *
 *                                                                             *
-*  Description : Initialise la classe des blocs de données binaires.          *
+*  Description : Initialise la classe des portions de données binaires.       *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -133,7 +170,7 @@ static void g_binary_portion_class_init(GBinPortionClass *klass)
 *                                                                             *
 *  Paramètres  : portion = instance à initialiser.                            *
 *                                                                             *
-*  Description : Initialise une instance de bloc de données binaires.         *
+*  Description : Initialise une instance de portion de données binaires.      *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -143,7 +180,7 @@ static void g_binary_portion_class_init(GBinPortionClass *klass)
 
 static void g_binary_portion_init(GBinPortion *portion)
 {
-    portion->level = 0;
+    portion->level = NULL;
 
 }
 
@@ -162,11 +199,6 @@ static void g_binary_portion_init(GBinPortion *portion)
 
 static void g_binary_portion_dispose(GBinPortion *portion)
 {
-    size_t i;                               /* Boucle de parcours          */
-
-    for (i = 0; i < portion->sub_count; i++)
-        g_object_unref(G_OBJECT(portion->sub_portions[i]));
-
     G_OBJECT_CLASS(g_binary_portion_parent_class)->dispose(G_OBJECT(portion));
 
 }
@@ -191,9 +223,6 @@ static void g_binary_portion_finalize(GBinPortion *portion)
     if (portion->desc != NULL)
         free(portion->desc);
 
-    if (portion->sub_portions != NULL)
-        free(portion->sub_portions);
-
     G_OBJECT_CLASS(g_binary_portion_parent_class)->finalize(G_OBJECT(portion));
 
 }
@@ -205,7 +234,7 @@ static void g_binary_portion_finalize(GBinPortion *portion)
 *                                                                             *
 *  Description : Crée une description de partie de code vierge.               *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Instance mise en place.                                      *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -226,6 +255,26 @@ GBinPortion *g_binary_portion_new(const char *code)
 
 /******************************************************************************
 *                                                                             *
+*  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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : a = premières informations à consulter.                      *
 *                b = secondes informations à consulter.                       *
 *                                                                             *
@@ -240,15 +289,32 @@ GBinPortion *g_binary_portion_new(const char *code)
 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'    */
 
-    if ((*a)->level < (*b)->level)
-        result = -1;
+    addr_a = get_mrange_addr(&(*a)->range);
+    addr_b = get_mrange_addr(&(*b)->range);
 
-    else if ((*a)->level > (*b)->level)
-        result = 1;
+    result = cmp_vmpa(addr_a, addr_b);
 
-    else
-        result = cmp_mrange(&(*a)->range, &(*b)->range);
+    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;
 
@@ -312,9 +378,6 @@ const char *g_binary_portion_get_desc(const GBinPortion *portion)
 
 void g_binary_portion_set_values(GBinPortion *portion, const vmpa2t *addr, phys_t size)
 {
-    copy_vmpa(&portion->addr, addr);
-    portion->size = size;
-
     init_mrange(&portion->range, addr, size);
 
 }
@@ -380,77 +443,8 @@ PortionAccessRights g_binary_portion_get_rights(const GBinPortion *portion)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
-*                sub     = portion à inclure dans la définition courante.     *
-*                                                                             *
-*  Description : Procède à l'inclusion d'une portion dans une autre.          *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_binary_portion_include(GBinPortion *portion, GBinPortion *sub)
-{
-    portion->sub_portions = (GBinPortion **)realloc(portion->sub_portions,
-                                                    ++portion->sub_count * sizeof(GBinPortion *));
-
-    portion->sub_portions[portion->sub_count - 1] = sub;
-
-    g_binary_portion_set_level(sub, portion->level + 1);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  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, unsigned int level)
-{
-    size_t i;                               /* Boucle de parcours          */
-
-    portion->level = level;
-
-    for (i = 0; i < portion->sub_count; i++)
-        g_binary_portion_set_level(portion->sub_portions[i], level + 1);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
-*                                                                             *
-*  Description : Indique le niveau de profondeur d'une portion donnée.        *
-*                                                                             *
-*  Retour      : Niveau de profondeur positif ou nul.                         *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-unsigned int g_binary_portion_get_level(GBinPortion *portion)
-{
-    return portion->level;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : portion  = portion mère à consulter.                         *
-*                sub      = portion fille à traiter.                          *
+*                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.    *
 *                                                                             *
@@ -462,16 +456,23 @@ unsigned int g_binary_portion_get_level(GBinPortion *portion)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_binary_portion_compute_sub_area(GBinPortion *portion, GBinPortion *sub, const GdkRectangle *area, GdkRectangle *sub_area)
+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 (sub->size == 0) return false;
+    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 + (get_phy_addr(&sub->addr) * area->width) / portion->size;
-    sub_area->width = (sub->size * area->width) / portion->size;
+    sub_area->x = area->x + (start * area->width) / full;
+    sub_area->width = (length * area->width) / full;
 
     return true;
 
@@ -480,27 +481,30 @@ static bool g_binary_portion_compute_sub_area(GBinPortion *portion, GBinPortion
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : portion = première portion amorçant la visite.               *
-*                visitor = fonction à appeler à chaque étape de la descente.  *
-*                data    = adresse pointant vers des données de l'utilisateur.*
+*  Paramètres  : portion = portion mère à consulter.                          *
+*                addr    = adresse du point de recherche.                     *
 *                                                                             *
-*  Description : Parcours un ensemble de portions binaires.                   *
+*  Description : Détermine si une portion contient une adresse donnée.        *
 *                                                                             *
-*  Retour      : true si la visite a été jusqu'à son terme, false sinon.      *
+*  Retour      : true ou false selon le résultat.                             *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_binary_portion_visit(GBinPortion *portion, visit_portion_fc visitor, void *data)
+static bool g_portion_layer_contains_addr(const GBinPortion *portion, const vmpa2t *addr)
 {
-    bool result;                            /* Etat à retourner            */
-    size_t i;                               /* Boucle de parcours          */
+    bool result;                            /* Bilan à retourner           */
+
+    result = false;
 
-    result = visitor(portion, data);
+    /* Portion non allouée en mémoire -> adresse nulle ; on écarte */
+    if (get_virt_addr(get_mrange_addr(&portion->range)) == 0)
+        goto not_found;
 
-    for (i = 0; i < portion->sub_count && result; i++)
-        result = g_binary_portion_visit(portion->sub_portions[i], visitor, data);
+    result = mrange_contains_addr(&portion->range, addr);
+
+ not_found:
 
     return result;
 
@@ -509,107 +513,80 @@ bool g_binary_portion_visit(GBinPortion *portion, visit_portion_fc visitor, void
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
-*                x       = abscisse du point de recherche.                    *
-*                y       = ordonnée du point de recherche.                    *
-*                area    = étendue de portion mère, puis celle trouvée. [OUT] *
+*  Paramètres  : portion = description de partie à consulter.                 *
+*                buffer  = espace où placer ledit contenu.                    *
+*                msize   = taille idéale des positions et adresses;           *
 *                                                                             *
-*  Description : Recherche la portion présente à un point donné.              *
+*  Description : Insère dans un tampon une description de portion.            *
 *                                                                             *
-*  Retour      : Portion trouvée à l'endroit indiqué.                         *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBinPortion *g_binary_portion_find_at_pos(GBinPortion *portion, gint x, GdkRectangle *area)
+void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, MemoryDataSize msize)
 {
-    GBinPortion *result;                    /* Portion à retourner         */
-    size_t i;                               /* Boucle de parcours          */
-    GBinPortion *sub;                       /* Portion incluse à traiter   */
-    GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
-
-    result = NULL;
+    mrange_t range;                         /* Couverture à fournir        */
+    GBufferLine *line;                      /* Nouvelle ligne à éditer     */
+    char rights[64];                        /* Traduction en texte         */
 
-    for (i = 0; i < portion->sub_count && !result; i++)
-    {
-        sub = portion->sub_portions[i];
+    /* On ne traite pas les portions anonymes ! */
+    if (portion->desc == NULL) return;
 
-        if (!g_binary_portion_compute_sub_area(portion, sub, area, &sub_area))
-            continue;
+    init_mrange(&range, get_mrange_addr(&portion->range), 0);
 
-        if (sub_area.x <= x && x < (sub_area.x + sub_area.width))
-        {
-            result = sub;
-            *area = sub_area;
-        }
+    line = g_code_buffer_append_new_line(buffer, &range);
+    g_buffer_line_fill_mrange(line, msize, msize);
 
-    }
+    g_buffer_line_add_flag(line, BLF_WIDTH_MANAGER);
 
-    if (result == NULL)
-        result = portion;
+    /* Séparation */
 
-    return result;
+    line = g_code_buffer_append_new_line(buffer, &range);
+    g_buffer_line_fill_mrange(line, msize, msize);
 
-}
+    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD,
+                              "; ======================================================", 56, RTT_COMMENT);
 
+    /* Retour à la ligne */
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
-*                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.          *
-*                                                                             *
-*  Retour      : Portion trouvée à l'endroit indiqué.                         *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    line = g_code_buffer_append_new_line(buffer, &range);
+    g_buffer_line_fill_mrange(line, msize, msize);
 
-GBinPortion *g_binary_portion_find_at_addr(GBinPortion *portion, const vmpa2t *addr, GdkRectangle *area)
-{
-    GBinPortion *result;                    /* Portion à retourner         */
-    size_t i;                               /* Boucle de parcours #1       */
-    GBinPortion *sub;                       /* Portion incluse à traiter   */
-    GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
-    size_t j;                               /* Boucle de parcours #2       */
+    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT);
 
-    result = NULL;
+    /* Description */
 
-    for (i = 0; i < portion->sub_count && result == NULL; i++)
-    {
-        sub = portion->sub_portions[i];
+    line = g_code_buffer_append_new_line(buffer, &range);
+    g_buffer_line_fill_mrange(line, msize, msize);
 
-        /* FIXME : cmp ? */
+    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
 
-        /* Portion non allouée en mémoire -> adresse nulle ; on écarte */
-        if (get_virt_addr(&sub->addr) == 0)
-            continue;
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT);
 
-        if (get_virt_addr(addr) < get_virt_addr(&sub->addr)
-            || get_virt_addr(addr) >= (get_virt_addr(&sub->addr) + sub->size))
-            continue;
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, portion->desc, strlen(portion->desc), RTT_COMMENT);
 
-        if (!g_binary_portion_compute_sub_area(portion, sub, area, &sub_area))
-            continue;
+    snprintf(rights, sizeof(rights), " (%s%s%s%s)",
+             _("rights: "),
+             portion->rights & PAC_READ ? "r" : "-",
+             portion->rights & PAC_WRITE ? "w" : "-",
+             portion->rights & PAC_EXEC ? "x" : "-");
 
-        for (j = 0; j < sub->sub_count && !result; j++)
-            result = g_binary_portion_find_at_addr(sub->sub_portions[j], addr, &sub_area);
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, rights, strlen(rights), RTT_COMMENT);
 
-        if (result == NULL)
-        {
-            result = sub;
-            *area = sub_area;
-        }
+    /* Retour à la ligne */
 
-    }
+    line = g_code_buffer_append_new_line(buffer, &range);
+    g_buffer_line_fill_mrange(line, msize, msize);
 
-    if (result == NULL)
-        result = portion;
+    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT);
 
-    return result;
+    line = g_code_buffer_append_new_line(buffer, &range);
+    g_buffer_line_fill_mrange(line, msize, msize);
 
 }
 
@@ -617,79 +594,132 @@ GBinPortion *g_binary_portion_find_at_addr(GBinPortion *portion, const vmpa2t *a
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : portion = description de partie à mettre à jour.             *
-*                x       = abscisse du point de recherche.                    *
-*                area    = étendue de représentation de la portion mère.      *
-*                addr    = adresse correspondante. [OUT]                      *
+*                tooltip = astuce à compléter. [OUT]                          *
 *                                                                             *
-*  Description : Fournit la position correspondant à une adresse donnée.      *
+*  Description : Prépare une astuce concernant une portion pour son affichage.*
 *                                                                             *
-*  Retour      : Succès de la traduction.                                     *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_binary_portion_get_addr_from_pos(GBinPortion *portion, gint x, const GdkRectangle *area, vmpa2t *addr)
+void g_binary_portion_query_tooltip(GBinPortion *portion, GtkTooltip *tooltip)
 {
-    GdkRectangle owner_area;                /* Aire de contenance          */
-    GBinPortion *owner;                     /* Conteneur propriétaire      */
+    char *markup;                           /* Description à construire    */
+    VMPA_BUFFER(value);                     /* Traduction en texte         */
 
-    owner_area = *area;
+    /* Nom */
 
-    owner = g_binary_portion_find_at_pos(portion, x, &owner_area);
-    if (owner == NULL) return false;
+    if (portion->desc != NULL)
+    {
+        markup = strdup("<b>");
+        markup = stradd(markup, portion->desc);
+        markup = stradd(markup, "</b>\n");
+        markup = stradd(markup, "\n");
 
-    copy_vmpa(addr, &owner->addr);
+    }
+    else markup = strdup("");
 
-    advance_vmpa(addr, (owner->size * (x - owner_area.x)) / owner_area.width);
+    markup = stradd(markup, "taille : ");
+    mrange_length_to_string(&portion->range, MDS_UNDEFINED, value, NULL);
+    markup = stradd(markup, value);
+    markup = stradd(markup, "\n");
 
-    return true;
+    /* Localisation */
 
-}
+    markup = stradd(markup, "<b>");
+    markup = stradd(markup, _("Localisation"));
+    markup = stradd(markup, "</b>\n");
 
+    markup = stradd(markup, _("physical: from "));
 
-/******************************************************************************
+    mrange_phys_to_string(&portion->range, MDS_UNDEFINED, true, value, NULL);
+    markup = stradd(markup, value);
+    markup = stradd(markup, _(" to "));
+    mrange_phys_to_string(&portion->range, MDS_UNDEFINED, false, value, NULL);
+    markup = stradd(markup, value);
+    markup = stradd(markup, "\n");
+
+    markup = stradd(markup, _("memory: from "));
+
+    mrange_virt_to_string(&portion->range, MDS_UNDEFINED, true, value, NULL);
+    markup = stradd(markup, value);
+    markup = stradd(markup, _(" to "));
+    mrange_virt_to_string(&portion->range, MDS_UNDEFINED, false, value, NULL);
+    markup = stradd(markup, value);
+
+    markup = stradd(markup, "\n\n");
+
+    /* Droits d'accès */
+
+    markup = stradd(markup, "<b>");
+    markup = stradd(markup, _("Rights"));
+    markup = stradd(markup, "</b>\n");
+
+    snprintf(value, 2 * VMPA_MAX_SIZE, "%s%s%s",
+             portion->rights & PAC_READ ? "r" : "-",
+             portion->rights & PAC_WRITE ? "w" : "-",
+             portion->rights & PAC_EXEC ? "x" : "-");
+
+    markup = stradd(markup, value);
+
+    /* Impression finale */
+
+    gtk_tooltip_set_markup(tooltip, markup);
+    free(markup);
+
+}
+
+
+/******************************************************************************
 *                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
-*                addr    = adresse du point de recherche.                     *
-*                area    = étendue de représentation de la portion mère.      *
-*                x       = position correspondante. [OUT]                     *
+*  Paramètres  : portion = description de partie à consulter.                 *
+*                cr      = contexte graphique pour le dessin.                 *
+*                area    = étendue mise à disposition.                        *
 *                                                                             *
-*  Description : Fournit l'adresse correspondant à une position donnée.       *
+*  Description : Représente la portion sur une bande dédiée.                  *
 *                                                                             *
-*  Retour      : Succès de la traduction.                                     *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_binary_portion_get_pos_from_addr(GBinPortion *portion, const vmpa2t *addr, const GdkRectangle *area, gint *x)
+void g_binary_portion_draw(const GBinPortion *portion, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area)
 {
-    GdkRectangle owner_area;                /* Aire de contenance          */
-    GBinPortion *owner;                     /* Conteneur propriétaire      */
-    off_t diff;                            /* Décallage à appliquer       */
+    //cairo_set_line_width(cr, 1.0);
 
-    owner_area = *area;
+    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
 
-    owner = g_binary_portion_find_at_addr(portion, addr, &owner_area);
-    if (owner == NULL) return false;
+    gtk_style_context_save(context);
 
-    diff = compute_vmpa_diff(addr, &owner->addr);
+    gtk_style_context_add_class(context, portion->code);
 
-    *x = owner_area.x + (diff * owner_area.width) / owner->size;
+    gtk_render_background(context, cr, area->x, area->y, area->width, area->height);
 
-    return true;
+    gtk_render_frame(context, cr, area->x, area->y, area->width, area->height);
+
+    gtk_style_context_restore(context);
 
 }
 
 
+
+/* ---------------------------------------------------------------------------------- */
+/*                            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  : portion = description de partie à consulter.                 *
-*                buffer  = espace où placer ledit contenu.                    *
-*                msize   = taille idéale des positions et adresses;           *
+*  Paramètres  : klass = classe à initialiser.                                *
 *                                                                             *
-*  Description : Insère dans un tampon une description de portion.            *
+*  Description : Initialise la classe des couches de portions binaires.       *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -697,219 +727,487 @@ bool g_binary_portion_get_pos_from_addr(GBinPortion *portion, const vmpa2t *addr
 *                                                                             *
 ******************************************************************************/
 
-void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, MemoryDataSize msize)
+static void g_portion_layer_class_init(GPortionLayerClass *klass)
 {
-    mrange_t range;                         /* Couverture à fournir        */
-    GBufferLine *line;                      /* Nouvelle ligne à éditer     */
-    char rights[64];                        /* Traduction en texte         */
+    GObjectClass *object;                   /* Autre version de la classe  */
 
-    /* On ne traite pas les portions anonymes ! */
-    if (portion->desc == NULL) return;
+    object = G_OBJECT_CLASS(klass);
 
-    init_mrange(&range, get_mrange_addr(&portion->range), 0);
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_portion_layer_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_portion_layer_finalize;
 
-    line = g_code_buffer_append_new_line(buffer, &range);
-    g_buffer_line_fill_mrange(line, msize, msize);
 
-    g_buffer_line_add_flag(line, BLF_WIDTH_MANAGER);
+}
 
-    /* Séparation */
 
-    line = g_code_buffer_append_new_line(buffer, &range);
-    g_buffer_line_fill_mrange(line, msize, msize);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : layer = instance à initialiser.                              *
+*                                                                             *
+*  Description : Initialise une instance de couche de portions binaires.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
-    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD,
-                              "; ======================================================", 56, RTT_COMMENT);
+static void g_portion_layer_init(GPortionLayer *layer)
+{
+    layer->level = 0;
 
-    /* Retour à la ligne */
+}
 
-    line = g_code_buffer_append_new_line(buffer, &range);
-    g_buffer_line_fill_mrange(line, msize, msize);
 
-    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
-    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : layer = instance d'objet GLib à traiter.                     *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    /* Description */
+static void g_portion_layer_dispose(GPortionLayer *layer)
+{
+    size_t i;                               /* Boucle de parcours          */
 
-    line = g_code_buffer_append_new_line(buffer, &range);
-    g_buffer_line_fill_mrange(line, msize, msize);
+    if (layer->sub_layer != NULL)
+        g_object_unref(G_OBJECT(layer->sub_layer));
 
-    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
+    for (i = 0; i < layer->count; i++)
+        g_object_unref(G_OBJECT(layer->portions[i]));
 
-    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT);
+    G_OBJECT_CLASS(g_portion_layer_parent_class)->dispose(G_OBJECT(layer));
 
-    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, portion->desc, strlen(portion->desc), RTT_COMMENT);
+}
 
-    snprintf(rights, sizeof(rights), " (%s%s%s%s)",
-             _("rights: "),
-             portion->rights & PAC_READ ? "r" : "-",
-             portion->rights & PAC_WRITE ? "w" : "-",
-             portion->rights & PAC_EXEC ? "x" : "-");
 
-    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, rights, strlen(rights), RTT_COMMENT);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : layer = instance d'objet GLib à traiter.                     *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    /* Retour à la ligne */
+static void g_portion_layer_finalize(GPortionLayer *layer)
+{
+    if (layer->portions != NULL)
+        free(layer->portions);
 
-    line = g_code_buffer_append_new_line(buffer, &range);
-    g_buffer_line_fill_mrange(line, msize, msize);
+    G_OBJECT_CLASS(g_portion_layer_parent_class)->finalize(G_OBJECT(layer));
 
-    g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
-    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT);
+}
 
-    line = g_code_buffer_append_new_line(buffer, &range);
-    g_buffer_line_fill_mrange(line, msize, msize);
+
+/******************************************************************************
+*                                                                             *
+*  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;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : portion = description de partie à mettre à jour.             *
-*                x       = abscisse du point de recherche.                    *
-*                y       = ordonnée du point de recherche.                    *
-*                area    = étendue de représentation de la portion mère.      *
-*                tooltip = astuce à compléter. [OUT]                          *
+*  Paramètres  : layer = couche rassemblant des portions à modifier.          *
+*  Paramètres  : sub   = couche inférieure à rattacher à la couche courante.  *
 *                                                                             *
-*  Description : Prépare une astuce concernant une portion pour son affichage.*
+*  Description : Attache une couche à une autre en tant que couche inférieure.*
 *                                                                             *
-*  Retour      : TRUE pour valider l'affichage.                               *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-gboolean g_binary_portion_query_tooltip(GBinPortion *portion, gint x, gint y, const GdkRectangle *area, GtkTooltip *tooltip)
+void g_portion_layer_attach_sub(GPortionLayer *layer, GPortionLayer *sub)
 {
-    GBinPortion *selected;                  /* Portion à décrire ici       */
-    char *markup;                           /* Description à construire    */
-    GBinPortion *iter;                      /* Remontée hiérarchique       */
-    char value[2 * VMPA_MAX_SIZE];          /* Traduction en texte         */
+    void set_layers_length(GPortionLayer *parent, GPortionLayer *child)
+    {
+        if (child->length == NO_LENGTH_YET)
+        {
+            assert(parent->length != NO_LENGTH_YET);
 
-    selected = g_binary_portion_find_at_pos(portion, x, (GdkRectangle []) { *area });
+            child->length = parent->length;
 
-    /* Nom */
+            if (child->sub_layer != NULL)
+                set_layers_length(child, child->sub_layer);
 
-    if (selected->desc != NULL)
-    {
-        markup = strdup("<b>");
-        markup = stradd(markup, selected->desc);
-        markup = stradd(markup, "</b>\n");
+        }
 
-        for (iter = selected->container; iter != NULL; iter = iter->container)
-            if (iter->desc != NULL)
-            {
-                markup = stradd(markup, selected->desc);
-                markup = stradd(markup, "\n");
-            }
+    }
 
-        markup = stradd(markup, "\n");
+    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);
 
     }
-    else markup = strdup("");
 
-    markup = stradd(markup, "taille : ");
-    snprintf(value, 2 * VMPA_MAX_SIZE, OFF_FMT, OFF_CAST(selected->size));
-    markup = stradd(markup, value);
-    markup = stradd(markup, "\n");
+    set_layers_length(layer, sub);
 
-    /* Localisation */
+    set_layers_depth(layer, sub);
 
-    markup = stradd(markup, "<b>");
-    markup = stradd(markup, _("Localisation"));
-    markup = stradd(markup, "</b>\n");
+    layer->sub_layer = sub;
 
-    markup = stradd(markup, _("physical: from "));
-    snprintf(value, 2 * VMPA_MAX_SIZE, OFF_FMT, OFF_CAST(get_phy_addr(&selected->addr)));
-    markup = stradd(markup, value);
-    markup = stradd(markup, _(" to "));
-    snprintf(value, 2 * VMPA_MAX_SIZE, OFF_FMT, OFF_CAST(get_phy_addr(&selected->addr) + selected->size));
-    markup = stradd(markup, value);
-    markup = stradd(markup, "\n");
+}
 
-    markup = stradd(markup, _("memory: from "));
-#if 0
-    snprintf(value, 2 * VMPA_MAX_SIZE, VMPA_FMT_LONG, VMPA_CAST(selected->addr));
-    markup = stradd(markup, value);
-    markup = stradd(markup, _(" to "));
-    snprintf(value, 2 * VMPA_MAX_SIZE, VMPA_FMT_LONG, VMPA_CAST(selected->addr + selected->size));
-    markup = stradd(markup, value);
-#endif
-    markup = stradd(markup, "\n\n");
 
-    /* Droits d'accès */
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : layer   = couche rassemblant les portions d'un même niveau.  *
+*                portion = portion à inclure dans la définition courante.     *
+*                                                                             *
+*  Description : Procède à l'inclusion d'une portion dans une couche.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    markup = stradd(markup, "<b>");
-    markup = stradd(markup, _("Rights"));
-    markup = stradd(markup, "</b>\n");
+void g_portion_layer_include(GPortionLayer *layer, GBinPortion *portion)
+{
+    layer->portions = (GBinPortion **)realloc(layer->portions,
+                                              ++layer->count * sizeof(GBinPortion *));
 
-    snprintf(value, 2 * VMPA_MAX_SIZE, "%s%s%s",
-             selected->rights & PAC_READ ? "r" : "-",
-             selected->rights & PAC_WRITE ? "w" : "-",
-             selected->rights & PAC_EXEC ? "x" : "-");
+    layer->portions[layer->count - 1] = portion;
 
-    markup = stradd(markup, value);
+    g_binary_portion_set_level(portion, &layer->level);
 
-    /* Impression finale */
+    qsort(layer->portions, layer->count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);
 
-    gtk_tooltip_set_markup(tooltip, markup);
-    free(markup);
+}
 
-    return TRUE;
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : layer = couche première à parcourir intégralement.           *
+*                count = nombre de portions trouvées et renvoyées. [OUT]      *
+*                                                                             *
+*  Description : Fournit une liste triée de portions d'un binaire.            *
+*                                                                             *
+*  Retour      : Liste de définitions de zones à libérer après usage.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBinPortion **g_portion_layer_collect_all_portions(const GPortionLayer *layer, size_t *count)
+{
+    GBinPortion **result;                   /* Liste construite à renvoyer */
+
+    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          */
+
+        start = *c;
+        *c += l->count;
+
+        lst = (GBinPortion **)realloc(lst, *c * sizeof(GBinPortion *));
+
+        for (i = 0; i < l->count; i++)
+            lst[start + i] = l->portions[i];
+
+        return lst;
+
+    }
+
+    result = do_collect(layer, NULL, count);
+
+    qsort(result, *count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : portion = description de partie à consulter.                 *
-*                cr      = contexte graphique pour le dessin.                 *
-*                area    = étendue mise à disposition.                        *
+*  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]   *
 *                                                                             *
-*  Description : Représente la portion sur une bande dédiée.                  *
+*  Description : Recherche la portion présente à un point donné.              *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Portion trouvée à l'endroit indiqué.                         *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_binary_portion_draw(GBinPortion *portion, GtkStyleContext *context, cairo_t *cr, const GdkRectangle *area)
+GBinPortion *g_portion_layer_find_portion_at_pos(const GPortionLayer *layer, gint x, GdkRectangle *area)
 {
+    GBinPortion *result;                    /* Portion à retourner         */
     size_t i;                               /* Boucle de parcours          */
-    GBinPortion *sub;                       /* Portion incluse à montrer   */
+    GBinPortion *sub;                       /* Portion incluse à traiter   */
     GdkRectangle sub_area;                  /* Etendue d'une sous-portion  */
 
-    /* Dessin de la portion courante */
+    if (layer->sub_layer != NULL)
+        result = g_portion_layer_find_portion_at_pos(layer->sub_layer, x, area);
+    else
+        result = NULL;
 
-    //cairo_set_line_width(cr, 1.0);
+    for (i = 0; i < layer->count && result == NULL; i++)
+    {
+        sub = layer->portions[i];
 
-    cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+        if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area))
+            continue;
 
-    gtk_style_context_save(context);
+        if (sub_area.x <= x && x < (sub_area.x + sub_area.width))
+        {
+            result = sub;
+            *area = sub_area;
+        }
 
-    gtk_style_context_add_class(context, portion->code);
+    }
 
-    gtk_render_background(context, cr, area->x, area->y, area->width, area->height);
+    return result;
 
-    gtk_render_frame(context, cr, area->x, area->y, area->width, area->height);
+}
 
-    gtk_style_context_restore(context);
 
-    /* Dessin des portions incluses */
+/******************************************************************************
+*                                                                             *
+*  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]   *
+*                                                                             *
+*  Description : Recherche la portion présente à une adresse donnée.          *
+*                                                                             *
+*  Retour      : Portion trouvée à l'endroit indiqué.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    sub_area.y = area->y;
-    sub_area.height = area->height;
+GBinPortion *g_portion_layer_find_portion_at_addr(const GPortionLayer *layer, const vmpa2t *addr, GdkRectangle *area)
+{
+    GBinPortion *result;                    /* Portion à retourner         */
+    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;
 
-    for (i = 0; i < portion->sub_count; i++)
+    for (i = 0; i < layer->count && result == NULL; i++)
     {
-        sub = portion->sub_portions[i];
+        sub = layer->portions[i];
 
-        if (!g_binary_portion_compute_sub_area(portion, sub, area, &sub_area))
+        if (!g_portion_layer_contains_addr(sub, addr))
+            continue;
+
+        if (!g_binary_portion_compute_sub_area(sub, layer->length, area, &sub_area))
+            continue;
+
+        result = sub;
+        *area = sub_area;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]                        *
+*                                                                             *
+*  Description : Fournit la position correspondant à une adresse donnée.      *
+*                                                                             *
+*  Retour      : Succès de la traduction.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_portion_layer_get_addr_from_pos(GPortionLayer *layer, 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);
+    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);
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]                       *
+*                                                                             *
+*  Description : Fournit l'adresse correspondant à une position donnée.       *
+*                                                                             *
+*  Retour      : Succès de la traduction.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_portion_layer_get_pos_from_addr(GPortionLayer *layer, const vmpa2t *addr, const GdkRectangle *area, gint *x)
+{
+    GdkRectangle owner_area;                /* Aire de contenance          */
+    GBinPortion *owner;                     /* Conteneur propriétaire      */
+    phys_t diff;                            /* Décallage à appliquer       */
+
+    owner_area = *area;
+
+    owner = g_portion_layer_find_portion_at_addr(layer, 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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : layer   = couche de portions à consulter.                    *
+*                x       = abscisse du point de recherche.                    *
+*                y       = ordonnée du point de recherche.                    *
+*                area    = étendue de représentation de la portion mère.      *
+*                tooltip = astuce à compléter. [OUT]                          *
+*                                                                             *
+*  Description : Prépare une astuce concernant une portion pour son affichage.*
+*                                                                             *
+*  Retour      : TRUE pour valider l'affichage.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gboolean g_portion_layer_query_tooltip(const GPortionLayer *layer, 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 });
+    if (selected == NULL) return FALSE;
+
+    g_binary_portion_query_tooltip(selected, tooltip);
+
+    return TRUE;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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);
+
 }
diff --git a/src/glibext/gbinportion.h b/src/glibext/gbinportion.h
index f92b87e..e5c7830 100644
--- a/src/glibext/gbinportion.h
+++ b/src/glibext/gbinportion.h
@@ -36,6 +36,9 @@
 
 
 
+/* ------------------------------- PORTION DE BINAIRE ------------------------------- */
+
+
 /**
  * Couleurs de représentation.
  */
@@ -73,11 +76,7 @@ typedef enum _PortionAccessRights
 } PortionAccessRights;
 
 
-/* Fonction appelée à chaque visite de portion.*/
-typedef bool (* visit_portion_fc) (GBinPortion *, void *);
-
-
-/* Indique le type défini par la GLib pour les blocs de données. */
+/* Indique le type défini par la GLib pour les portions de données binaires. */
 GType g_binary_portion_get_type(void);
 
 /* Crée une description de partie de code vierge. */
@@ -104,35 +103,77 @@ void g_binary_portion_set_rights(GBinPortion *, PortionAccessRights);
 /* Fournit les droits associés à une partie de code. */
 PortionAccessRights g_binary_portion_get_rights(const GBinPortion *);
 
-/* Procède à l'inclusion d'une portion dans une autre. */
-void g_binary_portion_include(GBinPortion *, GBinPortion *);
+/* Insère dans un tampon une description de portion. */
+void g_binary_portion_print(const GBinPortion *, GCodeBuffer *, MemoryDataSize);
 
-/* Indique le niveau de profondeur d'une portion donnée. */
-unsigned int g_binary_portion_get_level(GBinPortion *);
+/* Prépare une astuce concernant une portion pour son affichage. */
+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 *);
+
+
+
+/* -------------------------- 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))
 
-/* Parcours un ensemble de portions binaires. */
-bool g_binary_portion_visit(GBinPortion *, visit_portion_fc, void *);
+
+/* Couche de portions binaires quelconques (instance) */
+typedef struct _GPortionLayer GPortionLayer;
+
+/* Couche de portions binaires quelconques (classe) */
+typedef struct _GPortionLayerClass GPortionLayerClass;
+
+
+/* Taille à définir lors d'un rattachement */
+#define NO_LENGTH_YET VMPA_NO_PHYSICAL
+
+
+/* Indique le type défini par la GLib pour les couches de portions binaires. */
+GType g_portion_layer_get_type(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 *);
+
+/* 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_binary_portion_find_at_pos(GBinPortion *, gint, GdkRectangle *);
+GBinPortion *g_portion_layer_find_portion_at_pos(const GPortionLayer *, gint, GdkRectangle *);
 
 /* Recherche la portion présente à une adresse donnée. */
-GBinPortion *g_binary_portion_find_at_addr(GBinPortion *, const vmpa2t *, GdkRectangle *);
+GBinPortion *g_portion_layer_find_portion_at_addr(const GPortionLayer *, const vmpa2t *, GdkRectangle *);
 
 /* Fournit la position correspondant à une adresse donnée. */
-bool g_binary_portion_get_addr_from_pos(GBinPortion *, gint, const GdkRectangle *, vmpa2t *);
+bool g_portion_layer_get_addr_from_pos(GPortionLayer *, gint, const GdkRectangle *, vmpa2t *);
 
 /* Fournit l'adresse correspondant à une position donnée. */
-bool g_binary_portion_get_pos_from_addr(GBinPortion *, const vmpa2t *, const GdkRectangle *, gint *);
+bool g_portion_layer_get_pos_from_addr(GPortionLayer *, const vmpa2t *, const GdkRectangle *, gint *);
 
-/* Insère dans un tampon une description de portion. */
-void g_binary_portion_print(const GBinPortion *, GCodeBuffer *, MemoryDataSize);
+/* 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 *);
 
 /* Prépare une astuce concernant une portion pour son affichage. */
-gboolean g_binary_portion_query_tooltip(GBinPortion *, gint, gint, const GdkRectangle *, GtkTooltip *);
+gboolean g_portion_layer_query_tooltip(const GPortionLayer *, gint, gint, const GdkRectangle *, GtkTooltip *);
 
-/* Représente la portion sur une bande dédiée. */
-void g_binary_portion_draw(GBinPortion *, GtkStyleContext *, cairo_t *, const GdkRectangle *);
+/* Représente une couche de portions sur une bande dédiée. */
+void g_portion_layer_draw(const GPortionLayer *, GtkStyleContext *, cairo_t *, const GdkRectangle *);
 
 
 
diff --git a/src/gtkext/gtkbinarystrip.c b/src/gtkext/gtkbinarystrip.c
index e0016d2..0ad0763 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           */
-    GBinPortion *portions;                  /* Portions binaires à dessiner*/
+    GPortionLayer *layer;                   /* Couche première de portions */
     GdkRectangle area;                      /* Surface du composant        */
 
     GTK_WIDGET_CLASS(gtk_binary_strip_parent_class)->size_allocate(widget, allocation);
@@ -222,16 +222,18 @@ static void gtk_binary_strip_size_allocate(GtkWidget *widget, GtkAllocation *all
         return;
 
     format = g_loaded_binary_get_format(strip->binary);
-    portions = g_exe_format_get_portions(format);
+    layer = g_exe_format_get_main_layer(format);
 
     area.x = 0;
     area.y = 0;
     area.width = allocation->width;
     area.height = allocation->height;
 
-    if (!g_binary_portion_get_pos_from_addr(portions, &strip->cursor_addr, &area, &strip->cursor_pos))
+    if (!g_portion_layer_get_pos_from_addr(layer, &strip->cursor_addr, &area, &strip->cursor_pos))
         strip->cursor_pos = 0;
 
+    g_object_unref(G_OBJECT(layer));
+
 }
 
 
@@ -254,7 +256,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           */
-    GBinPortion *portions;                  /* Portions binaires à dessiner*/
+    GPortionLayer *layer;                   /* Couche première de portions */
     GdkRectangle area;                      /* Surface du composant        */
     vmpa2t addr;                            /* Adresse à sélectionner      */
 
@@ -269,27 +271,26 @@ static gboolean gtk_binary_strip_button_release(GtkWidget *widget, GdkEventButto
 
     strip = GTK_BINARY_STRIP(widget);
     format = g_loaded_binary_get_format(strip->binary);
-    portions = g_exe_format_get_portions(format);
+    layer = g_exe_format_get_main_layer(format);
 
     area.x = 0;
     area.y = 0;
     area.width = width;
     area.height = height;
 
-    if (g_binary_portion_get_addr_from_pos(portions, event->x, &area, &addr))
+    if (g_portion_layer_get_addr_from_pos(layer, event->x, &area, &addr))
     {
         copy_vmpa(&strip->cursor_addr, &addr);
         strip->cursor_pos = event->x;
 
         gtk_widget_queue_draw(GTK_WIDGET(strip));
 
-        printf("got :: %p\n", &addr);
-        printf("  -> 0x%x 0x%x\n", (unsigned int)get_phy_addr(&addr), (unsigned int)get_virt_addr(&addr));
-
         g_signal_emit_by_name(strip, "select-address");
 
     }
 
+    g_object_unref(G_OBJECT(layer));
+
     return FALSE;
 
 }
@@ -312,7 +313,7 @@ static gboolean gtk_binary_strip_draw(GtkWidget *widget, cairo_t *cr)
 {
     GtkBinaryStrip *strip;                  /* Autre vision du composant   */
     GExeFormat *format;                     /* Format du binaire           */
-    GBinPortion *portions;                  /* Portions binaires à dessiner*/
+    GPortionLayer *layer;                   /* Couche première de portions */
     GdkRectangle full;                      /* Taille totale de la surface */
     GtkStyleContext *context;               /* Contexte du thème actuel    */
     GdkRGBA *color;                         /* Couleur du curseur          */
@@ -322,11 +323,11 @@ static gboolean gtk_binary_strip_draw(GtkWidget *widget, cairo_t *cr)
     if (strip->binary == NULL)
         return FALSE;
 
-    format = g_loaded_binary_get_format(strip->binary);
-    portions = g_exe_format_get_portions(format);
-
     /* Dessin des portions de binaire */
 
+    format = g_loaded_binary_get_format(strip->binary);
+    layer = g_exe_format_get_main_layer(format);
+
     full.x = 0;
     full.y = 1;
     full.width = gtk_widget_get_allocated_width(widget);
@@ -334,7 +335,9 @@ static gboolean gtk_binary_strip_draw(GtkWidget *widget, cairo_t *cr)
 
     context = gtk_widget_get_style_context(widget);
 
-    g_binary_portion_draw(portions, context, cr, &full);
+    g_portion_layer_draw(layer, context, cr, &full);
+
+    g_object_unref(G_OBJECT(layer));
 
     /* Dessin de la position */
 
@@ -389,7 +392,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           */
-    GBinPortion *portions;                  /* Portions binaires à dessiner*/
+    GPortionLayer *layer;                   /* Couches binaires à consulter*/
     GdkRectangle area;                      /* Surface du composant        */
 
     if (keyboard) return FALSE;
@@ -399,14 +402,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);
-        portions = g_exe_format_get_portions(format);
+        layer = g_exe_format_get_main_layer(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_binary_portion_query_tooltip(portions, x, y, &area, tooltip);
+        result = g_portion_layer_query_tooltip(layer, x, y, &area, tooltip);
+
+        g_object_unref(G_OBJECT(layer));
 
     }
     else result = FALSE;
diff --git a/src/gtkext/gtkstatusstack.c b/src/gtkext/gtkstatusstack.c
index e9a61d8..148dd03 100644
--- a/src/gtkext/gtkstatusstack.c
+++ b/src/gtkext/gtkstatusstack.c
@@ -462,7 +462,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      */
-    GBinPortion *portions;                  /* Portions binaires existantes*/
+    GPortionLayer *layer;                   /* 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 */
@@ -491,9 +491,9 @@ void gtk_status_stack_update_current_instruction(GtkStatusStack *stack, const GL
 
     /* Zone d'appartenance */
 
-    portions = g_exe_format_get_portions(format);
+    layer = g_exe_format_get_main_layer(format);
 
-    portion = g_binary_portion_find_at_addr(portions, addr, (GdkRectangle []) { });
+    portion = g_portion_layer_find_portion_at_addr(layer, addr, (GdkRectangle []) { });
 
     text = g_binary_portion_get_desc(portion);
 
@@ -502,6 +502,8 @@ void gtk_status_stack_update_current_instruction(GtkStatusStack *stack, const GL
     else
         info->segment = strdup(_("Binary"));
 
+    g_object_unref(G_OBJECT(layer));
+
     /* Adresses de base */
 
     vmpa2_phys_to_string(addr, MDS_UNDEFINED, info->phys, NULL);
-- 
cgit v0.11.2-87-g4458