From 3669bdaf8552f53baa5cfb2b0d360959eea61236 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 22 Nov 2012 19:51:17 +0000
Subject: Rewritten parts of the Android plugin to insert indications about
 exceptions.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@288 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                          |  14 ++
 plugins/androhelpers/try_n_catch.c | 297 ++++++++++++++++++++++++-------------
 src/glibext/gbufferline.c          |  10 ++
 src/glibext/gbufferline.h          |   1 +
 src/glibext/gbuffersegment.c       |   3 +
 src/glibext/gcodebuffer.c          | 175 ++++++++++++++++++----
 src/glibext/gcodebuffer.h          |   6 +
 7 files changed, 369 insertions(+), 137 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f5e628d..e1d758a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+12-11-22  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/androhelpers/try_n_catch.c:
+	Rewrite parts of the Android plugin to insert indications about exceptions.
+
+	* src/glibext/gbufferline.c:
+	* src/glibext/gbufferline.h:
+	* src/glibext/gbuffersegment.c:
+	Introduce a new style for code indications.
+
+	* src/glibext/gcodebuffer.c:
+	* src/glibext/gcodebuffer.h:
+	Add a function to complete in order to insert line at given addresses.
+
 12-11-20  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gui/panels/glance.c:
diff --git a/plugins/androhelpers/try_n_catch.c b/plugins/androhelpers/try_n_catch.c
index fc7b2bb..7db0f70 100644
--- a/plugins/androhelpers/try_n_catch.c
+++ b/plugins/androhelpers/try_n_catch.c
@@ -25,6 +25,7 @@
 
 
 #include <malloc.h>
+#include <stdio.h>
 
 
 #include <format/dex/dex-int.h>
