From a9328553fc558bca2e75f2c93b35acc5518d9568 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 7 Aug 2017 23:50:38 +0200
Subject: Stored all errors detected when loading and disassembling a binary
 file.

---
 ChangeLog                         |  24 +++++
 plugins/pychrysa/arch/processor.c | 153 +++++++++++++++++++++++++-
 plugins/pychrysa/format/format.c  | 157 +++++++++++++++++++++++++++
 src/analysis/disass/output.c      |   8 ++
 src/arch/processor-int.h          |  19 +++-
 src/arch/processor.c              | 171 ++++++++++++++++++++++++++++-
 src/arch/processor.h              |  29 +++++
 src/format/format-int.h           |  18 ++++
 src/format/format.c               | 219 +++++++++++++++++++++++++++++++++++++-
 src/format/format.h               |  28 +++++
 src/format/preload.c              |  14 ++-
 tests/arch/errors.py              |  35 ++++++
 tests/format/errors.py            |  58 ++++++++++
 13 files changed, 923 insertions(+), 10 deletions(-)
 create mode 100644 tests/arch/errors.py
 create mode 100644 tests/format/errors.py

diff --git a/ChangeLog b/ChangeLog
index f33c247..4981236 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+17-08-07  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/pychrysa/arch/processor.c:
+	* plugins/pychrysa/format/format.c:
+	Update the Python bindings.
+
+	* src/analysis/disass/output.c:
+	Update code.
+
+	* src/arch/processor-int.h:
+	* src/arch/processor.c:
+	* src/arch/processor.h:
+	* src/format/format-int.h:
+	* src/format/format.c:
+	* src/format/format.h:
+	Store all errors detected when loading and disassembling a binary file.
+
+	* src/format/preload.c:
+	Fix bugs when freeing the memory used by preloaded info.
+
+	* tests/arch/errors.py:
+	* tests/format/errors.py:
+	New entries: extend the test suite.
+
 17-08-06  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gui/panels/panel-int.h:
diff --git a/plugins/pychrysa/arch/processor.c b/plugins/pychrysa/arch/processor.c
index c3d744b..4470e78 100644
--- a/plugins/pychrysa/arch/processor.c
+++ b/plugins/pychrysa/arch/processor.c
@@ -55,12 +55,18 @@
 
 
 
+/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */
 
 
+/* Etend la liste des soucis détectés avec de nouvelles infos. */
+static PyObject *py_arch_processor_add_error(PyObject *, PyObject *);
+
+/* Fournit les éléments concernant tous les soucis détectés. */
+static PyObject *py_arch_processor_get_errors(PyObject *, void *);
 
 
-/* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */
 
+/* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */
 
 
 /* Fournit les instructions désassemblées pour une architecture. */
@@ -74,6 +80,109 @@ static PyObject *py_arch_processor_find_instr_by_addr(PyObject *, PyObject *);
 
 
 
