From 13be5aa2ac44f7bfc70ee25e7ba20ae2adf58ad5 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 7 May 2017 23:13:00 +0200
Subject: Made the preloading process work as intended.

---
 ChangeLog                    | 21 ++++++++++++
 src/analysis/disass/area.c   |  4 ++-
 src/analysis/disass/fetch.c  | 20 +++++++----
 src/analysis/disass/output.c | 55 +++++++++++++++++++-----------
 src/common/array.c           | 58 +++++++++++++++++++++++++++++++
 src/common/array.h           |  3 ++
 src/format/format.c          | 27 ++++++++++++---
 src/format/format.h          |  7 ++--
 src/format/preload.c         | 81 ++++++++++++++++++++++----------------------
 src/format/preload.h         |  8 ++---
 10 files changed, 207 insertions(+), 77 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index dbced06..8f374bd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,26 @@
 17-05-07  Cyrille Bagard <nocbos@gmail.com>
 
+	* src/analysis/disass/area.c:
+	Update code.
+
+	* src/analysis/disass/fetch.c:
+	* src/analysis/disass/output.c:
+	Make the preloading process work as intended.
+
+	* src/common/array.c:
+	* src/common/array.h:
+	Reset a flat array when needed.
+
+	* src/format/format.c:
+	* src/format/format.h:
+	Distinguish two steps to extend disassembly context: setup and start.
+
+	* src/format/preload.c:
+	* src/format/preload.h:
+	Optimize memory access for instructions and comments.
+
+17-05-07  Cyrille Bagard <nocbos@gmail.com>
+
 	* src/arch/archbase.h:
 	Create a macro for memory data signs.
 
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c
index 130a7f0..f01b89c 100644
--- a/src/analysis/disass/area.c
+++ b/src/analysis/disass/area.c
@@ -1556,7 +1556,7 @@ static void g_area_collector_do_insert(GAreaCollector *collector, GtkStatusStack
 
     for (i = collector->start; i < collector->stop; i++)
     {
-        instr = _g_preload_info_get_instruction(collector->info, i);
+        instr = _g_preload_info_grab_instruction(collector->info, i);
         range = g_arch_instruction_get_range(instr);
         addr = get_mrange_addr(range);
 
@@ -1651,6 +1651,8 @@ void populate_fresh_memory_areas(wgroup_id_t gid, GtkStatusStack *status, mem_ar
 
     _g_preload_info_drain_instructions(info);
 
+    assert(_g_preload_info_count_instructions(info) == 0);
+
     g_preload_info_unlock_instructions(info);
 
     gtk_status_stack_remove_activity(status, id);
diff --git a/src/analysis/disass/fetch.c b/src/analysis/disass/fetch.c
index c5489d6..586c084 100644
--- a/src/analysis/disass/fetch.c
+++ b/src/analysis/disass/fetch.c
@@ -417,8 +417,6 @@ GArchInstruction **disassemble_binary_content(GLoadedBinary *binary, GProcContex
 
     template.areas = collect_memory_areas(gid, status, binary, length, &template.count);
 
-    populate_fresh_memory_areas(gid, status, template.areas, template.count, G_PRELOAD_INFO(ctx));
-
     template.status = status;
 
     /* Amorce des traitements */
@@ -432,7 +430,17 @@ GArchInstruction **disassemble_binary_content(GLoadedBinary *binary, GProcContex
     g_proc_context_attach_counter(template.ctx, &remaining_counter);
 
     /**
-     * Première phase de désassemblage : suivi des chemins tracés.
+     * Première phase de désassemblage : intégration des infos du format.
+     */
+
+    g_binary_format_preload_disassembling_context(format, template.ctx, status);
+
+    populate_fresh_memory_areas(gid, status, template.areas, template.count, G_PRELOAD_INFO(ctx));
+
+    g_work_queue_wait_for_completion(queue, gid);
+
+    /**
+     * Seconde phase : suivi des chemins tracés.
      */
 
     g_work_queue_set_extra_wait_callback(queue, gid,
@@ -445,12 +453,12 @@ GArchInstruction **disassemble_binary_content(GLoadedBinary *binary, GProcContex
                                                 _("Disassembling following the execution flow..."),
                                                 length);
 
-    g_binary_format_setup_disassembling_context(format, template.ctx, status);
+    g_binary_format_activate_disassembling_context(format, template.ctx, status);
 
     g_work_queue_wait_for_completion(queue, gid);
 
     /**
-     * Seconde phase : on comble les trous laissés.
+     * Troisième phase : on comble les trous laissés.
      */
 
     gtk_status_stack_update_activity(status, template.id, _("Disassembling the remaining instructions..."));
@@ -466,7 +474,7 @@ GArchInstruction **disassemble_binary_content(GLoadedBinary *binary, GProcContex
     gtk_status_stack_remove_activity(status, template.id);
 
     /**
-     * Troisième et dernière phase : récolte des fruits.
+     * Quatrième et dernière phase : récolte des fruits.
      */
 
     result = collect_disassembled_instructions(gid, status, template.areas, template.count, count);
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index 5a74d92..421cfb6 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -24,6 +24,9 @@
 #include "output.h"
 
 
+#include <assert.h>
+
+
 #include <i18n.h>
 
 
@@ -67,6 +70,8 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang,
     bool expect_outro;                      /* Fin de zone de code définie */
 
 
+    size_t comment_count;                   /* Quantité de commentaires    */
+    size_t comment_index;                   /* Indice du commantaire actif */
     GDbComment *comment;                    /* Commentaire à ajouter       */
     const vmpa2t *caddr;                    /* Localisation du commentaire */
 
@@ -137,11 +142,22 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang,
 
     expect_outro = false;
 
-    comment = g_preload_info_pop_comment(info);
+    g_preload_info_lock_comments(info);
 
-    if (comment != NULL)
+    comment_count = _g_preload_info_count_comments(info);
+    comment_index = 0;
+
+    if (comment_index < comment_count)
+    {
+        comment = _g_preload_info_grab_comment(info, comment_index);
         caddr = g_db_comment_get_address(comment);
 
+        comment_index++;
+
+    }
+
+    else
+        comment = NULL;
 
     /*
     if (comment != NULL)
@@ -306,32 +322,29 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang,
         {
             compared = cmp_vmpa(iaddr, caddr);
 
-            if (compared == 0)
+            if (compared >= 0)
             {
-                if (g_loaded_binary_add_to_collection(binary, G_DB_ITEM(comment)))
+                if (compared == 0)
                     g_db_item_apply(G_DB_ITEM(comment), binary);
 
                 else
-                    g_object_unref(G_OBJECT(comment));
-
-            }
-
-            else if (compared > 0)
-            {
-                log_variadic_message(LMT_BAD_BINARY,
-                                     _("Unable to find a proper location for comment '%s' @ 0x%08x"),
-                                     g_db_comment_get_text(comment), get_phy_addr(caddr));
+                    log_variadic_message(LMT_BAD_BINARY,
+                                         _("Unable to find a proper location for comment '%s' @ 0x%08x"),
+                                         g_db_comment_get_text(comment), get_phy_addr(caddr));
 
                 g_object_unref(G_OBJECT(comment));
 
-            }
+                if (comment_index < comment_count)
+                {
+                    comment = _g_preload_info_grab_comment(info, comment_index);
+                    caddr = g_db_comment_get_address(comment);
 
-            if (compared >= 0)
-            {
-                comment = g_preload_info_pop_comment(info);
+                    comment_index++;
 
-                if (comment != NULL)
-                    caddr = g_db_comment_get_address(comment);
+                }
+
+                else
+                    comment = NULL;
 
             }
 
@@ -343,6 +356,10 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang,
 
     }
 
+    assert(comment_index == comment_count);
+
+    g_preload_info_unlock_comments(info);
+
     gtk_status_stack_remove_activity(status, id);
 
     g_arch_processor_unlock(proc);
diff --git a/src/common/array.c b/src/common/array.c
index e4e7bb1..f520d1d 100644
--- a/src/common/array.c
+++ b/src/common/array.c
@@ -157,6 +157,64 @@ void unlock_flat_array(flat_array_t **array)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : array = tableau compressé à mettre à jour. [OUT]             *
+*                                                                             *
+*  Description : Réinitialise un tableau sans traitement excessif.            *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void reset_flat_array(flat_array_t **array)
+{
+    size_t count;                           /* Nombre d'éléments présents  */
+    ext_flat_array_t *extended;             /* Version de tableau étendue  */
+
+    assert(FLAT_ARRAY_IS_LOCKED(*array));
+
+    count = count_flat_array_items(*array);
+
+    switch (count)
+    {
+        case 0:
+            break;
+
+        case 1:
+
+            assert(FLAT_ARRAY_HAS_NO_INDEX(*array));
+
+            free(GET_LONELY_ITEM(*array));
+
+            *array = NULL;
+
+            lock_flat_array(array);
+
+            break;
+
+        default:
+
+            assert(!FLAT_ARRAY_HAS_NO_INDEX(*array));
+
+            extended = EXTENDED_ARRAY(*array);
+
+            free(extended->items);
+            free(extended);
+
+            *array = NULL;
+
+            lock_flat_array(array);
+
+            break;
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  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 2dd5b9f..bdb1ae4 100644
--- a/src/common/array.h
+++ b/src/common/array.h
@@ -40,6 +40,9 @@ void lock_flat_array(flat_array_t **);
 /* Déverrouille l'accès à un tableau compressé. */
 void unlock_flat_array(flat_array_t **);
 
+/* Réinitialise un tableau sans traitement excessif. */
+void reset_flat_array(flat_array_t **);
+
 /* 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/format.c b/src/format/format.c
index 11216a2..1eef759 100644
--- a/src/format/format.c
+++ b/src/format/format.c
@@ -250,7 +250,7 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent
 *                ctx    = contexte de désassemblage à préparer.               *
 *                status = barre de statut à tenir informée.                   *
 *                                                                             *
-*  Description : Fournit un contexte initialisé pour un désassemblage.        *
+*  Description : Intègre dans un contexte les informations tirées d'un format.*
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -258,12 +258,31 @@ void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, bool ent
 *                                                                             *
 ******************************************************************************/
 
-void g_binary_format_setup_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status)
+void g_binary_format_preload_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status)
 {
-    size_t i;                               /* Boucle de parcours          */
-
     preload_binary_format(PGA_FORMAT_PRELOAD, format, G_PRELOAD_INFO(ctx), status);
 
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : format = description de l'exécutable à consulter.            *
+*                ctx    = contexte de désassemblage à préparer.               *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Définit les points de départ d'un contexte de désassemblage. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_binary_format_activate_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status)
+{
+    size_t i;                               /* Boucle de parcours          */
+
     g_rw_lock_reader_lock(&format->pt_lock);
 
     for (i = 0; i < format->ep_count; i++)
diff --git a/src/format/format.h b/src/format/format.h
index b04f11b..e1c4e37 100644
--- a/src/format/format.h
+++ b/src/format/format.h
@@ -65,8 +65,11 @@ SourceEndian g_binary_format_get_endianness(const GBinFormat *);
 /* Enregistre une adresse comme début d'une zone de code. */
 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(GBinFormat *, GProcContext *, GtkStatusStack *);
+/* Intègre dans un contexte les informations tirées d'un format. */
+void g_binary_format_preload_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *);
+
+/* Définit les points de départ d'un contexte de désassemblage. */
+void g_binary_format_activate_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *);
 
 /* Ajoute un symbole à la collection du format binaire. */
 bool g_binary_format_add_symbol(GBinFormat *, GBinSymbol *);
diff --git a/src/format/preload.c b/src/format/preload.c
index 145dfd9..750a67c 100644
--- a/src/format/preload.c
+++ b/src/format/preload.c
@@ -110,6 +110,12 @@ static void g_preload_info_dispose(GPreloadInfo *info)
 
     g_preload_info_lock_instructions(info);
 
+    while (_g_preload_info_count_instructions(info) > 0)
+    {
+        instr = _g_preload_info_grab_instruction(info, 0);
+        g_object_unref(G_OBJECT(instr));
+    }
+
     _g_preload_info_drain_instructions(info);
 
     g_preload_info_unlock_instructions(info);
@@ -118,14 +124,12 @@ static void g_preload_info_dispose(GPreloadInfo *info)
 
     while (_g_preload_info_count_comments(info) > 0)
     {
-        comment = _g_preload_info_get_comment(info, 0);
-
-        rem_item_from_flat_array(&info->comments, 0, sizeof(GDbComment *));
-
+        comment = _g_preload_info_grab_comment(info, 0);
         g_object_unref(G_OBJECT(comment));
-
     }
 
+    _g_preload_info_drain_comments(info);
+
     g_preload_info_unlock_comments(info);
 
     G_OBJECT_CLASS(g_preload_info_parent_class)->dispose(G_OBJECT(info));
@@ -286,7 +290,7 @@ size_t _g_preload_info_count_instructions(const GPreloadInfo *info)
 *                                                                             *
 ******************************************************************************/
 
-GArchInstruction *_g_preload_info_get_instruction(const GPreloadInfo *info, size_t index)
+GArchInstruction *_g_preload_info_grab_instruction(const GPreloadInfo *info, size_t index)
 {
     GArchInstruction *result;               /* Opérande à retourner        */
     GArchInstruction **ptr;                 /* Adresse dans le tableau     */
@@ -295,7 +299,14 @@ GArchInstruction *_g_preload_info_get_instruction(const GPreloadInfo *info, size
 
     result = *ptr;
 
-    g_object_ref(G_OBJECT(result));
+    /**
+     * La propriétée de l'élément est transmise à l'appelant.
+     *
+     * Ainsi, pour vider une liste via _g_preload_info_drain_instructions(),
+     * il suffit juste de libérer la mémoire occupée pour le stockage sans
+     * se préoccuper des références contenues ; le gain de temps est important
+     * puisqu'on évite là un parcours et des déplacements.
+     */
 
     return result;
 
@@ -354,17 +365,12 @@ GArchInstruction *g_preload_info_pop_instruction(GPreloadInfo *info)
 
 void _g_preload_info_drain_instructions(GPreloadInfo *info)
 {
-    GArchInstruction *instr;                /* Instruction à libérer       */
-
-    while (_g_preload_info_count_instructions(info) > 0)
-    {
-        instr = _g_preload_info_get_instruction(info, 0);
-
-        rem_item_from_flat_array(&info->instructions, 0, sizeof(GArchInstruction *));
-
-        g_object_unref(G_OBJECT(instr));
+    /**
+     * A utiliser en conjonction avec _g_preload_info_grab_instruction()
+     * uniquement.
+     */
 
-    }
+    reset_flat_array(&info->instructions);
 
 }
 
@@ -480,7 +486,7 @@ size_t _g_preload_info_count_comments(const GPreloadInfo *info)
 *                                                                             *
 ******************************************************************************/
 
-GDbComment *_g_preload_info_get_comment(const GPreloadInfo *info, size_t index)
+GDbComment *_g_preload_info_grab_comment(const GPreloadInfo *info, size_t index)
 {
     GDbComment *result;                     /* Opérande à retourner        */
     GDbComment **ptr;                       /* Adresse dans le tableau     */
@@ -489,7 +495,14 @@ GDbComment *_g_preload_info_get_comment(const GPreloadInfo *info, size_t index)
 
     result = *ptr;
 
-    g_object_ref(G_OBJECT(result));
+    /**
+     * La propriétée de l'élément est transmise à l'appelant.
+     *
+     * Ainsi, pour vider une liste via _g_preload_info_drain_comments(),
+     * il suffit juste de libérer la mémoire occupée pour le stockage sans
+     * se préoccuper des références contenues ; le gain de temps est important
+     * puisqu'on évite là un parcours et des déplacements.
+     */
 
     return result;
 
@@ -500,35 +513,21 @@ GDbComment *_g_preload_info_get_comment(const GPreloadInfo *info, size_t index)
 *                                                                             *
 *  Paramètres  : info = instance à manipuler.                                 *
 *                                                                             *
-*  Description : Dépile un commentaire présent dans les préchargements.       *
+*  Description : Retire des préchargements tous les commentaires.             *
 *                                                                             *
-*  Retour      : Commentaire retiré ou NULL si aucune.                        *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GDbComment *g_preload_info_pop_comment(GPreloadInfo *info)
+void _g_preload_info_drain_comments(GPreloadInfo *info)
 {
-    GDbComment *result;                     /* Instruction à retourner     */
-    GDbComment **ptr;                       /* Adresse dans le tableau     */
-
-    g_preload_info_lock_comments(info);
+    /**
+     * A utiliser en conjonction avec _g_preload_info_grab_comment()
+     * uniquement.
+     */
 
-    if (_g_preload_info_count_comments(info) == 0)
-        result = NULL;
-
-    else
-    {
-        ptr = get_flat_array_item(info->comments, 0, sizeof(GDbComment *));
-        result = *ptr;
-
-        rem_item_from_flat_array(&info->comments, 0, sizeof(GDbComment *));
-
-    }
-
-    g_preload_info_unlock_comments(info);
-
-    return result;
+    reset_flat_array(&info->comments);
 
 }
diff --git a/src/format/preload.h b/src/format/preload.h
index a915462..d88366a 100644
--- a/src/format/preload.h
+++ b/src/format/preload.h
@@ -67,7 +67,7 @@ void g_preload_info_add_instruction(GPreloadInfo *, GArchInstruction *);
 size_t _g_preload_info_count_instructions(const GPreloadInfo *);
 
 /* Fournit une instruction préchargée donnée. */
-GArchInstruction *_g_preload_info_get_instruction(const GPreloadInfo *, size_t);
+GArchInstruction *_g_preload_info_grab_instruction(const GPreloadInfo *, size_t);
 
 /* Dépile une instruction présente dans les préchargements. */
 GArchInstruction *g_preload_info_pop_instruction(GPreloadInfo *);
@@ -88,10 +88,10 @@ void g_preload_info_add_comment(GPreloadInfo *, GDbComment *);
 size_t _g_preload_info_count_comments(const GPreloadInfo *);
 
 /* Fournit un commentaire préchargé donné. */
-GDbComment *_g_preload_info_get_comment(const GPreloadInfo *, size_t);
+GDbComment *_g_preload_info_grab_comment(const GPreloadInfo *, size_t);
 
-/* Dépile un commentaire présent dans les préchargements. */
-GDbComment *g_preload_info_pop_comment(GPreloadInfo *);
+/* Retire des préchargements tous les commentaires. */
+void _g_preload_info_drain_comments(GPreloadInfo *);
 
 
 
-- 
cgit v0.11.2-87-g4458