/* Chrysalide - Outil d'analyse de fichiers binaires * routines.c - étude des flots d'exécution dans les routines * * Copyright (C) 2016-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 "routines.h" #include "dragon.h" #include "limit.h" #include "loop.h" #include "rank.h" #include "../../glibext/delayed-int.h" /* Fraction de routines à limiter (instance) */ struct _GRoutinesStudy { GDelayedWork parent; /* A laisser en premier */ GArchProcessor *proc; /* Processeurs avec ses instr. */ GBinPortion *portions; /* Couches de binaire bornées */ GBinSymbol **symbols; /* Liste de symboles à traiter */ size_t count; /* Taille de cette liste */ rtn_fallback_cb fallback; /* Routine de traitement finale*/ size_t begin; /* Point de départ du parcours */ size_t end; /* Point d'arrivée exclu */ activity_id_t id; /* Identifiant pour messages */ }; /* Fraction de routines à limiter (classe) */ struct _GRoutinesStudyClass { GDelayedWorkClass parent; /* A laisser en premier */ }; /* Indique le type défini pour les tâches d'étude de routines. */ GType g_routines_study_get_type(void); /* Initialise la classe des tâches d'étude de routines. */ static void g_routines_study_class_init(GRoutinesStudyClass *); /* Initialise une tâche d'étude de routines. */ static void g_routines_study_init(GRoutinesStudy *); /* Supprime toutes les références externes. */ static void g_routines_study_dispose(GRoutinesStudy *); /* Procède à la libération totale de la mémoire. */ static void g_routines_study_finalize(GRoutinesStudy *); /* Assure l'étude des routines en différé. */ static void g_routines_study_process(GRoutinesStudy *, GtkStatusStack *); /* Indique le type défini pour les tâches d'étude de routines. */ G_DEFINE_TYPE(GRoutinesStudy, g_routines_study, G_TYPE_DELAYED_WORK); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des tâches d'étude de routines. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_routines_study_class_init(GRoutinesStudyClass *klass) { GObjectClass *object; /* Autre version de la classe */ GDelayedWorkClass *work; /* Version en classe parente */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_routines_study_dispose; object->finalize = (GObjectFinalizeFunc)g_routines_study_finalize; work = G_DELAYED_WORK_CLASS(klass); work->run = (run_task_fc)g_routines_study_process; } /****************************************************************************** * * * Paramètres : study = instance à initialiser. * * * * Description : Initialise une tâche d'étude de routines. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_routines_study_init(GRoutinesStudy *study) { } /****************************************************************************** * * * Paramètres : study = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_routines_study_dispose(GRoutinesStudy *study) { g_object_unref(G_OBJECT(study->portions)); G_OBJECT_CLASS(g_routines_study_parent_class)->dispose(G_OBJECT(study)); } /****************************************************************************** * * * Paramètres : study = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_routines_study_finalize(GRoutinesStudy *study) { G_OBJECT_CLASS(g_routines_study_parent_class)->finalize(G_OBJECT(study)); } /****************************************************************************** * * * Paramètres : proc = ensemble d'instructions désassemblées. * * portions = ensemble de couches binaires bornées. * * symbols = liste de symboles à parcourir. * * 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. * * fallback = routine de traitements particuliers. * * * * Description : Crée une tâche d'étude de routines différée. * * * * Retour : Tâche créée. * * * * Remarques : - * * * ******************************************************************************/ GRoutinesStudy *g_routines_study_new(GArchProcessor *proc, GBinPortion *portions, GBinSymbol **symbols, size_t count, size_t begin, size_t end, activity_id_t id, rtn_fallback_cb fallback) { GRoutinesStudy *result; /* Tâche à retourner */ result = g_object_new(G_TYPE_ROUTINES_STUDY, NULL); result->proc = proc; result->portions = portions; g_object_ref(G_OBJECT(portions)); result->symbols = symbols; result->count = count; result->fallback = fallback; result->begin = begin; result->end = end; result->id = id; return result; } /****************************************************************************** * * * Paramètres : study = étude de routines à mener. * * status = barre de statut à tenir informée. * * * * Description : Assure l'étude des routines en différé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_routines_study_process(GRoutinesStudy *study, GtkStatusStack *status) { size_t i; /* Boucle de parcours */ GBinRoutine *routine; /* Routine à traiter */ for (i = study->begin; i < study->end; i++) { routine = g_binary_symbol_get_routine(study->symbols[i]); if (routine != NULL) study->fallback(study, routine, i); gtk_status_stack_update_activity_value(status, study->id, 1); } } /****************************************************************************** * * * Paramètres : study = étude de routines à mener. * * routine = routine à traiter. * * index = indice de l'insruction visée. * * * * Description : Détermine si besoin est les bornes des routines. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_routines_study_compute_limits(GRoutinesStudy *study, GBinRoutine *routine, size_t index) { const mrange_t *range; /* Zone du symbole suivant */ const vmpa2t *next; /* Début de la zone suivante */ if ((index + 1) < study->count) { range = g_binary_symbol_get_range(study->symbols[index + 1]); next = get_mrange_addr(range); } else next = NULL; compute_routine_limit(routine, next, study->proc, study->portions); } /****************************************************************************** * * * Paramètres : study = étude de routines à mener. * * routine = routine à traiter. * * index = indice de l'insruction visée. * * * * Description : Procède au traitement des blocs de routines. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_routines_study_handle_blocks(GRoutinesStudy *study, GBinRoutine *routine, size_t index) { const mrange_t *range; /* Couverture d'une routine */ const vmpa2t *start; /* Adresse de départ */ const instr_coverage *coverage; /* Instructions couvertes */ dragon_knight *knight; /* Complexité de code posée */ GBlockList *blocks; /* Liste de blocs basiques */ /* Préparatifs communs */ range = g_binary_routine_get_range(routine); start = get_mrange_addr(range); coverage = g_arch_processor_find_coverage_by_address(study->proc, start); knight = begin_dragon_knight(study->proc, coverage, range, start); /** * FIXME * L'état 'knight == NULL' peut avoir deux origines : * - soit le binaire est mal-formé. * - soit le désassemblage s'est mal déroulé. * Dans les deux cas, on obtient un symbole qui n'a pas d'instruction de départ. * A traiter autrement qu'en filtrant sur knight... */ if (knight == NULL) return; /* Traitement par blocs */ detect_loops_in_code(knight); blocks = translate_dragon_knight(knight); g_binary_routine_set_basic_blocks(routine, blocks); rank_routine_blocks(routine); /* Nettoyage final */ end_dragon_knight(knight); }