+
+
+/* Définit les constantes pour les types d'erreurs. */
+static bool define_python_arch_processor_constants(PyTypeObject *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                    CONSERVATION DES SOUCIS DURANT LE CHARGEMENT                    */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = architecture concernée par la procédure.              *
+*                args = instruction représentant le point de départ.          *
+*                                                                             *
+*  Description : Etend la liste des soucis détectés avec de nouvelles infos.  *
+*                                                                             *
+*  Retour      : None.                                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_processor_add_error(PyObject *self, PyObject *args)
+{
+    ArchProcessingError type;               /* Type d'erreur détectée      */
+    vmpa2t addr;                            /* Position d'une erreur       */
+    char *desc;                             /* Description d'une erreur    */
+    int ret;                                /* Bilan de lecture des args.  */
+    GArchProcessor *proc;                   /* Processeur manipulé         */
+
+    ret = PyArg_ParseTuple(args, "IO&s", &type, convert_any_to_vmpa, &addr, &desc);
+    if (!ret) return NULL;
+
+    proc = G_ARCH_PROCESSOR(pygobject_get(self));
+
+    g_arch_processor_add_error(proc, type, &addr, desc);
+
+    Py_RETURN_NONE;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit les éléments concernant tous les soucis détectés.    *
+*                                                                             *
+*  Retour      : Liste des erreurs relevées au niveau de l'assembleur.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_processor_get_errors(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Instance Python à retourner */
+    GArchProcessor *proc;                   /* Architecture visée          */
+    size_t count;                           /* Nombre d'éléments à traiter */
+    size_t i;                               /* Boucle de parcours          */
+#ifndef NDEBUG
+    bool status;                            /* Bilan d'un appel            */
+#endif
+    ArchProcessingError type;               /* Type d'erreur détectée      */
+    vmpa2t addr;                            /* Position d'une erreur       */
+    char *desc;                             /* Description d'une erreur    */
+    PyObject *error;                        /* Nouvelle erreur à rajouter  */
+
+    proc = G_ARCH_PROCESSOR(pygobject_get(self));
+
+    g_arch_processor_lock_errors(proc);
+
+    count = g_arch_processor_count_errors(proc);
+
+    result = PyTuple_New(count);
+
+    for (i = 0; i < count; i++)
+    {
+#ifndef NDEBUG
+        status = g_arch_processor_get_error(proc, i, &type, &addr, &desc);
+        assert(status);
+#else
+        g_arch_processor_get_error(proc, i, &type, &addr, &desc);
+#endif
+
+        error = Py_BuildValue("IO&s", type, build_from_internal_vmpa, &addr, desc);
+
+        PyTuple_SetItem(result, i, error);
+
+    }
+
+    g_arch_processor_unlock_errors(proc);
+
+    return result;
+
+}
+
+
+
 /* ---------------------------------------------------------------------------------- */
 /*                    MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES                    */
 /* ---------------------------------------------------------------------------------- */
@@ -227,6 +336,36 @@ static PyObject *py_arch_processor_find_instr_by_addr(PyObject *self, PyObject *
 }
 
 
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
+*                                                                             *
+*  Description : Définit les constantes pour les types d'erreurs.             *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool define_python_arch_processor_constants(PyTypeObject *obj_type)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    result &= PyDict_AddIntMacro(obj_type, APE_DISASSEMBLY);
+    result &= PyDict_AddIntMacro(obj_type, APE_LABEL);
+
+    return result;
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : -                                                            *
@@ -243,6 +382,11 @@ PyTypeObject *get_python_arch_processor_type(void)
 {
     static PyMethodDef py_arch_processor_methods[] = {
         {
+            "add_error", py_arch_processor_add_error,
+            METH_VARARGS,
+            "add_error($self, type, addr, desc, /)\n--\n\nExtend the list of detected disassembling errors."
+        },
+        {
             "find_instr_by_addr", py_arch_processor_find_instr_by_addr,
             METH_VARARGS,
             "find_instr_by_addr($self, addr, /)\n--\n\nLook for an instruction located at a given address."
@@ -252,6 +396,10 @@ PyTypeObject *get_python_arch_processor_type(void)
 
     static PyGetSetDef py_arch_processor_getseters[] = {
         {
+            "errors", py_arch_processor_get_errors, NULL,
+            "List of all detected errors which occurred during the disassembling process.", NULL
+        },
+        {
             "instrs", py_arch_processor_get_instrs, py_arch_processor_set_instrs,
             "Give access to the disassembled instructions run by the current processor.", NULL
         },
@@ -303,6 +451,9 @@ bool register_python_arch_processor(PyObject *module)
     if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, py_arch_processor_type, &PyGObject_Type))
         return false;
 
+    if (!define_python_arch_processor_constants(py_arch_processor_type))
+        return false;
+
     return true;
 
 }
diff --git a/plugins/pychrysa/format/format.c b/plugins/pychrysa/format/format.c
index cc9e819..773b928 100644
--- a/plugins/pychrysa/format/format.c
+++ b/plugins/pychrysa/format/format.c
@@ -84,6 +84,25 @@ static PyObject *py_binary_format_get_symbols(PyObject *, void *);
 
 
 
+/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */
+
+
+/* Etend la liste des soucis détectés avec de nouvelles infos. */
+static PyObject *py_binary_format_add_error(PyObject *, PyObject *);
+
+/* Fournit les éléments concernant tous les soucis détectés. */
+static PyObject *py_binary_format_get_errors(PyObject *, void *);
+
+
+
+
+
+
+/* Définit les constantes pour les types d'erreurs. */
+static bool define_python_binary_format_constants(PyTypeObject *);
+
+
+
 /* ---------------------------------------------------------------------------------- */
 /*                          PARCOURS DE SYMBOLES DE BINAIRES                          */
 /* ---------------------------------------------------------------------------------- */
@@ -538,6 +557,132 @@ static PyObject *py_binary_format_get_symbols(PyObject *self, void *closure)
 }
 
 
+
+/* ---------------------------------------------------------------------------------- */
+/*                    CONSERVATION DES SOUCIS DURANT LE CHARGEMENT                    */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = architecture concernée par la procédure.              *
+*                args = instruction représentant le point de départ.          *
+*                                                                             *
+*  Description : Etend la liste des soucis détectés avec de nouvelles infos.  *
+*                                                                             *
+*  Retour      : None.                                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_format_add_error(PyObject *self, PyObject *args)
+{
+    BinaryFormatError type;                 /* Type d'erreur détectée      */
+    vmpa2t addr;                            /* Position d'une erreur       */
+    char *desc;                             /* Description d'une erreur    */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBinFormat *format;                     /* Format binaire manipulé     */
+
+    ret = PyArg_ParseTuple(args, "IO&s", &type, convert_any_to_vmpa, &addr, &desc);
+    if (!ret) return NULL;
+
+    format = G_BIN_FORMAT(pygobject_get(self));
+
+    g_binary_format_add_error(format, type, &addr, desc);
+
+    Py_RETURN_NONE;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit les éléments concernant tous les soucis détectés.    *
+*                                                                             *
+*  Retour      : Liste des erreurs relevées au niveau de l'assembleur.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_binary_format_get_errors(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Instance Python à retourner */
+    GBinFormat *format;                     /* Format binaire manipulé     */
+    size_t count;                           /* Nombre d'éléments à traiter */
+    size_t i;                               /* Boucle de parcours          */
+#ifndef NDEBUG
+    bool status;                            /* Bilan d'un appel            */
+#endif
+    BinaryFormatError type;                 /* Type d'erreur détectée      */
+    vmpa2t addr;                            /* Position d'une erreur       */
+    char *desc;                             /* Description d'une erreur    */
+    PyObject *error;                        /* Nouvelle erreur à rajouter  */
+
+    format = G_BIN_FORMAT(pygobject_get(self));
+
+    g_binary_format_lock_errors(format);
+
+    count = g_binary_format_count_errors(format);
+
+    result = PyTuple_New(count);
+
+    for (i = 0; i < count; i++)
+    {
+#ifndef NDEBUG
+        status = g_binary_format_get_error(format, i, &type, &addr, &desc);
+        assert(status);
+#else
+        g_binary_format_get_error(format, i, &type, &addr, &desc);
+#endif
+
+        error = Py_BuildValue("IO&s", type, build_from_internal_vmpa, &addr, desc);
+
+        PyTuple_SetItem(result, i, error);
+
+    }
+
+    g_binary_format_unlock_errors(format);
+
+    return result;
+
+}
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
+*                                                                             *
+*  Description : Définit les constantes pour les types d'erreurs.             *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool define_python_binary_format_constants(PyTypeObject *obj_type)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    result &= PyDict_AddIntMacro(obj_type, BFE_STRUCTURE);
+
+    return result;
+
+}
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : -                                                            *
@@ -573,6 +718,11 @@ PyTypeObject *get_python_binary_format_type(void)
             METH_VARARGS,
             "resolve_symbol($self, addr, strict, /)\n--\n\nSearch a position inside a routine by a given address."
         },
