From d7f78fe9a75d96b6f3d441335dcf50a5c026d8ea Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 13 Jul 2017 00:47:38 +0200
Subject: Taken into account that raw immediate values can be used more than
 once.

---
 ChangeLog                       |  17 +++++
 src/analysis/db/items/comment.c |   2 +-
 src/arch/arm/v7/fetch.c         |  38 ++++++++++--
 src/common/array.c              |  66 ++++++++++++++++++++
 src/common/array.h              |   3 +
 src/format/preload.c            | 134 ++++++++++++++++++++++++++++++++++++++--
 src/format/preload.h            |  12 ++++
 src/glibext/gbuffercache.c      |  31 ++++++++--
 8 files changed, 285 insertions(+), 18 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6562f78..9064308 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+17-07-13  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/db/items/comment.c:
+	Collect the text from all portions, not the first one.
+
+	* src/arch/arm/v7/fetch.c:
+	Take into account that raw immediate values can be used more than once.
+
+	* src/common/array.c:
+	* src/common/array.h:
+	* src/format/preload.c:
+	* src/format/preload.h:
+	Extend code.
+
+	* src/glibext/gbuffercache.c:
+	Handle comments with more than one line.
+
 17-07-12  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/disass/dragon.c:
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index 9368291..cad2d64 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -1129,7 +1129,7 @@ char *g_db_comment_get_text(GDbComment *comment)
 
     for (i = 0; i < count; i++)
     {
-        string = get_flat_array_item(comment->text, 0, sizeof(rle_string));
+        string = get_flat_array_item(comment->text, i, sizeof(rle_string));
 
         assert(!is_rle_string_empty(string));
 
diff --git a/src/arch/arm/v7/fetch.c b/src/arch/arm/v7/fetch.c
index 929c877..42788af 100644
--- a/src/arch/arm/v7/fetch.c
+++ b/src/arch/arm/v7/fetch.c
@@ -367,6 +367,7 @@ void help_fetching_with_instruction_ldr_literal_with_orig(GArchInstruction *inst
     uint32_t target;                        /* Adresse virtuelle visée     */
     vmpa2t pos;                             /* Tête de lecture de valeur   */
     VMPA_BUFFER(loc);                       /* Adresse au format texte     */
+    GPreloadInfo *info;                     /* Informations préchargées    */
     GArchInstruction *loaded;               /* Instruction de valeur       */
     char *desc;                             /* Description d'accompagnement*/
     GDbComment *comment;                    /* Définition de commentaire   */
@@ -439,18 +440,43 @@ void help_fetching_with_instruction_ldr_literal_with_orig(GArchInstruction *inst
 
     copy_vmpa(&pos, &loaded_addr);
 
-    loaded = g_raw_instruction_new_from_value(&pos, MDS_32_BITS_UNSIGNED, target);
+    info = G_PRELOAD_INFO(context);
 
-    g_preload_info_add_instruction(G_PRELOAD_INFO(context), loaded);
+    g_preload_info_lock_instructions(info);
+
+    if (!_g_preload_info_has_instruction_at(info, &loaded_addr))
+    {
+        loaded = g_raw_instruction_new_from_value(&pos, MDS_32_BITS_UNSIGNED, target);
+        _g_preload_info_add_instruction(info, loaded);
+    }
+
+    g_preload_info_unlock_instructions(info);
 
     vmpa2_virt_to_string(get_mrange_addr(range), MDS_32_BITS, loc, NULL);
     asprintf(&desc, _("Value used @ %s"), loc);
 
-    comment = g_db_comment_new_inlined(&loaded_addr, BLF_HAS_CODE, false);
-    g_db_comment_add_static_text(comment, desc);
-    g_db_item_set_volatile(G_DB_ITEM(comment), true);
+    g_preload_info_lock_comments(info);
+
+    comment = _g_preload_info_find_comment_at(info, &loaded_addr);
+
+    if (comment != NULL)
+    {
+        g_db_comment_add_static_text(comment, "\n");
+        g_db_comment_add_dynamic_text(comment, desc);
+    }
+
+    else
+    {
+        comment = g_db_comment_new_inlined(&loaded_addr, BLF_HAS_CODE, false);
+        g_db_item_set_volatile(G_DB_ITEM(comment), true);
+
+        g_db_comment_add_dynamic_text(comment, desc);
+
+        _g_preload_info_add_comment(info, comment);
+
+    }
 
-    g_preload_info_add_comment(G_PRELOAD_INFO(context), comment);
+    g_preload_info_unlock_comments(info);
 
     /* Mise à jour de l'affichage et conclusion */
 
diff --git a/src/common/array.c b/src/common/array.c
index dcb9344..36c30a1 100644
--- a/src/common/array.c
+++ b/src/common/array.c
@@ -632,3 +632,69 @@ void *get_flat_array_item(flat_array_t *array, size_t index, size_t size)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : array  = tableau compressé à consulter.                      *
+*                size   = taille de ce nouvel élément.                        *
+*                compar = méthode de comparaison entre éléments.              *
+*                key    = élément de comparaison fourni.                      *
+*                                                                             *
+*  Description : Recherche un élément dans un tableau trié.                   *
+*                                                                             *
+*  Retour      : Eventuel élément trouvé ou NULL.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void *find_item_in_flat_array(flat_array_t *array, size_t size, __compar_fn_t compar, const void *key)
+{
+    void *result;                           /* Trouvaille à retourner      */
+    size_t count;                           /* Nombre d'éléments présents  */
+    void *item;                             /* Elément isolé présent       */
+    ext_flat_array_t *extended;             /* Version de tableau étendue  */
+    size_t index;                           /* Indice de l'élément trouvé  */
+
+    assert(FLAT_ARRAY_IS_LOCKED(array));
+
+    count = count_flat_array_items(array);
+
+    switch (count)
+    {
+        case 0:
+            result = NULL;
+            break;
+
+        case 1:
+
+            assert(FLAT_ARRAY_HAS_NO_INDEX(array));
+
+            item = GET_LONELY_ITEM(array);
+
+            if (compar(key, item) == 0)
+                result = item;
+            else
+                result = NULL;
+
+            break;
+
+        default:
+
+            assert(!FLAT_ARRAY_HAS_NO_INDEX(array));
+
+            extended = EXTENDED_ARRAY(array);
+
+            if (bsearch_index(key, extended->items, extended->count, size, compar, &index))
+                result = (void *)(((char *)extended->items) + index * size);
+            else
+                result = NULL;
+
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/src/common/array.h b/src/common/array.h
index 546de1a..5ddc9ba 100644
--- a/src/common/array.h
+++ b/src/common/array.h
@@ -67,6 +67,9 @@ void rem_item_from_flat_array(flat_array_t **, size_t, size_t);
 /* Fournit un élément présent dans un tableau compressé. */
 void *get_flat_array_item(flat_array_t *, size_t, size_t);
 
+/* Recherche un élément dans un tableau trié. */
+void *find_item_in_flat_array(flat_array_t *, size_t, __compar_fn_t, const void *);
+
 
 
 #endif  /* _COMMON_ARRAY_H */
diff --git a/src/format/preload.c b/src/format/preload.c
index 2eec92e..7f7a435 100644
--- a/src/format/preload.c
+++ b/src/format/preload.c
@@ -261,6 +261,30 @@ void g_preload_info_unlock_instructions(GPreloadInfo *info)
 
 void g_preload_info_add_instruction(GPreloadInfo *info, GArchInstruction *instr)
 {
+    g_preload_info_lock_instructions(info);
+
+    _g_preload_info_add_instruction(info, instr);
+
+    g_preload_info_unlock_instructions(info);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info  = instance à mettre à jour.                            *
+*                instr = instruction à venir associer.                        *
+*                                                                             *
+*  Description : Ajoute une instruction supplémentaire aux préchargements.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void _g_preload_info_add_instruction(GPreloadInfo *info, GArchInstruction *instr)
+{
     int cmp_instr_by_addr(const GArchInstruction **a, const GArchInstruction **b)
     {
         const mrange_t *range_a;            /* Emplacement pour l'instr. A */
@@ -273,12 +297,46 @@ void g_preload_info_add_instruction(GPreloadInfo *info, GArchInstruction *instr)
 
     }
 
-    g_preload_info_lock_instructions(info);
-
     insert_item_into_flat_array(&info->instructions, &instr, sizeof(GArchInstruction *),
                                 (__compar_fn_t)cmp_instr_by_addr);
 
-    g_preload_info_unlock_instructions(info);
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info  = instance à mettre à jour.                            *
+*                addr = localisation du commentaire recherché.                *
+*                                                                             *
+*  Description : Détermine si une instruction est présente à un point donné.  *
+*                                                                             *
+*  Retour      : true si une instruction existe à l'emplacement indiqué.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool _g_preload_info_has_instruction_at(GPreloadInfo *info, const vmpa2t *addr)
+{
+    bool result;                            /* Bilan à retourner           */
+    GArchInstruction **ptr;                 /* Adresse dans le tableau     */
+
+    int cmp_instr_by_addr(const vmpa2t *key, const GArchInstruction **i)
+    {
+        const mrange_t *range;              /* Emplacement pour l'instr.   */
+
+        range = g_arch_instruction_get_range(*i);
+
+        return cmp_vmpa(key, get_mrange_addr(range));
+
+    }
+
+    ptr = find_item_in_flat_array(info->instructions, sizeof(GArchInstruction *),
+                                  (__compar_fn_t)cmp_instr_by_addr, addr);
+
+    result = (ptr != NULL);
+
+    return result;
 
 }
 
@@ -457,6 +515,30 @@ void g_preload_info_unlock_comments(GPreloadInfo *info)
 
 void g_preload_info_add_comment(GPreloadInfo *info, GDbComment *comment)
 {
+    g_preload_info_lock_comments(info);
+
+    _g_preload_info_add_comment(info, comment);
+
+    g_preload_info_unlock_comments(info);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info    = instance à mettre à jour.                          *
+*                comment = commentaire à venir associer.                      *
+*                                                                             *
+*  Description : Ajoute un commentaire supplémentaire aux préchargements.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void _g_preload_info_add_comment(GPreloadInfo *info, GDbComment *comment)
+{
     int cmp_comment_by_addr(const GDbComment * const *a, const GDbComment * const *b)
     {
         const vmpa2t *addr_a;               /* Position du commentaire A   */
@@ -469,12 +551,52 @@ void g_preload_info_add_comment(GPreloadInfo *info, GDbComment *comment)
 
     }
 
-    g_preload_info_lock_comments(info);
-
     insert_item_into_flat_array(&info->comments, &comment, sizeof(GDbComment *),
                                 (__compar_fn_t)cmp_comment_by_addr);
 
-    g_preload_info_unlock_comments(info);
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info = instance à mettre à consulter.                        *
+*                addr = localisation du commentaire recherché.                *
+*                                                                             *
+*  Description : Recherche un commentaire dans des préchargements.            *
+*                                                                             *
+*  Retour      : Eventuel commenaire retrouvé ou NULL.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GDbComment *_g_preload_info_find_comment_at(GPreloadInfo *info, const vmpa2t *addr)
+{
+    GDbComment *result;                     /* Trouvaille à retourner      */
+    GDbComment **ptr;                       /* Adresse dans le tableau     */
+
+    int cmp_comment_by_addr(const vmpa2t *key, const GDbComment * const *comment)
+    {
+        const vmpa2t *caddr;                /* Position du commentaire     */
+
+        caddr = g_db_comment_get_address(*comment);
+
+        return cmp_vmpa(key, caddr);
+
+    }
+
+    ptr = find_item_in_flat_array(info->comments, sizeof(GDbComment *),
+                                     (__compar_fn_t)cmp_comment_by_addr, addr);
+
+    if (ptr != NULL)
+    {
+        result = *ptr;
+        g_object_ref(G_OBJECT(result));
+    }
+    else
+        result = NULL;
+
+    return result;
 
 }
 
diff --git a/src/format/preload.h b/src/format/preload.h
index 59c81b7..1e28222 100644
--- a/src/format/preload.h
+++ b/src/format/preload.h
@@ -66,6 +66,12 @@ void g_preload_info_unlock_instructions(GPreloadInfo *);
 /* Ajoute une instruction supplémentaire aux préchargements. */
 void g_preload_info_add_instruction(GPreloadInfo *, GArchInstruction *);
 
+/* Ajoute une instruction supplémentaire aux préchargements. */
+void _g_preload_info_add_instruction(GPreloadInfo *, GArchInstruction *);
+
+/* Détermine si une instruction est présente à un point donné. */
+bool _g_preload_info_has_instruction_at(GPreloadInfo *, const vmpa2t *);
+
 /* Indique la quantité d'instructions préchargées disponibles. */
 size_t _g_preload_info_count_instructions(const GPreloadInfo *);
 
@@ -87,6 +93,12 @@ void g_preload_info_unlock_comments(GPreloadInfo *);
 /* Ajoute un commentaire supplémentaire aux préchargements. */
 void g_preload_info_add_comment(GPreloadInfo *, GDbComment *);
 
+/* Ajoute un commentaire supplémentaire aux préchargements. */
+void _g_preload_info_add_comment(GPreloadInfo *, GDbComment *);
+
+/* Recherche un commentaire dans des préchargements. */
+GDbComment *_g_preload_info_find_comment_at(GPreloadInfo *, const vmpa2t *);
+
 /* Indique la quantité de commentaires préchargés disponibles. */
 size_t _g_preload_info_count_comments(const GPreloadInfo *);
 
diff --git a/src/glibext/gbuffercache.c b/src/glibext/gbuffercache.c
index fd7c987..f7dc49f 100644
--- a/src/glibext/gbuffercache.c
+++ b/src/glibext/gbuffercache.c
@@ -903,10 +903,15 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
             cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info));
         }
     }
-#ifndef NDEBUG
-    else
-        assert(needed == 1);
-#endif
+
+    else if (needed > 1)
+    {
+        if ((cache->used + needed - 1) >= cache->count)
+        {
+            cache->count += needed - 1 + LINE_ALLOC_BULK;
+            cache->lines = (cache_info *)realloc(cache->lines, cache->count * sizeof(cache_info));
+        }
+    }
 
     /* Insertion du générateur */
 
@@ -934,7 +939,23 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
 
         g_width_tracker_update(cache->tracker, index);
 
-        g_signal_emit_by_name(cache, "size-changed", true, index, 1);
+        if (needed > 1)
+        {
+            /* On déborde sur les lignes suivantes, donc on crée de l'espace ! */
+
+            memmove(&cache->lines[index + 1],
+                    &cache->lines[index + 1 + needed - 1], (cache->used - index - 1) * sizeof(cache_info));
+
+            for (i = 1; i < needed; i++)
+                init_cache_info(&cache->lines[index + i], generator, i, BLF_NONE);
+
+            cache->used += needed - 1;
+
+            g_width_tracker_update_added(cache->tracker, index + 1, needed - 1);
+
+        }
+
+        g_signal_emit_by_name(cache, "size-changed", true, index, needed - 1);
 
     }
 
-- 
cgit v0.11.2-87-g4458