/* Chrysalide - Outil d'analyse de fichiers binaires * virtual.c - encadrement des instructions par blocs virtuels * * Copyright (C) 2012-2013 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 "virtual.h" #include #include "flow.h" #include "../block-int.h" /* Description d'un bloc d'exécution d'instructions (instance) */ struct _GVirtualBlock { GInstrBlock parent; /* A laisser en premier */ GArchInstruction *instrs; /* Liste complète d'instruct° */ GArchInstruction *first; /* Première instruction */ GArchInstruction *last; /* Dernière instruction */ GInstrBlock **children; /* Sous-blocs intégrés */ size_t children_count; /* Nombre de ces sous-blocs */ #if 0 reg_access *accesses; /* Commodités d'accès #1 */ size_t count; /* Commodités d'accès #2 */ #endif }; /* Description d'un bloc d'exécution d'instructions (classe) */ struct _GVirtualBlockClass { GInstrBlockClass parent; /* A laisser en premier */ }; /* Initialise la classe des blocs d'instructions. */ static void g_virtual_block_class_init(GVirtualBlockClass *); /* Initialise un bloc d'instructions. */ static void g_virtual_block_init(GVirtualBlock *); /* Supprime toutes les références externes. */ static void g_virtual_block_dispose(GVirtualBlock *); /* Procède à la libération totale de la mémoire. */ static void g_virtual_block_finalize(GVirtualBlock *); /* Recherche le bloc contenant une adresse donnée. */ static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *, const vmpa2t *, bool); /* Parcourt le bloc d'instructions dans un ordre donné. */ static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void *); /* Etablit la liste de tous les blocs présents. */ static void g_virtual_block_list_all_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *); /* Etablit la liste de tous les blocs terminaux. */ static void g_virtual_block_list_leafs_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *); /* Fournit les différents accès aux registres. */ //static const reg_access *g_virtual_block_list_regs_accesses(const GVirtualBlock *, size_t *); /* Indique le type défini pour un bloc virtuel d'instructions. */ G_DEFINE_TYPE(GVirtualBlock, g_virtual_block, G_TYPE_INSTR_BLOCK); /****************************************************************************** * * * Paramètres : class = classe à initialiser. * * * * Description : Initialise la classe des blocs d'instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_virtual_block_class_init(GVirtualBlockClass *class) { GObjectClass *object; /* Autre version de la classe */ GInstrBlockClass *block_class; /* Version parente du la classe*/ object = G_OBJECT_CLASS(class); block_class = G_INSTR_BLOCK_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)g_virtual_block_dispose; object->finalize = (GObjectFinalizeFunc)g_virtual_block_finalize; block_class->find_by_addr = (find_by_addr_fc)g_virtual_block_find_by_addr; block_class->visit_blocks = (visit_all_blocks_fc)g_virtual_block_visit; block_class->list_blocks = (list_all_blocks_fc)g_virtual_block_list_all_blocks; block_class->list_leafs = (list_leafs_blocks_fc)g_virtual_block_list_leafs_blocks; //block_class->list_regs = (list_regs_accesses_fc)g_virtual_block_list_regs_accesses; } /****************************************************************************** * * * Paramètres : block = instance à initialiser. * * * * Description : Initialise un bloc d'instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_virtual_block_init(GVirtualBlock *block) { } /****************************************************************************** * * * Paramètres : block = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_virtual_block_dispose(GVirtualBlock *block) { size_t i; /* Boucle de parcours */ for (i = 0; i < block->children_count; i++) g_object_unref(G_OBJECT(block->children[i])); G_OBJECT_CLASS(g_virtual_block_parent_class)->dispose(G_OBJECT(block)); } /****************************************************************************** * * * Paramètres : block = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_virtual_block_finalize(GVirtualBlock *block) { if (block->children != NULL) free(block->children); G_OBJECT_CLASS(g_virtual_block_parent_class)->finalize(G_OBJECT(block)); } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un bloc virtuel d'instructions. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GInstrBlock *g_virtual_block_new(void) { GVirtualBlock *result; /* Structure à retourner */ result = g_object_new(G_TYPE_VIRTUAL_BLOCK, NULL); return G_INSTR_BLOCK(result); } /****************************************************************************** * * * Paramètres : block = bloc de départ des recherches. * * addr = ensemble de blocs à parcourir. * * final = indique si la cible ou le conteneur est renvoyée. * * * * Description : Recherche le bloc contenant une adresse donnée. * * * * Retour : bloc basique trouvé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *block, const vmpa2t *addr, bool final) { GInstrBlock *result; /* Resultat à retourner */ size_t i; /* Boucle de parcours */ GInstrBlock *ret; /* Retour des inspections */ result = NULL; for (i = 0; i < block->children_count && result == NULL; i++) { ret = g_instr_block_find_by_addr(block->children[i], addr, final); if (ret != NULL) { if (final) result = ret; else result = (G_IS_FLOW_BLOCK(ret) ? G_INSTR_BLOCK(block) : ret); } } return result; } /****************************************************************************** * * * Paramètres : block = bloc d'instructions concerné par la visite. * * callback = ensemble de blocs à parcourir. * * data = donnée utilisateur à associer au parcours. * * * * Description : Parcourt le bloc d'instructions dans un ordre donné. * * * * Retour : true si le parcours a été jusqu'à son terme, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_virtual_block_visit(GVirtualBlock *block, instr_block_visitor_cb callback, void *data) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ result = callback(G_INSTR_BLOCK(block), BVO_IN, data); for (i = 0; i < block->children_count && result; i++) result = g_instr_block_visit(block->children[i], callback, data); result &= callback(G_INSTR_BLOCK(block), BVO_OUT, data); return true; } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * list = ensemble de blocs à compléter. [OUT] * * count = nombre de blocs au total. [OUT] * * * * Description : Etablit la liste de tous les blocs présents. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_virtual_block_list_all_blocks(const GVirtualBlock *block, GInstrBlock ***list, size_t *count) { size_t i; /* Boucle de parcours */ for (i = 0; i < block->children_count; i++) g_instr_block_list_all_blocks(block->children[i], list, count); } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * list = ensemble de blocs à compléter. [OUT] * * count = nombre de blocs au total. [OUT] * * * * Description : Etablit la liste de tous les blocs terminaux. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_virtual_block_list_leafs_blocks(const GVirtualBlock *block, GInstrBlock ***list, size_t *count) { if (block->children_count > 0) g_instr_block_list_leafs_blocks(block->children[block->children_count - 1], list, count); } #if 0 /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * count = nombre de registres consignés. [OUT] * * * * Description : Fournit les différents accès aux registres. * * * * Retour : Liste des accès aux registres. * * * * Remarques : - * * * ******************************************************************************/ static const reg_access *g_virtual_block_list_regs_accesses(const GVirtualBlock *block, size_t *count) { *count = 0; return NULL; } #endif /****************************************************************************** * * * Paramètres : block = bloc d'instructions à compléter. * * child = sous-bloc à insérer. * * * * Description : Ajoute un bloc au groupe courant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_virtual_block_add_child(GVirtualBlock *block, GInstrBlock *child) { block->children = (GInstrBlock **)realloc(block->children, ++block->children_count * sizeof(GInstrBlock *)); block->children[block->children_count - 1] = child; g_object_ref(G_OBJECT(child)); } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * * * Description : Compte le nombre de blocs contenus dans le groupe courant. * * * * Retour : Quantité normalement non nulle. * * * * Remarques : - * * * ******************************************************************************/ size_t g_virtual_block_count_children(const GVirtualBlock *block) { return block->children_count; } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * index = indice du sous-bloc recherché. * * * * Description : Renvoie un des blocs contenus dans le groupe courant. * * * * Retour : Un des blocs du groupe. * * * * Remarques : - * * * ******************************************************************************/ GInstrBlock *g_virtual_block_get_child(const GVirtualBlock *block, size_t index) { if (index >= block->children_count) return NULL; else return block->children[index]; }