+        {
+            "add_error", py_binary_format_add_error,
+            METH_VARARGS,
+            "add_error($self, type, addr, desc, /)\n--\n\nExtend the list of detected disassembling errors."
+        },
         { NULL }
     };
 
@@ -585,6 +735,10 @@ PyTypeObject *get_python_binary_format_type(void)
             "symbols", py_binary_format_get_symbols, NULL,
             "Iterable list of all symbols found in the binary format.", NULL
         },
+        {
+            "errors", py_binary_format_get_errors, NULL,
+            "List of all detected errors which occurred while loading the binary.", NULL
+        },
         { NULL }
     };
 
@@ -635,6 +789,9 @@ bool register_python_binary_format(PyObject *module)
     if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, py_bin_format_type, &PyGObject_Type))
         return false;
 
+    if (!define_python_binary_format_constants(py_bin_format_type))
+        return false;
+
     return true;
 
 }
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index 063280c..8e74d1c 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -83,6 +83,7 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang,
     GLineGenerator *generator;              /* Générateur de contenu ajouté*/
     const vmpa2t *saddr;                    /* Adresse de symbole          */
     int compared;                           /* Bilan d'une comparaison     */
+    char *errmsg;                           /* Description d'une erreur    */
     SymbolType stype;                       /* Type de symbole trouvé      */
     vmpa2t intro_addr;                      /* Adresse de début de code    */
     vmpa2t outro_addr;                      /* Adresse de fin de code      */
