From f828d126a74facac145531822c6ea9c8259b50e0 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 19 May 2016 23:21:30 +0200
Subject: Loaded the ELF internal symbols using all the available CPUs.

---
 ChangeLog                          |  66 ++++++++
 plugins/mobicore/mclf.c            |   3 +-
 plugins/mobicore/mclf.h            |   2 +-
 plugins/pychrysa/format/elf/elf.c  |   2 +-
 src/analysis/disass/instructions.c |  14 +-
 src/analysis/disass/routines.c     |  14 +-
 src/core/formats.c                 |   8 +-
 src/core/formats.h                 |   3 +-
 src/format/dex/dex.c               |   3 +-
 src/format/dex/dex.h               |   2 +-
 src/format/dwarf/v2/dwarf.c        |   3 +-
 src/format/dwarf/v2/dwarf.h        |   2 +-
 src/format/dwarf/v3/dwarf.c        |   3 +-
 src/format/dwarf/v3/dwarf.h        |   2 +-
 src/format/dwarf/v4/dwarf.c        |   3 +-
 src/format/dwarf/v4/dwarf.h        |   2 +-
 src/format/elf/Makefile.am         |   1 +
 src/format/elf/elf.c               |   5 +-
 src/format/elf/elf.h               |   2 +-
 src/format/elf/loading.c           | 291 ++++++++++++++++++++++++++++++++
 src/format/elf/loading.h           |  71 ++++++++
 src/format/elf/symbols.c           | 328 +++++++++++++++++++++++--------------
 src/format/elf/symbols.h           |   6 +-
 src/format/format-int.h            |   2 +
 src/format/format.c                |  12 +-
 src/format/format.h                |   2 +-
 src/glibext/delayed.c              |  13 +-
 src/glibext/delayed.h              |   7 +-
 src/gtkext/gtkstatusstack.c        | 160 ++++++++++--------
 src/gtkext/gtkstatusstack.h        |   3 +
 src/gui/core/Makefile.am           |   1 +
 src/gui/core/global.c              |  68 ++++++++
 src/gui/core/global.h              |  40 +++++
 src/gui/status.c                   |   3 +-
 src/main.c                         |   3 +-
 35 files changed, 919 insertions(+), 231 deletions(-)
 create mode 100644 src/format/elf/loading.c
 create mode 100644 src/format/elf/loading.h
 create mode 100644 src/gui/core/global.c
 create mode 100644 src/gui/core/global.h

diff --git a/ChangeLog b/ChangeLog
index 3b5eb64..95bc008 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,69 @@
+16-05-19  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/mobicore/mclf.c:
+	* plugins/mobicore/mclf.h:
+	* plugins/pychrysa/format/elf/elf.c:
+	Update code.
+
+	* src/analysis/disass/instructions.c:
+	* src/analysis/disass/routines.c:
+	Typo.
+
+	* src/core/formats.c:
+	* src/core/formats.h:
+	Use the global status bar to load binary formats.
+
+	* src/format/dex/dex.c:
+	* src/format/dex/dex.h:
+	* src/format/dwarf/v2/dwarf.c:
+	* src/format/dwarf/v2/dwarf.h:
+	* src/format/dwarf/v3/dwarf.c:
+	* src/format/dwarf/v3/dwarf.h:
+	* src/format/dwarf/v4/dwarf.c:
+	* src/format/dwarf/v4/dwarf.h:
+	Update code.
+
+	* src/format/elf/Makefile.am:
+	Add the 'loading.[ch]' files to libformatelf_la_SOURCES.
+
+	* src/format/elf/elf.c:
+	* src/format/elf/elf.h:
+	Update code.
+
+	* src/format/elf/loading.c:
+	* src/format/elf/loading.h:
+	New entries: display some progress information while loading ELF symbols.
+
+	* src/format/elf/symbols.c:
+	* src/format/elf/symbols.h:
+	Load the ELF internal symbols using all the available CPUs.
+
+	* src/format/format-int.h:
+	* src/format/format.c:
+	* src/format/format.h:
+	Avoid memory corruptions using locks.
+
+	* src/glibext/delayed.c:
+	* src/glibext/delayed.h:
+	Update code.
+
+	* src/gtkext/gtkstatusstack.c:
+	* src/gtkext/gtkstatusstack.h:
+	Define extendable activities. Update code.
+
+	* src/gui/core/Makefile.am:
+	Add the 'global.[ch]' files to libguicore_la_SOURCES.
+
+	* src/gui/core/global.c:
+	* src/gui/core/global.h:
+	New entries: define and provide global GUI references.
+
+	* src/gui/status.c:
+	Register the global status bar.
+
+	* src/main.c:
+	Update code.
+
 16-05-13  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/glibext/gbufferview.c:
diff --git a/plugins/mobicore/mclf.c b/plugins/mobicore/mclf.c
index 8e99fc7..6ff967b 100644
--- a/plugins/mobicore/mclf.c
+++ b/plugins/mobicore/mclf.c
@@ -193,6 +193,7 @@ static void g_mclf_format_finalize(GMCLFFormat *format)
 *                                                                             *
 *  Paramètres  : content = contenu binaire à parcourir.                       *
 *                parent  = éventuel format exécutable déjà chargé.            *
+                 status  = barre de statut à tenir informée.                  *
 *                                                                             *
 *  Description : Prend en charge un nouveau format MCLF.                      *
 *                                                                             *
