summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-08-06 17:43:08 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-08-06 17:43:08 (GMT)
commitf1d0462ab0f41ace04d8db02dd8ae3ee37f41a58 (patch)
treee3d9cf75f0adf14f73ca8f62e81fececd60e744e
parente59544bb61b0043d82946918ece144cae2749d53 (diff)
Allowed to add or remove instructions once a binary analysis is over.
-rw-r--r--src/analysis/binary.c105
-rw-r--r--src/arch/processor-int.h4
-rw-r--r--src/arch/processor.c445
-rw-r--r--src/arch/processor.h18
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);