@@ -36,6 +37,7 @@
 /* Mémorisation d'un lien vers un gestionnaire */
 typedef struct _caught_exception
 {
+    vmpa_t addr;                            /* Adresse du code de gestion  */
     GArchInstruction *instr;                /* Première instruction visée  */
     char *desc;                             /* Nom de l'exception          */
 
@@ -46,14 +48,17 @@ typedef struct _caught_exception
 /* Valide la zone couverte par le gestionnaire d'exceptions. */
 static bool check_covered_area(const try_item *, const GBinRoutine *);
 
-/* Construit une liste pointant sur les différentes gestions. */
-static caught_exception *build_destinations_list(GLoadedBinary *, const try_item *, const encoded_catch_handler_list *, const GBinRoutine *, size_t *);
-
 /* Rattache les gestionnaires d'exception à leur code couvert. */
-static void attach_caught_code(GLoadedBinary *, const try_item *, const encoded_catch_handler_list *, const GBinRoutine *);
+static void attach_caught_code(const GLoadedBinary *, const GBinRoutine *, const try_item *, const caught_exception *, size_t);
+
+/* Insère des indications dans le texte humainement lisible. */
+static void mark_exception_handlers(const GLoadedBinary *, uleb128_t, caught_exception **, size_t *);
+
+/* Construit des listes pointant sur les différentes gestions. */
+static caught_exception **build_all_destinations_list(const GLoadedBinary *, const GBinRoutine *, const encoded_catch_handler_list *, size_t **);
 
 /* Recherche et met en avant tous les gestionnaires d'exception. */
-static void look_for_exception_handlers(GLoadedBinary *, const GDexFormat *, GDexMethod *);
+static void look_for_exception_handlers(const GLoadedBinary *, const GDexFormat *, GDexMethod *);
 
 
 
@@ -88,169 +93,210 @@ static bool check_covered_area(const try_item *try, const GBinRoutine *routine)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : binary  = représentation binaire à traiter.                  *
-*                try     = informations sur la gestion à consulter.           *
-*                hlist   = liste de tous les gestionnaires en place.          *
-*                routine = routine associée, pour l'accès au instructions.    *
-*                count   = quantité de destinations trouvées. [OUT]           *
+*  Paramètres  : binary   = représentation binaire à traiter.                 *
+*                routine  = routine associée, pour l'accès au instructions.   *
+*                try      = informations sur la gestion à consulter.          *
+*                handlers = arrivées des liens vers les gestionnaires.        *
+*                count    = nombre de ces arrivées.                           *
 *                                                                             *
-*  Description : Construit une liste pointant sur les différentes gestions.   *
+*  Description : Rattache les gestionnaires d'exception à leur code couvert.  *
 *                                                                             *
-*  Retour      : Adresse des codes à lier systématiquement.                   *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static caught_exception *build_destinations_list(GLoadedBinary *binary, const try_item *try, const encoded_catch_handler_list *hlist, const GBinRoutine *routine, size_t *count)
+static void attach_caught_code(const GLoadedBinary *binary, const GBinRoutine *routine, const try_item *try, const caught_exception *handlers, size_t count)
 {
-    caught_exception *result;               /* Liste à retourner           */
-    GDexFormat *format;                     /* Format du binaire chargé    */
-    vmpa_t start;                           /* Début du code de la routine */
+    vmpa_t start;                           /* Début de la zone couverte   */
+    vmpa_t end;                             /* Début de la zone couverte   */
     GArchInstruction *instrs;               /* Instructions Dalvik         */
-    uleb128_t index;                        /* Indice du bon gestionnaire  */
-    encoded_catch_handler *handlers;        /* Groupe de gestionnaires     */
-    leb128_t max;                           /* Quantité d'exception        */
-    leb128_t i;                             /* Boucle de parcours          */
-    vmpa_t handler_addr;                    /* Adresse du code de gestion  */
-    GDataType *type;                        /* Type de l'exception         */
-
-    format = G_DEX_FORMAT(g_loaded_binary_get_format(binary));
+    GArchInstruction *first;                /* Première instruction        */
+    GArchInstruction *next;                 /* Dernière instruction + 1    */
+    GArchInstruction *prev;                 /* Instruction à détacher      */
+    GArchInstruction *iter;                 /* Boucle de parcours          */
+    size_t i;                               /* Boucle de parcours          */
 
     start = g_binary_routine_get_address(routine);
+    start += try->start_addr * sizeof(uint16_t);
+
+    end = start + try->insn_count * sizeof(uint16_t);
 
     instrs = g_loaded_binary_get_instructions(binary);
-    instrs = g_arch_instruction_find_by_address(instrs, start, true);
+    first = g_arch_instruction_find_by_address(instrs, start, true);
+    next = g_arch_instruction_find_by_address(instrs, end, true);
 
-    for (index = 0; index < hlist->size; index++)
-        if (try->handler_off == hlist->list[index].offset)
-            break;
+    /* Si des détachements sont nécessaires... */
 
-    if (index == hlist->size)
+    if (!g_arch_instruction_has_sources(first))
     {
-        *count = 0;
-        return NULL;
+        prev = g_arch_instruction_get_prev_iter(instrs, first);
+        g_arch_instruction_link_with(prev, first, ILT_EXEC_FLOW);
     }
 
-    handlers = &hlist->list[index];
-    max = leb128_abs(handlers->size);
-
-    *count = max + (handlers->size < 0 ? 1 : 0);
-    result = (caught_exception *)calloc(*count, sizeof(caught_exception));
+    if (!g_arch_instruction_has_sources(next))
+    {
+        prev = g_arch_instruction_get_prev_iter(instrs, next);
+        g_arch_instruction_link_with(prev, next, ILT_EXEC_FLOW);
+    }
 
-    *count = 0;
+    /* Rattachements ? */
 
-    for (i = 0; i < max; i++)
+    if (handlers != NULL)
     {
-        handler_addr = start + handlers->handlers[i].addr * sizeof(uint16_t);
-        result[*count].instr = g_arch_instruction_find_by_address(instrs, handler_addr, true);
-
-        if (result[*count].instr == NULL)
-            continue;
+        for (iter = first;
+             iter != NULL;
+             iter = g_arch_instruction_get_next_iter(instrs, iter, end))
+        {
+            if (!g_arch_instruction_has_destinations(iter))
+                continue;
 
-        type = get_type_from_dex_pool(format, handlers->handlers[i].type_idx);
-        result[*count].desc = g_data_type_to_string(type);
+            for (i = 0; i < count; i++)
+                g_arch_instruction_link_with(iter, handlers[i].instr, ILT_CATCH_EXCEPTION);
 
-        (*count)++;
+        }
 
     }
 
-    if (handlers->size < 0)
-    {
-        handler_addr = start + handlers->catch_all_addr * sizeof(uint16_t);
-        result[*count].instr = g_arch_instruction_find_by_address(instrs, handler_addr, true);
+}
 
-        if (result[*count].instr != NULL)
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary   = représentation binaire à traiter.                 *
+*                size     = nombre de groupe à parcourir.                     *
+*                handlers = ensemble des groupes de gestionnaires.            *
+*                count    = liste des quantités de gestionnaires groupés.     *
+*                                                                             *
+*  Description : Insère des indications dans le texte humainement lisible.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void mark_exception_handlers(const GLoadedBinary *binary, uleb128_t size, caught_exception **handlers, size_t *count)
+{
+    GCodeBuffer *buffer;                    /* Contenu textuel à modifier  */
+    uleb128_t i;                            /* Boucle de parcours #1       */
+    size_t j;                               /* Boucle de parcours #2       */
+    GBufferLine *line;                      /* Nouvelle ligne à compléter  */
+    size_t len;                             /* Taille de la description    */
+    char *fulldesc;                         /* Description complète        */
+
+    buffer = g_loaded_binary_get_disassembled_buffer(binary);
+
+    for (i = 0; i < size; i++)
+        for (j = 0; j < count[i]; j++)
         {
-            result[*count].desc = strdup(_("default"));
-            (*count)++;
-        }
+            line = g_code_buffer_insert_at(buffer, handlers[i][j].addr, true);
+            g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
 
-    }
+            g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_INDICATION);
 
-    return result;
+            len = strlen(_("Handler for caught '%s'")) + strlen(handlers[i][j].desc);
+            fulldesc = (char *)calloc(len + 1, sizeof(char));
+            snprintf(fulldesc, len + 1, _("Handler for caught '%s'"), handlers[i][j].desc);
+
+            g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, fulldesc, len, RTT_INDICATION);
+
+            free(fulldesc);
+
+        }
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : binary   = représentation binaire à traiter.                 *
-*                try      = informations sur la gestion à consulter.          *
-*                handlers = liste de tous les gestionnaires en place.         *
-*                routine  = routine associée, pour l'accès au instructions.   *
+*  Paramètres  : binary  = représentation binaire à traiter.                  *
+*                routine = routine associée, pour l'accès au instructions.    *
+*                hlist   = liste de tous les gestionnaires en place.          *
+*                count   = quantité de destinations trouvées. [OUT]           *
 *                                                                             *
