From f1d0462ab0f41ace04d8db02dd8ae3ee37f41a58 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 6 Aug 2018 19:43:08 +0200
Subject: Allowed to add or remove instructions once a binary analysis is over.

---
 src/analysis/binary.c    | 105 +++++++++++
 src/arch/processor-int.h |   4 +
 src/arch/processor.c     | 445 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/arch/processor.h     |  18 +-
 4 files changed, 563 insertions(+), 9 deletions(-)

diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index c4f05f3..db3f509 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -51,6 +51,7 @@
 #include "../core/params.h"
 #include "../core/processors.h"
 //#include "../glibext/chrysamarshal.h"
+#include "../glibext/gbinarycursor.h"
 #include "../glibext/gloadedpanel.h"
 #include "../gtkext/easygtk.h"
 #include "../gtkext/gtkblockdisplay.h"
@@ -159,6 +160,9 @@ static const char *g_loaded_binary_get_format_name(const GLoadedBinary *);
 /* Assure le désassemblage en différé. */
 static bool g_loaded_binary_analyze(GLoadedBinary *, wgroup_id_t, GtkStatusStack *);
 
+/* Prend note d'une variation des instructions désassemblées. */
+static void on_binary_processor_changed(GArchProcessor *, GArchInstruction *, gboolean, GLoadedBinary *);
+
 /* Fournit le désignation associée à l'élément chargé. */
 static const char *g_loaded_binary_describe(const GLoadedBinary *, bool);
 
@@ -1558,6 +1562,8 @@ static bool g_loaded_binary_analyze(GLoadedBinary *binary, wgroup_id_t gid, GtkS
         goto glba_exit;
     }
 
+    g_signal_connect(binary->proc, "changed", G_CALLBACK(on_binary_processor_changed), binary);
+
     has_virt = g_arch_processor_has_virtual_space(binary->proc);
 
     g_display_options_set(binary->options[BVW_BLOCK], BLC_VIRTUAL, has_virt);
