/* 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 Chrysalide. 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_PRELOAD_INFO);
/******************************************************************************
* *
* 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);
}