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