@@ -1594,6 +1600,105 @@ static bool g_loaded_binary_analyze(GLoadedBinary *binary, wgroup_id_t gid, GtkS
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : proc   = processeur dont l'ensemble des instructions a varié.*
+*                instr  = instruction à l'origine de la procédure.            *
+*                added  = précise s'il s'agit d'un ajout ou d'un retrait.     *
+*                binary = élément chargé à consulter.                         *
+*                                                                             *
+*  Description : Prend note d'une variation des instructions désassemblées.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void on_binary_processor_changed(GArchProcessor *proc, GArchInstruction *instr, gboolean added, GLoadedBinary *binary)
+{
+    const mrange_t *range;                  /* Emplacement de l'instruction*/
+    BufferLineFlags flags;                  /* Propriétés pour la ligne    */
+    GBinSymbol *symbol;                     /* Symbole présent à l'adresse */
+    SymbolType stype;                       /* Type de symbole rencontré   */
+    instr_iter_t *iter;                     /* Boucle de parcours          */
+    GArchInstruction *next;                 /* Instruction suivante        */
+    GLineCursor *cursor;                    /* Emplacement dans un tampon  */
+    size_t index;                           /* Indice de ligne à traiter   */
+
+    if (binary->disass_cache != NULL)
+    {
+        range = g_arch_instruction_get_range(instr);
+
+        if (added)
+        {
+            flags = BLF_NONE;
+
+            if (g_binary_format_find_symbol_at(G_BIN_FORMAT(binary->format), get_mrange_addr(range), &symbol))
+            {
+                /**
+                 * Pour le choix des fanions, se référer au code similaire de
+                 * la fonction print_disassembled_instructions().
+                 */
+
+                stype = g_binary_symbol_get_target_type(symbol);
+
+                if (stype == STP_ENTRY_POINT)
+                    flags |= BLF_ENTRYPOINT;
+
+                if (stype != STP_DYN_STRING)
+                    flags |= BLF_WIDTH_MANAGER;
+
+                g_object_unref(G_OBJECT(symbol));
+
+            }
+
+            iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(range));
+
+            next = get_instruction_iterator_next(iter);
+
+            delete_instruction_iterator(iter);
+
+            if (next == NULL)
+                g_buffer_cache_append(binary->disass_cache, G_LINE_GENERATOR(instr), flags);
+
+            else
+            {
+                range = g_arch_instruction_get_range(next);
+
+                cursor = g_binary_cursor_new();
+                g_binary_cursor_update(G_BINARY_CURSOR(cursor), get_mrange_addr(range));
+
+                index = g_buffer_cache_find_index_by_cursor(binary->disass_cache, cursor, true);
+
+                g_object_unref(G_OBJECT(cursor));
+
+                g_object_unref(G_OBJECT(next));
+
+                g_buffer_cache_insert_at(binary->disass_cache, index, G_LINE_GENERATOR(instr), flags, true, false);
+
+            }
+
+        }
+
+        else
+        {
+            cursor = g_binary_cursor_new();
+            g_binary_cursor_update(G_BINARY_CURSOR(cursor), get_mrange_addr(range));
+
+            index = g_buffer_cache_find_index_by_cursor(binary->disass_cache, cursor, true);
+
+            g_object_unref(G_OBJECT(cursor));
+
+            g_buffer_cache_delete_at(binary->disass_cache, index);
+
+        }
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : binary = élément chargé à consulter.                         *
 *                full   = précise s'il s'agit d'une version longue ou non.    *
 *                                                                             *
diff --git a/src/arch/processor-int.h b/src/arch/processor-int.h
index 153f9ae..ac8dbf8 100644
--- a/src/arch/processor-int.h
+++ b/src/arch/processor-int.h
@@ -105,6 +105,10 @@ struct _GArchProcessorClass
 
     disass_instr_fc disassemble;            /* Traduction en instructions  */
 
+    /* Signaux */
+
+    void (* changed) (GArchProcessor *, GArchInstruction *, gboolean);
+
 };
 
 
diff --git a/src/arch/processor.c b/src/arch/processor.c
index 81bbd4f..09b91de 100644
--- a/src/arch/processor.c
+++ b/src/arch/processor.c
@@ -30,12 +30,15 @@
 #include <string.h>
 
 
-
+#include <i18n.h>
 
 
 #include "instruction-int.h"
 #include "processor-int.h"
 #include "raw.h"
+#include "../common/sort.h"
+#include "../core/logs.h"
+#include "../glibext/chrysamarshal.h"
 
 
 
@@ -79,6 +82,15 @@ static void g_arch_processor_add_new_coverage(GArchProcessor *, GArchInstruction
 /* Termine la définition d'un nouveau groupe d'instructions. */
 static void g_arch_processor_finish_last_coverage(GArchProcessor *, GArchInstruction *, size_t);
 
+/* Coupe un groupe d'instructions en deux. */
+static instr_coverage *g_arch_processor_split_coverages(GArchProcessor *, instr_coverage *, GArchInstruction *, size_t);
+
+/* Fusionne deux groupes d'instructions. */
+static void g_arch_processor_merge_coverages(GArchProcessor *, instr_coverage *, instr_coverage *);
+
+/* Met à jour une série de groupes d'instructions. */
+static void g_arch_processor_update_coverages(GArchProcessor *, instr_coverage *, bool);
+
 /* Recherche rapidement un indice d'instruction via une adresse. */
 static bool g_arch_processor_find_covered_index_by_address(const GArchProcessor *, const instr_coverage *, const vmpa2t *, bool, size_t *);
 
@@ -113,6 +125,14 @@ static void g_arch_processor_class_init(GArchProcessorClass *klass)
     object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_processor_dispose;
     object->finalize = (GObjectFinalizeFunc)g_arch_processor_finalize;
 
+    g_signal_new("changed",
+                 G_TYPE_ARCH_PROCESSOR,
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET(GArchProcessorClass, changed),
+                 NULL, NULL,
+                 g_cclosure_user_marshal_VOID__OBJECT_BOOLEAN,
+                 G_TYPE_NONE, 2, G_TYPE_ARCH_INSTRUCTION, G_TYPE_BOOLEAN);
+
 }
 
 
@@ -508,6 +528,230 @@ void g_arch_processor_set_instructions(GArchProcessor *proc, GArchInstruction **
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : proc  = architecture visée par la procédure.                 *
+*                instr = instruction à ajouter à l'ensemble.                  *
+*                                                                             *
+*  Description : Ajoute une instruction désassemblée à la liste.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_arch_processor_add_instruction(GArchProcessor *proc, GArchInstruction *instr)
+{
+    const mrange_t *range;                  /* Couverture de l'instruction */
+    size_t ins_index;                       /* Indice de l'instruction     */
+#ifndef NDEBUG
+    bool found;                             /* Présence d'un élément       */
+#endif
+    instr_coverage *coverage;               /* Couverture fine impactée    */
+    instr_coverage new;                     /* Nouveau groupe à insérer    */
+
+    g_arch_processor_lock(proc);
+
+    /**
+     * Ajout de l'instruction.
+     */
+
+    int compare_instructions(const GArchInstruction **a, const GArchInstruction **b)
+    {
+        const mrange_t *range_a;            /* Couverture d'instruction A  */
+        const mrange_t *range_b;            /* Couverture d'instruction B  */
+
+        range_a = g_arch_instruction_get_range(*a);
+        range_b = g_arch_instruction_get_range(*b);
+
+        return cmp_mrange(range_a, range_b);
+
+    }
+
+#ifndef NDEBUG
+    found = bsearch_index(&instr, proc->instructions, proc->instr_count,
+                          sizeof(GArchInstruction *), (__compar_fn_t)compare_instructions, &ins_index);
+    assert(!found);
+#else
+    bsearch_index(&instr, proc->instructions, proc->instr_count,
+                  sizeof(GArchInstruction *), (__compar_fn_t)compare_instructions, &ins_index);
+#endif
+
+    proc->instructions = _qinsert(proc->instructions, &proc->instr_count,
+                                  sizeof(GArchInstruction *), &instr, ins_index);
+
+    /**
+     * Actualisation des couvertures de code.
+     */
+
+    range = g_arch_instruction_get_range(instr);
+
+    coverage = (instr_coverage *)g_arch_processor_find_coverage_by_address(proc, get_mrange_addr(range));
+
+    if (coverage)
+    {
+        if (g_arch_instruction_get_flags(instr) & AIF_ROUTINE_START)
+        {
+            coverage = g_arch_processor_split_coverages(proc, coverage, instr, ins_index);
+
+            if (coverage != NULL)
+                g_arch_processor_update_coverages(proc, coverage, true);
+
+        }
+
+        else
+            g_arch_processor_update_coverages(proc, coverage, true);
+
+    }
+
+    else
+    {
+        /**
+         * Il n'existe pas de couverture pour l'instruction ajoutée.
+         *
+         * Donc on en crée une dédiée, et on l'insère au bon endroit.
+         */
+
+        copy_mrange(&new.range, range);
+
+        new.start = ins_index;
+        new.count = 1;
+
+
+        int compare_coverages(const instr_coverage *a, const instr_coverage *b)
+        {
+            return cmp_mrange(&a->range, &b->range);
+        }
+
+
+        proc->coverages = qinsert(proc->coverages, &proc->cov_count,
+                                  sizeof(instr_coverage), (__compar_fn_t)compare_coverages, &new);
+
+    }
+
+    proc->stamp++;
+
+    g_arch_processor_unlock(proc);
+
+    g_signal_emit_by_name(proc, "changed", instr, true);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc  = architecture visée par la procédure.                 *
+*                instr = instruction à retirer de l'ensemble.                 *
+*                                                                             *
+*  Description : Retire une instruction désassemblée de la liste.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_arch_processor_remove_instruction(GArchProcessor *proc, GArchInstruction *instr)
+{
+    bool emit;                              /* Ordre d'émission de signal  */
+    const mrange_t *irange;                 /* Couverture de l'instruction */
+    instr_coverage *coverage;               /* Couverture fine impactée    */
+    VMPA_BUFFER(pos);                       /* Traduction de position      */
+    size_t index;                           /* Indice de l'instruction     */
+    bool status;                            /* Bilan d'une recherche       */
+
+    emit = false;
+
+    g_arch_instruction_delete_all_links(instr);
+
+    irange = g_arch_instruction_get_range(instr);
+
+    g_arch_processor_lock(proc);
+
+    coverage = (instr_coverage *)g_arch_processor_find_coverage_by_address(proc, get_mrange_addr(irange));
+
+    /**
+     * L'instruction doit se trouve dans l'ensemble des instructions enregistrées.
+     * Donc une couverture associée doit exister.
+     */
+
+    assert(coverage != NULL);
+
+    if (coverage == NULL)
+    {
+        vmpa2_phys_to_string(get_mrange_addr(irange), MDS_UNDEFINED, pos, NULL);
+        log_variadic_message(LMT_ERROR, _("Can not find coverage for instruction @ %s"), pos);
+        goto done;
+    }
+
+    /**
+     * Mises à jour des groupes d'instructions.
+     */
+
+    /* Si l'instruction est en début de couverture */
+    if (cmp_vmpa(get_mrange_addr(&coverage->range), get_mrange_addr(irange)) == 0)
+    {
+        if (coverage == proc->coverages)
+            copy_vmpa(get_mrange_addr(&coverage->range), get_mrange_addr(irange));
+
+        else
+        {
+            assert(g_arch_instruction_get_flags(instr) & AIF_ROUTINE_START);
+
+            g_arch_processor_merge_coverages(proc, coverage - 1, coverage);
+
+            coverage = (instr_coverage *)g_arch_processor_find_coverage_by_address(proc, get_mrange_addr(irange));
+            assert(coverage != NULL);
+
+        }
+
+    }
+
+    set_mrange_length(&coverage->range, get_mrange_length(&coverage->range) - get_mrange_length(irange));
+
+    g_arch_processor_update_coverages(proc, coverage, false);
+
+    /**
+     * Retrait effectif de l'instruction.
+     */
+
+    status = g_arch_processor_find_covered_index_by_address(proc, coverage, get_mrange_addr(irange), false, &index);
+
+    assert(status);
+
+    if (!status)
+    {
+        vmpa2_phys_to_string(get_mrange_addr(irange), MDS_UNDEFINED, pos, NULL);
+        log_variadic_message(LMT_ERROR, _("Can not find instruction @ %s"), pos);
+        goto done;
+    }
+
+    if ((index + 1) < proc->instr_count)
+        memmove(&proc->instructions[index], &proc->instructions[index + 1],
+                (proc->instr_count - index - 1) * sizeof(GArchInstruction *));
+
+    proc->instr_count--;
+
+    proc->instructions = (GArchInstruction **)realloc(proc->instructions,
+                                                      proc->instr_count * sizeof(GArchInstruction *));
+
+    proc->stamp++;
+
+    emit = true;
+
+ done:
+
+    g_arch_processor_unlock(proc);
+
+    if (emit)
+        g_signal_emit_by_name(proc, "changed", instr, false);
+
+    g_object_unref(G_OBJECT(instr));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : proc = architecture visée par la procédure.                  *
 *                index = indice de l'instruction visée.                       *
 *                                                                             *
@@ -720,6 +964,8 @@ static void g_arch_processor_add_new_coverage(GArchProcessor *proc, GArchInstruc
     instr_coverage *coverage;               /* Couverture à définir        */
     const mrange_t *irange;                 /* Couverture de l'instruction */
 
+    assert(g_atomic_int_get(&proc->locked) == 1);
+
     /* Mise à disposition de d'avantage d'espace */
     if (proc->cov_allocated == proc->cov_count)
     {
@@ -761,6 +1007,8 @@ static void g_arch_processor_finish_last_coverage(GArchProcessor *proc, GArchIns
     const mrange_t *irange;                 /* Couverture de l'instruction */
     phys_t diff;                            /* Ecart entre les extrémités  */
 
+    assert(g_atomic_int_get(&proc->locked) == 1);
+
     coverage = &proc->coverages[proc->cov_count - 1];
 
     irange = g_arch_instruction_get_range(last);
@@ -777,6 +1025,197 @@ static void g_arch_processor_finish_last_coverage(GArchProcessor *proc, GArchIns
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : proc      = architecture à modifier via la procédure.        *
+*                coverage  = couverture comprenant l'instruction fournie.     *
+*                instr     = point de coupure du groupe en question.          *
+*                ins_index = indice de l'instruction dans la liste.           *
+*                                                                             *
+*  Description : Coupe un groupe d'instructions en deux.                      *
+*                                                                             *
+*  Retour      : Première couverture avec les indices décalés.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static instr_coverage *g_arch_processor_split_coverages(GArchProcessor *proc, instr_coverage *coverage, GArchInstruction *instr, size_t ins_index)
+{
+    instr_coverage *result;                 /* Groupe suivant à renvoyer   */
+    const mrange_t *range;                  /* Emplacement de l'instruction*/
+    size_t cov_index;                       /* Indice du groupe indiqué    */
+    bool first;                             /* Première instruction ?      */
+    size_t remaining;                       /* Qté d'instructions restantes*/
+    vmpa2t end;                             /* Position finale d'un groupe */
+    phys_t diff;                            /* Taille d'un groupe          */
+
+    /* Tour de situation */
+
+    range = g_arch_instruction_get_range(instr);
+
+    cov_index = coverage - proc->coverages;
+
+    first = (ins_index == coverage->start);
+
+    /* Mise en place d'une zone supplémentaire */
+
+    if (proc->cov_allocated == proc->cov_count)
+    {
+        proc->cov_allocated += COV_ALLOC_BLOCK;
+
+        proc->coverages = (instr_coverage *)realloc(proc->coverages,
+                                                    proc->cov_allocated * sizeof(instr_coverage));
+
+    }
+
+    assert(cov_index < proc->cov_count);
+
+    memmove(&proc->coverages[cov_index + 1], &proc->coverages[cov_index],
+            (proc->cov_count - cov_index) * sizeof(instr_coverage));
+
+    proc->cov_count++;
+
+    /* Actualisation des informations */
+
+    if (first)
+    {
+        /* Première zone */
+
+        coverage = &proc->coverages[cov_index];
+
+        copy_mrange(&coverage->range, range);
+        coverage->start = ins_index;
+        coverage->count = 1;
+
+        /* Seconde zone et zones suivantes */
+
+        result = &proc->coverages[cov_index + 1];
+
+    }
+
+    else
+    {
+        /* Première zone */
+
+        coverage = &proc->coverages[cov_index];
+
+        remaining = coverage->count;
+
+        compute_mrange_end_addr(&coverage->range, &end);
+
+        diff = compute_vmpa_diff(get_mrange_addr(&coverage->range), get_mrange_addr(range));
+
+        set_mrange_length(&coverage->range, diff);
+        coverage->count = ins_index - coverage->start;
+
+        assert(coverage->count > 0);
+
+        remaining -= coverage->count;
+
+        /* Seconde zone */
+
+        coverage = &proc->coverages[cov_index + 1];
+
+        diff = compute_vmpa_diff(get_mrange_addr(range), &end);
+
+        init_mrange(&coverage->range, get_mrange_addr(range), diff);
+
+        coverage->start = ins_index;
+        coverage->count = 1 + remaining;
+
+        /* Zones suivantes */
+
+        if ((cov_index + 2) < proc->cov_count)
+            result = &proc->coverages[cov_index + 2];
+        else
+            result = NULL;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc = architecture à modifier via la procédure.             *
+*                a    = premier groupe d'instructions à traiter.              *
+*                b    = second groupe d'instructions à traiter.               *
+*                                                                             *
+*  Description : Fusionne deux groupes d'instructions.                        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_arch_processor_merge_coverages(GArchProcessor *proc, instr_coverage *a, instr_coverage *b)
+{
+    vmpa2t end;                             /* Limite de la couverture B   */
+    phys_t diff;                            /* Ecart entre les extrémités  */
+    size_t b_idx;                           /* Indice de la couverture B   */
+
+    assert(g_atomic_int_get(&proc->locked) == 1);
+
+    assert(a < b);
+
+    compute_mrange_end_addr(&b->range, &end);
+
+    diff = compute_vmpa_diff(get_mrange_addr(&a->range), &end);
+
+    set_mrange_length(&a->range, diff);
+
+    a->count += b->count;
+
+    b_idx = (b - proc->coverages);
+
+    assert(b_idx < proc->cov_count);
+
+    if ((b_idx + 1) < proc->cov_count)
+        memmove(b, b + 1, (proc->cov_count - b_idx - 1) * sizeof(instr_coverage));
+
+    proc->cov_count--;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : proc  = architecture à modifier via la procédure.            *
+*                first = premier groupe d'instructions à traiter.             *
+*                add   = nature de la modification.                           *
+*                                                                             *
+*  Description : Met à jour une série de groupes d'instructions.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_arch_processor_update_coverages(GArchProcessor *proc, instr_coverage *first, bool add)
+{
+    size_t index;                           /* Indice de la couverture     */
+    size_t i;                               /* Boucle de parcours          */
+
+    assert(g_atomic_int_get(&proc->locked) == 1);
+
+    index = first - proc->coverages;
+
+    for (i = index; i < proc->cov_count; i++)
+    {
+        if (add)
+            proc->coverages[i].count++;
+        else
+            proc->coverages[i].count--;
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : proc  = processeur recensant diverses instructions.          *
 *                addr  = position en mémoire ou physique à chercher.          *
 *                                                                             *
@@ -793,7 +1232,7 @@ const instr_coverage *g_arch_processor_find_coverage_by_address(const GArchProce
     instr_coverage *result;                 /* Trouvaille à retourner      */
     void *ptr;                              /* Résultat des recherches     */
 
-    // TODO : assert locked !
+    //assert(g_atomic_int_get(&proc->locked) == 1);
 
     int search_for_coverage_by_addr(const vmpa2t *a, const instr_coverage *c)
     {
@@ -837,7 +1276,7 @@ static bool g_arch_processor_find_covered_index_by_address(const GArchProcessor
     void *ptr;                              /* Résultat des recherches     */
     __compar_fn_t fn;                       /* Fonction auxiliaire adaptée */
 
-    assert(g_atomic_int_get(&proc->locked) == 1);
+    //assert(g_atomic_int_get(&proc->locked) == 1);
 
     int search_for_instr_by_addr(const vmpa2t *a, const GArchInstruction **b)
     {
diff --git a/src/arch/processor.h b/src/arch/processor.h
index 40a610b..878e4c0 100644
--- a/src/arch/processor.h
+++ b/src/arch/processor.h
@@ -36,12 +36,12 @@
 
 
 
-#define G_TYPE_ARCH_PROCESSOR               g_arch_processor_get_type()
-#define G_ARCH_PROCESSOR(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_processor_get_type(), GArchProcessor))
-#define G_IS_ARCH_PROCESSOR(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_processor_get_type()))
-#define G_ARCH_PROCESSOR_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_PROCESSOR, GArchProcessorClass))
-#define G_IS_ARCH_PROCESSOR_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_PROCESSOR))
-#define G_ARCH_PROCESSOR_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_PROCESSOR, GArchProcessorClass))
+#define G_TYPE_ARCH_PROCESSOR            g_arch_processor_get_type()
+#define G_ARCH_PROCESSOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARCH_PROCESSOR, GArchProcessor))
+#define G_IS_ARCH_PROCESSOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARCH_PROCESSOR))
+#define G_ARCH_PROCESSOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_PROCESSOR, GArchProcessorClass))
+#define G_IS_ARCH_PROCESSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_PROCESSOR))
+#define G_ARCH_PROCESSOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_PROCESSOR, GArchProcessorClass))
 
 
 
@@ -96,6 +96,12 @@ size_t g_arch_processor_count_instructions(const GArchProcessor *);
 /* Note les instructions désassemblées avec une architecture. */
 void g_arch_processor_set_instructions(GArchProcessor *, GArchInstruction **, size_t);
 
+/* Ajoute une instruction désassemblée à la liste. */
+void g_arch_processor_add_instruction(GArchProcessor *, GArchInstruction *);
+
+/* Retire une instruction désassemblée de la liste. */
+void g_arch_processor_remove_instruction(GArchProcessor *proc, GArchInstruction *);
+
 /* Fournit une instruction désassemblée pour une architecture. */
 GArchInstruction *g_arch_processor_get_instruction(const GArchProcessor *, size_t);
 
-- 
cgit v0.11.2-87-g4458