/* OpenIDA - Outil d'analyse de fichiers binaires * flow.c - encadrement des instructions par blocs d'exécution * * Copyright (C) 2012 Cyrille Bagard * * This file is part of OpenIDA. * * 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 "flow.h" #include #include "../block-int.h" /* Description d'un bloc d'exécution d'instructions (instance) */ struct _GFlowBlock { GInstrBlock parent; /* A laisser en premier */ GArchInstruction *instrs; /* Liste complète d'instruct° */ GArchInstruction *first; /* Première instruction */ GArchInstruction *last; /* Dernière instruction */ reg_access *accesses; /* Commodités d'accès #1 */ size_t count; /* Commodités d'accès #2 */ }; /* Description d'un bloc d'exécution d'instructions (classe) */ struct _GFlowBlockClass { GInstrBlockClass parent; /* A laisser en premier */ }; /* Initialise la classe des blocs d'instructions. */ static void g_flow_block_class_init(GFlowBlockClass *); /* Initialise un bloc d'instructions. */ static void g_flow_block_init(GFlowBlock *); /* Supprime toutes les références externes. */ static void g_flow_block_dispose(GFlowBlock *); /* Procède à la libération totale de la mémoire. */ static void g_flow_block_finalize(GFlowBlock *); /* Recherche le bloc contenant une adresse donnée. */ static GInstrBlock *g_flow_block_find_by_addr(const GFlowBlock *, vmpa_t); /* Parcours le bloc d'instructions dans un ordre donné. */ static bool g_flow_block_visit(GFlowBlock *, instr_block_visitor_cb, void *); /* Etablit la liste de tous les blocs présents. */ static void g_flow_block_list_all_blocks(const GFlowBlock *, GInstrBlock ***, size_t *); /* Prend note de l'usage d'un registre, au besoin. */ static void g_flow_block_memorize_access(GFlowBlock *, GArchRegister *, RegAccessType, vmpa_t); /* Note les différents accès aux registres. */ static void g_flow_block_compute_regs_access(GFlowBlock *); /* Fournit les différents accès aux registres. */ static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *, size_t *); /* Indique le type défini pour un bloc d'exécution d'instructions. */ G_DEFINE_TYPE(GFlowBlock, g_flow_block, G_TYPE_INSTR_BLOCK); /****************************************************************************** * * * Paramètres : class = classe à initialiser. * * * * Description : Initialise la classe des blocs d'instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_flow_block_class_init(GFlowBlockClass *class) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)g_flow_block_dispose; object->finalize = (GObjectFinalizeFunc)g_flow_block_finalize; } /****************************************************************************** * * * Paramètres : block = instance à initialiser. * * * * Description : Initialise un bloc d'instructions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_flow_block_init(GFlowBlock *block) { GInstrBlock *parent; /* Instance parente */ parent = G_INSTR_BLOCK(block); parent->find_by_addr = (find_by_addr_fc)g_flow_block_find_by_addr; parent->visit_blocks = (visit_all_blocks_fc)g_flow_block_visit; parent->list_blocks = (list_all_blocks_fc)g_flow_block_list_all_blocks; parent->list_regs = (list_regs_accesses_fc)g_flow_block_list_regs_accesses; } /****************************************************************************** * * * Paramètres : block = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_flow_block_dispose(GFlowBlock *block) { size_t i; /* Boucle de parcours */ g_object_unref(G_OBJECT(block->instrs)); g_object_unref(G_OBJECT(block->first)); g_object_unref(G_OBJECT(block->last)); for (i = 0; i < block->count; i++) g_object_unref(G_OBJECT(block->accesses[i].reg)); G_OBJECT_CLASS(g_flow_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_flow_block_finalize(GFlowBlock *block) { if (block->accesses != NULL) free(block->accesses); G_OBJECT_CLASS(g_flow_block_parent_class)->finalize(G_OBJECT(block)); } /****************************************************************************** * * * Paramètres : instrs = liste de toutes les instructions. * * first = première instruction du bloc. * * last = dernière instruction du bloc. * * * * Description : Crée un bloc d'exécution d'instructions. * * * * Retour : Adresse de la structure mise en place. * * * * Remarques : - * * * ******************************************************************************/ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first, GArchInstruction *last) { GFlowBlock *result; /* Structure à retourner */ //vmpa_t addr; /* Adresse de la destination */ result = g_object_new(G_TYPE_FLOW_BLOCK, NULL); /* g_arch_instruction_get_location(first, NULL, NULL, &addr); printf(" ! new block @ 0x%llx - ", addr); g_arch_instruction_get_location(last, NULL, NULL, &addr); printf("0x%llx\n", addr); */ result->instrs = instrs; result->first = first; result->last = last; g_object_ref(G_OBJECT(result->instrs)); g_object_ref(G_OBJECT(result->first)); g_object_ref(G_OBJECT(result->last)); g_flow_block_compute_regs_access(result); return G_INSTR_BLOCK(result); } /****************************************************************************** * * * Paramètres : block = bloc de départ des recherches. * * addr = ensemble de blocs à parcourir. * * * * Description : Recherche le bloc contenant une adresse donnée. * * * * Retour : bloc basique trouvé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GInstrBlock *g_flow_block_find_by_addr(const GFlowBlock *block, vmpa_t addr) { GInstrBlock *result; /* Resultat à retourner */ vmpa_t start; /* Adresse de début du bloc */ vmpa_t end; /* Adresse de fin du bloc */ g_flow_block_get_boundary_addresses(block, &start, &end); if (start <= addr && addr <= end) result = G_INSTR_BLOCK(block); else result = NULL; 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 : Parcours le bloc d'instructions dans un ordre donné. * * * * Retour : true si le parcours a été jusqu'à son terme, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool g_flow_block_visit(GFlowBlock *block, instr_block_visitor_cb callback, void *data) { return callback(G_INSTR_BLOCK(block), BVO_PENDING, data); } /****************************************************************************** * * * 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_flow_block_list_all_blocks(const GFlowBlock *block, GInstrBlock ***list, size_t *count) { (*list) = (GInstrBlock **)realloc(*list, ++(*count) * sizeof(GInstrBlock *)); (*list)[*count - 1] = G_INSTR_BLOCK(block); } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à mettre à jour. * * reg = registre visé par l'opération. * * type = type d'accès à l'opérande. * * addr = adresse de l'instruction associée. * * * * Description : Prend note de l'usage d'un registre, au besoin. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_flow_block_memorize_access(GFlowBlock *block, GArchRegister *reg, RegAccessType type, vmpa_t addr) { reg_access **accesses; /* Commodités d'accès #1 */ size_t *count; /* Commodités d'accès #2 */ reg_access *access; /* Accès à manipuler */ bool need_sort; /* Insertion donc tri à faire */ accesses = &block->accesses; count = &block->count; /* Recherche de l'élément à mettre à jour */ access = bsearch((reg_access []) { { .reg = reg } }, *accesses, *count, sizeof(reg_access), (__compar_fn_t)compare_reg_accesses); if (access == NULL) { *accesses = (reg_access *)realloc(*accesses, ++(*count) * sizeof(reg_access)); access = &(*accesses)[*count - 1]; g_object_ref(G_OBJECT(reg)); access->reg = reg; access->first_access = RAT_NONE; access->last_write = VMPA_MAX; need_sort = true; } else need_sort = false; /* Mise à jour */ if (access->first_access == RAT_NONE) access->first_access = type; if (type == RAT_WRITE) access->last_write = addr; /* Remise en conditions éventuelle */ if (need_sort) qsort(*accesses, *count, sizeof(reg_access), (__compar_fn_t)compare_reg_accesses); } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à parcourir. * * * * Description : Note les différents accès aux registres. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_flow_block_compute_regs_access(GFlowBlock *block) { GArchInstruction *iter; /* Boucle de parcours #1 */ vmpa_t max; /* Adresse de fin */ vmpa_t addr; /* Adresse d'instruction */ GArchRegister **rregs; /* Liste des registres lus */ size_t rcount; /* Nombre de registres lus */ GArchRegister **wregs; /* Liste des registres écrits */ size_t wcount; /* Nombre de registres écrits */ size_t i; /* Boucle de parcours #2 */ g_arch_instruction_get_location(block->last, NULL, NULL, &max); max++; for (iter = block->first; iter != NULL; iter = g_arch_instruction_get_next_iter(block->instrs, iter, max)) { g_arch_instruction_get_location(iter, NULL, NULL, &addr); g_arch_instruction_get_rw_registers(iter, &rregs, &rcount, &wregs, &wcount); for (i = 0; i < rcount; i++) { g_flow_block_memorize_access(block, rregs[i], RAT_READ, addr); g_object_unref(G_OBJECT(rregs[i])); } for (i = 0; i < wcount; i++) { g_flow_block_memorize_access(block, wregs[i], RAT_WRITE, addr); g_object_unref(G_OBJECT(wregs[i])); } if (rregs != NULL) free(rregs); if (wregs != NULL) free(wregs); } } /****************************************************************************** * * * 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_flow_block_list_regs_accesses(const GFlowBlock *block, size_t *count) { *count = block->count; return block->accesses; } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * * * Description : Fournit la liste d'appartenance des instructions du bloc. * * * * Retour : Liste de l'ensemble des instructions. * * * * Remarques : - * * * ******************************************************************************/ GArchInstruction *g_flow_block_get_all_instructions_list(const GFlowBlock *block) { return block->instrs; } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * first = instruction de départ du bloc. [OUT] * * last = dernière instruction du bloc. [OUT] * * * * Description : Fournit les instructions limites d'un bloc d'exécution. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_flow_block_get_boundary(const GFlowBlock *block, GArchInstruction **first, GArchInstruction **last) { if (first != NULL) *first = block->first; if (last != NULL) *last = block->last; } /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * * start = adresse de départ du bloc. [OUT] * * end = dernière adresse du bloc. [OUT] * * * * Description : Fournit les adresses limites d'un bloc d'exécution. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_flow_block_get_boundary_addresses(const GFlowBlock *block, vmpa_t *start, vmpa_t *end) { if (start != NULL) g_arch_instruction_get_location(block->first, NULL, NULL, start); if (end != NULL) g_arch_instruction_get_location(block->last, NULL, NULL, end); }