From 5fce21379baac06b7b9359c4b0fcb7fb3867c301 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 12 May 2017 23:28:01 +0200
Subject: Added the ELF strings to the preloaded instruction list.

---
 ChangeLog                           |  41 ++++++
 plugins/pychrysa/arch/Makefile.am   |   1 +
 plugins/pychrysa/arch/instruction.c |   3 +-
 plugins/pychrysa/arch/module.c      |   2 +
 plugins/pychrysa/arch/raw.c         | 263 ++++++++++++++++++++++++++++++++++++
 plugins/pychrysa/arch/raw.h         |  42 ++++++
 src/common/array.c                  |  81 +++++++++++
 src/common/array.h                  |   6 +
 src/format/dex/dex.c                |   3 +
 src/format/elf/elf.c                |  13 ++
 src/format/elf/strings.c            |  14 +-
 src/format/format-int.h             |   3 +
 src/format/format.c                 |  17 ++-
 src/format/preload.c                |  29 ++++
 src/format/preload.h                |   3 +
 tests/format/elf/Makefile           |   9 +-
 tests/format/elf/strings.asm        |  77 +++++++++++
 tests/format/elf/strings.py         |  74 ++++++++++
 18 files changed, 668 insertions(+), 13 deletions(-)
 create mode 100644 plugins/pychrysa/arch/raw.c
 create mode 100644 plugins/pychrysa/arch/raw.h
 create mode 100644 tests/format/elf/strings.asm
 create mode 100644 tests/format/elf/strings.py

diff --git a/ChangeLog b/ChangeLog
index 818be7e..e894d2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,44 @@
+17-05-12  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/pychrysa/arch/Makefile.am:
+	Add the 'raw.[ch]' files to libpychrysaarch_la_SOURCES.
+
+	* plugins/pychrysa/arch/instruction.c:
+	Typo.
+
+	* plugins/pychrysa/arch/module.c:
+	Register the new bindings.
+
+	* plugins/pychrysa/arch/raw.c:
+	* plugins/pychrysa/arch/raw.h:
+	New entries: add support for raw instructions with Python.
+
+	* src/common/array.c:
+	* src/common/array.h:
+	Provide a way to copy flat array content.
+
+	* src/format/dex/dex.c:
+	* src/format/elf/elf.c:
+	Update code.
+
+	* src/format/elf/strings.c:
+	Add the ELF strings to the preloaded instruction list.
+
+	* src/format/format-int.h:
+	* src/format/format.c:
+	Update code.
+
+	* src/format/preload.c:
+	* src/format/preload.h:
+	Copy preloaded information when requested.
+
+	* tests/format/elf/Makefile:
+	Include 'strings' as executable to build.
+
+	* tests/format/elf/strings.asm:
+	* tests/format/elf/strings.py:
+	New entries: extend the test suite for ELF strings.
+
 17-05-11  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/disass/area.c:
diff --git a/plugins/pychrysa/arch/Makefile.am b/plugins/pychrysa/arch/Makefile.am
index 21e3856..9421e04 100644
--- a/plugins/pychrysa/arch/Makefile.am
+++ b/plugins/pychrysa/arch/Makefile.am
@@ -8,6 +8,7 @@ libpychrysaarch_la_SOURCES =			\
 	module.h module.c					\
 	operand.h operand.c					\
 	processor.h processor.c				\
+	raw.h raw.c							\
 	vmpa.h vmpa.c
 
 libpychrysaarch_la_LIBADD =				\