-*  Description : Rattache les gestionnaires d'exception à leur code couvert.  *
+*  Description : Construit des listes pointant sur les différentes gestions.  *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Adresses des codes à lier systématiquement.                  *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void attach_caught_code(GLoadedBinary *binary, const try_item *try, const encoded_catch_handler_list *handlers, const GBinRoutine *routine)
+static caught_exception **build_all_destinations_list(const GLoadedBinary *binary, const GBinRoutine *routine, const encoded_catch_handler_list *hlist, size_t **count)
 {
-    vmpa_t start;                           /* Début de la zone couverte   */
-    vmpa_t end;                             /* Début de la zone couverte   */
+    caught_exception **result;              /* Liste de listes à retourner */
+    GDexFormat *format;                     /* Format du binaire chargé    */
+    vmpa_t start;                           /* Début du code de la routine */
     GArchInstruction *instrs;               /* Instructions Dalvik         */
-    GArchInstruction *first;                /* Première instruction        */
-    GArchInstruction *next;                 /* Dernière instruction + 1    */
-    GArchInstruction *prev;                 /* Instruction à détacher      */
-    GArchInstruction *iter;                 /* Boucle de parcours          */
-    size_t dests_count;                     /* Nombre de points d'arrivée  */
-    caught_exception *dests;                /* Points d'arrivée            */
-    size_t i;                               /* Boucle de parcours          */
+    uleb128_t i;                            /* Boucle de parcours #1       */
+    encoded_catch_handler *handlers;        /* Groupe de gestionnaires     */
+    leb128_t max;                           /* Quantité d'exception        */
+    leb128_t j;                             /* Boucle de parcours #2       */
+    caught_exception *excep;                /* Raccourci confortable       */
+    GDataType *type;                        /* Type de l'exception         */
 
-    start = g_binary_routine_get_address(routine);
-    start += try->start_addr * sizeof(uint16_t);
+    format = G_DEX_FORMAT(g_loaded_binary_get_format(binary));
 
-    end = start + try->insn_count * sizeof(uint16_t);
+    start = g_binary_routine_get_address(routine);
 
     instrs = g_loaded_binary_get_instructions(binary);
-    first = g_arch_instruction_find_by_address(instrs, start, true);
-    next = g_arch_instruction_find_by_address(instrs, end, true);
+    instrs = g_arch_instruction_find_by_address(instrs, start, true);
 
-    /* Si des détachements sont nécessaires... */
+    /* Création d'un espace mémoire pour les listes */
 
-    if (!g_arch_instruction_has_sources(first))
-    {
-        prev = g_arch_instruction_get_prev_iter(instrs, first);
-        g_arch_instruction_link_with(prev, first, ILT_EXEC_FLOW);
-    }
+    result = (caught_exception **)calloc(hlist->size, sizeof(caught_exception *));
+    *count = (size_t *)calloc(hlist->size, sizeof(size_t));
 
-    if (!g_arch_instruction_has_sources(next))
+    /* Parcours de chaque groupe de gestionnaires */
+
+    for (i = 0; i < hlist->size; i++)
     {
-        prev = g_arch_instruction_get_prev_iter(instrs, next);
-        g_arch_instruction_link_with(prev, next, ILT_EXEC_FLOW);
-    }
+        handlers = &hlist->list[i];
+        max = leb128_abs(handlers->size);
 
-    /* Détermination du code des exceptions */
-    dests = build_destinations_list(binary, try, handlers, routine, &dests_count);
+        (*count)[i] = max + (handlers->size < 0 ? 1 : 0);
+        result[i] = (caught_exception *)calloc((*count)[i], sizeof(caught_exception));
 
-    if (dests != NULL)
-    {
-        /* Rattachements */
-        for (iter = first;
-             iter != NULL;
-             iter = g_arch_instruction_get_next_iter(instrs, iter, end))
+        (*count)[i] = 0;
+
+        for (j = 0; j < max; j++)
         {
-            if (!g_arch_instruction_has_destinations(iter))
+            excep = &result[i][(*count)[i]];
+
+            excep->addr = start + handlers->handlers[j].addr * sizeof(uint16_t);
+            excep->instr = g_arch_instruction_find_by_address(instrs, excep->addr, true);
+
+            if (excep->instr == NULL)
                 continue;
 
-            for (i = 0; i < dests_count; i++)
-                g_arch_instruction_link_with(iter, dests[i].instr, ILT_CATCH_EXCEPTION);
+            type = get_type_from_dex_pool(format, handlers->handlers[j].type_idx);
+            excep->desc = g_data_type_to_string(type);
+
+            (*count)[i]++;
 
         }
 
-        /* Libération de la mémoire utilisée */
+        if (handlers->size < 0)
+        {
+            excep = &result[i][(*count)[i]];
 
-        for (i = 0; i < dests_count; i++)
-            free(dests[i].desc);
+            excep->addr = start + handlers->catch_all_addr * sizeof(uint16_t);
+            excep->instr = g_arch_instruction_find_by_address(instrs, excep->addr, true);
 
-        free(dests);
+            if (excep->instr != NULL)
+            {
+                excep->desc = strdup(_("default"));
+                (*count)[i]++;
+            }
+
+        }
 
     }
 
+    return result;
+
 }
 
 