@@ -220,6 +221,13 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang,
                                      _("Unable to find a proper location for symbol '%s' @ 0x%08x"),
                                      g_binary_symbol_get_label(symbols[sym_index]), get_phy_addr(saddr));
 
+                asprintf(&errmsg, _("Unable to find a proper location for symbol '%s'"),
+                         g_binary_symbol_get_label(symbols[sym_index]));
+
+                g_arch_processor_add_error(proc, APE_LABEL, saddr, errmsg);
+
+                free(errmsg);
+
                 _missing++;
 
                 if (++sym_index == sym_count)
diff --git a/src/arch/processor-int.h b/src/arch/processor-int.h
index 0a95fde..a308bb8 100644
--- a/src/arch/processor-int.h
+++ b/src/arch/processor-int.h
@@ -59,6 +59,16 @@ typedef GArchInstruction * (* disass_instr_fc) (const GArchProcessor *, GProcCon
 
 
 
+/* Description d'une erreur */
+typedef struct _proc_error
+{
+    ArchProcessingError type;               /* Type d'erreur               */
+
+    vmpa2t addr;                            /* Localisation du problème    */
+    char *desc;                             /* Description du soucis       */
+
+} proc_error;
+
 /* Couverture d'un groupe d'instructions */
 struct _instr_coverage
 {
@@ -70,8 +80,6 @@ struct _instr_coverage
 };
 
 
-
-
 /* Définition générique d'un processeur d'architecture (instance) */
 struct _GArchProcessor
 {
@@ -92,6 +100,13 @@ struct _GArchProcessor
     gint locked;                            /* Statut d'accès à la liste   */
 #endif
 
+    proc_error *errors;                     /* Liste d'erreurs rencontrées */
+    size_t error_count;                     /* Taille de cette liste       */
+    GMutex error_mutex;                     /* Verrou pour l'accès         */
+#ifndef NDEBUG
+    gint error_locked;                      /* Statut d'accès à la liste   */
+#endif
+
     instr_coverage *coverages;              /* Liste de couvertures        */
     size_t cov_allocated;                   /* Taille de la liste allouée  */
     size_t cov_count;                       /* Taille de la liste utilisée */
diff --git a/src/arch/processor.c b/src/arch/processor.c
index 38c39e6..21b6c49 100644
--- a/src/arch/processor.c
+++ b/src/arch/processor.c
@@ -27,6 +27,7 @@
 #include <assert.h>
 #include <malloc.h>
 #include <stdlib.h>
+#include <string.h>
 
 
 
@@ -129,10 +130,17 @@ static void g_arch_processor_class_init(GArchProcessorClass *klass)
 
 static void g_arch_processor_init(GArchProcessor *proc)
 {
+    g_mutex_init(&proc->mutex);
 #ifndef DEBUG
     g_atomic_int_set(&proc->locked, 0);
 #endif
-    g_mutex_init(&proc->mutex);
+
+    proc->errors = NULL;
+    proc->error_count = 0;
+    g_mutex_init(&proc->error_mutex);
+#ifndef DEBUG
+    g_atomic_int_set(&proc->error_locked, 0);
+#endif
 
     proc->coverages = NULL;
     proc->cov_allocated = 0;
@@ -157,6 +165,8 @@ static void g_arch_processor_dispose(GArchProcessor *proc)
 {
     g_mutex_clear(&proc->mutex);
 
+    g_mutex_clear(&proc->error_mutex);
+
     G_OBJECT_CLASS(g_arch_processor_parent_class)->dispose(G_OBJECT(proc));
 
 }
@@ -176,6 +186,18 @@ static void g_arch_processor_dispose(GArchProcessor *proc)
 
 static void g_arch_processor_finalize(GArchProcessor *proc)
 {
+    size_t i;                               /* Boucle de parcours          */
+
+    if (proc->errors != NULL)
+    {
+        for (i = 0; i < proc->error_count; i++)
+            if (proc->errors[i].desc != NULL)
+                free(proc->errors[i].desc);
+
+        free(proc->errors);
+
+    }
+
     G_OBJECT_CLASS(g_arch_processor_parent_class)->finalize(G_OBJECT(proc));
 
 }
@@ -498,6 +520,153 @@ GArchInstruction *g_arch_processor_get_instruction(const GArchProcessor *proc, s
 
 
 /* ---------------------------------------------------------------------------------- */
+/*                    CONSERVATION DES SOUCIS DURANT LE CHARGEMENT                    */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc  = architecture à manipuler.                            *
+*                state = nouvel état de l'accès aux erreurs relevées.         *
+*                                                                             *
+*  Description : Protège ou lève la protection de l'accès aux erreurs.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_arch_processor_lock_unlock_errors(GArchProcessor *proc, bool state)
+{
+    if (state)
+    {
+        g_mutex_lock(&proc->error_mutex);
+        g_atomic_int_set(&proc->error_locked, 1);
+    }
+    else
+    {
+        g_atomic_int_set(&proc->error_locked, 0);
+        g_mutex_unlock(&proc->error_mutex);
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc  = architecture concernée par la procédure.             *
+*                index = indice du problème visé.                             *
+*                type  = type d'erreur retrouvée.                             *
+*                addr  = localisation associée.                               *
+*                desc  = éventuelle description humaine de description.       *
+*                                                                             *
+*  Description : Etend la liste des soucis détectés avec de nouvelles infos.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_arch_processor_add_error(GArchProcessor *proc, ArchProcessingError type, const vmpa2t *addr, const char *desc)
+{
+    proc_error *error;                      /* Raccourci de confort        */
+
+    g_arch_processor_lock_errors(proc);
+
+    proc->errors = realloc(proc->errors, ++proc->error_count * sizeof(proc_error));
+
+    error = &proc->errors[proc->error_count - 1];
+
+    error->type = type;
+
+    copy_vmpa(&error->addr, addr);
+
+    if (desc != NULL)
+        error->desc = strdup(desc);
+    else
+        error->desc = NULL;
+
+    g_arch_processor_unlock_errors(proc);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc = architecture à consulter durant la procédure.         *
+*                                                                             *
+*  Description : Indique le nombre d'erreurs relevées au niveau assembleur.   *
+*                                                                             *
+*  Retour      : Nombre d'erreurs en stock.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_arch_processor_count_errors(GArchProcessor *proc)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    assert(g_atomic_int_get(&proc->error_locked) == 1);
+
+    result = proc->error_count;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc  = architecture concernée par la procédure.             *
+*                index = indice du problème visé.                             *
+*                type  = type d'erreur retrouvée. [OUT]                       *
+*                addr  = localisation associée. [OUT]                         *
+*                desc  = éventuelle description humaine de description. [OUT] *
+*                                                                             *
+*  Description : Fournit les éléments concernant un soucis détecté.           *
+*                                                                             *
+*  Retour      : Validité des informations renseignées.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_arch_processor_get_error(GArchProcessor *proc, size_t index, ArchProcessingError *type, vmpa2t *addr, char **desc)
+{
+    bool result;                            /* Bilan à retourner           */
+    proc_error *error;                      /* Raccourci de confort        */
+
+    assert(g_atomic_int_get(&proc->error_locked) == 1);
+
+    result = (index < proc->error_count);
+
+    assert(result);
+
+    if (result)
+    {
+        error = &proc->errors[index];
+
+        *type = error->type;
+
+        copy_vmpa(addr, &error->addr);
+
+        if (error->desc != NULL)
+            *desc = strdup(error->desc);
+        else
+            *desc = NULL;
+
+    }
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
 /*                    MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES                    */
 /* ---------------------------------------------------------------------------------- */
 
diff --git a/src/arch/processor.h b/src/arch/processor.h
index 2a8a8c1..87c0738 100644
--- a/src/arch/processor.h
+++ b/src/arch/processor.h
@@ -98,6 +98,35 @@ GArchInstruction *g_arch_processor_get_instruction(const GArchProcessor *, size_
 
 
 
+/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */
+
+
+/* Types d'erreurs détectées */
+typedef enum _ArchProcessingError
+{
+    APE_DISASSEMBLY = ((0 << 2) | (1 << 0)),/* Code non reconnu            */
+    APE_LABEL       = ((1 << 2) | (1 << 0)) /* Etiquette non référencée    */
+
+} ArchProcessingError;
+
+
+/* Protège ou lève la protection de l'accès aux erreurs. */
+void g_arch_processor_lock_unlock_errors(GArchProcessor *, bool);
+
+#define g_arch_processor_lock_errors(p) g_arch_processor_lock_unlock_errors(p, true)
+#define g_arch_processor_unlock_errors(p) g_arch_processor_lock_unlock_errors(p, false)
+
+/* Etend la liste des soucis détectés avec de nouvelles infos. */
+void g_arch_processor_add_error(GArchProcessor *, ArchProcessingError, const vmpa2t *, const char *);
+
+/* Indique le nombre d'erreurs relevées au niveau assembleur. */
+size_t g_arch_processor_count_errors(GArchProcessor *);
+
+/* Fournit les éléments concernant un soucis détecté. */
+bool g_arch_processor_get_error(GArchProcessor *, size_t, ArchProcessingError *, vmpa2t *, char **);
+
+
+
 /* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */
 
 
diff --git a/src/format/format-int.h b/src/format/format-int.h
index d50b053..0ab0e85 100644
--- a/src/format/format-int.h
+++ b/src/format/format-int.h
@@ -47,6 +47,17 @@ typedef void (* format_decompile_fc) (const GBinFormat *, void/*GCodeBuffer*/ *,
 #define EXTRA_POINT_BLOCK 100
 
 
+/* Description d'une erreur */
+typedef struct _fmt_error
+{
+    BinaryFormatError type;                 /* Type d'erreur               */
+
+    vmpa2t addr;                            /* Localisation du problème    */
+    char *desc;                             /* Description du soucis       */
+
+} fmt_error;
+
+
 /* Format binaire générique (instance) */
 struct _GBinFormat
 {
@@ -74,6 +85,13 @@ struct _GBinFormat
     size_t def_source;                      /* Fichier source principal    */
     format_decompile_fc decompile;          /* Décompilation d'un fichier  */
 
+    fmt_error *errors;                      /* Liste d'erreurs rencontrées */
+    size_t error_count;                     /* Taille de cette liste       */
+    GMutex error_mutex;                     /* Verrou pour l'accès         */
+#ifndef NDEBUG
+    gint error_locked;                      /* Statut d'accès à la liste   */
+#endif
+
 };
 
 /* Format binaire générique (classe) */
diff --git a/src/format/format.c b/src/format/format.c
index 5d845e4..293e5da 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -50,6 +50,12 @@ static void g_binary_format_class_init(GBinFormatClass *);
 /* Initialise une instance de format binaire générique. */
 static void g_binary_format_init(GBinFormat *);
 
+/* Supprime toutes les références externes. */
+static void g_binary_format_dispose(GBinFormat *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_binary_format_finalize(GBinFormat *);
+
 /* Retire un symbole de la collection du format binaire. */
 static void _g_binary_format_remove_symbol(GBinFormat *, size_t);
 
@@ -79,6 +85,12 @@ G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_OBJECT);
 
 static void g_binary_format_class_init(GBinFormatClass *klass)
 {
+    GObjectClass *object;                   /* Autre version de la classe  */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_format_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_binary_format_finalize;
 
 }
 
@@ -103,14 +115,70 @@ static void g_binary_format_init(GBinFormat *format)
 
     g_rw_lock_init(&format->syms_lock);
 
+    format->errors = NULL;
+    format->error_count = 0;
+    g_mutex_init(&format->error_mutex);
+#ifndef DEBUG
+    g_atomic_int_set(&format->error_locked, 0);
+#endif
+
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_binary_format_dispose(GBinFormat *format)
+{
+    g_object_unref(format->info);
+
+    g_rw_lock_clear(&format->syms_lock);
 
-/* FIXME : g_object_unref(format->info); */
+    g_mutex_clear(&format->error_mutex);
 
-/* FIXME : g_rw_lock_clear(&format->syms_lock);*/
+    G_OBJECT_CLASS(g_binary_format_parent_class)->dispose(G_OBJECT(format));
 
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_binary_format_finalize(GBinFormat *format)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    if (format->errors != NULL)
+    {
+        for (i = 0; i < format->error_count; i++)
+            if (format->errors[i].desc != NULL)
+                free(format->errors[i].desc);
+
+        free(format->errors);
+
+    }
+
+    G_OBJECT_CLASS(g_binary_format_parent_class)->finalize(G_OBJECT(format));
+
+}
 
 
 /******************************************************************************
@@ -964,3 +1032,150 @@ void g_binary_format_decompile(const GBinFormat *format, GCodeBuffer *buffer, co
 
 }
 #endif
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                    CONSERVATION DES SOUCIS DURANT LE CHARGEMENT                    */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = architecture à manipuler.                           *
+*                state  = nouvel état de l'accès aux erreurs relevées.        *
+*                                                                             *
+*  Description : Protège ou lève la protection de l'accès aux erreurs.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_binary_format_lock_unlock_errors(GBinFormat *format, bool state)
+{
+    if (state)
+    {
+        g_mutex_lock(&format->error_mutex);
+        g_atomic_int_set(&format->error_locked, 1);
+    }
+    else
+    {
+        g_atomic_int_set(&format->error_locked, 0);
+        g_mutex_unlock(&format->error_mutex);
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = architecture concernée par la procédure.            *
+*                index  = indice du problème visé.                            *
+*                type   = type d'erreur retrouvée.                            *
+*                addr   = localisation associée.                              *
+*                desc   = éventuelle description humaine de description.      *
+*                                                                             *
+*  Description : Etend la liste des soucis détectés avec de nouvelles infos.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_binary_format_add_error(GBinFormat *format, BinaryFormatError type, const vmpa2t *addr, const char *desc)
+{
+    fmt_error *error;                       /* Raccourci de confort        */
+
+    g_binary_format_lock_errors(format);
+
+    format->errors = realloc(format->errors, ++format->error_count * sizeof(fmt_error));
+
+    error = &format->errors[format->error_count - 1];
+
+    error->type = type;
+
+    copy_vmpa(&error->addr, addr);
+
+    if (desc != NULL)
+        error->desc = strdup(desc);
+    else
+        error->desc = NULL;
+
+    g_binary_format_unlock_errors(format);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = architecture à consulter durant la procédure.       *
+*                                                                             *
+*  Description : Indique le nombre d'erreurs relevées au niveau assembleur.   *
+*                                                                             *
+*  Retour      : Nombre d'erreurs en stock.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_binary_format_count_errors(GBinFormat *format)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    assert(g_atomic_int_get(&format->error_locked) == 1);
+
+    result = format->error_count;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = architecture concernée par la procédure.            *
+*                index  = indice du problème visé.                            *
+*                type   = type d'erreur retrouvée. [OUT]                      *
+*                addr   = localisation associée. [OUT]                        *
+*                desc   = éventuelle description humaine de description. [OUT]*
+*                                                                             *
+*  Description : Fournit les éléments concernant un soucis détecté.           *
+*                                                                             *
+*  Retour      : Validité des informations renseignées.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_binary_format_get_error(GBinFormat *format, size_t index, BinaryFormatError *type, vmpa2t *addr, char **desc)
+{
+    bool result;                            /* Bilan à retourner           */
+    fmt_error *error;                       /* Raccourci de confort        */
+
+    assert(g_atomic_int_get(&format->error_locked) == 1);
+
+    result = (index < format->error_count);
+
+    assert(result);
+
+    if (result)
+    {
+        error = &format->errors[index];
+
+        *type = error->type;
+
+        copy_vmpa(addr, &error->addr);
+
+        if (error->desc != NULL)
+            *desc = strdup(error->desc);
+        else
+            *desc = NULL;
+
+    }
+
+    return result;
+
+}
diff --git a/src/format/format.h b/src/format/format.h
index ec78236..3c1bbea 100644
--- a/src/format/format.h
+++ b/src/format/format.h
@@ -105,4 +105,32 @@ const char * const *g_binary_format_get_source_files(const GBinFormat *, size_t
 
 
 
+/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */
+
+
+/* Types d'erreurs détectées */
+typedef enum _BinaryFormatError
+{
+    BFE_STRUCTURE = ((0 << 2) | (0 << 0))   /* Code non reconnu            */
+
+} BinaryFormatError;
+
+
+/* Protège ou lève la protection de l'accès aux erreurs. */
+void g_binary_format_lock_unlock_errors(GBinFormat *, bool);
+
+#define g_binary_format_lock_errors(p) g_binary_format_lock_unlock_errors(p, true)
+#define g_binary_format_unlock_errors(p) g_binary_format_lock_unlock_errors(p, false)
+
+/* Etend la liste des soucis détectés avec de nouvelles infos. */
+void g_binary_format_add_error(GBinFormat *, BinaryFormatError, const vmpa2t *, const char *);
+
+/* Indique le nombre d'erreurs relevées au niveau assembleur. */
+size_t g_binary_format_count_errors(GBinFormat *);
+
+/* Fournit les éléments concernant un soucis détecté. */
+bool g_binary_format_get_error(GBinFormat *, size_t, BinaryFormatError *, vmpa2t *, char **);
+
+
+
 #endif  /* _FORMAT_FORMAT_H */
diff --git a/src/format/preload.c b/src/format/preload.c
index 7f7a435..cddc60e 100644
--- a/src/format/preload.c
+++ b/src/format/preload.c
@@ -105,14 +105,18 @@ static void g_preload_info_init(GPreloadInfo *info)
 
 static void g_preload_info_dispose(GPreloadInfo *info)
 {
+    size_t count;                           /* Borne de parcours           */
+    size_t i;                               /* Boucle de parcours          */
     GArchInstruction *instr;                /* Instruction à libérer       */
     GDbComment *comment;                    /* Commentaire à libérer       */
 
     g_preload_info_lock_instructions(info);
 
-    while (_g_preload_info_count_instructions(info) > 0)
+    count = _g_preload_info_count_instructions(info);
+
+    for (i = 0; i < count; i++)
     {
-        instr = _g_preload_info_grab_instruction(info, 0);
+        instr = _g_preload_info_grab_instruction(info, i);
         g_object_unref(G_OBJECT(instr));
     }
 
@@ -122,9 +126,11 @@ static void g_preload_info_dispose(GPreloadInfo *info)
 
     g_preload_info_lock_comments(info);
 
-    while (_g_preload_info_count_comments(info) > 0)
+    count = _g_preload_info_count_comments(info);
+
+    for (i = 0; i < count; i++)
     {
-        comment = _g_preload_info_grab_comment(info, 0);
+        comment = _g_preload_info_grab_comment(info, i);
         g_object_unref(G_OBJECT(comment));
     }
 
diff --git a/tests/arch/errors.py b/tests/arch/errors.py
new file mode 100644
index 0000000..9d5e273
--- /dev/null
+++ b/tests/arch/errors.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+# Tests minimalistes pour valider la gestion des erreurs relevées.
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.arch import vmpa
+from pychrysalide.arch import ArchProcessor
+
+
+class TestArchErrors(ChrysalideTestCase):
+    """TestCase for arch.ArchProcessor errors."""
+
+    def testBasic(self):
+        """Perform some sanity tests on architecture error handling."""
+
+        errlen = 3
+
+        pattern = []
+
+        for i in range(errlen):
+
+            addr = vmpa(vmpa.VMPA_NO_PHYSICAL, 0x100 + i * 0x10)
+
+            pattern.append([ArchProcessor.APE_LABEL, addr, 'random desc #%d' % i])
+
+        proc = ArchProcessor()
+
+        for i in range(errlen):
+
+            proc.add_error(pattern[i][0], pattern[i][1], pattern[i][2])
+
+        self.assertEqual(len(proc.errors), errlen)
diff --git a/tests/format/errors.py b/tests/format/errors.py
new file mode 100644
index 0000000..36b7129
--- /dev/null
+++ b/tests/format/errors.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+# Tests minimalistes pour valider la gestion des erreurs relevées.
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.arch import vmpa
+from pychrysalide.format import BinFormat
+from pychrysalide.format.elf import ElfFormat
+import os
+import sys
+
+
+class TestFormatErrors(ChrysalideTestCase):
+    """TestCase for format.BinFormat errors."""
+
+    @classmethod
+    def setUpClass(cls):
+
+        super(TestFormatErrors, cls).setUpClass()
+
+        cls.log('Compile binary "strings" if needed...')
+
+        fullname = sys.modules[cls.__module__].__file__
+        dirpath = os.path.dirname(fullname)
+
+        os.system('make -C %s%self strings 2>&1 > /dev/null' % (dirpath, os.sep))
+
+
+    def testBasic(self):
+        """Perform some sanity tests on format error handling."""
+
+        errlen = 3
+
+        pattern = []
+
+        for i in range(errlen):
+
+            addr = vmpa(vmpa.VMPA_NO_PHYSICAL, 0x100 + i * 0x10)
+
+            pattern.append([BinFormat.BFE_STRUCTURE, addr, 'random desc #%d' % i])
+
+        fullname = sys.modules[self.__class__.__module__].__file__
+        filename = os.path.basename(fullname)
+
+        baselen = len(fullname) - len(filename)
+
+        cnt = FileContent(fullname[:baselen] + 'elf' + os.sep + 'strings')
+        fmt = ElfFormat(cnt, None, None)
+
+        for i in range(errlen):
+
+            fmt.add_error(pattern[i][0], pattern[i][1], pattern[i][2])
+
+        self.assertEqual(len(fmt.errors), errlen)
-- 
cgit v0.11.2-87-g4458