diff --git a/plugins/pychrysa/arch/instruction.c b/plugins/pychrysa/arch/instruction.c
index 0e10728..0efca5a 100644
--- a/plugins/pychrysa/arch/instruction.c
+++ b/plugins/pychrysa/arch/instruction.c
@@ -229,6 +229,7 @@ static PyObject *py_arch_instruction_get_range(PyObject *self, void *closure)
 
 }
 
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
@@ -437,7 +438,7 @@ PyTypeObject *get_python_arch_instruction_type(void)
 
 bool register_python_arch_instruction(PyObject *module)
 {
-    PyTypeObject *py_arch_instruction_type; /* Type Python 'BinContent'    */
+    PyTypeObject *py_arch_instruction_type; /* Type Python 'ArchInstruc...'*/
     PyObject *dict;                         /* Dictionnaire du module      */
 
     py_arch_instruction_type = get_python_arch_instruction_type();
diff --git a/plugins/pychrysa/arch/module.c b/plugins/pychrysa/arch/module.c
index 68f702d..d9eabed 100644
--- a/plugins/pychrysa/arch/module.c
+++ b/plugins/pychrysa/arch/module.c
@@ -36,6 +36,7 @@
 #include "instruction.h"
 #include "operand.h"
 #include "processor.h"
+#include "raw.h"
 #include "vmpa.h"
 #include "arm/module.h"
 #include "../helpers.h"
@@ -146,6 +147,7 @@ bool add_arch_module_to_python_module(PyObject *super)
     result &= register_python_arch_operand(module);
     result &= register_python_arch_processor(module);
     result &= register_python_instr_iterator(module);
+    result &= register_python_raw_instruction(module);
     result &= register_python_vmpa(module);
     result &= register_python_mrange(module);
 
diff --git a/plugins/pychrysa/arch/raw.c b/plugins/pychrysa/arch/raw.c
new file mode 100644
index 0000000..39b5fe7
--- /dev/null
+++ b/plugins/pychrysa/arch/raw.c
@@ -0,0 +1,263 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * raw.c - équivalent Python du fichier "arch/raw.h"
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "raw.h"
+
+
+#include <pygobject.h>
+
+
+#include <arch/raw.h>
+
+
+#include "instruction.h"
+#include "../helpers.h"
+
+
+
+/* Indique si le contenu de l'instruction est du bourrage. */
+static PyObject *py_arch_instruction_is_padding(PyObject *, void *);
+
+/* Marque l'instruction comme ne contenant que du bourrage. */
+static int py_arch_instruction_mark_as_padding(PyObject *, PyObject *, void *);
+
+/* Indique si le contenu de l'instruction est un texte. */
+static PyObject *py_arch_instruction_is_string(PyObject *, void *);
+
+/* Marque l'instruction comme contenant une chaîne de texte. */
+static int py_arch_instruction_mark_as_string(PyObject *, PyObject *, void *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = classe représentant une instruction.               *
+*                closure = adresse non utilisée ici.                          *
+*                                                                             *
+*  Description : Indique si le contenu de l'instruction est du bourrage.      *
+*                                                                             *
+*  Retour      : Valeur associée à la propriété consultée.                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_instruction_is_padding(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Conversion à retourner      */
+    GRawInstruction *instr;                 /* Version native              */
+    bool state;                             /* Etat courant à consulter    */
+
+    instr = G_RAW_INSTRUCTION(pygobject_get(self));
+
+    state = g_raw_instruction_is_padding(instr);
+
+    result = state ? Py_True : Py_False;
+    Py_INCREF(result);
+
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                value   = valeur fournie à intégrer ou prendre en compte.    *
+*                closure = adresse non utilisée ici.                          *
+*                                                                             *
+*  Description : Marque l'instruction comme ne contenant que du bourrage.     *
+*                                                                             *
+*  Retour      : Bilan de l'opération pour Python.                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_arch_instruction_mark_as_padding(PyObject *self, PyObject *value, void *closure)
+{
+    bool state;                             /* Nouvel état à définir       */
+    GRawInstruction *instr;                 /* Version native              */
+
+    if (value != Py_True && value != Py_False)
+        return -1;
+
+    state = (value == Py_True);
+
+    instr = G_RAW_INSTRUCTION(pygobject_get(self));
+
+    g_raw_instruction_mark_as_padding(instr, state);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = classe représentant une instruction.               *
+*                closure = adresse non utilisée ici.                          *
+*                                                                             *
+*  Description : Indique si le contenu de l'instruction est un texte.         *
+*                                                                             *
+*  Retour      : Valeur associée à la propriété consultée.                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_instruction_is_string(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Conversion à retourner      */
+    GRawInstruction *instr;                 /* Version native              */
+    bool state;                             /* Etat courant à consulter    */
+
+    instr = G_RAW_INSTRUCTION(pygobject_get(self));
+
+    state = g_raw_instruction_is_string(instr);
+
+    result = state ? Py_True : Py_False;
+    Py_INCREF(result);
+
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                value   = valeur fournie à intégrer ou prendre en compte.    *
+*                closure = adresse non utilisée ici.                          *
+*                                                                             *
+*  Description : Marque l'instruction comme contenant une chaîne de texte.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération pour Python.                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_arch_instruction_mark_as_string(PyObject *self, PyObject *value, void *closure)
+{
+    bool state;                             /* Nouvel état à définir       */
+    GRawInstruction *instr;                 /* Version native              */
+
+    if (value != Py_True && value != Py_False)
+        return -1;
+
+    state = (value == Py_True);
+
+    instr = G_RAW_INSTRUCTION(pygobject_get(self));
+
+    g_raw_instruction_mark_as_string(instr, state);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_raw_instruction_type(void)
+{
+    static PyMethodDef py_raw_instruction_methods[] = {
+        { NULL }
+    };
+
+    static PyGetSetDef py_raw_instruction_getseters[] = {
+        {
+            "is_padding", py_arch_instruction_is_padding, py_arch_instruction_mark_as_padding,
+            "Report if the instruction is seen as padding.", NULL
+        },
+        {
+            "is_string", py_arch_instruction_is_string, py_arch_instruction_mark_as_string,
+            "Report if the instruction is seen as a string.", NULL
+        },
+        { NULL }
+    };
+
+    static PyTypeObject py_raw_instruction_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.arch.RawInstruction",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT,
+
+        .tp_doc         = "PyChrysalide raw instruction for a all architectures.",
+
+        .tp_methods     = py_raw_instruction_methods,
+        .tp_getset      = py_raw_instruction_getseters,
+
+    };
+
+    return &py_raw_instruction_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide.arch.ArchInstruction'. *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool register_python_raw_instruction(PyObject *module)
+{
+    PyTypeObject *py_raw_instruction_type;  /* Type Python 'RawInstruction'*/
+    PyObject *dict;                         /* Dictionnaire du module      */
+    PyTypeObject *base;                     /* Base parente pour héritage  */
+
+    py_raw_instruction_type = get_python_raw_instruction_type();
+
+    dict = PyModule_GetDict(module);
+
+    base = get_python_arch_instruction_type();
+
+    if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, py_raw_instruction_type, base))
+        return false;
+
+    return true;
+
+}
diff --git a/plugins/pychrysa/arch/raw.h b/plugins/pychrysa/arch/raw.h
new file mode 100644
index 0000000..4c1db7a
--- /dev/null
+++ b/plugins/pychrysa/arch/raw.h
@@ -0,0 +1,42 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * raw.h - prototypes pour l'équivalent Python du fichier "arch/raw.h"
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSA_ARCH_RAW_H
+#define _PLUGINS_PYCHRYSA_ARCH_RAW_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_raw_instruction_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.arch.RawInstruction'. */
+bool register_python_raw_instruction(PyObject *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSA_ARCH_RAW_H */
diff --git a/src/common/array.c b/src/common/array.c
index f520d1d..dcb9344 100644
--- a/src/common/array.c
+++ b/src/common/array.c
@@ -215,6 +215,87 @@ void reset_flat_array(flat_array_t **array)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : src    = tableau compressé à consulter.                      *
+*                dest   = tableau compressé à constituer. [OUT]               *
+*                size   = taille de ce nouvel élément.                        *
+*                notify = éventuelle fonction à appeler sur chaque élément.   *
+*                                                                             *
+*  Description : Copie le contenu d'un tableau d'éléments dans un autre.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void copy_flat_array_items(flat_array_t **src, flat_array_t **dest, size_t size, item_notify_cb notify)
+{
+    void *item;                             /* Elément manipulé            */
+    ext_flat_array_t *extended;             /* Version de tableau étendue  */
+    ext_flat_array_t *new;                  /* Nouvelle copie créée        */
+    size_t i;                               /* Boucle de parcours          */
+
+    assert(!FLAT_ARRAY_IS_LOCKED(*src));
+    assert(!FLAT_ARRAY_IS_LOCKED(*dest));
+
+    lock_flat_array(src);
+    lock_flat_array(dest);
+
+    assert(FLAT_ARRAY_IS_EMPTY(*dest));
+
+    if (FLAT_ARRAY_IS_EMPTY(*src))
+        goto cfai_done;
+
+    if (FLAT_ARRAY_HAS_NO_INDEX(*src))
+    {
+        item = GET_LONELY_ITEM(*src);
+
+        if (notify != NULL)
+            notify(item);
+
+        *dest = malloc(size);
+        memcpy(*dest, item, size);
+
+        lock_flat_array(dest);
+
+    }
+
+    else
+    {
+        extended = EXTENDED_ARRAY(*src);
+
+        new = (ext_flat_array_t *)malloc(sizeof(ext_flat_array_t));
+
+        new->items = malloc(extended->count * size);
+        new->count = extended->count;
+
+        memcpy(new->items, extended->items, new->count * size);
+
+        if (notify != NULL)
+            for (i = 0; i < new->count; i++)
+            {
+                item = (void *)(((char *)new->items) + i * size);
+                notify(item);
+            }
+
+        FLAT_ARRAY_SET_INDEX(new);
+
+        *dest = (flat_array_t *)new;
+
+        lock_flat_array(dest);
+
+    }
+
+ cfai_done:
+
+    unlock_flat_array(src);
+    unlock_flat_array(dest);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : array = tableau compressé à consulter.                       *
 *                                                                             *
 *  Description : Indique la quantité d'éléments présents dans le tableau.     *
diff --git a/src/common/array.h b/src/common/array.h
index bdb1ae4..546de1a 100644
--- a/src/common/array.h
+++ b/src/common/array.h
@@ -33,6 +33,9 @@
 /* Type déclaratif de tableau compressé, à 0 ou 1 élément */
 typedef void *flat_array_t;
 
+/* Parcours d'éléments */
+typedef void (* item_notify_cb) (void *);
+
 
 /* Verrouille l'accès à un tableau compressé. */
 void lock_flat_array(flat_array_t **);
@@ -43,6 +46,9 @@ void unlock_flat_array(flat_array_t **);
 /* Réinitialise un tableau sans traitement excessif. */
 void reset_flat_array(flat_array_t **);
 
+/* Copie le contenu d'un tableau d'éléments dans un autre. */
+void copy_flat_array_items(flat_array_t **, flat_array_t **, size_t, item_notify_cb);
+
 /* Indique la quantité d'éléments présents dans le tableau. */
 size_t count_flat_array_items(const flat_array_t *);
 
diff --git a/src/format/dex/dex.c b/src/format/dex/dex.c
index e34318f..b0b32a7 100755
--- a/src/format/dex/dex.c
+++ b/src/format/dex/dex.c
@@ -32,6 +32,7 @@
 
 #include "dex-int.h"
 #include "pool.h"
+#include "../../plugins/pglist.h"
 
 
 
@@ -287,6 +288,8 @@ GBinFormat *g_dex_format_new(GBinContent *content, GExeFormat *parent, GtkStatus
     if (!load_all_dex_classes(result, gid, status))
         goto gdfn_error;
 
+    preload_binary_format(PGA_FORMAT_PRELOAD, base, base->info, status);
+
     if (!g_executable_format_complete_loading(exe_format, status))
         goto gdfn_error;
 
diff --git a/src/format/elf/elf.c b/src/format/elf/elf.c
index bc48eb5..0336ba3 100644
--- a/src/format/elf/elf.c
+++ b/src/format/elf/elf.c
@@ -39,6 +39,7 @@
 #include "strings.h"
 #include "symbols.h"
 #include "../../gui/panels/log.h"
+#include "../../plugins/pglist.h"
 
 
 
@@ -293,6 +294,18 @@ GBinFormat *g_elf_format_new(GBinContent *content, GExeFormat *parent, GtkStatus
 
 
 
+    /**
+     * On inscrit les éléments préchargés avant tout !
+     *
+     * Cela permet de partir d'une base vide, et d'ajouter les instructions et
+     * leurs commentaires par paires.
+     *
+     * Ensuite, on inscrit le reste (comme les chaînes de caractères).
+     */
+
+    preload_binary_format(PGA_FORMAT_PRELOAD, base, base->info, status);
+
+
     if (!load_elf_symbols(result, status))
     {
         /* TODO */
diff --git a/src/format/elf/strings.c b/src/format/elf/strings.c
index 8901db9..d350200 100644
--- a/src/format/elf/strings.c
+++ b/src/format/elf/strings.c
@@ -37,7 +37,7 @@
 
 
 /* Enregistre toutes les chaînes de caractères trouvées. */
-bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t);
+static bool parse_elf_string_data(GElfFormat *, phys_t, phys_t, virt_t);
 
 
 
@@ -148,9 +148,10 @@ bool find_all_elf_strings(GElfFormat *format)
 *                                                                             *
 ******************************************************************************/
 
-bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address)
+static bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t address)
 {
     bool result;                            /* Bilan à faire remonter      */
+    GBinFormat *base;                       /* Autre version du format     */
     GBinContent *content;                   /* Contenu binaire à lire      */
     const bin_t *data;                      /* Contenu complet et original */
     vmpa2t pos;                             /* Tête de lecture             */
@@ -168,7 +169,9 @@ bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t
 
     /* Préparation des accès */
 
-    content = g_binary_format_get_content(G_BIN_FORMAT(format));
+    base = G_BIN_FORMAT(format);
+
+    content = g_binary_format_get_content(base);
 
     init_vmpa(&pos, start, address);
 
@@ -199,6 +202,9 @@ bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t
 
             g_raw_instruction_mark_as_string(G_RAW_INSTRUCTION(instr), true);
 
+            g_preload_info_add_instruction(base->info, instr);
+
+            g_object_ref(G_OBJECT(instr));
             ADD_STR_AS_SYM(format, symbol, instr);
 
             /* Jointure avec la chaîne précédente ? */
@@ -207,7 +213,7 @@ bool parse_elf_string_data(GElfFormat *format, phys_t start, phys_t size, virt_t
             {
                 init_vmpa(&pos, start + i, address + i);
 
-                label = create_string_label(G_BIN_FORMAT(format), &pos, end - i);
+                label = create_string_label(base, &pos, end - i);
 
                 g_binary_symbol_set_alt_label(symbol, label);
 
diff --git a/src/format/format-int.h b/src/format/format-int.h
index f82190f..30fb666 100644
--- a/src/format/format-int.h
+++ b/src/format/format-int.h
@@ -28,6 +28,7 @@
 #include "format.h"
 
 
+#include "preload.h"
 #include "../gtkext/gtkstatusstack.h"
 
 
@@ -62,6 +63,8 @@ struct _GBinFormat
 
     GRWLock pt_lock;                        /* Accès à la liste des points */
 
+    GPreloadInfo *info;                     /* Préchargements du format    */
+
     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 1eef759..d5cbda4 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -99,11 +99,20 @@ static void g_binary_format_init(GBinFormat *format)
 {
     g_rw_lock_init(&format->pt_lock);
 
+    format->info = g_preload_info_new();
+
     g_rw_lock_init(&format->syms_lock);
 
 }
 
 
+
+/* FIXME : g_object_unref(format->info); */
+
+/* FIXME : g_rw_lock_clear(&format->syms_lock);*/
+
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format = instance à traiter.                                 *
@@ -128,12 +137,6 @@ bool g_binary_format_complete_loading(GBinFormat *format, GtkStatusStack *status
 }
 
 
-
-
-/* FIXME : g_rw_lock_clear(&format->syms_lock);*/
-
-
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : format  = description de l'exécutable à consulter.           *
@@ -260,7 +263,7 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent
 
 void g_binary_format_preload_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status)
 {
-    preload_binary_format(PGA_FORMAT_PRELOAD, format, G_PRELOAD_INFO(ctx), status);
+    g_preload_info_copy(format->info, G_PRELOAD_INFO(ctx));
 
 }
 
diff --git a/src/format/preload.c b/src/format/preload.c
index 750a67c..2eec92e 100644
--- a/src/format/preload.c
+++ b/src/format/preload.c
@@ -181,6 +181,35 @@ GPreloadInfo *g_preload_info_new(void)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : src  = collecte à consulter.                                 *
+*                dest = collecte à constituer. [OUT]                          *
+*                                                                             *
+*  Description : Copie le contenu d'une collecte d'informations préchargées.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_preload_info_copy(GPreloadInfo *src, GPreloadInfo *dest)
+{
+    void inc_preloaded_item_ref(GObject **item)
+    {
+        g_object_ref(*item);
+    }
+
+    copy_flat_array_items(&src->instructions, &dest->instructions,
+                          sizeof(GArchInstruction *), (item_notify_cb)inc_preloaded_item_ref);
+
+    copy_flat_array_items(&src->comments, &dest->comments,
+                          sizeof(GDbComment *), (item_notify_cb)inc_preloaded_item_ref);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : info = préchargements à mettre à jour.                       *
 *                                                                             *
 *  Description : Verrouille les accès à la liste des instructions.            *
diff --git a/src/format/preload.h b/src/format/preload.h
index d88366a..59c81b7 100644
--- a/src/format/preload.h
+++ b/src/format/preload.h
@@ -54,6 +54,9 @@ GType g_preload_info_get_type(void);
 /* Crée une nouvelle collecte d'informations préchargées. */
 GPreloadInfo *g_preload_info_new(void);
 
+/* Copie le contenu d'une collecte d'informations préchargées. */
+void g_preload_info_copy(GPreloadInfo *, GPreloadInfo *);
+
 /* Verrouille les accès à la liste des instructions. */
 void g_preload_info_lock_instructions(GPreloadInfo *);
 
diff --git a/tests/format/elf/Makefile b/tests/format/elf/Makefile
index 8695bb1..0511308 100644
--- a/tests/format/elf/Makefile
+++ b/tests/format/elf/Makefile
@@ -1,5 +1,5 @@
 
-EXECUTABLES=oob_section_name overlapping_areas
+EXECUTABLES=oob_section_name overlapping_areas strings
 
 all: $(EXECUTABLES)
 
@@ -9,6 +9,13 @@ oob_section_name: oob_section_name.o
 overlapping_areas: overlapping_areas.o
 	$(ARM_CROSS)objcopy $< -O binary $@
 
+strings: strings.asm
+	grep .global strings.asm | cut -d ' ' -f 2 > keep.lst
+	$(ARM_CROSS)as -o strings.o strings.asm
+	$(ARM_CROSS)ld -s --retain-symbols-file=keep.lst -o strings strings.o
+	rm -f keep.lst
+
+
 %.o: %.asm
 	$(ARM_CROSS)as -c $< -o $@
 
diff --git a/tests/format/elf/strings.asm b/tests/format/elf/strings.asm
new file mode 100644
index 0000000..d9a75d3
--- /dev/null
+++ b/tests/format/elf/strings.asm
@@ -0,0 +1,77 @@
+
+.data
+
+.global msg
+.global no_arg_msg
+.global got_arg_msg
+
+msg:
+    .ascii      "Hello, ARM!\n"
+
+len = . - msg
+
+no_arg_msg:
+    .ascii      "No command line argument...\n"
+
+no_arg_len = . - no_arg_msg
+
+got_arg_msg:
+    .ascii      "Got command line argument(s)...\n"
+
+got_arg_len = . - got_arg_msg
+
+.text
+
+.global do_syscalls
+
+do_syscalls:
+
+    /**
+     * syscall write(int fd, const void *buf, size_t count)
+     */
+
+    mov     %r0, $1     /* fd -> stdout */
+    ldr     %r1, =msg   /* buf -> msg */
+    ldr     %r2, =len   /* count -> len(msg) */
+    mov     %r7, $4     /* write is syscall #4 */
+    swi     $0          /* invoke syscall */
+
+    /**
+     * syscall write(int fd, const void *buf, size_t count)
+     */
+
+    mov     %r0, $2     /* fd -> stderr */
+    mov     %r7, $4     /* write is syscall #4 */
+
+    ldr     %r3, [sp]   /* argc */
+    cmp     %r3, $1
+
+    beq     no_arg
+
+    ldr     %r1, =got_arg_msg   /* buf -> msg */
+    ldr     %r2, =got_arg_len   /* count -> len(msg) */
+
+    b       process_arg
+
+no_arg:
+
+    ldr     %r1, =no_arg_msg   /* buf -> msg */
+    ldr     %r2, =no_arg_len   /* count -> len(msg) */
+
+process_arg:
+
+    swi     $0          /* invoke syscall */
+
+    /**
+     * syscall exit(int status)
+     */
+
+    mov     %r0, $123   /* status -> 0 */
+    mov     %r7, $1     /* exit is syscall #1 */
+    swi     $0          /* invoke syscall */
+
+.global _start
+
+_start:
+
+    bl      do_syscalls
diff --git a/tests/format/elf/strings.py b/tests/format/elf/strings.py
new file mode 100644
index 0000000..0e09d75
--- /dev/null
+++ b/tests/format/elf/strings.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+
+# S'assure que les chaînes présentes sont bien chargées en tant que telles.
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.analysis import LoadedBinary
+from pychrysalide.arch import RawInstruction
+from threading import Event
+import os
+import sys
+
+
+class TestElfString(ChrysalideTestCase):
+    """TestCase for ELF strings."""
+
+    @classmethod
+    def setUpClass(cls):
+
+        super(TestElfString, 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 strings 2>&1 > /dev/null' % dirpath)
+
+
+    def testElfStrings(self):
+        """Ensure available strings are loaded as strings."""
+
+        fullname = sys.modules[self.__class__.__module__].__file__
+        filename = os.path.basename(fullname)
+
+        baselen = len(fullname) - len(filename)
+
+        cnt = FileContent(fullname[:baselen] + 'strings')
+        self.assertIsNotNone(cnt)
+
+        binary = LoadedBinary(cnt)
+        self.assertIsNotNone(binary)
+
+        def disass_done(binary):
+            worker.set()
+
+        binary.connect('disassembly-done', disass_done)
+
+        worker = Event()
+
+        binary.analyse()
+
+        worker.wait()
+
+        expected = {
+            'hello_arm_str'        : False,
+            'no_command_line_str'  : False,
+            'got_command_line_str' : False
+        }
+
+        for sym in binary.format.symbols:
+
+            if sym.label in expected.keys():
+
+                ins = binary.processor.find_instr_by_addr(sym.range.addr)
+
+                if type(ins) is RawInstruction:
+                    expected[sym.label] = ins.is_string
+
+        for k in expected.keys():
+            self.assertTrue(expected[k])
-- 
cgit v0.11.2-87-g4458