summaryrefslogtreecommitdiff
path: root/src/analysis/disass/area.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/disass/area.c')
-rw-r--r--src/analysis/disass/area.c637
1 files changed, 402 insertions, 235 deletions
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c
index 71e2784..2bc7a53 100644
--- a/src/analysis/disass/area.c
+++ b/src/analysis/disass/area.c
@@ -35,6 +35,7 @@
#include "../../analysis/contents/restricted.h"
#include "../../arch/raw.h"
#include "../../common/bits.h"
+#include "../../common/sort.h"
#include "../../format/format.h"
#include "../../glibext/delayed-int.h"
#include "../../gui/panels/log.h"
@@ -115,11 +116,32 @@ typedef struct _GAreaCollector
mem_area *areas; /* Zone de productions */
- size_t begin; /* Début du parcours à mener */
- size_t end; /* Fin de ce même parcours */
+ union
+ {
+ struct
+ {
+ size_t acount; /* Nombre de zones créées */
+
+ GLoadedBinary *binary; /* Binaire à associer aux zones*/
- GArchInstruction **collected; /* Instructions collectées */
- size_t count; /* Quantité de ces instructions*/
+ phys_t first; /* Début de traitement */
+ phys_t last; /* Fin de traitement */
+
+ bool closing; /* Tâche clôturant le parcours */
+
+ };
+
+ struct
+ {
+ size_t begin; /* Début du parcours à mener */
+ size_t end; /* Fin de ce même parcours */
+
+ GArchInstruction **collected; /* Instructions collectées */
+ size_t ccount; /* Quantité de ces instructions*/
+
+ };
+
+ };
} GAreaCollector;
@@ -149,6 +171,12 @@ static void g_area_collector_finalize(GAreaCollector *);
/* Assure un traitement particulier concernant les zones. */
static void g_area_collector_process(GAreaCollector *, GtkStatusStack *);
+/* Crée une tâche de calcul des zones binaires à désassembler. */
+static GAreaCollector *g_area_collector_new_intro(activity_id_t, GLoadedBinary *, phys_t, phys_t, bool);
+
+/* Construit une liste bornée de zones contigües. */
+static void g_area_collector_do_compute(GAreaCollector *, GtkStatusStack *);
+
/* Crée une tâche de récupération d'instructions différée. */
static GAreaCollector *g_area_collector_new_outro(activity_id_t, mem_area *, size_t, size_t);
@@ -779,230 +807,6 @@ static GArchInstruction **get_instructions_from_mem_area(const mem_area *area, G
/******************************************************************************
* *
-* Paramètres : binary = binaire analysé contenant quantités d'infos. *
-* bin_length = quantité d'octets à traiter au total. *
-* count = nombre de zones mises en place. [OUT] *
-* *
-* Description : Détermine une liste de zones contigües à traiter. *
-* *
-* Retour : Liste de zones mémoire à libérer après usage. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-mem_area *compute_memory_areas(const GLoadedBinary *binary, phys_t bin_length, size_t *count)
-{
- mem_area *result; /* Liste à renvoyer */
- GExeFormat *format; /* Format de fichier associé */
- mrange_t *exe_ranges; /* Liste de zones exécutables */
- size_t exe_count; /* Nombre de ces zones */
- GBinSymbol **symbols; /* Symboles à représenter */
- size_t sym_count; /* Qté de symboles présents */
- vmpa2t last; /* Dernière bordure rencontrée */
- bool status; /* Bilan d'une conversion */
- size_t i; /* Boucle de parcours #1 */
- const vmpa2t *border; /* Nouvelle bordure rencontrée */
- mem_area *area; /* Zone avec valeurs à éditer */
- vmpa2t tmp; /* Stockage temporaire */
- GPortionLayer *layer; /* Couche première de portions */
- GBinPortion **portions; /* Morceaux d'encadrement */
- size_t portions_count; /* Taille de cette liste */
- const vmpa2t *portion_start; /* Point de départ de portion */
- const vmpa2t *portion_next; /* Départ de portion suivante */
- size_t j; /* Boucle de parcours #2 */
- SymbolType type; /* Nature d'un symbole */
- const mrange_t *range; /* Couverture d'un symbole */
- phys_t length; /* Taille de ce même symbole */
- phys_t new_length; /* Nouvelle taille déterminée */
-
- result = NULL;
- *count = 0;
-
- /**
- * Le parcours n'est valide que si les zones exécutables sont triées !
- */
-
- format = g_loaded_binary_get_format(binary);
-
- exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);
-
- symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
-
- /* Première étape : on comble les trous ! */
-
- status = g_exe_format_translate_offset_into_vmpa(format, 0, &last);
- assert(status);
-
- for (i = 0; i < exe_count; i++)
- {
- border = get_mrange_addr(&exe_ranges[i]);
-
- /* Zone tampon à constituer */
-
- if (cmp_vmpa(&last, border) < 0)
- {
- result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
- area = &result[*count - 1];
-
- init_mem_area_from_addr(area, &last, compute_vmpa_diff(&last, border), binary);
- area->is_exec = false;
-
- }
-
- /* Insertion d'une zone exécutable déjà définie */
-
- result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
- area = &result[*count - 1];
-
- init_mem_area_from_addr(area, get_mrange_addr(&exe_ranges[i]),
- get_mrange_length(&exe_ranges[i]), binary);
- area->is_exec = true;
-
- /* Avancée du curseur */
-
- compute_mrange_end_addr(&exe_ranges[i], &last);
-
- }
-
- /* Extension finale complémentaire ? */
-
- area = &result[*count - 1];
-
- copy_vmpa(&tmp, get_mrange_addr(&area->range));
- advance_vmpa(&tmp, get_mrange_length(&area->range));
-
- if (get_phy_addr(&tmp) < bin_length)
- {
- result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
- area = &result[*count - 1];
-
- init_mem_area_from_addr(area, &tmp, bin_length - get_phy_addr(&tmp), binary);
- area->is_exec = false;
-
- }
-
- /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */
-
- layer = g_exe_format_get_main_layer(format);
-
- portions = g_portion_layer_collect_all_portions(layer, &portions_count);
-
- for (i = 1; i < portions_count; i++)
- {
- portion_start = get_mrange_addr(g_binary_portion_get_range(portions[i]));
-
- /**
- * Si plusieurs portions débutent au même endroit, il ne sert
- * à rien de découper plusieurs fois.
- */
- if ((i + 1) < portions_count)
- {
- portion_next = get_mrange_addr(g_binary_portion_get_range(portions[i + 1]));
-
- if (cmp_vmpa(portion_start, portion_next) == 0)
- continue;
-
- }
-
- for (j = 0; j < *count; j++)
- {
- area = &result[j];
-
- if (!mrange_contains_addr(&area->range, portion_start))
- continue;
-
- /* Si le déccoupage actuel ne correspond pas au besoin des portions... */
- if (cmp_vmpa(get_mrange_addr(&area->range), portion_start) != 0)
- {
- fini_mem_area(&result[j]);
-
- result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
-
- memmove(&result[j + 2], &result[j + 1], (*count - j - 2) * sizeof(mem_area));
-
- status = result[j].is_exec;
-
- /* Première moitié */
-
- area = &result[j];
-
- copy_vmpa(&tmp, get_mrange_addr(&area->range));
- length = get_mrange_length(&area->range);
-
- new_length = compute_vmpa_diff(&tmp, portion_start);
-
- init_mem_area_from_addr(area, &tmp, new_length, binary);
- area->is_exec = status;
-
- /* Seconde moitié */
-
- length -= get_mrange_length(&area->range);
-
- area = &result[j + 1];
-
- init_mem_area_from_addr(area, portion_start, length, binary);
- area->is_exec = status;
-
- }
-
- j = *count;
-
- }
-
- }
-
- if (portions != NULL)
- free(portions);
-
- g_object_unref(G_OBJECT(layer));
-
- /* Troisième étape : on insère les symboles existants */
-
- for (i = 0; i < sym_count; i++)
- {
- type = g_binary_symbol_get_target_type(symbols[i]);
-
- /**
- * On ne garde que les symboles renvoyant directement une ou
- * plusieurs instructions, c'est à dire les symboles valides
- * pour un appel à g_binary_symbol_get_instruction().
- *
- * Les instructions des autres symboles sont obtenues et mises
- * en place durant la procédure de désassemblage.
- */
-
- if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL)
- continue;
-
- range = g_binary_symbol_get_range(symbols[i]);
-
- length = get_mrange_length(range);
-
- if (length == 0)
- continue;
-
- insert_extra_symbol_into_mem_areas(result, *count, symbols[i]);
-
- }
-
- /* Nettoyage final */
-
- if (exe_ranges != NULL)
- free(exe_ranges);
-
- g_object_unref(G_OBJECT(format));
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : list = listes de zones utable à consulter. *
* count = nombre de zones mises en place. *
* addr = adresse à retrouver dans les aires présentes. *
@@ -1212,6 +1016,9 @@ static void g_area_collector_init(GAreaCollector *collector)
static void g_area_collector_dispose(GAreaCollector *collector)
{
+ if (collector->run == (run_task_fc)g_area_collector_do_compute)
+ g_object_unref(G_OBJECT(collector->binary));
+
G_OBJECT_CLASS(g_area_collector_parent_class)->dispose(G_OBJECT(collector));
}
@@ -1258,6 +1065,366 @@ static void g_area_collector_process(GAreaCollector *collector, GtkStatusStack *
/******************************************************************************
* *
+* Paramètres : id = identifiant pour signaler la progression courante. *
+* binary = binaire chargé à conserver dans les zones définies.*
+* first = localisation du début de la portion à traiter. *
+* last = localisation de la fin de la portion à traiter. *
+* closing = indique si la tâche doit terminer l'analyse. *
+* *
+* Description : Crée une tâche de calcul des zones binaires à désassembler. *
+* *
+* Retour : Tâche créée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GAreaCollector *g_area_collector_new_intro(activity_id_t id, GLoadedBinary *binary, phys_t first, phys_t last, bool closing)
+{
+ GAreaCollector *result; /* Tâche à retourner */
+
+ result = g_object_new(G_TYPE_AREA_COLLECTOR, NULL);
+
+ result->id = id;
+ result->run = (run_task_fc)g_area_collector_do_compute;
+
+ result->areas = NULL;
+
+ result->acount = 0;
+
+ result->binary = binary;
+ g_object_ref(G_OBJECT(binary));
+
+ result->first = first;
+ result->last = last;
+
+ result->closing = closing;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fetching = récupération à mener. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Construit une liste bornée de zones contigües. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_area_collector_do_compute(GAreaCollector *collector, GtkStatusStack *status)
+{
+ mem_area **list; /* Liste de zones à constituer */
+ size_t *count; /* Nombre d'éléments intégrés */
+ vmpa2t first; /* Point de départ */
+ vmpa2t last; /* Point d'arrivée */
+ GExeFormat *format; /* Format du binaire */
+ vmpa2t prev; /* Dernière bordure rencontrée */
+ bool state; /* Bilan d'une conversion */
+ GBinSymbol **symbols; /* Symboles à représenter */
+ size_t sym_count; /* Qté de symboles présents */
+ bool has_sym_index; /* Détermine une validité */
+ size_t sym_index; /* Prochain symbole non traité */
+ GBinPortion *portions; /* Couche première de portions */
+
+ void populate_with_symbols(const vmpa2t *limit)
+ {
+ GBinSymbol *symbol; /* Symbole en cours d'analyse */
+ SymbolType type; /* Nature d'un symbole */
+ const mrange_t *range; /* Couverture d'un symbole */
+ vmpa2t end; /* Adresse de fin du symbole */
+
+ for (; sym_index < sym_count; sym_index++)
+ {
+ symbol = symbols[sym_index];
+
+ type = g_binary_symbol_get_target_type(symbol);
+
+ /**
+ * On ne garde que les symboles renvoyant directement une ou
+ * plusieurs instructions, c'est à dire les symboles valides
+ * pour un appel à g_binary_symbol_get_instruction().
+ *
+ * Les instructions des autres symboles sont obtenues et mises
+ * en place durant la procédure de désassemblage.
+ */
+
+ if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL)
+ continue;
+
+ range = g_binary_symbol_get_range(symbol);
+
+ if (get_mrange_length(range) == 0)
+ continue;
+
+ if (cmp_vmpa(get_mrange_addr(range), limit) >= 0)
+ break;
+
+ compute_mrange_end_addr(range, &end);
+
+ /**
+ * Si un symbole est à cheval entre deux zones, tant pis pour lui !
+ */
+
+ if (cmp_vmpa(&end, limit) > 0)
+ break;
+
+ insert_extra_symbol_into_mem_areas(*list, *count, symbol);
+
+ }
+
+ }
+
+ void fill_gap(vmpa2t *old, vmpa2t *new, bool exec)
+ {
+ phys_t diff; /* Espace entre bordures */
+ mem_area *area; /* Zone avec valeurs à éditer */
+
+ diff = compute_vmpa_diff(old, new);
+
+ /**
+ * S'il existe un écart entre la dernière bordure ajoutée et
+ * l'extréminité de la portion courante, on le comble !
+ */
+
+ if (diff > 0)
+ {
+ /* Zone tampon à constituer */
+
+ *list = (mem_area *)realloc(*list, ++(*count) * sizeof(mem_area));
+
+ area = &(*list)[*count - 1];
+
+ init_mem_area_from_addr(area, old, diff, collector->binary);
+ area->is_exec = exec;
+
+ /* Insertion des symboles existants */
+
+ if (!has_sym_index)
+ {
+ int cmp_vmpa_with_symbol(const vmpa2t *a, const GBinSymbol **s)
+ {
+ return g_binary_symbol_cmp_with_vmpa(*s, a);
+ }
+
+ bsearch_index(old, symbols, sym_count, sizeof(GBinSymbol *),
+ (__compar_fn_t)cmp_vmpa_with_symbol, &sym_index);
+
+ has_sym_index = true;
+
+ }
+
+ populate_with_symbols(new);
+
+ /* Avancée du curseur */
+
+ copy_vmpa(old, new);
+
+ gtk_status_stack_update_activity_value(status, collector->id, diff);
+
+ }
+
+ }
+
+ bool build_area_from_portion(GBinPortion *portion, GBinPortion *parent, BinaryPortionVisit visit, void *unused)
+ {
+ const mrange_t *range; /* Espace de portion à traiter */
+ vmpa2t border; /* Nouvelle bordure rencontrée */
+ bool on_track; /* Le tronçon courant est bon ?*/
+ PortionAccessRights rights; /* Droits d'accès à analyser */
+
+ range = g_binary_portion_get_range(portion);
+
+ if (visit == BPV_ENTER)
+ {
+ copy_vmpa(&border, get_mrange_addr(range));
+
+ on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0;
+
+ if (on_track)
+ {
+ rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE);
+ fill_gap(&prev, &border, rights & PAC_EXEC);
+ }
+ else
+ copy_vmpa(&prev, &border);
+
+ }
+
+ else if (visit == BPV_SHOW)
+ {
+ copy_vmpa(&border, get_mrange_addr(range));
+
+ on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0;
+
+ if (on_track)
+ {
+ rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE);
+ fill_gap(&prev, &border, rights & PAC_EXEC);
+
+ compute_mrange_end_addr(range, &border);
+
+ rights = g_binary_portion_get_rights(portion);
+ fill_gap(&prev, &border, rights & PAC_EXEC);
+
+ }
+ else
+ compute_mrange_end_addr(range, &prev);
+
+ }
+
+ else if (visit == BPV_EXIT)
+ {
+ compute_mrange_end_addr(range, &border);
+
+ if (collector->closing)
+ on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) <= 0;
+ else
+ on_track = cmp_vmpa(&first, &border) <= 0 && cmp_vmpa(&border, &last) < 0;
+
+ if (on_track)
+ {
+ rights = (parent != NULL ? g_binary_portion_get_rights(parent) : PAC_NONE);
+ fill_gap(&prev, &border, rights & PAC_EXEC);
+ }
+ else
+ copy_vmpa(&prev, &border);
+
+ }
+
+#ifndef NDEBUG
+ else
+ assert(false);
+#endif
+
+ return (cmp_vmpa(&prev, &last) < 0);
+
+ }
+
+ list = &collector->areas;
+ count = &collector->acount;
+
+ init_vmpa(&first, collector->first, VMPA_NO_VIRTUAL);
+ init_vmpa(&last, collector->last, VMPA_NO_VIRTUAL);
+
+ format = g_loaded_binary_get_format(collector->binary);
+
+#ifndef NDEBUG
+ state = g_exe_format_translate_offset_into_vmpa(format, 0, &prev);
+ assert(state);
+#else
+ g_exe_format_translate_offset_into_vmpa(format, 0, &prev);
+#endif
+
+ symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
+
+ has_sym_index = false;
+
+ portions = g_exe_format_get_portions(format);
+
+ g_binary_portion_visit(portions, (visit_portion_fc)build_area_from_portion, NULL);
+
+ g_object_unref(G_OBJECT(portions));
+
+ g_object_unref(G_OBJECT(format));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : gid = groupe de travail impliqué. *
+* status = barre de statut à tenir informée. *
+* binary = binaire analysé contenant quantités d'infos. *
+* length = quantité d'octets à traiter au total. *
+* count = nombre de zones mises en place. [OUT] *
+* *
+* Description : Détermine une liste de zones contigües à traiter. *
+* *
+* Retour : Liste de zones mémoire à libérer après usage. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+mem_area *collect_memory_areas(wgroup_id_t gid, GtkStatusStack *status, GLoadedBinary *binary, phys_t length, size_t *count)
+{
+ mem_area *result; /* Liste finale à retourner */
+ guint runs_count; /* Qté d'exécutions parallèles */
+ GAreaCollector **collectors; /* Collecteurs à suivre */
+ phys_t run_size; /* Volume réparti par exécution*/
+ GWorkQueue *queue; /* Gestionnaire de différés */
+ activity_id_t id; /* Identifiant de progression */
+ guint i; /* Boucle de parcours */
+ phys_t first; /* Début de zone de traitement */
+ bool closing; /* Détection de fin en amont */
+ phys_t last; /* Fin de zone de traitement */
+
+ runs_count = g_get_num_processors();
+
+ collectors = (GAreaCollector **)calloc(runs_count, sizeof(GAreaCollector *));
+
+ run_size = length / runs_count;
+
+ queue = get_work_queue();
+
+ id = gtk_status_stack_add_activity(status, _("Computing memory areas to disassemble"), length);
+
+ for (i = 0; i < runs_count; i++)
+ {
+ first = i * run_size;
+
+ closing = ((i + 1) == runs_count);
+
+ if (closing)
+ last = length;
+ else
+ last = first + run_size;
+
+ collectors[i] = g_area_collector_new_intro(id, binary, first, last, closing);
+
+ g_object_ref(G_OBJECT(collectors[i]));
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(collectors[i]), gid);
+
+ }
+
+ g_work_queue_wait_for_completion(queue, gid);
+
+ /* Récupération des aires */
+
+ result = NULL;
+ *count = 0;
+
+ for (i = 0; i < runs_count; i++)
+ {
+ result = (mem_area *)realloc(result, (*count + collectors[i]->acount) * sizeof(mem_area));
+
+ memcpy(&result[*count], collectors[i]->areas, collectors[i]->acount * sizeof(mem_area));
+ *count += collectors[i]->acount;
+
+ g_object_unref(G_OBJECT(collectors[i]));
+
+ }
+
+ /* Fin */
+
+ free(collectors);
+
+ gtk_status_stack_remove_activity(status, id);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : id = identifiant pour signaler la progression courante. *
* list = liste des zones en place à parcourir. *
* begin = indice de la première zone à traiter. *
@@ -1286,7 +1453,7 @@ static GAreaCollector *g_area_collector_new_outro(activity_id_t id, mem_area *li
result->end = end;
result->collected = NULL;
- result->count = 0;
+ result->ccount = 0;
return result;
@@ -1313,7 +1480,7 @@ static void g_area_collector_do_collect(GAreaCollector *collector, GtkStatusStac
for (i = collector->begin; i < collector->end; i++)
{
collector->collected = get_instructions_from_mem_area(&collector->areas[i],
- collector->collected, &collector->count);
+ collector->collected, &collector->ccount);
fini_mem_area(&collector->areas[i]);
@@ -1326,8 +1493,8 @@ static void g_area_collector_do_collect(GAreaCollector *collector, GtkStatusStac
/******************************************************************************
* *
-* Paramètres : gid = groupe de travail impliqué. *
-* status = barre de statut à tenir informée. *
+* Paramètres : gid = groupe de travail impliqué. *
+* status = barre de statut à tenir informée. *
* list = liste des zones de données à relire puis libérer. *
* acount = taille de cette liste de zones. *
* icount = nombre d'instructions récupérées. [OUT] *
@@ -1388,10 +1555,10 @@ GArchInstruction **collect_disassembled_instructions(wgroup_id_t gid, GtkStatusS
for (i = 0; i < runs_count; i++)
{
result = (GArchInstruction **)realloc(result,
- (*icount + collectors[i]->count) * sizeof(GArchInstruction *));
+ (*icount + collectors[i]->ccount) * sizeof(GArchInstruction *));
- memcpy(&result[*icount], collectors[i]->collected, collectors[i]->count * sizeof(GArchInstruction *));
- *icount += collectors[i]->count;
+ memcpy(&result[*icount], collectors[i]->collected, collectors[i]->ccount * sizeof(GArchInstruction *));
+ *icount += collectors[i]->ccount;
g_object_unref(G_OBJECT(collectors[i]));