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