/* Chrysalide - Outil d'analyse de fichiers binaires
* limit.c - détermination des bornes des routines
*
* Copyright (C) 2012-2013 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* OpenIDA 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.
*
* OpenIDA 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 "limit.h"
#include
#include "../../glibext/delayed-int.h"
/* ------------------------- CALCULS DE LIMITES DE ROUTINES ------------------------- */
#define G_TYPE_LIMIT_COMPUTING g_limit_computing_get_type()
#define G_LIMIT_COMPUTING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_limit_computing_get_type(), GLimitComputing))
#define G_IS_LIMIT_COMPUTING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_limit_computing_get_type()))
#define G_LIMIT_COMPUTING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LIMIT_COMPUTING, GLimitComputingClass))
#define G_IS_LIMIT_COMPUTING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LIMIT_COMPUTING))
#define G_LIMIT_COMPUTING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LIMIT_COMPUTING, GLimitComputingClass))
/* Fraction de routines à limiter (instance) */
typedef struct _GLimitComputing
{
GDelayedWork parent; /* A laisser en premier */
const GArchProcessor *proc; /* Processeurs avec ses instr. */
mrange_t *exe_ranges; /* Liste de zones exécutables */
size_t exe_count; /* Nombre de ces zones */
GBinRoutine **routines; /* Liste de routines à traiter */
size_t count; /* Taille de cette liste */
size_t begin; /* Point de départ du parcours */
size_t end; /* Point d'arrivée exclu */
bstatus_id_t id; /* Identifiant pour messages */
} GLimitComputing;
/* Fraction de routines à limiter (classe) */
typedef struct _GLimitComputingClass
{
GDelayedWorkClass parent; /* A laisser en premier */
} GLimitComputingClass;
/* Indique le type défini pour les tâches de calculs de limites. */
GType g_limit_computing_get_type(void);
/* Initialise la classe des tâches de calculs de limites. */
static void g_limit_computing_class_init(GLimitComputingClass *);
/* Initialise une tâche de calculs de limites. */
static void g_limit_computing_init(GLimitComputing *);
/* Supprime toutes les références externes. */
static void g_limit_computing_dispose(GLimitComputing *);
/* Procède à la libération totale de la mémoire. */
static void g_limit_computing_finalize(GLimitComputing *);
/* Crée une tâche de calculs de limites différée. */
static GLimitComputing *g_limit_computing_new(const GArchProcessor *, mrange_t *, size_t, GBinRoutine **, size_t, size_t, size_t, bstatus_id_t);
/* Recherche la zone correspond à une adresse donnée. */
static const mrange_t *find_x_range_for_addr(const mrange_t *, size_t, const vmpa2t *);
/* Assure le calcul de limites de routines en différé. */
static void g_limit_computing_process(GLimitComputing *, GtkExtStatusBar *);
/* ---------------------------------------------------------------------------------- */
/* CALCULS DE LIMITES DE ROUTINES */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour les tâches de calculs de limites. */
G_DEFINE_TYPE(GLimitComputing, g_limit_computing, G_TYPE_DELAYED_WORK);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des tâches de calculs de limites. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_limit_computing_class_init(GLimitComputingClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GDelayedWorkClass *work; /* Version en classe parente */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_limit_computing_dispose;
object->finalize = (GObjectFinalizeFunc)g_limit_computing_finalize;
work = G_DELAYED_WORK_CLASS(klass);
work->run = (run_task_fc)g_limit_computing_process;
}
/******************************************************************************
* *
* Paramètres : computing = instance à initialiser. *
* *
* Description : Initialise une tâche de calculs de limites. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_limit_computing_init(GLimitComputing *computing)
{
}
/******************************************************************************
* *
* Paramètres : computing = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_limit_computing_dispose(GLimitComputing *computing)
{
G_OBJECT_CLASS(g_limit_computing_parent_class)->dispose(G_OBJECT(computing));
}
/******************************************************************************
* *
* Paramètres : computing = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_limit_computing_finalize(GLimitComputing *computing)
{
G_OBJECT_CLASS(g_limit_computing_parent_class)->finalize(G_OBJECT(computing));
}
/******************************************************************************
* *
* Paramètres : proc = ensemble d'instructions désassemblées. *
* routines = prototypes existants à insérer. *
* count = quantité de ces prototypes. *
* begin = point de départ du parcours de liste. *
* end = point d'arrivée exclu du parcours. *
* id = identifiant du message affiché à l'utilisateur. *
* *
* Description : Crée une tâche de calculs de limites différée. *
* *
* Retour : Tâche créée. *
* *
* Remarques : - *
* *
******************************************************************************/
static GLimitComputing *g_limit_computing_new(const GArchProcessor *proc, mrange_t *exe_ranges, size_t exe_count, GBinRoutine **routines, size_t count, size_t begin, size_t end, bstatus_id_t id)
{
GLimitComputing *result; /* Tâche à retourner */
result = g_object_new(G_TYPE_LIMIT_COMPUTING, NULL);
result->proc = proc;
result->exe_ranges = exe_ranges;
result->exe_count = exe_count;
result->routines = routines;
result->count = count;
result->begin = begin;
result->end = end;
result->id = id;
return result;
}
/******************************************************************************
* *
* Paramètres : ranges = liste de zones offrant une exécution et disponibles.*
* count = taille de cette liste. *
* *
* Description : Recherche la zone correspond à une adresse donnée. *
* *
* Retour : Zone trouvée ou NULL si aucune ne correspond. *
* *
* Remarques : - *
* *
******************************************************************************/
static const mrange_t *find_x_range_for_addr(const mrange_t *ranges, size_t count, const vmpa2t *addr)
{
const mrange_t *result; /* Zone à retourner */
size_t i; /* Boucle de parcours */
result = NULL;
for (i = 0; i < count && result == NULL; i++)
if (mrange_contains_addr(&ranges[i], addr))
result = &ranges[i];
return result;
}
/******************************************************************************
* *
* Paramètres : computing = récupération à mener. *
* statusbar = barre de statut à tenir informée. *
* *
* Description : Assure le calcul de limites de routines en différé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_limit_computing_process(GLimitComputing *computing, GtkExtStatusBar *statusbar)
{
size_t i; /* Boucle de parcours */
GBinRoutine *routine; /* Routine en traitement */
const mrange_t *range; /* Emplacement courant */
vmpa2t addr; /* Adresse à conserver */
GArchInstruction *start; /* Première instruction */
phys_t diff; /* Taille définie par déduction*/
mrange_t new; /* Nouvel emplacement taillé */
for (i = computing->begin; i < computing->end; i++)
{
//gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
routine = computing->routines[i];
range = g_binary_routine_get_range(routine);
if (get_mrange_length(range) > 0) continue;
copy_vmpa(&addr, get_mrange_addr(range));
/* Marquage de la première instruction */
start = g_arch_processor_find_instr_by_address(computing->proc, &addr);
if (start == NULL) continue;
g_arch_instruction_set_flag(start, AIF_ROUTINE_START);
/* Si on peut se raccrocher à la routine suivante... */
if ((i + 1) < computing->count)
{
range = g_binary_routine_get_range(computing->routines[i + 1]);
diff = compute_vmpa_diff(&addr, get_mrange_addr(range));
}
/* Sinon on va jusqu'à la fin de la zone ! */
else
{
range = find_x_range_for_addr(computing->exe_ranges, computing->exe_count, &addr);
if (range == NULL) continue;
diff = compute_vmpa_diff(&addr, get_mrange_addr(range));
diff = get_mrange_length(range) - diff;
}
init_mrange(&new, &addr, diff);
g_binary_routine_set_range(routine, &new);
}
}
/* ---------------------------------------------------------------------------------- */
/* POINT D'ENTREE ET DECOUPAGES */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : format = format du binaire concerné par la procédure. *
* proc = ensemble d'instructions désassemblées. *
* routines = prototypes existants à insérer. *
* count = quantité de ces prototypes. *
* gid = identifiant du groupe de travail à utiliser. *
* id = identifiant du message affiché à l'utilisateur. *
* *
* Description : S'assure que toutes les routines ont une taille définie. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void limit_all_routines(GExeFormat *format, const GArchProcessor *proc, GBinRoutine **routines, size_t count, wgroup_id_t gid, bstatus_id_t id)
{
mrange_t *exe_ranges; /* Liste de zones exécutables */
size_t exe_count; /* Nombre de ces zones */
guint runs_count; /* Qté d'exécutions parallèles */
size_t run_size; /* Volume réparti par exécution*/
GWorkQueue *queue; /* Gestionnaire de différés */
guint i; /* Boucle de parcours */
size_t begin; /* Début de bloc de traitement */
size_t end; /* Fin d'un bloc de traitement */
GLimitComputing *computing; /* Tâche de calcul à programmer*/
exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);
runs_count = g_get_num_processors();
run_size = count / runs_count;
queue = get_work_queue();
for (i = 0; i < runs_count; i++)
{
begin = i * run_size;
if ((i + 1) < runs_count)
end = count - begin;
else
end = begin + run_size;
computing = g_limit_computing_new(proc, exe_ranges, exe_count, routines, count, begin, end, id);
g_work_queue_schedule_work(queue, G_DELAYED_WORK(computing), gid);
}
g_work_queue_wait_for_completion(queue, gid);
if (exe_ranges != NULL)
free(exe_ranges);
do
{
const mrange_t *_range;
vmpa2t _end;
printf("LIMIT == %zu routines\n", count);
for (i = 0; i < count; i++)
{
_range = g_binary_routine_get_range(routines[i]);
compute_mrange_end_addr(_range, &_end);
printf(" 0x%08x <-> 0x%08x '%s'\n",
(unsigned int)((get_mrange_addr(_range))->virtual),
(unsigned int)_end.virtual,
g_binary_routine_to_string(routines[i]));
}
} while (0);
}