@@ -202,7 +203,7 @@ static void g_mclf_format_finalize(GMCLFFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-GBinFormat *g_mclf_format_new(GBinContent *content, GExeFormat *parent)
+GBinFormat *g_mclf_format_new(GBinContent *content, GExeFormat *parent, GtkStatusStack *status)
 {
     GMCLFFormat *result;                    /* Structure à retourner       */
 
diff --git a/plugins/mobicore/mclf.h b/plugins/mobicore/mclf.h
index 78ed57b..a8fe6ea 100644
--- a/plugins/mobicore/mclf.h
+++ b/plugins/mobicore/mclf.h
@@ -58,7 +58,7 @@ FormatMatchStatus mclf_is_matching(GBinContent *, GExeFormat *, void *, char **)
 GType g_mclf_format_get_type(void);
 
 /* Prend en charge un nouveau format MCLF. */
-GBinFormat *g_mclf_format_new(GBinContent *, GExeFormat *);
+GBinFormat *g_mclf_format_new(GBinContent *, GExeFormat *, GtkStatusStack *);
 
 
 
diff --git a/plugins/pychrysa/format/elf/elf.c b/plugins/pychrysa/format/elf/elf.c
index 72a9647..2787702 100644
--- a/plugins/pychrysa/format/elf/elf.c
+++ b/plugins/pychrysa/format/elf/elf.c
@@ -77,7 +77,7 @@ static PyObject *py_elf_format_new(PyTypeObject *type, PyObject *args, PyObject
     }
 
     content = G_BIN_CONTENT(pygobject_get(content_obj));
-    format = g_elf_format_new(content, NULL);
+    format = g_elf_format_new(content, NULL, NULL/*FIXME*/);
 
     result = pygobject_new(G_OBJECT(format));
 
diff --git a/src/analysis/disass/instructions.c b/src/analysis/disass/instructions.c
index 7e76a5d..b88d69f 100644
--- a/src/analysis/disass/instructions.c
+++ b/src/analysis/disass/instructions.c
@@ -112,7 +112,7 @@ static void g_instructions_study_class_init(GInstructionsStudyClass *klass)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : computing = instance à initialiser.                          *
+*  Paramètres  : study = instance à initialiser.                              *
 *                                                                             *
 *  Description : Initialise une tâche d'étude d'instructions.                 *
 *                                                                             *
@@ -130,7 +130,7 @@ static void g_instructions_study_init(GInstructionsStudy *study)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
+*  Paramètres  : study = instance d'objet GLib à traiter.                     *
 *                                                                             *
 *  Description : Supprime toutes les références externes.                     *
 *                                                                             *
@@ -140,16 +140,16 @@ static void g_instructions_study_init(GInstructionsStudy *study)
 *                                                                             *
 ******************************************************************************/
 
-static void g_instructions_study_dispose(GInstructionsStudy *computing)
+static void g_instructions_study_dispose(GInstructionsStudy *study)
 {
-    G_OBJECT_CLASS(g_instructions_study_parent_class)->dispose(G_OBJECT(computing));
+    G_OBJECT_CLASS(g_instructions_study_parent_class)->dispose(G_OBJECT(study));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
+*  Paramètres  : study = instance d'objet GLib à traiter.                     *
 *                                                                             *
 *  Description : Procède à la libération totale de la mémoire.                *
 *                                                                             *
@@ -159,9 +159,9 @@ static void g_instructions_study_dispose(GInstructionsStudy *computing)
 *                                                                             *
 ******************************************************************************/
 
-static void g_instructions_study_finalize(GInstructionsStudy *computing)
+static void g_instructions_study_finalize(GInstructionsStudy *study)
 {
-    G_OBJECT_CLASS(g_instructions_study_parent_class)->finalize(G_OBJECT(computing));
+    G_OBJECT_CLASS(g_instructions_study_parent_class)->finalize(G_OBJECT(study));
 
 }
 
diff --git a/src/analysis/disass/routines.c b/src/analysis/disass/routines.c
index 94afbe4..de515d0 100644
--- a/src/analysis/disass/routines.c
+++ b/src/analysis/disass/routines.c
@@ -117,7 +117,7 @@ static void g_routines_study_class_init(GRoutinesStudyClass *klass)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : computing = instance à initialiser.                          *
+*  Paramètres  : study = instance à initialiser.                              *
 *                                                                             *
 *  Description : Initialise une tâche d'étude de routines.                    *
 *                                                                             *
@@ -135,7 +135,7 @@ static void g_routines_study_init(GRoutinesStudy *study)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
+*  Paramètres  : study = instance d'objet GLib à traiter.                     *
 *                                                                             *
 *  Description : Supprime toutes les références externes.                     *
 *                                                                             *
@@ -145,16 +145,16 @@ static void g_routines_study_init(GRoutinesStudy *study)
 *                                                                             *
 ******************************************************************************/
 
-static void g_routines_study_dispose(GRoutinesStudy *computing)
+static void g_routines_study_dispose(GRoutinesStudy *study)
 {
-    G_OBJECT_CLASS(g_routines_study_parent_class)->dispose(G_OBJECT(computing));
+    G_OBJECT_CLASS(g_routines_study_parent_class)->dispose(G_OBJECT(study));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : computing = instance d'objet GLib à traiter.                 *
+*  Paramètres  : study = instance d'objet GLib à traiter.                     *
 *                                                                             *
 *  Description : Procède à la libération totale de la mémoire.                *
 *                                                                             *
@@ -164,9 +164,9 @@ static void g_routines_study_dispose(GRoutinesStudy *computing)
 *                                                                             *
 ******************************************************************************/
 
-static void g_routines_study_finalize(GRoutinesStudy *computing)
+static void g_routines_study_finalize(GRoutinesStudy *study)
 {
-    G_OBJECT_CLASS(g_routines_study_parent_class)->finalize(G_OBJECT(computing));
+    G_OBJECT_CLASS(g_routines_study_parent_class)->finalize(G_OBJECT(study));
 
 }
 
diff --git a/src/core/formats.c b/src/core/formats.c
index 5543331..c6b664c 100644
--- a/src/core/formats.c
+++ b/src/core/formats.c
@@ -368,6 +368,7 @@ FormatMatchStatus find_matching_format(GBinContent *content, GExeFormat *parent,
 *                                                                             *
 *  Paramètres  : key     = nom technique du processeur recherché.             *
 *                content = contenu binaire pré-chargé à traiter.              *
+*                parent  = contenu binaire principal éventuel déjà chargé.    *
 *                                                                             *
 *  Description : Charge le format binaire correspondant à un type.            *
 *                                                                             *
@@ -389,7 +390,12 @@ GBinFormat *load_new_named_format(const char *key, GBinContent *content, GExeFor
     if (def == NULL)
         result = NULL;
     else
-        result = def->func(content, parent);
+    {
+        extern GtkStatusStack *get_global_status(void);
+
+        result = def->func(content, parent, get_global_status());
+
+    }
 
     g_rw_lock_reader_unlock(&_formats_lock);
 
diff --git a/src/core/formats.h b/src/core/formats.h
index 76b57d0..e3dc871 100644
--- a/src/core/formats.h
+++ b/src/core/formats.h
@@ -31,6 +31,7 @@
 
 #include "../format/format.h"
 #include "../format/executable.h"
+#include "../gtkext/gtkstatusstack.h"
 
 
 
@@ -50,7 +51,7 @@ typedef enum _FormatMatchStatus
 typedef FormatMatchStatus (* format_match_fc) (GBinContent *, GExeFormat *, void *, char **);
 
 /* Méthode de chargement d'un format */
-typedef GBinFormat * (* format_load_fc) (GBinContent *, GExeFormat *);
+typedef GBinFormat * (* format_load_fc) (GBinContent *, GExeFormat *, GtkStatusStack *);
 
 
 /* Enregistre un détection de format(s) binaire(s). */
diff --git a/src/format/dex/dex.c b/src/format/dex/dex.c
index 2897ee3..3388861 100755
--- a/src/format/dex/dex.c
+++ b/src/format/dex/dex.c
@@ -233,6 +233,7 @@ static void g_dex_format_finalize(GDexFormat *format)
 *                                                                             *
 *  Paramètres  : content = contenu binaire à parcourir.                       *
 *                parent  = éventuel format exécutable déjà chargé.            *
+                 status  = barre de statut à tenir informée.                  *
 *                                                                             *
 *  Description : Prend en charge un nouveau format Dex.                       *
 *                                                                             *
@@ -242,7 +243,7 @@ static void g_dex_format_finalize(GDexFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-GBinFormat *g_dex_format_new(GBinContent *content, GExeFormat *parent)
+GBinFormat *g_dex_format_new(GBinContent *content, GExeFormat *parent, GtkStatusStack *status)
 {
     GDexFormat *result;                     /* Structure à retourner       */
     GBinFormat *base;                       /* Version basique du format   */
diff --git a/src/format/dex/dex.h b/src/format/dex/dex.h
index 28d2a49..0283a0c 100755
--- a/src/format/dex/dex.h
+++ b/src/format/dex/dex.h
@@ -56,7 +56,7 @@ FormatMatchStatus dex_is_matching(GBinContent *, GExeFormat *, void *, char **);
 GType g_dex_format_get_type(void);
 
 /* Prend en charge un nouveau format DEX. */
-GBinFormat *g_dex_format_new(GBinContent *, GExeFormat *);
+GBinFormat *g_dex_format_new(GBinContent *, GExeFormat *, GtkStatusStack *);
 
 /* Présente l'en-tête DEX du format chargé. */
 const dex_header *g_dex_format_get_header(const GDexFormat *);
diff --git a/src/format/dwarf/v2/dwarf.c b/src/format/dwarf/v2/dwarf.c
index ccef01f..5e417c3 100644
--- a/src/format/dwarf/v2/dwarf.c
+++ b/src/format/dwarf/v2/dwarf.c
@@ -153,6 +153,7 @@ static void g_dwarfv2_format_finalize(GDwarfV2Format *format)
 *                                                                             *
 *  Paramètres  : content = contenu binaire à parcourir.                       *
 *                parent  = éventuel format exécutable déjà chargé.            *
+                 status  = barre de statut à tenir informée.                  *
 *                                                                             *
 *  Description : Prend en charge un nouveau format DWARF (v2).                *
 *                                                                             *
@@ -162,7 +163,7 @@ static void g_dwarfv2_format_finalize(GDwarfV2Format *format)
 *                                                                             *
 ******************************************************************************/
 
-GBinFormat *g_dwarfv2_format_new(GBinContent *content, GExeFormat *parent)
+GBinFormat *g_dwarfv2_format_new(GBinContent *content, GExeFormat *parent, GtkStatusStack *status)
 {
     GDwarfV2Format *result;                 /* Structure à retourner       */
 
diff --git a/src/format/dwarf/v2/dwarf.h b/src/format/dwarf/v2/dwarf.h
index 360a2e6..732007b 100644
--- a/src/format/dwarf/v2/dwarf.h
+++ b/src/format/dwarf/v2/dwarf.h
@@ -52,7 +52,7 @@ typedef struct _GDwarfV2FormatClass GDwarfV2FormatClass;
 GType g_dwarfv2_format_get_type(void);
 
 /* Prend en charge un nouveau format DWARF (v2). */
-GBinFormat *g_dwarfv2_format_new(GBinContent *, GExeFormat *);
+GBinFormat *g_dwarfv2_format_new(GBinContent *, GExeFormat *, GtkStatusStack *);
 
 
 
diff --git a/src/format/dwarf/v3/dwarf.c b/src/format/dwarf/v3/dwarf.c
index d6198f7..0fcd38f 100644
--- a/src/format/dwarf/v3/dwarf.c
+++ b/src/format/dwarf/v3/dwarf.c
@@ -145,6 +145,7 @@ static void g_dwarfv3_format_finalize(GDwarfV3Format *format)
 *                                                                             *
 *  Paramètres  : content = contenu binaire à parcourir.                       *
 *                parent  = éventuel format exécutable déjà chargé.            *
+                 status  = barre de statut à tenir informée.                  *
 *                                                                             *
 *  Description : Prend en charge un nouveau format DWARF (v3).                *
 *                                                                             *
@@ -154,7 +155,7 @@ static void g_dwarfv3_format_finalize(GDwarfV3Format *format)
 *                                                                             *
 ******************************************************************************/
 
-GBinFormat *g_dwarfv3_format_new(GBinContent *content, GExeFormat *parent)
+GBinFormat *g_dwarfv3_format_new(GBinContent *content, GExeFormat *parent, GtkStatusStack *status)
 {
     GDwarfV3Format *result;                 /* Structure à retourner       */
 
diff --git a/src/format/dwarf/v3/dwarf.h b/src/format/dwarf/v3/dwarf.h
index 2aaf891..e316a52 100644
--- a/src/format/dwarf/v3/dwarf.h
+++ b/src/format/dwarf/v3/dwarf.h
@@ -52,7 +52,7 @@ typedef struct _GDwarfV3FormatClass GDwarfV3FormatClass;
 GType g_dwarfv3_format_get_type(void);
 
 /* Prend en charge un nouveau format DWARF (v3). */
-GBinFormat *g_dwarfv3_format_new(GBinContent *, GExeFormat *);
+GBinFormat *g_dwarfv3_format_new(GBinContent *, GExeFormat *, GtkStatusStack *);
 
 
 
diff --git a/src/format/dwarf/v4/dwarf.c b/src/format/dwarf/v4/dwarf.c
index 52345e8..995d4f7 100644
--- a/src/format/dwarf/v4/dwarf.c
+++ b/src/format/dwarf/v4/dwarf.c
@@ -153,6 +153,7 @@ static void g_dwarfv4_format_finalize(GDwarfV4Format *format)
 *                                                                             *
 *  Paramètres  : content = contenu binaire à parcourir.                       *
 *                parent  = éventuel format exécutable déjà chargé.            *
+                 status  = barre de statut à tenir informée.                  *
 *                                                                             *
 *  Description : Prend en charge un nouveau format DWARF (v4).                *
 *                                                                             *
@@ -162,7 +163,7 @@ static void g_dwarfv4_format_finalize(GDwarfV4Format *format)
 *                                                                             *
 ******************************************************************************/
 
-GBinFormat *g_dwarfv4_format_new(GBinContent *content, GExeFormat *parent)
+GBinFormat *g_dwarfv4_format_new(GBinContent *content, GExeFormat *parent, GtkStatusStack *status)
 {
     GDwarfV4Format *result;                 /* Structure à retourner       */
 
diff --git a/src/format/dwarf/v4/dwarf.h b/src/format/dwarf/v4/dwarf.h
index af3c2c4..d0f5b7a 100644
--- a/src/format/dwarf/v4/dwarf.h
+++ b/src/format/dwarf/v4/dwarf.h
@@ -52,7 +52,7 @@ typedef struct _GDwarfV4FormatClass GDwarfV4FormatClass;
 GType g_dwarfv4_format_get_type(void);
 
 /* Prend en charge un nouveau format DWARF (v4). */
-GBinFormat *g_dwarfv4_format_new(GBinContent *, GExeFormat *);
+GBinFormat *g_dwarfv4_format_new(GBinContent *, GExeFormat *, GtkStatusStack *);
 
 
 
diff --git a/src/format/elf/Makefile.am b/src/format/elf/Makefile.am
index 4317e1d..78dabcd 100644
--- a/src/format/elf/Makefile.am
+++ b/src/format/elf/Makefile.am
@@ -8,6 +8,7 @@ libformatelf_la_SOURCES =				\
 	dynamic.h dynamic.c					\
 	helper_arm.h helper_arm.c			\
 	helper_x86.h helper_x86.c			\
+	loading.h loading.c					\
 	program.h program.c					\
 	section.h section.c					\
 	strings.h strings.c					\
diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c
index 0c7760c..d09b845 100644
--- a/src/format/elf/elf.c
+++ b/src/format/elf/elf.c
@@ -230,6 +230,7 @@ static void g_elf_format_finalize(GElfFormat *format)
 *                                                                             *
 *  Paramètres  : content = contenu binaire à parcourir.                       *
 *                parent  = éventuel format exécutable déjà chargé.            *
+                 status  = barre de statut à tenir informée.                  *
 *                                                                             *
 *  Description : Prend en charge un nouveau format ELF.                       *
 *                                                                             *
@@ -239,7 +240,7 @@ static void g_elf_format_finalize(GElfFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-GBinFormat *g_elf_format_new(GBinContent *content, GExeFormat *parent)
+GBinFormat *g_elf_format_new(GBinContent *content, GExeFormat *parent, GtkStatusStack *status)
 {
     GElfFormat *result;                     /* Structure à retourner       */
 
@@ -287,7 +288,7 @@ GBinFormat *g_elf_format_new(GBinContent *content, GExeFormat *parent)
 
 
 
-    if (!load_elf_symbols(result))
+    if (!load_elf_symbols(result, status))
     {
         /* TODO */
         return NULL;
diff --git a/src/format/elf/elf.h b/src/format/elf/elf.h
index d6f631e..3343927 100644
--- a/src/format/elf/elf.h
+++ b/src/format/elf/elf.h
@@ -56,7 +56,7 @@ FormatMatchStatus elf_is_matching(GBinContent *, GExeFormat *, void *, char **);
 GType g_elf_format_get_type(void);
 
 /* Prend en charge un nouveau format ELF. */
-GBinFormat *g_elf_format_new(GBinContent *, GExeFormat *);
+GBinFormat *g_elf_format_new(GBinContent *, GExeFormat *, GtkStatusStack *);
 
 /* Présente l'en-tête ELF du format chargé. */
 const elf_header *g_elf_format_get_header(const GElfFormat *);
diff --git a/src/format/elf/loading.c b/src/format/elf/loading.c
new file mode 100644
index 0000000..b833720
--- /dev/null
+++ b/src/format/elf/loading.c
@@ -0,0 +1,291 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * loading.c - chargements parallèles des symboles de format ELF
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "loading.h"
+
+
+#include <i18n.h>
+
+
+#include "elf-int.h"
+#include "section.h"
+#include "../../glibext/delayed-int.h"
+#include "../../gui/panels/log.h"
+
+
+
+/* Fraction de routines à limiter (instance) */
+struct _GElfLoading
+{
+    GDelayedWork parent;                    /* A laisser en premier        */
+
+    GElfFormat *format;                     /* Format à faire évoluer      */
+
+    union
+    {
+        struct
+        {
+            const elf_shdr *section;        /* Section à éplucher          */
+            bool use_virt;                  /* Représentatio par défaut    */
+
+            elf_shdr strtab;                /* Section .strtab trouvée     */
+            bool has_strtab;                /* Présence de cette section   */
+
+        };
+
+    };
+
+    elf_loading_cb callback;                /* Routine de traitement finale*/
+    phys_t first;                           /* Position du premier élément */
+    phys_t begin;                           /* Point de départ du parcours */
+    phys_t end;                             /* Point d'arrivée exclu       */
+
+    activity_id_t id;                       /* Identifiant pour messages   */
+
+};
+
+/* Fraction de routines à limiter (classe) */
+struct _GElfLoadingClass
+{
+    GDelayedWorkClass parent;               /* A laisser en premier        */
+
+};
+
+
+/* Initialise la classe des tâches des chargements pour ELF. */
+static void g_elf_loading_class_init(GElfLoadingClass *);
+
+/* Initialise une tâche de chargements pour ELF. */
+static void g_elf_loading_init(GElfLoading *);
+
+/* Supprime toutes les références externes. */
+static void g_elf_loading_dispose(GElfLoading *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_elf_loading_finalize(GElfLoading *);
+
+/* Assure le chargement pour un format ELF en différé. */
+static void g_elf_loading_process(GElfLoading *, GtkStatusStack *);
+
+
+
+/* Indique le type défini pour les tâches de chargements pour format ELF. */
+G_DEFINE_TYPE(GElfLoading, g_elf_loading, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des tâches des chargements pour ELF.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_elf_loading_class_init(GElfLoadingClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GDelayedWorkClass *work;                /* Version en classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_elf_loading_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_elf_loading_finalize;
+
+    work = G_DELAYED_WORK_CLASS(klass);
+
+    work->run = (run_task_fc)g_elf_loading_process;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : loading = instance à initialiser.                            *
+*                                                                             *
+*  Description : Initialise une tâche de chargements pour ELF.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_elf_loading_init(GElfLoading *loading)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : loading = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_elf_loading_dispose(GElfLoading *loading)
+{
+    G_OBJECT_CLASS(g_elf_loading_parent_class)->dispose(G_OBJECT(loading));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : loading = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_elf_loading_finalize(GElfLoading *loading)
+{
+    G_OBJECT_CLASS(g_elf_loading_parent_class)->finalize(G_OBJECT(loading));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = = ensemble d'instructions désassemblées.            *
+*                section  = prototypes existants à insérer.                   *
+*                use_virt = quantité de ces prototypes.                       *
+*                first    = position du premier élément.                      *
+*                begin    = point de départ du parcours de liste.             *
+*                end      = point d'arrivée exclu du parcours.                *
+*                id       = identifiant du message affiché à l'utilisateur.   *
+*                callback = routine de traitements particuliers.              *
+*                                                                             *
+*  Description : Crée une tâche de chargement pour ELF différée.              *
+*                                                                             *
+*  Retour      : Tâche créée.                                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GElfLoading *g_elf_loading_new(GElfFormat *format, const elf_shdr *section, bool use_virt, phys_t first, phys_t begin, phys_t end, activity_id_t id, elf_loading_cb callback)
+{
+    GElfLoading *result;                    /* Tâche à retourner           */
+
+    result = g_object_new(G_TYPE_ELF_LOADING, NULL);
+
+    result->format = format;
+
+    result->section = section;
+    result->use_virt = use_virt;
+
+    result->has_strtab = find_elf_section_by_index(format,
+                                                   ELF_SHDR(format, *section, sh_link),
+                                                   &result->strtab);
+
+    result->callback = callback;
+    result->first = first;
+    result->begin = begin;
+    result->end = end;
+
+    result->id = id;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : study  = étude de routines à mener.                          *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Assure le chargement pour un format ELF en différé.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_elf_loading_process(GElfLoading *loading, GtkStatusStack *status)
+{
+    phys_t iter;                            /* Boucle de parcours          */
+    phys_t old;                             /* Sauvegarde du point d'avant */
+    bool ret;                               /* Bilan d'un appel            */
+
+    for (iter = loading->begin; iter < loading->end; )
+    {
+        old = iter;
+        ret = loading->callback(loading, loading->format, &iter);
+
+        if (!ret)
+        {
+            log_variadic_message(LMT_ERROR, _("Error while loading ELF data @ 0x%08x!"), old);
+            break;
+        }
+
+        gtk_status_stack_update_activity_value(status, loading->id, 1);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : loading    = chargement pour ELF à mener.                    *
+*                section    = prototypes existants à insérer. [OUT]           *
+*                use_virt   = quantité de ces prototypes. [OUT]               *
+*                strtab     = informations quant à la table des chaînes. [OUT]*
+*                has_strtab = validité du champ précédemment renseigné. [OUT] *
+*                first      = position du premier élément. [OUT]              *
+*                                                                             *
+*  Description : Fournit les infos utiles au chargement de symbols internes.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_elf_loading_get_internal_info(GElfLoading *loading, const elf_shdr **section, bool *use_virt, const elf_shdr **strtab, bool *has_strtab, phys_t *first)
+{
+    *section = loading->section;
+    *use_virt = loading->use_virt;
+
+    *strtab = &loading->strtab;
+    *has_strtab = loading->has_strtab;
+
+    *first = loading->first;
+
+}
diff --git a/src/format/elf/loading.h b/src/format/elf/loading.h
new file mode 100644
index 0000000..ac7701f
--- /dev/null
+++ b/src/format/elf/loading.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * loading.h - prototypes pour les chargements parallèles des symboles de format ELF
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _FORMAT_ELF_LOADING_H
+#define _FORMAT_ELF_LOADING_H
+
+
+#include "elf.h"
+#include "../../gtkext/gtkstatusstack.h"
+
+
+
+
+//#include "../routine.h"
+//#include "../../arch/processor.h"
+//#include "../../format/executable.h"
+//#include "../../gtkext/gtkstatusstack.h"
+
+
+
+#define G_TYPE_ELF_LOADING              g_elf_loading_get_type()
+#define G_ELF_LOADING(obj)              (G_TYPE_CHECK_INSTANCE_CAST((obj), g_elf_loading_get_type(), GElfLoading))
+#define G_IS_ELF_LOADING(obj)           (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_elf_loading_get_type()))
+#define G_ELF_LOADING_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ELF_LOADING, GElfLoadingClass))
+#define G_IS_ELF_LOADING_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ELF_LOADING))
+#define G_ELF_LOADING_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ELF_LOADING, GElfLoadingClass))
+
+
+/* Fraction de loading à limiter (instance) */
+typedef struct _GElfLoading GElfLoading;
+
+/* Fraction de loading à limiter (classe) */
+typedef struct _GElfLoadingClass GElfLoadingClass;
+
+
+/* Assure un chargement pour ELF en différé. */
+typedef bool (* elf_loading_cb) (GElfLoading *, GElfFormat *, phys_t *);
+
+
+/* Indique le type défini pour les tâches de chargements pour format ELF. */
+GType g_elf_loading_get_type(void);
+
+/* Crée une tâche de chargement pour ELF différée. */
+GElfLoading *g_elf_loading_new(GElfFormat *, const elf_shdr *, bool, phys_t, phys_t, phys_t, activity_id_t, elf_loading_cb);
+
+/* Fournit les infos utiles au chargement de symbols internes. */
+void g_elf_loading_get_internal_info(GElfLoading *, const elf_shdr **, bool *, const elf_shdr **, bool *, phys_t *);
+
+
+
+#endif  /* _FORMAT_ELF_LOADING_H */
diff --git a/src/format/elf/symbols.c b/src/format/elf/symbols.c
index 29a8c3c..cfd0a09 100644
--- a/src/format/elf/symbols.c
+++ b/src/format/elf/symbols.c
@@ -36,6 +36,7 @@
 #include "elf-int.h"
 #include "helper_arm.h"
 #include "helper_x86.h"
+#include "loading.h"
 #include "program.h"
 #include "section.h"
 #include "../mangling/demangler.h"
@@ -47,6 +48,12 @@
 
 
 
+
+
+
+
+
+
 /* Enregistre un point d'entrée au sein d'un binaire ELF. */
 static void register_elf_entry_point(GElfFormat *, virt_t, phys_t, GBinRoutine *);
 
@@ -64,8 +71,11 @@ static bool load_all_elf_basic_entry_points(GElfFormat *);
 /* -------------------------- DETAIL DES SYMBOLES INTERNES -------------------------- */
 
 
+/* Assure le chargement des symboles internes ELF en différé. */
+static bool do_elf_internal_symbol_loading(GElfLoading *, GElfFormat *, phys_t *);
+
 /* Charge tous les symboles internes possibles. */
-static bool load_elf_internal_symbols(GElfFormat *);
+static bool load_elf_internal_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *);
 
 
 
@@ -87,9 +97,13 @@ static bool load_elf_external_symbols(GElfFormat *, const elf_shdr *);
 
 
 
+
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = description de l'exécutable à compléter.            *
+                 status = barre de statut à tenir informée.                   *
 *                                                                             *
 *  Description : Charge en mémoire la liste humaine des symboles.             *
 *                                                                             *
@@ -99,18 +113,21 @@ static bool load_elf_external_symbols(GElfFormat *, const elf_shdr *);
 *                                                                             *
 ******************************************************************************/
 
-bool load_elf_symbols(GElfFormat *format)
+bool load_elf_symbols(GElfFormat *format, GtkStatusStack *status)
 {
     bool result;                            /* Bilan à retourner           */
+    wgroup_id_t gid;                        /* Identifiant pour les tâches */
 
     elf_shdr *sections;                     /* Groupe de sections trouvées */
     size_t count;                           /* Quantité de données         */
 
     result = true;
 
+    gid = g_work_queue_define_work_group(get_work_queue());
+
     /* Symboles internes */
 
-    result &= load_elf_internal_symbols(format);
+    result &= load_elf_internal_symbols(format, gid, status);
 
 
 
@@ -150,6 +167,9 @@ bool load_elf_symbols(GElfFormat *format)
 }
 
 
+
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format  = description de l'exécutable à compléter.           *
@@ -493,200 +513,262 @@ const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const e
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : format = description de l'exécutable à compléter.            *
+*  Paramètres  : loading = chargement de symboles internes en cours.          *
+*                format  = format ELF à compléter.                            *
+*                iter    = tête de lecture évoluant avec le temps. [OUT]      *
 *                                                                             *
-*  Description : Charge tous les symboles internes possibles.                 *
+*  Description : Assure le chargement des symboles internes ELF en différé.   *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool load_elf_internal_symbols(GElfFormat *format)
+static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter)
 {
     bool result;                            /* Bilan à retourner           */
-    bool no_name;                           /* Choix de construction de nom*/
-    elf_shdr *sections;                      /* Groupe de sections trouvées */
-    size_t count;                           /* Quantité de données         */
-    size_t i;                               /* Boucle de parcours          */
+    elf_sym sym;                            /* Symbole aux infos visées    */
+    virt_t virt;                            /* Adresse virtuelle           */
+    const elf_shdr *section;                /* Groupe de sections trouvées */
+    bool use_virt;                          /* Choix de construction de nom*/
+    const elf_shdr *strtab;                 /* Section .strtab trouvée     */
+    bool has_strtab;                        /* Présence de cette section   */
+    phys_t first;                           /* Position du premier élément */
+    const char *name;                       /* Nom du symbole trouvé       */
+    GBinFormat *base;                       /* Version basique du format   */
+    vmpa2t addr;                            /* Localisation d'une routine  */
+    GBinSymbol *symbol;                     /* Nouveau symbole construit   */
+    char alt_name[6 + VMPA_MAX_LEN];        /* Nom abstrait de substitution*/
+    virt_t final_virt;                      /* Adresse virtuelle retenue   */
+    mrange_t range;                         /* Couverture mémoire associée */
+    GBinRoutine *routine;                   /* Nouvelle routine trouvée    */
 
-    result = true;
+    result = read_elf_symbol(format, iter, &sym);
+    if (!result) goto geslp_done;
 
-    /* Charge tous les symboles définis dans une section */
-    bool add_all_symbols_from_section(GElfFormat *format, const elf_shdr *section, bool use_virt)
-    {
-        GBinFormat *base;                   /* Version basique du format   */
-        elf_shdr strtab;                    /* Section .strtab trouvée     */
-        bool has_strtab;                    /* Présence de cette section   */
-        phys_t start;                       /* Début de la zone à traiter  */
-        phys_t size;                        /* Taille de cette même zone   */
-        phys_t iter;                        /* Boucle de parcours          */
-        elf_sym sym;                        /* Symbole aux infos visées    */
-        virt_t virt;                        /* Adresse virtuelle           */
-        virt_t final_virt;                  /* Adresse virtuelle retenue   */
-        vmpa2t addr;                        /* Localisation d'une routine  */
-        mrange_t range;                     /* Couverture mémoire associée */
-        const char *name;                   /* Nom du symbole trouvé       */
-        char alt_name[6 + VMPA_MAX_LEN];    /* Nom abstrait de substitution*/
-        GBinRoutine *routine;               /* Nouvelle routine trouvée    */
-        GBinSymbol *symbol;                 /* Nouveau symbole construit   */
+    /* On rejette les symboles qui ne sont pas définis au sein du binaire */
 
-        base = G_BIN_FORMAT(format);
+    if (ELF_SYM(format, sym, st_shndx) == 0) goto geslp_done;
 
-        has_strtab = find_elf_section_by_index(format, ELF_SHDR(format, *section, sh_link), &strtab);
+    /* Résolution précise d'adresse */
 
-        get_elf_section_content(format, section, &start, &size, NULL);
+    virt = ELF_SYM(format, sym, st_value);
+    if (virt == 0) goto geslp_done;
 
-        for (iter = start; iter < (start + size); )
-        {
-            result = read_elf_symbol(format, &iter, &sym);
-            if (!result) break;
 
-            /* On rejette les symboles qui ne sont pas définis au sein du binaire */
-            if (ELF_SYM(format, sym, st_shndx) == 0) continue;
+    /* TODO */
 
-#if 0
+    //init_vmpa(&addr, VMPA_NO_PHYSICAL, ELF_SYM(format, sym, st_value));
 
-            Elf64_Word    st_name;                /* Symbol name (string tbl index) */
-  unsigned char st_info;                /* Symbol type and binding */
-  unsigned char st_other;               /* Symbol visibility */
-  Elf64_Section st_shndx;               /* Section index */
-  Elf64_Addr    st_value;               /* Symbol value */
-  Elf64_Xword   st_size;                /* Symbol size */
 
-#endif
+    //init_mrange(&range, &addr, 0);
 
 
-            if (ELF_SYM(format, sym, st_value) == 0) continue;
+    /* Première ébauche de nom */
 
-            /* Résolution précise d'adresse */
+    g_elf_loading_get_internal_info(loading, &section, &use_virt, &strtab, &has_strtab, &first);
 
+    if (!has_strtab)
+        name = NULL;
 
-            /* TODO */
+    else
+        name = get_elf_symbol_name(format, section, strtab,
+                                   ((*iter - first) / ELF_SIZEOF_SYM(format)) - 1);
 
-            //init_vmpa(&addr, VMPA_NO_PHYSICAL, ELF_SYM(format, sym, st_value));
+    /* Traitements particuliers */
 
-            virt = ELF_SYM(format, sym, st_value);
+    base = G_BIN_FORMAT(format);
 
-            //init_mrange(&range, &addr, 0);
+    switch (ELF_ST_TYPE(format, sym))
+    {
+        case STT_OBJECT:
 
+            /* Ajustement de la position */
 
-            /* Première ébauche de nom */
+            if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, &addr))
+            {
+                symbol = NULL;
+                break;
+            }
 
-            if (!has_strtab) name = NULL;
-            else name = get_elf_symbol_name(format, section, &strtab,
-                                            ((iter - start) / ELF_SIZEOF_SYM(format)) - 1);
+            /* Création d'un nom unique ? */
 
-            /* Traitements particuliers */
+            if (name == NULL)
+            {
+                strcpy(alt_name, "obj_");
 
-            switch (ELF_ST_TYPE(format, sym))
+                if (use_virt)
+                    vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
+                else
+                    vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
+
+                name = alt_name;
+
+            }
+
+
+            /* TODO */
+
+            symbol = NULL;
+
+
+            break;
+
+        case STT_FUNC:
+
+            /* Ajustement de la position */
+
+            if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
+                final_virt = virt & ~0x1;
+            else
+                final_virt = virt;
+
+            if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_virt, &addr))
             {
-                case STT_OBJECT:
+                symbol = NULL;
+                break;
+            }
 
-                    /* Ajustement de la position */
+            init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));
 
-                    if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, &addr))
-                    {
-                        symbol = NULL;
-                        break;
-                    }
+            /* Création d'un nom unique ? */
 
-                    /* Création d'un nom unique ? */
+            if (name == NULL)
+            {
+                strcpy(alt_name, "func_");
 
-                    if (name != NULL)
-                    {
-                        strcpy(alt_name, "obj_");
+                if (use_virt)
+                    vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
+                else
+                    vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
 
-                        if (use_virt)
-                            vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
-                        else
-                            vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
+                name = alt_name;
 
-                    }
+            }
 
+            /* Routine */
 
-                    /* TODO */
+            routine = try_to_demangle_routine(name);
 
-                    symbol = NULL;
+            g_binary_routine_set_range(routine, &range);
 
+            /* Symbole uniquement */
 
-                    break;
+            symbol = g_binary_symbol_new(STP_ROUTINE);
+            g_binary_symbol_attach_routine(symbol, routine);
 
-                case STT_FUNC:
+            /* Comptabilisation pour le désassemblage brut */
 
-                    /* Ajustement de la position */
+            g_binary_format_register_code_point(G_BIN_FORMAT(format), virt, false);
 
-                    if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
-                        final_virt = virt & ~0x1;
-                    else
-                        final_virt = virt;
+            break;
 
-                    if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_virt, &addr))
-                    {
-                        symbol = NULL;
-                        break;
-                    }
+        default:
+            symbol = NULL;
+            break;
 
-                    init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));
+    }
 
-                    /* Création d'un nom unique ? */
+    if (symbol != NULL)
+        g_binary_format_add_symbol(base, symbol);
 
-                    if (name != NULL)
-                    {
-                        strcpy(alt_name, "func_");
+ geslp_done:
 
-                        if (use_virt)
-                            vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
-                        else
-                            vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
+    return result;
 
-                    }
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = description de l'exécutable à compléter.            *
+*                gid    = groupe de travail impliqué.                         *
+                 status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Charge tous les symboles internes possibles.                 *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-                    /* Routine */
+static bool load_elf_internal_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status)
+{
+    bool result;                            /* Bilan à retourner           */
+    bool no_name;                           /* Choix de construction de nom*/
+    activity_id_t msg;                      /* Message de progression      */
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    elf_shdr *dynsym_sections;              /* Groupe de sections trouvées */
+    size_t count;                           /* Quantité de données         */
+    elf_shdr *symtab_sections;              /* Groupe de sections trouvées */
+    size_t i;                               /* Boucle de parcours          */
 
-					printf("SYM ADDING>> '%s' @ 0x%08x\n", name, (unsigned int)virt);
+    result = true;
 
-                    routine = try_to_demangle_routine(name);
+    /* Charge tous les symboles définis dans une section */
+    void add_all_symbols_from_section(const elf_shdr *section, bool use_virt, GWorkQueue *wq, activity_id_t id)
+    {
+        phys_t start;                       /* Début de la zone à traiter  */
+        phys_t size;                        /* Taille de cette même zone   */
+        phys_t sym_size;                    /* Taille de chaque symbole lu */
+        guint runs_count;                   /* Qté d'exécutions parallèles */
+        phys_t run_size;                    /* Volume réparti par exécution*/
+        guint i;                            /* Boucle de parcours          */
+        phys_t begin;                       /* Début de zone de traitement */
+        phys_t end;                         /* Fin d'un zone de traitement */
+        GElfLoading *loading;               /* Tâche de chargement à lancer*/
 
-                    g_binary_routine_set_range(routine, &range);
+        get_elf_section_content(format, section, &start, &size, NULL);
 
-                    /* Symbole uniquement */
+        sym_size = ELF_SIZEOF_SYM(format);
 
-                    symbol = g_binary_symbol_new(STP_ROUTINE);
-                    g_binary_symbol_attach_routine(symbol, routine);
+        runs_count = g_get_num_processors();
 
-                    /* Comptabilisation pour le désassemblage brut */
+        run_size = size / (sym_size * runs_count);
 
-                    g_binary_format_register_code_point(base, virt, false);
+        gtk_status_stack_extend_activity(status, id, size / sym_size);
 
-                    break;
+        for (i = 0; i < runs_count; i++)
+        {
+            begin = start + i * run_size * sym_size;
 
-                default:
-                    symbol = NULL;
-                    break;
+            if ((i + 1) == runs_count)
+                end = start + size;
+            else
+                end = begin + run_size * sym_size;
 
-            }
+            loading = g_elf_loading_new(format, section, use_virt, start, begin, end,
+                                        id, do_elf_internal_symbol_loading);
 
-            if (symbol != NULL)
-                g_binary_format_add_symbol(base, symbol);
+            g_work_queue_schedule_work(wq, G_DELAYED_WORK(loading), gid);
 
         }
 
-        return true;
-
     }
 
     if (!g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &no_name))
         return false;
 
-    if (find_elf_sections_by_type(format, SHT_DYNSYM, &sections, &count))
-        for (i = 0; i < count && result; i++)
-            result = add_all_symbols_from_section(format, &sections[i], no_name);
+    msg = gtk_status_stack_add_activity(status, _("Loading internal symbols..."), 0);
+
+    queue = get_work_queue();
+
+    if (find_elf_sections_by_type(format, SHT_DYNSYM, &dynsym_sections, &count))
+        for (i = 0; i < count; i++)
+            add_all_symbols_from_section(&dynsym_sections[i], no_name, queue, msg);
+
+    if (find_elf_sections_by_type(format, SHT_SYMTAB, &symtab_sections, &count))
+        for (i = 0; i < count; i++)
+            add_all_symbols_from_section(&symtab_sections[i], no_name, queue, msg);
+
+    g_work_queue_wait_for_completion(get_work_queue(), gid);
+
+    gtk_status_stack_remove_activity(status, msg);
 
-    if (find_elf_sections_by_type(format, SHT_SYMTAB, &sections, &count))
-        for (i = 0; i < count && result; i++)
-            result = add_all_symbols_from_section(format, &sections[i], no_name);
+    if (dynsym_sections != NULL) free(dynsym_sections);
+    if (symtab_sections != NULL) free(symtab_sections);
 
     return result;
 
diff --git a/src/format/elf/symbols.h b/src/format/elf/symbols.h
index 086cb0d..77ff373 100644
--- a/src/format/elf/symbols.h
+++ b/src/format/elf/symbols.h
@@ -28,8 +28,12 @@
 #include "elf.h"
 
 
+#include "../../gtkext/gtkstatusstack.h"
+
+
+
 /* Charge en mémoire la liste humaine des symboles. */
-bool load_elf_symbols(GElfFormat *);
+bool load_elf_symbols(GElfFormat *, GtkStatusStack *);
 
 /* Récupère la définition complète d'un symbole donné. */
 bool get_elf_symbol_by_index(GElfFormat *, const elf_shdr *, off_t, elf_sym *);
diff --git a/src/format/format-int.h b/src/format/format-int.h
index f8a7204..b19749d 100644
--- a/src/format/format-int.h
+++ b/src/format/format-int.h
@@ -57,6 +57,8 @@ struct _GBinFormat
     size_t xp_allocated;                    /* Taille d'inscription allouée*/
     size_t xp_count;                        /* Nombre de points enregistrés*/
 
+    GRWLock pt_lock;                        /* Accès à la liste des points */
+
     GBinSymbol **symbols;                   /* Liste des symboles trouvés  */
     size_t symbols_count;                   /* Quantité de ces symboles    */
     GRWLock syms_lock;                      /* Accès à la liste de symboles*/
diff --git a/src/format/format.c b/src/format/format.c
index 1ee3001..ea67d2d 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -97,6 +97,8 @@ static void g_binary_format_class_init(GBinFormatClass *klass)
 
 static void g_binary_format_init(GBinFormat *format)
 {
+    g_rw_lock_init(&format->pt_lock);
+
     g_rw_lock_init(&format->syms_lock);
 
 }
@@ -212,6 +214,8 @@ SourceEndian g_binary_format_get_endianness(const GBinFormat *format)
 
 void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool entry)
 {
+    g_rw_lock_writer_lock(&format->pt_lock);
+
     if (entry)
     {
         format->entry_points = (virt_t *)realloc(format->entry_points,
@@ -235,6 +239,8 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent
 
     }
 
+    g_rw_lock_writer_unlock(&format->pt_lock);
+
 }
 
 
@@ -251,16 +257,20 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent
 *                                                                             *
 ******************************************************************************/
 
-void g_binary_format_setup_disassembling_context(const GBinFormat *format, GProcContext *ctx)
+void g_binary_format_setup_disassembling_context(GBinFormat *format, GProcContext *ctx)
 {
     size_t i;                               /* Boucle de parcours          */
 
+    g_rw_lock_reader_lock(&format->pt_lock);
+
     for (i = 0; i < format->ep_count; i++)
         g_proc_context_push_drop_point(ctx, 0, format->entry_points[i]);
 
     for (i = 0; i < format->xp_count; i++)
         g_proc_context_push_drop_point(ctx, 0, format->extra_points[i]);
 
+    g_rw_lock_reader_unlock(&format->pt_lock);
+
 }
 
 
diff --git a/src/format/format.h b/src/format/format.h
index 19c2b0a..e21e478 100644
--- a/src/format/format.h
+++ b/src/format/format.h
@@ -65,7 +65,7 @@ SourceEndian g_binary_format_get_endianness(const GBinFormat *);
 void g_binary_format_register_code_point(GBinFormat *, virt_t, bool);
 
 /* Fournit un contexte initialisé pour un désassemblage. */
-void g_binary_format_setup_disassembling_context(const GBinFormat *, GProcContext *);
+void g_binary_format_setup_disassembling_context(GBinFormat *, GProcContext *);
 
 /* Ajoute un symbole à la collection du format binaire. */
 void g_binary_format_add_symbol(GBinFormat *, GBinSymbol *);
diff --git a/src/glibext/delayed.c b/src/glibext/delayed.c
index 37b3ed7..f0aa141 100644
--- a/src/glibext/delayed.c
+++ b/src/glibext/delayed.c
@@ -814,7 +814,7 @@ static void g_work_queue_finalize(GWorkQueue *queue)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : ref = espace de référencements global.                       *
+*  Paramètres  : status = barre de statut à tenir informée.                   *
 *                                                                             *
 *  Description : Procède au chargement du gestionnaire d'analyse différées.   *
 *                                                                             *
@@ -824,19 +824,16 @@ static void g_work_queue_finalize(GWorkQueue *queue)
 *                                                                             *
 ******************************************************************************/
 
-bool init_work_queue(GObject *ref)
+bool init_work_queue(GtkStatusStack *status)
 {
     GWorkQueue *queue;                      /* Singleton à mettre en place */
 
     queue = g_object_new(G_TYPE_WORK_QUEUE, NULL);
 
-    if (ref != NULL)
-    {
-        queue->status = g_object_get_data(ref, "statusbar");
+    queue->status = status;
+
+    if (status != NULL)
         g_object_ref(G_OBJECT(queue->status));
-    }
-    else
-        queue->status = NULL;
 
     if (queue != NULL)
         _get_work_queue(queue);
diff --git a/src/glibext/delayed.h b/src/glibext/delayed.h
index 4902e68..14d54a1 100644
--- a/src/glibext/delayed.h
+++ b/src/glibext/delayed.h
@@ -30,6 +30,11 @@
 
 
 
+/* Abstration d'une gestion de barre de statut (instance) */
+typedef struct _GtkStatusStack GtkStatusStack;
+
+
+
 /* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */
 
 
@@ -88,7 +93,7 @@ typedef unsigned long long wgroup_id_t;
 GType g_work_queue_get_type(void);
 
 /* Procède au chargement du gestionnaire d'analyse différées. */
-bool init_work_queue(GObject *);
+bool init_work_queue(GtkStatusStack *);
 
 /* Fournit le gestionnaire de traitements parallèles courant. */
 GWorkQueue *_get_work_queue(GWorkQueue *);
diff --git a/src/gtkext/gtkstatusstack.c b/src/gtkext/gtkstatusstack.c
index d84f179..95166d7 100644
--- a/src/gtkext/gtkstatusstack.c
+++ b/src/gtkext/gtkstatusstack.c
@@ -24,6 +24,7 @@
 #include "gtkstatusstack.h"
 
 
+#include <assert.h>
 #include <inttypes.h>
 #include <malloc.h>
 #include <string.h>
@@ -878,6 +879,43 @@ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *m
 }
 
 
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : stack = barre de statut à actualiser.                        *
+*                id    = identifiant de l'activité à cibler.                  *
+*                extra = nouvelle échéance supplémentaire des traitements.    *
+*                                                                             *
+*  Description : Etend la portée des travaux d'une nouvelle activité.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_status_stack_extend_activity(GtkStatusStack *stack, activity_id_t id, unsigned long extra)
+{
+    progress_info *info;                    /* Informations à consulter    */
+    size_t i;                               /* Boucle de parcours          */
+
+    info = stack->prog_info;
+
+    g_mutex_lock(&info->access);
+
+    for (i = 0; i < info->count; i++)
+        if (info->statuses[i].id == id)
+            break;
+
+    assert(i < info->count);
+
+    info->statuses[i].max += extra;
+
+    g_mutex_unlock(&info->access);
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : stack = barre de statut à actualiser.                        *
@@ -907,38 +945,36 @@ void gtk_status_stack_update_activity(GtkStatusStack *stack, activity_id_t id, c
         if (info->statuses[i].id == id)
             break;
 
-    if (i < info->count)
-    {
-        /* Intitulé */
+    assert(i < info->count);
 
-        if (info->statuses[i].message != NULL)
-        {
-            if (msg == NULL)
-                msg_changed = true;
-            else
-                msg_changed = (strcmp(info->statuses[i].message, msg) != 0);
-
-            free(info->statuses[i].message);
-
-        }
-        else
-            msg_changed = (msg != NULL);
+    /* Intitulé */
 
+    if (info->statuses[i].message != NULL)
+    {
         if (msg == NULL)
-            info->statuses[i].message = NULL;
+            msg_changed = true;
         else
-            info->statuses[i].message = strdup(msg);
+            msg_changed = (strcmp(info->statuses[i].message, msg) != 0);
 
-        /* On n'actualise que le sommet de la pile */
+        free(info->statuses[i].message);
 
-        if ((i + 1) == info->count)
-        {
-            if (info->tag != 0)
-                g_source_remove(info->tag);
+    }
+    else
+        msg_changed = (msg != NULL);
 
-            info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+    if (msg == NULL)
+        info->statuses[i].message = NULL;
+    else
+        info->statuses[i].message = strdup(msg);
 
-        }
+    /* On n'actualise que le sommet de la pile */
+
+    if ((i + 1) == info->count)
+    {
+        if (info->tag != 0)
+            g_source_remove(info->tag);
+
+        info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
 
     }
 
@@ -977,30 +1013,28 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t
         if (info->statuses[i].id == id)
             break;
 
-    if (i < info->count)
-    {
-        status = &info->statuses[i];
+    assert(i < info->count);
 
-        /* Valeur */
+    status = &info->statuses[i];
 
-        status->current += inc;
+    /* Valeur */
 
-        new = (status->current * 1.0) / status->max;
+    status->current += inc;
 
-        /* On n'actualise que le sommet de la pile */
+    new = (status->current * 1.0) / status->max;
 
+    /* On n'actualise que le sommet de la pile */
 
-        //fprintf(stderr, "PROG %g -> %g <=> %g ==> %d\n", old, new, new - old, (new - old) > 0.1);
 
+    //fprintf(stderr, "PROG %g -> %g <=> %g ==> %d\n", old, new, new - old, (new - old) > 0.1);
 
-        if ((i + 1) == info->count && (new - status->last_updated) > 0.1)
-        {
-            if (info->tag != 0)
-                g_source_remove(info->tag);
 
-            info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+    if ((i + 1) == info->count && (new - status->last_updated) > 0.1)
+    {
+        if (info->tag != 0)
+            g_source_remove(info->tag);
 
-        }
+        info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
 
     }
 
@@ -1034,40 +1068,38 @@ void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
         if (info->statuses[i].id == id)
             break;
 
-    if (i < info->count)
-    {
-        if (info->tag != 0)
-            g_source_remove(info->tag);
+    assert(i < info->count);
 
-        if (info->statuses[i].message != NULL)
-            free(info->statuses[i].message);
+    if (info->tag != 0)
+        g_source_remove(info->tag);
 
-        if (info->count == 1)
-        {
-            free(info->statuses);
-            info->statuses = NULL;
-        }
-        else
-        {
-            memmove(&info->statuses[i], &info->statuses[i + 1],
-                    (info->count - i - 1) * sizeof(progress_status));
+    if (info->statuses[i].message != NULL)
+        free(info->statuses[i].message);
 
-            info->statuses = (progress_status *)realloc(info->statuses,
-                                                        (info->count - 1) * sizeof(progress_status));
+    if (info->count == 1)
+    {
+        free(info->statuses);
+        info->statuses = NULL;
+    }
+    else
+    {
+        memmove(&info->statuses[i], &info->statuses[i + 1],
+                (info->count - i - 1) * sizeof(progress_status));
 
-        }
+        info->statuses = (progress_status *)realloc(info->statuses,
+                                                    (info->count - 1) * sizeof(progress_status));
 
-        info->count--;
+    }
 
-        if (info->count == 0)
-        {
-            info->tag = 0;
-            g_idle_add((GSourceFunc)gtk_status_stack_show_current_instruction, stack);
-        }
-        else
-            info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
+    info->count--;
 
+    if (info->count == 0)
+    {
+        info->tag = 0;
+        g_idle_add((GSourceFunc)gtk_status_stack_show_current_instruction, stack);
     }
+    else
+        info->tag = g_idle_add((GSourceFunc)gtk_status_stack_show_current_activity, stack);
 
     g_mutex_unlock(&info->access);
 
diff --git a/src/gtkext/gtkstatusstack.h b/src/gtkext/gtkstatusstack.h
index 590f562..1701d77 100644
--- a/src/gtkext/gtkstatusstack.h
+++ b/src/gtkext/gtkstatusstack.h
@@ -79,6 +79,9 @@ typedef unsigned long activity_id_t;
 /* Démarre le suivi d'une nouvelle activité. */
 activity_id_t gtk_status_stack_add_activity(GtkStatusStack *, const char *, unsigned long);
 
+/* Etend la portée des travaux d'une nouvelle activité. */
+void gtk_status_stack_extend_activity(GtkStatusStack *, activity_id_t, unsigned long);
+
 /* Actualise les informations concernant une activité. */
 void gtk_status_stack_update_activity(GtkStatusStack *, activity_id_t, const char *);
 
diff --git a/src/gui/core/Makefile.am b/src/gui/core/Makefile.am
index 2000f58..75b342f 100755
--- a/src/gui/core/Makefile.am
+++ b/src/gui/core/Makefile.am
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libguicore.la
 
 libguicore_la_SOURCES =					\
 	core.h core.c						\
+	global.h global.c					\
 	panels.h panels.c
 
 libguicore_la_LDFLAGS = $(LIBGTK_LIBS) $(LIBXML_LIBS)
diff --git a/src/gui/core/global.c b/src/gui/core/global.c
new file mode 100644
index 0000000..10db31a
--- /dev/null
+++ b/src/gui/core/global.c
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * global.c - conservation de variables globales à vocation graphique
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "global.h"
+
+
+
+/* Barre de statut principale */
+static GtkStatusStack *_status = NULL;
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : status  = barre de statut à tenir informée.                  *
+*                                                                             *
+*  Description : Note l'adresse de la barre de statut principale.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void set_global_status(GtkStatusStack *status)
+{
+    _status = status;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit l'adresse de la barre de statut principale.          *
+*                                                                             *
+*  Retour      : barre de statut à tenir informée.                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkStatusStack *get_global_status(void)
+{
+    return _status;
+
+}
diff --git a/src/gui/core/global.h b/src/gui/core/global.h
new file mode 100644
index 0000000..dfd5cc2
--- /dev/null
+++ b/src/gui/core/global.h
@@ -0,0 +1,40 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * global.h - prototypes pour la conservation de variables globales à vocation graphique
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GUI_CORE_GLOBAL_H
+#define _GUI_CORE_GLOBAL_H
+
+
+#include "../../gtkext/gtkstatusstack.h"
+
+
+
+/* Note l'adresse de la barre de statut principale. */
+void set_global_status(GtkStatusStack *);
+
+/* Fournit l'adresse de la barre de statut principale. */
+GtkStatusStack *get_global_status(void);
+
+
+
+#endif  /* _GUI_CORE_GLOBAL_H */
diff --git a/src/gui/status.c b/src/gui/status.c
index f1171bd..0a3572a 100644
--- a/src/gui/status.c
+++ b/src/gui/status.c
@@ -34,6 +34,7 @@
 
 
 #include "editem-int.h"
+#include "core/global.h"
 #include "../common/extstr.h"
 #include "../gtkext/gtkbufferview.h"
 #include "../gtkext/gtkblockview.h"
@@ -199,7 +200,7 @@ GEditorItem *g_status_info_new(GObject *ref)
     g_object_ref(ref);
     item->ref = ref;
 
-    g_object_set_data(ref, "statusbar", item->widget);
+    set_global_status(GTK_STATUS_STACK(item->widget));
 
     return G_EDITOR_ITEM(result);
 
diff --git a/src/main.c b/src/main.c
index ec379bc..821773d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -38,6 +38,7 @@
 #include "gtkext/theme.h"
 #include "gui/editor.h"
 #include "gui/core/core.h"
+#include "gui/core/global.h"
 #include "plugins/pglist.h"
 
 
@@ -172,7 +173,7 @@ int main(int argc, char **argv)
     editor = create_editor();
     gtk_widget_show_now(editor);
 
-    init_work_queue(G_OBJECT(editor));
+    init_work_queue(get_global_status());
 
     init_all_plugins(G_OBJECT(editor));
 
-- 
cgit v0.11.2-87-g4458