From f1d0462ab0f41ace04d8db02dd8ae3ee37f41a58 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard 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 - +#include #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