/* Chrysalide - Outil d'analyse de fichiers binaires * context.c - contexte lié à l'exécution d'un processeur * * Copyright (C) 2011-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "context.h" #include #include #include #include "context-int.h" /* Taille des blocs d'allocations */ #define DB_ALLOC_SIZE 20 /* Initialise la classe des contextes de processeur. */ static void g_proc_context_class_init(GProcContextClass *); /* Initialise une instance de contexte de processeur. */ static void g_proc_context_init(GProcContext *); /* Supprime toutes les références externes. */ static void g_proc_context_dispose(GProcContext *); /* Procède à la libération totale de la mémoire. */ static void g_proc_context_finalize(GProcContext *); /* Ajoute une adresse virtuelle comme point de départ de code. */ static void _g_proc_context_push_drop_point(GProcContext *, DisassPriorityLevel, virt_t, va_list); /* Indique le type définit par la GLib pour le contexte de processeur. */ G_DEFINE_TYPE(GProcContext, g_proc_context, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des contextes de processeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_proc_context_class_init(GProcContextClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_proc_context_dispose; object->finalize = (GObjectFinalizeFunc)g_proc_context_finalize; klass->push_point = (push_drop_point_fc)_g_proc_context_push_drop_point; g_signal_new("drop-point-pushed", G_TYPE_PROC_CONTEXT, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GProcContextClass, drop_point_pushed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /****************************************************************************** * * * Paramètres : ctx = instance à initialiser. * * * * Description : Initialise une instance de contexte de processeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_proc_context_init(GProcContext *ctx) { DisassPriorityLevel i; /* Boucle de parcours */ for (i = 0; i < DPL_COUNT; i++) { ctx->drop_points[i] = NULL; ctx->dp_allocated[i] = 0; ctx->dp_count[i] = 0; } g_mutex_init(&ctx->dp_access); ctx->extra_symbols = NULL; ctx->esyms_count = 0; g_mutex_init(&ctx->es_access); g_mutex_init(&ctx->items_mutex); } /****************************************************************************** * * * Paramètres : ctx = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_proc_context_dispose(GProcContext *ctx) { size_t i; /* Boucle de parcours */ for (i = 0; i < ctx->items_count; i++) g_object_unref(G_OBJECT(ctx->items[i])); g_mutex_clear(&ctx->items_mutex); G_OBJECT_CLASS(g_proc_context_parent_class)->dispose(G_OBJECT(ctx)); } /****************************************************************************** * * * Paramètres : ctx = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_proc_context_finalize(GProcContext *ctx) { if (ctx->items != NULL) free(ctx->items); G_OBJECT_CLASS(g_proc_context_parent_class)->finalize(G_OBJECT(ctx)); } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage à mettre à jour. * * counter = adresse du compteur à modifier. * * * * Description : Enregistre un compteur pour le décompte des points à traiter.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_proc_context_attach_counter(GProcContext *ctx, gint *counter) { ctx->counter = counter; } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage à compléter. * * level = indication de priorité et d'origine de l'adresse. * * addr = adresse d'un nouveau point de départ à traiter. * * ap = éventuelles informations complémentaires. * * * * Description : Ajoute une adresse virtuelle comme point de départ de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void _g_proc_context_push_drop_point(GProcContext *ctx, DisassPriorityLevel level, virt_t addr, va_list ap) { assert(level < DPL_COUNT); if (ctx->dp_count[level] >= ctx->dp_allocated[level]) { ctx->dp_allocated[level] += DP_ALLOC_BLOCK; ctx->drop_points[level] = (virt_t *)realloc(ctx->drop_points[level], ctx->dp_allocated[level] * sizeof(virt_t)); } ctx->drop_points[level][ctx->dp_count[level]] = addr; ctx->dp_count[level]++; } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage à compléter. * * level = indication de priorité et d'origine de l'adresse. * * addr = adresse d'un nouveau point de départ à traiter. * * ... = éventuelles informations complémentaires. * * * * Description : Ajoute une adresse virtuelle comme point de départ de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_proc_context_push_drop_point(GProcContext *ctx, DisassPriorityLevel level, virt_t addr, ...) { va_list ap; /* Arguments complémentaires ? */ va_start(ap, addr); g_mutex_lock(&ctx->dp_access); if (ctx->counter != NULL) g_atomic_int_inc(ctx->counter); G_PROC_CONTEXT_GET_CLASS(ctx)->push_point(ctx, level, addr, ap); g_mutex_unlock(&ctx->dp_access); g_signal_emit_by_name(ctx, "drop-point-pushed"); va_end(ap); } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage à compléter. * * level = degré d'importance de l'adresse retournée. [OUT] * * virt = adresse d'un point de départ de code à traiter. [OUT]* * * * Description : Fournit une adresse virtuelle comme point de départ de code. * * * * Retour : true si une adresse a pu être dépilée, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_proc_context_pop_drop_point(GProcContext *ctx, DisassPriorityLevel *level, virt_t *virt) { bool result; /* Bilan d'accès à retourner */ DisassPriorityLevel i; /* Boucle de parcours */ result = false; g_mutex_lock(&ctx->dp_access); for (i = 0; i < DPL_COUNT && !result; i++) if (ctx->dp_count[i] > 0) { result = true; *level = i; *virt = ctx->drop_points[i][0]; if (ctx->dp_count[i] > 1) memmove(&ctx->drop_points[i][0], &ctx->drop_points[i][1], (ctx->dp_count[i] - 1) * sizeof(virt_t)); ctx->dp_count[i]--; } g_mutex_unlock(&ctx->dp_access); return result; } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage à compléter. * * addr = adresse d'un nouveau symbole à traiter. * * * * Description : Empile une adresse de nouveau symbole à prendre en compte. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_proc_context_push_new_symbol_at(GProcContext *ctx, const vmpa2t *addr) { g_mutex_lock(&ctx->es_access); ctx->extra_symbols = (vmpa2t *)realloc(ctx->extra_symbols, ++ctx->esyms_count * sizeof(vmpa2t)); copy_vmpa(&ctx->extra_symbols[ctx->esyms_count - 1], addr); g_mutex_unlock(&ctx->es_access); } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage à compléter. * * addr = adresse d'un nouveau symbole à traiter. * * * * Description : Dépile une adresse de nouveau symbole à prendre en compte. * * * * Retour : true si un symbole était bien encore en stock, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool g_proc_context_pop_new_symbol_at(GProcContext *ctx, vmpa2t *addr) { bool result; /* Bilan à retourner */ g_mutex_lock(&ctx->es_access); result = (ctx->esyms_count > 0); if (result) { ctx->esyms_count--; copy_vmpa(addr, &ctx->extra_symbols[ctx->esyms_count]); } g_mutex_unlock(&ctx->es_access); return result; } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage générique à consulter. * * item = élément pour base de données à conserver. * * * * Description : Note la mise en place d'un élément pendant le désassemblage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_proc_context_add_db_item(GProcContext *ctx, GDbItem *item) { g_mutex_lock(&ctx->items_mutex); if ((ctx->items_count + 1) > ctx->items_allocated) { ctx->items_allocated += DB_ALLOC_SIZE; ctx->items = (GDbItem **)realloc(ctx->items, sizeof(GDbItem *) * ctx->items_allocated); } ctx->items[ctx->items_count++] = item; g_mutex_unlock(&ctx->items_mutex); } /****************************************************************************** * * * Paramètres : ctx = contexte de désassemblage générique à consulter. * * func = fonction à appeler pour chaque élément. * * data = éventuelles données à associer à l'appel. * * * * Description : Effectue un traitement sur chaque élement de base de données.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_proc_context_foreach_db_item(GProcContext *ctx, GFunc func, void *data) { size_t i; /* Boucle de parcours */ g_mutex_lock(&ctx->items_mutex); for (i = 0; i < ctx->items_count; i++) func(ctx->items[i], data); g_mutex_unlock(&ctx->items_mutex); }