@@ -268,11 +314,17 @@ static void attach_caught_code(GLoadedBinary *binary, const try_item *try, const
 *                                                                             *
 ******************************************************************************/
 
-static void look_for_exception_handlers(GLoadedBinary *binary, const GDexFormat *format, GDexMethod *method)
+static void look_for_exception_handlers(const GLoadedBinary *binary, const GDexFormat *format, GDexMethod *method)
 {
     const code_item *body;                  /* Description du corps        */
     GBinRoutine *routine;                   /* Abstraction globale         */
-    uint16_t i;                             /* Boucle de parcours          */
+    encoded_catch_handler_list *hlist;      /* Confort vers la liste brute */
+    caught_exception **handlers;            /* Interprétation des gestions */
+    size_t *count;                          /* Tailles des groupes         */
+    uint16_t i;                             /* Boucle de parcours #1       */
+    try_item *try;                          /* Raccourci vers une zone     */
+    uleb128_t index;                        /* Indice du bon gestionnaire  */
+    size_t j;                               /* Boucle de parcours #2       */
 
     body = g_dex_method_get_dex_body(method);
 
@@ -281,15 +333,48 @@ static void look_for_exception_handlers(GLoadedBinary *binary, const GDexFormat
 
     routine = g_dex_method_get_routine(method);
 
+    hlist = body->handlers;
+    handlers = build_all_destinations_list(binary, routine, hlist, &count);
+
+    /* Pour chaque zone couverte... */
+
     for (i = 0; i < body->tries_size; i++)
     {
-        if (!check_covered_area(&body->tries[i], routine))
+        try = &body->tries[i];
+
+        if (!check_covered_area(try, routine))
             continue;
 
-        attach_caught_code(binary, &body->tries[i], body->handlers, routine);
+        for (index = 0; index < hlist->size; index++)
+            if (try->handler_off == hlist->list[index].offset)
+                break;
+
+        if (index == hlist->size)
+            continue;
+
+        attach_caught_code(binary, routine, try, handlers[index], count[index]);
+
+    }
+
+    /* Ajout des précisions */
+
+    mark_exception_handlers(binary, hlist->size, handlers, count);
+
+    /* Libération de la mémoire utilisée */
+
+    for (index = 0; index < hlist->size; index++)
+    {
+        for (j = 0; j < count[index]; j++)
+            free(handlers[index][j].desc);
+
+        if (handlers[index] != NULL)
+            free(handlers[index]);
 
     }
 
+    if (handlers != NULL) free(handlers);
+    if (count != NULL) free(count);
+
 }
 
 
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index ce3e19f..c8ff5f2 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -345,6 +345,16 @@ static void g_buffer_line_class_init(GBufferLineClass *class)
     attrib = pango_attr_foreground_new(14335, 45311, 23551);
     pango_attr_list_insert(class->attribs[RTT_COMMENT], attrib);
 
+    /* RTT_INDICATION */
+
+    class->attribs[RTT_INDICATION] = pango_attr_list_new();
+
+    attrib = pango_attr_foreground_new(33410, 33410, 33410);
+    pango_attr_list_insert(class->attribs[RTT_INDICATION], attrib);
+
+    attrib = pango_attr_style_new(PANGO_STYLE_ITALIC);
+    pango_attr_list_insert(class->attribs[RTT_INDICATION], attrib);
+
     /* RTT_RAW_CODE */
 
     class->attribs[RTT_RAW_CODE] = pango_attr_list_new();
diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h
index 3cc992b..670df99 100644
--- a/src/glibext/gbufferline.h
+++ b/src/glibext/gbufferline.h
@@ -71,6 +71,7 @@ typedef enum _RenderingTagType
     RTT_RAW,                                /* Contenu brut                */
 
     RTT_COMMENT,                            /* Commentaire                 */
+    RTT_INDICATION,                         /* Aide à la lecture           */
     RTT_RAW_CODE,                           /* Code binaire brut           */
 
     RTT_INSTRUCTION,                        /* Code binaire brut           */
diff --git a/src/glibext/gbuffersegment.c b/src/glibext/gbuffersegment.c
index 5125631..9510fa2 100644
--- a/src/glibext/gbuffersegment.c
+++ b/src/glibext/gbuffersegment.c
@@ -231,6 +231,9 @@ static void g_buffer_segment_prepare(GBufferSegment *segment, PangoContext *cont
     attrib = pango_attr_iterator_get(iterator, PANGO_ATTR_WEIGHT);
     must_use_pango |= (attrib != NULL);
 
+    attrib = pango_attr_iterator_get(iterator, PANGO_ATTR_STYLE);
+    must_use_pango |= (attrib != NULL);
+
     pango_attr_iterator_destroy(iterator);
 
     if (must_use_pango)
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index aec3303..4ffc15a 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -121,6 +121,9 @@ static void g_code_buffer_class_init(GCodeBufferClass *);
 static void g_code_buffer_init(GCodeBuffer *);
 
 /* Convertit une adresse en indice de ligne. */
+static size_t _g_code_buffer_get_index_from_address(GCodeBuffer *, vmpa_t);
+
+/* Convertit une adresse en indice de ligne. */
 static size_t g_code_buffer_get_index_from_address(GCodeBuffer *, vmpa_t);
 
 
@@ -292,15 +295,16 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkExtStatusBar *statusbar)
 
     id = gtk_extended_status_bar_push(statusbar, scan->message, true);
 
-    for (i = first; i <= last; i++)
-    {
-        if (!scan->process(scan->buffer, lines[i], scan->user_data))
-            break;
+    if (scan->buffer->used > 0)
+        for (i = first; i <= last; i++)
+        {
+            if (!scan->process(scan->buffer, lines[i], scan->user_data))
+                break;
 
-        gtk_extended_status_bar_update_activity(statusbar, id,
-                                                (i - first) * 1.0 / (last - first));
+            gtk_extended_status_bar_update_activity(statusbar, id,
+                                                    (i - first) * 1.0 / (last - first));
 
-    }
+        }
 
     /* TODO : unlock scan->buffer->lines */
 
@@ -380,6 +384,7 @@ GCodeBuffer *g_code_buffer_new(void)
 
 }
 
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : buffer = composant GTK à mettre à jour.                      *
@@ -393,17 +398,48 @@ GCodeBuffer *g_code_buffer_new(void)
 *                                                                             *
 ******************************************************************************/
 
-static size_t g_code_buffer_get_index_from_address(GCodeBuffer *buffer, vmpa_t addr)
+static size_t _g_code_buffer_get_index_from_address(GCodeBuffer *buffer, vmpa_t addr)
 {
     size_t result;                          /* Indice à retourner          */
 
     if (addr == VMPA_MAX)
         return (buffer->used > 0 ? buffer->used - 1 : 0);
 
+    /* TODO : coder un parcours plus optimal ! */
+
     for (result = 0; result < buffer->used; result++)
         if (g_buffer_line_get_address(buffer->lines[result]) == addr)
             break;
 
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
+*                addr   = adresse où va se situer la ligne.                   *
+*                                                                             *
+*  Description : Convertit une adresse en indice de ligne.                    *
+*                                                                             *
+*  Retour      : Indice de l'adresse trouvée, ou 0 en cas d'échec.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static size_t g_code_buffer_get_index_from_address(GCodeBuffer *buffer, vmpa_t addr)
+{
+    size_t result;                          /* Indice à retourner          */
+
+    result = _g_code_buffer_get_index_from_address(buffer, addr);
+
+    /**
+     * Par commodités, on évite certaines instructions en cas d'échec dans les
+     * fonctions d'appels : la condition des boucles utilisant l'indice retourné (0)
+     * fait son office directement !
+     */
     if (result == buffer->used)
         result = 0;
 
@@ -419,7 +455,7 @@ static size_t g_code_buffer_get_index_from_address(GCodeBuffer *buffer, vmpa_t a
 *                                                                             *
 *  Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Nouvelle ligne vierge à écrire.                              *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
@@ -451,6 +487,82 @@ GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *buffer, vmpa_t addr)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : buffer = composant GTK à mettre à jour.                      *
+*                addr   = adresse où va se situer la ligne.                   *
+*                before = emplacement de l'insertion.                         *
+*                                                                             *
+*  Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. *
+*                                                                             *
+*  Retour      : Nouvelle ligne vierge à écrire.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBufferLine *g_code_buffer_insert_at(GCodeBuffer *buffer, vmpa_t addr, bool before)
+{
+    GBufferLine *result;                    /* Instance à retourner        */
+    size_t index;                           /* Indice de la ligne visée    */
+
+    index = _g_code_buffer_get_index_from_address(buffer, addr);
+    if (index == buffer->used) return NULL;
+
+    if (buffer->used == buffer->count)
+    {
+        buffer->count += LINE_ALLOC_BULK;
+        buffer->lines = (GBufferLine **)realloc(buffer->lines,
+                                                buffer->count * sizeof(GBufferLine *));
+    }
+
+    if (before)
+    {
+        memmove(&buffer->lines[index + 1], &buffer->lines[index],
+                sizeof(GBufferLine *) * (buffer->used - index));
+
+        buffer->used++;
+
+        result = g_buffer_line_new(addr);
+        buffer->lines[index] = result;
+
+    }
+
+
+    else
+    /* FIXME */
+        ;
+
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
+*                line   = point d'insertion.                                  *
+*                                                                             *
+*  Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. *
+*                                                                             *
+*  Retour      : Nouvelle ligne vierge à écrire.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBufferLine *g_code_buffer_insert_after(GCodeBuffer *buffer, GBufferLine *line)
+{
+
+    /* FIXME */
+
+    return NULL;
+
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
 *                addr   = adresse où retrouver la ligne recherchée.           *
 *                                                                             *
 *  Description : Retrouve une ligne au sein d'un tampon avec une adresse.     *
@@ -464,15 +576,14 @@ GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *buffer, vmpa_t addr)
 GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, vmpa_t addr)
 {
     GBufferLine *result;                    /* Instance à retourner        */
-    size_t i;                               /* Boucle de parcours          */
+    size_t index;                           /* Indice de la ligne visée    */
 
-    result = NULL;
+    index = _g_code_buffer_get_index_from_address(buffer, addr);
 
-    /* TODO : coder un parcours plus optimal ! */
-
-    for (i = 0; i < buffer->used && result == NULL; i++)
-        if (g_buffer_line_get_address(buffer->lines[i]) == addr)
-            result = buffer->lines[i];
+    if (index == buffer->used)
+        result = NULL;
+    else
+        result = buffer->lines[index];
 
     return result;
 
@@ -749,12 +860,13 @@ static void g_buffer_view_compute_required_widths(GBufferView *view)
     view->left_margin = 2 * view->line_height;
     view->left_text = 2.5 * view->line_height;
 
-    for (i = first; i <= last; i++)
-        for (j = 0; j < BLC_COUNT; j++)
-        {
-            width = g_buffer_line_get_width(lines[i], j);
-            view->max_widths[j] = MAX(view->max_widths[j], width);
-        }
+    if (view->buffer->used > 0)
+        for (i = first; i <= last; i++)
+            for (j = 0; j < BLC_COUNT; j++)
+            {
+                width = g_buffer_line_get_width(lines[i], j);
+                view->max_widths[j] = MAX(view->max_widths[j], width);
+            }
 
 }
 
@@ -1086,19 +1198,20 @@ bool g_buffer_view_get_address_coordinates(GBufferView *view, vmpa_t addr, gint
     first = g_code_buffer_get_index_from_address(view->buffer, view->start);
     last = g_code_buffer_get_index_from_address(view->buffer, view->end);
 
-    for (i = first; i <= last; i++)
-    {
-        current = g_buffer_line_get_address(view->buffer->lines[i]);
+    if (view->buffer->used > 0)
+        for (i = first; i <= last; i++)
+        {
+            current = g_buffer_line_get_address(view->buffer->lines[i]);
 
-        if (current == addr)
-            break;
+            if (current == addr)
+                break;
 
-        if (current > addr)
-            return false;
+            if (current > addr)
+                return false;
 
-        *y += lheight;
+            *y += lheight;
 
-    }
+        }
 
     return (current == addr);
 
diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h
index b92f38b..725bd1f 100644
--- a/src/glibext/gcodebuffer.h
+++ b/src/glibext/gcodebuffer.h
@@ -62,6 +62,12 @@ GCodeBuffer *g_code_buffer_new(void);
 /* Ajoute une nouvelle ligne à un tampon pour code désassemblé. */
 GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *, vmpa_t);
 
+/* Ajoute une nouvelle ligne à un tampon pour code désassemblé. */
+GBufferLine *g_code_buffer_insert_at(GCodeBuffer *, vmpa_t, bool);
+
+/* Ajoute une nouvelle ligne à un tampon pour code désassemblé. */
+GBufferLine *g_code_buffer_insert_after(GCodeBuffer *, GBufferLine *);
+
 /* Retrouve une ligne au sein d'un tampon avec une adresse. */
 GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, vmpa_t);
 
-- 
cgit v0.11.2-87-g4458