From 35a6cd881528b5f77ce09476eccb39d02d9cc634 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 13 Jan 2013 20:23:05 +0000 Subject: Defined the registers allocation needs for each basic block. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@323 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 26 +++ src/analysis/block-int.h | 6 +- src/analysis/block.c | 26 +-- src/analysis/block.h | 36 +--- src/analysis/blocks/Makefile.am | 1 + src/analysis/blocks/flow.c | 200 ++++++++++++++------- src/analysis/blocks/flow.h | 24 +++ src/analysis/blocks/raccess.c | 387 ++++++++++++++++++++++++++++++++++++++++ src/analysis/blocks/raccess.h | 105 +++++++++++ src/analysis/blocks/virtual.c | 31 ++-- src/analysis/decomp/il.c | 153 +++++++++++++++- 11 files changed, 851 insertions(+), 144 deletions(-) create mode 100644 src/analysis/blocks/raccess.c create mode 100644 src/analysis/blocks/raccess.h diff --git a/ChangeLog b/ChangeLog index 74e3608..31709b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +13-01-13 Cyrille Bagard + + * src/analysis/block.c: + * src/analysis/block.h: + * src/analysis/block-int.h: + Remove all stuff related to registers access. Extend the search of blocks. + + * src/analysis/blocks/flow.c: + * src/analysis/blocks/flow.h: + Remove all stuff related to registers access. Extend the search of blocks. + Implement a design pattern to follow the execution flow. + + * src/analysis/blocks/Makefile.am: + Add the 'raccess.[ch]' files to libanalysisblocks_la_SOURCES. + + * src/analysis/blocks/raccess.c: + * src/analysis/blocks/raccess.h: + New entries: provide an easy access to all registers used in a block. + + * src/analysis/blocks/virtual.c: + Remove all stuff related to registers access. Extend the search of blocks. + + * src/analysis/decomp/il.c: + Define the registers allocation needs for each basic block. Clean + the code a little bit. + 13-01-10 Cyrille Bagard * src/analysis/block.c: diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h index f016e35..249aa57 100644 --- a/src/analysis/block-int.h +++ b/src/analysis/block-int.h @@ -30,7 +30,7 @@ /* Recherche le bloc contenant une adresse donnée. */ -typedef GInstrBlock * (* find_by_addr_fc) (const GInstrBlock *, vmpa_t); +typedef GInstrBlock * (* find_by_addr_fc) (const GInstrBlock *, vmpa_t, bool); /* Parcours tous les blocs d'instructions dans un ordre donné. */ typedef bool (* visit_all_blocks_fc) (GInstrBlock *, instr_block_visitor_cb, void *); @@ -39,7 +39,7 @@ typedef bool (* visit_all_blocks_fc) (GInstrBlock *, instr_block_visitor_cb, voi typedef void (* list_all_blocks_fc) (const GInstrBlock *, GInstrBlock ***, size_t *); /* Fournit les différents accès aux registres. */ -typedef const reg_access * (* list_regs_accesses_fc) (const GInstrBlock *, size_t *); +//typedef const reg_access * (* list_regs_accesses_fc) (const GInstrBlock *, size_t *); @@ -51,7 +51,7 @@ struct _GInstrBlock find_by_addr_fc find_by_addr; /* Recherche par adresse */ visit_all_blocks_fc visit_blocks; /* Visite des différents blocs */ list_all_blocks_fc list_blocks; /* Liste de tous les blocs */ - list_regs_accesses_fc list_regs; /* Liste des accès registres */ + //list_regs_accesses_fc list_regs; /* Liste des accès registres */ GInstrBlock *links_block; /* Lieu des blocs attachés */ diff --git a/src/analysis/block.c b/src/analysis/block.c index 1ec9804..d6f3df3 100644 --- a/src/analysis/block.c +++ b/src/analysis/block.c @@ -47,27 +47,6 @@ static void g_instr_block_finalize(GInstrBlock *); -/****************************************************************************** -* * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * -* * -* Description : Compare un accès registre avec un autre. * -* * -* Retour : Bilan de la comparaison. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int compare_reg_accesses(const reg_access *a, const reg_access *b) -{ - return g_arch_register_compare(a->reg, b->reg); - -} - - - @@ -162,6 +141,7 @@ static void g_instr_block_finalize(GInstrBlock *block) * * * 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. * * * @@ -171,9 +151,9 @@ static void g_instr_block_finalize(GInstrBlock *block) * * ******************************************************************************/ -GInstrBlock *g_instr_block_find_by_addr(const GInstrBlock *block, vmpa_t addr) +GInstrBlock *g_instr_block_find_by_addr(const GInstrBlock *block, vmpa_t addr, bool final) { - return block->find_by_addr(block, addr); + return block->find_by_addr(block, addr, final); } diff --git a/src/analysis/block.h b/src/analysis/block.h index 125ff0e..223649f 100644 --- a/src/analysis/block.h +++ b/src/analysis/block.h @@ -27,40 +27,10 @@ #include #include +#include -#include "../arch/register.h" - - - - - - - - -/* Note sur le premier accès */ -typedef enum _RegAccessType -{ - RAT_NONE = (0 << 0), /* Registre non rencontré */ - RAT_READ = (1 << 0), /* Lecture */ - RAT_WRITE = (1 << 1) /* Ecriture */ - -} RegAccessType; - -/* Description minimale des accès à un registre */ -typedef struct _reg_access -{ - GArchRegister *reg; /* Register concerné */ - - RegAccessType first_access; /* Type du premier accès */ - vmpa_t last_write; /* Dernière écriture */ - -} reg_access; - - -/* Compare un accès registre avec un autre. */ -int compare_reg_accesses(const reg_access *, const reg_access *); - +#include "../arch/archbase.h" @@ -96,7 +66,7 @@ typedef bool (* instr_block_visitor_cb) (GInstrBlock *, BlockVisitOrder, void *) GType g_instr_block_get_type(void); /* Recherche le bloc contenant une adresse donnée. */ -GInstrBlock *g_instr_block_find_by_addr(const GInstrBlock *, vmpa_t); +GInstrBlock *g_instr_block_find_by_addr(const GInstrBlock *, vmpa_t, bool); /* Parcours tous les blocs d'instructions dans un ordre donné. */ bool g_instr_block_visit(GInstrBlock *, instr_block_visitor_cb, void *); diff --git a/src/analysis/blocks/Makefile.am b/src/analysis/blocks/Makefile.am index 7a9e371..fe1452a 100755 --- a/src/analysis/blocks/Makefile.am +++ b/src/analysis/blocks/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libanalysisblocks.la libanalysisblocks_la_SOURCES = \ flow.h flow.c \ + raccess.h raccess.c \ virtual.h virtual.c libanalysisblocks_la_LIBADD = diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c index 6fb5849..6f56f9d 100644 --- a/src/analysis/blocks/flow.c +++ b/src/analysis/blocks/flow.c @@ -40,8 +40,8 @@ struct _GFlowBlock 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 */ + GRAccessList *regs; /* Accès aux registres */ + GRAccessList *awaited; /* Registres définis pour après*/ }; @@ -66,7 +66,7 @@ static void g_flow_block_dispose(GFlowBlock *); 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); +static GInstrBlock *g_flow_block_find_by_addr(const GFlowBlock *, vmpa_t, bool); /* Parcours le bloc d'instructions dans un ordre donné. */ static bool g_flow_block_visit(GFlowBlock *, instr_block_visitor_cb, void *); @@ -81,7 +81,7 @@ static void g_flow_block_memorize_access(GFlowBlock *, GArchRegister *, RegAcces 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 *); +//static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *, size_t *); @@ -134,7 +134,10 @@ static void g_flow_block_init(GFlowBlock *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; + //parent->list_regs = (list_regs_accesses_fc)g_flow_block_list_regs_accesses; + + block->regs = g_raccess_list_new(); + block->awaited = g_raccess_list_new(); } @@ -153,14 +156,12 @@ static void g_flow_block_init(GFlowBlock *block) 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_unref(G_OBJECT(block->regs)); + g_object_unref(G_OBJECT(block->awaited)); G_OBJECT_CLASS(g_flow_block_parent_class)->dispose(G_OBJECT(block)); @@ -181,9 +182,6 @@ static void g_flow_block_dispose(GFlowBlock *block) 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)); } @@ -242,6 +240,7 @@ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first, * * * 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. * * * @@ -251,7 +250,7 @@ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first, * * ******************************************************************************/ -static GInstrBlock *g_flow_block_find_by_addr(const GFlowBlock *block, vmpa_t addr) +static GInstrBlock *g_flow_block_find_by_addr(const GFlowBlock *block, vmpa_t addr, bool final) { GInstrBlock *result; /* Resultat à retourner */ vmpa_t start; /* Adresse de début du bloc */ @@ -331,47 +330,28 @@ static void g_flow_block_list_all_blocks(const GFlowBlock *block, GInstrBlock ** 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 */ + reg_access *found; /* Accès à mettre à jour */ + reg_access access; /* Accès à mettre en place */ - access = bsearch((reg_access []) { { .reg = reg } }, *accesses, *count, sizeof(reg_access), - (__compar_fn_t)compare_reg_accesses); + found = g_raccess_list_find(block->regs, reg); - if (access == NULL) + /* Simpple mise à jour ? */ + if (found != 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; - + if (type == RAT_WRITE) + found->last_write = addr; } - else need_sort = false; - - /* Mise à jour */ - - if (access->first_access == RAT_NONE) - access->first_access = type; - if (type == RAT_WRITE) - access->last_write = addr; + /* Ou ajout pur et simple ? */ + else + { + access.reg = reg; + access.first_access = type; + access.last_write = (type == RAT_WRITE ? addr : VMPA_MAX); - /* Remise en conditions éventuelle */ + g_raccess_list_add(block->regs, &access); - if (need_sort) - qsort(*accesses, *count, sizeof(reg_access), (__compar_fn_t)compare_reg_accesses); + } } @@ -433,28 +413,6 @@ static void g_flow_block_compute_regs_access(GFlowBlock *block) /****************************************************************************** * * * 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. * * * @@ -519,3 +477,107 @@ void g_flow_block_get_boundary_addresses(const GFlowBlock *block, vmpa_t *start, g_arch_instruction_get_location(block->last, NULL, NULL, end); } + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions démarrant la visite. * +* list = ensemble des blocs basiques à parcourir. * +* mask = points de passage à marquer. * +* callback = ensemble de blocs à parcourir. * +* data = donnée utilisateur à associer au parcours. * +* * +* Description : Suit le flot d'excution bloc par bloc. * +* * +* Retour : true si le parcours a été jusqu'à son terme, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_flow_block_follow(GFlowBlock *block, const GInstrBlock *list, BlockFollowPosition mask, flow_block_follow_cb callback, void *data) +{ + bool result; /* Bilan à retourner */ + GArchInstruction **dests; /* Instr. visée par une autre */ + InstructionLinkType *types; /* Type de lien entre lignes */ + size_t dcount; /* Nombre de liens de dest. */ + size_t i; /* Boucle de parcours */ + vmpa_t addr; /* Adresse de la destination */ + GInstrBlock *next; /* Bloc suivant à visiter */ + + result = true; + + if (mask & BFP_ENTER) + result = callback(block, BFP_ENTER, data); + + dcount = g_arch_instruction_get_destinations(block->last, &dests, &types); + + for (i = 0; i < dcount && result; i++) + switch (types[i]) + { + case ILT_EXEC_FLOW: + case ILT_JUMP: + case ILT_CASE_JUMP: + case ILT_JUMP_IF_TRUE: + case ILT_JUMP_IF_FALSE: + + g_arch_instruction_get_location(dests[i], NULL, NULL, &addr); + next = g_instr_block_find_by_addr(list, addr, true); + + if (next) + { + result = callback(block, BFP_FOLLOW, data); + result &= g_flow_block_follow(G_FLOW_BLOCK(next), list, mask, callback, data); + result &= callback(block, BFP_BACK, data); + } + break; + + default: + break; + + } + + if (mask & BFP_EXIT) + result &= callback(block, BFP_EXIT, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions à consulter. * +* * +* Description : Fournit les différents accès aux registres. * +* * +* Retour : Liste des accès aux registres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const GRAccessList *g_flow_block_list_regs_accesses(const GFlowBlock *block) +{ + return block->regs; + +} + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions à consulter. * +* * +* Description : Fournit les registres écrits par le bloc et utilisées après. * +* * +* Retour : Liste des accès aux registres. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRAccessList *g_flow_block_list_awaited_regs(const GFlowBlock *block) +{ + return block->awaited; + +} diff --git a/src/analysis/blocks/flow.h b/src/analysis/blocks/flow.h index 28fb5a9..a01ef64 100644 --- a/src/analysis/blocks/flow.h +++ b/src/analysis/blocks/flow.h @@ -29,6 +29,7 @@ #include +#include "raccess.h" #include "../block.h" #include "../../arch/instruction.h" @@ -49,6 +50,20 @@ typedef struct _GFlowBlock GFlowBlock; typedef struct _GFlowBlockClass GFlowBlockClass; +/* Position au cours d'une visite */ +typedef enum _BlockFollowPosition +{ + BFP_ENTER = (1 << 0), /* Entrée dans le bloc */ + BFP_FOLLOW = (1 << 1), /* Suivi des liens : aller... */ + BFP_BACK = (1 << 2), /* Suivi des liens : retour ! */ + BFP_EXIT = (1 << 3) /* Sortie du bloc */ + +} BlockFollowPosition; + +/* Rappel à chaque bloc visité */ +typedef bool (* flow_block_follow_cb) (GFlowBlock *, BlockFollowPosition, void *); + + /* Indique le type défini pour un bloc d'exécution d'instructions. */ GType g_flow_block_get_type(void); @@ -64,6 +79,15 @@ void g_flow_block_get_boundary(const GFlowBlock *, GArchInstruction **, GArchIns /* Fournit les adresses limites d'un bloc d'exécution. */ void g_flow_block_get_boundary_addresses(const GFlowBlock *, vmpa_t *, vmpa_t *); +/* Suit le flot d'excution bloc par bloc. */ +bool g_flow_block_follow(GFlowBlock *, const GInstrBlock *, BlockFollowPosition, flow_block_follow_cb, void *); + +/* Fournit les différents accès aux registres. */ +const GRAccessList *g_flow_block_list_regs_accesses(const GFlowBlock *); + +/* Fournit les registres écrits par le bloc et utilisées après. */ +GRAccessList *g_flow_block_list_awaited_regs(const GFlowBlock *); + #endif /* _ANALYSIS_BLOCKS_FLOW_H */ diff --git a/src/analysis/blocks/raccess.c b/src/analysis/blocks/raccess.c new file mode 100644 index 0000000..7fe084c --- /dev/null +++ b/src/analysis/blocks/raccess.c @@ -0,0 +1,387 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * raccess.c - suivi des accès aux registres + * + * Copyright (C) 2013 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 "raccess.h" + + +#include +#include +#include + + + +/* Description d'une liste d'accès à des registres (instance) */ +struct _GRAccessList +{ + GObject parent; /* A laisser en premier */ + + reg_access *accesses; /* Liste des accès */ + size_t count; /* Taille de cette liste */ + +}; + +/* Description d'une liste d'accès à des registres (classe) */ +struct _GRAccessListClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des listes d'accès aux registres. */ +static void g_raccess_list_class_init(GRAccessListClass *); + +/* Initialise une liste d'accès aux registres. */ +static void g_raccess_list_init(GRAccessList *); + +/* Supprime toutes les références externes. */ +static void g_raccess_list_dispose(GRAccessList *); + +/* Procède à la libération totale de la mémoire. */ +static void g_raccess_list_finalize(GRAccessList *); + + + +/* Indique le type défini pour une liste d'accès à des registres. */ +G_DEFINE_TYPE(GRAccessList, g_raccess_list, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* * +* Description : Initialise la classe des listes d'accès aux registres. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_raccess_list_class_init(GRAccessListClass *class) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(class); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_raccess_list_dispose; + object->finalize = (GObjectFinalizeFunc)g_raccess_list_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : list = instance à initialiser. * +* * +* Description : Initialise une liste d'accès aux registres. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_raccess_list_init(GRAccessList *list) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : block = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_raccess_list_dispose(GRAccessList *list) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < list->count; i++) + g_object_unref(G_OBJECT(list->accesses[i].reg)); + + if (list->accesses != NULL) + free(list->accesses); + + G_OBJECT_CLASS(g_raccess_list_parent_class)->dispose(G_OBJECT(list)); + +} + + +/****************************************************************************** +* * +* Paramètres : block = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_raccess_list_finalize(GRAccessList *list) +{ + G_OBJECT_CLASS(g_raccess_list_parent_class)->finalize(G_OBJECT(list)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une liste d'accès à des registres. * +* * +* Retour : Adresse de la structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRAccessList *g_raccess_list_new(void) +{ + GRAccessList *result; /* Liste à retourner */ + + result = g_object_new(G_TYPE_RACCESS_LIST, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste des accès à venir grossir. * +* src = liste dont les accès sont à reprendre. * +* * +* Description : Intègre une liste d'accès à des registres dans une autre. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_raccess_list_merge(GRAccessList *list, GRAccessList *src) +{ + size_t count; /* Taille d'un parcours */ + size_t i; /* Boucle de parcours */ + reg_access *access; /* Accès à un registre */ + + count = g_raccess_list_count(src); + + for (i = 0; i < count; i++) + { + access = g_raccess_list_get(src, i); + + if (g_raccess_list_find(list, access->reg) == NULL) + g_raccess_list_add(list, access); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* * +* Description : Compare un accès registre avec un autre. * +* * +* Retour : Bilan de la comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int compare_reg_accesses(const reg_access *a, const reg_access *b) +{ + return g_arch_register_compare(a->reg, b->reg); + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'accès à consulter. * +* reg = registre matériel à rechercher. * +* * +* Description : Recherche des informations existantes sur un registre. * +* * +* Retour : Bilan de la recherche. * +* * +* Remarques : - * +* * +******************************************************************************/ + +reg_access *g_raccess_list_find(const GRAccessList *list, GArchRegister *reg) +{ + reg_access *result; /* Trouaille à retourner */ + + result = bsearch((reg_access []) { { .reg = reg } }, list->accesses, list->count, + sizeof(reg_access), (__compar_fn_t)compare_reg_accesses); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'accès à mettre à jour. * +* template = patron de l'accès à intégrer. * +* * +* Description : Recherche des informations existantes sur un registre. * +* * +* Retour : Bilan de la recherche. * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_raccess_list_add(GRAccessList *list, const reg_access *template) +{ + g_object_ref(G_OBJECT(template->reg)); + + list->accesses = (reg_access *)realloc(list->accesses, ++list->count * sizeof(reg_access)); + list->accesses[list->count - 1] = *template; + + qsort(list->accesses, list->count, sizeof(reg_access), (__compar_fn_t)compare_reg_accesses); + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'accès à consulter. * +* * +* Description : Dénombre les accès aux registres comptabilisés. * +* * +* Retour : Quantité d'accès pris en compte. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_raccess_list_count(const GRAccessList *list) +{ + return list->count; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'accès à consulter. * +* index = indice de l'accès recherché. * +* * +* Description : Fournit un accès donné de la liste. * +* * +* Retour : Accès à un registre. * +* * +* Remarques : - * +* * +******************************************************************************/ + +reg_access *g_raccess_list_get(const GRAccessList *list, size_t index) +{ + reg_access *result; /* Accès à renvoyer */ + + if (index >= list->count) + result = NULL; + else + result = &list->accesses[index]; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'accès à mettre à jour. * +* access = accès visé par la procédure. * +* * +* Description : Retire un accès donné de la liste. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_raccess_list_delete(GRAccessList *list, reg_access *access) +{ + size_t index; /* Indice correspondant */ + + if (list->count > 0) + { + index = (access - list->accesses) / sizeof(reg_access); + g_raccess_list_delete_by_index(list, index); + } + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble d'accès à mettre à jour. * +* index = indice de l'accès visé par la procédure. * +* * +* Description : Retire un accès donné de la liste. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_raccess_list_delete_by_index(GRAccessList *list, size_t index) +{ + if (index >= list->count) + return; + + if ((index + 1) < list->count) + memmove(&list->accesses[index], &list->accesses[index + 1], + (list->count - index - 1) * sizeof(reg_access)); + + list->count--; + + if (list->count == 0) + { + free(list->accesses); + list->accesses = NULL; + } + else + list->accesses = (reg_access *)realloc(list->accesses, list->count * sizeof(reg_access)); + +} diff --git a/src/analysis/blocks/raccess.h b/src/analysis/blocks/raccess.h new file mode 100644 index 0000000..cc2fd00 --- /dev/null +++ b/src/analysis/blocks/raccess.h @@ -0,0 +1,105 @@ + +/* OpenIDA - Outil d'analyse de fichiers binaires + * raccess.h - prototypes pour le suivi des accès aux registres + * + * Copyright (C) 2013 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 . + */ + + +#ifndef _ANALYSIS_BLOCKS_RACCESS_H +#define _ANALYSIS_BLOCKS_RACCESS_H + + +#include +#include + +#include + + +#include "../../arch/register.h" + + + +/* Note sur le premier accès */ +typedef enum _RegAccessType +{ + RAT_NONE = (0 << 0), /* Registre non rencontré */ + RAT_READ = (1 << 0), /* Lecture */ + RAT_WRITE = (1 << 1) /* Ecriture */ + +} RegAccessType; + +/* Description minimale des accès à un registre */ +typedef struct _reg_access +{ + GArchRegister *reg; /* Register concerné */ + + RegAccessType first_access; /* Type du premier accès */ + vmpa_t last_write; /* Dernière écriture */ + +} reg_access; + + +#define G_TYPE_RACCESS_LIST g_raccess_list_get_type() +#define G_RACCESS_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_raccess_list_get_type(), GRAccessList)) +#define G_IS_RACCESS_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_raccess_list_get_type())) +#define G_RACCESS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RACCESS_LIST, GRAccessListClass)) +#define G_IS_RACCESS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RACCESS_LIST)) +#define G_RACCESS_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RACCESS_LIST, GRAccessListClass)) + + +/* Description d'une liste d'accès à des registres (instance) */ +typedef struct _GRAccessList GRAccessList; + +/* Description d'une liste d'accès à des registres (classe) */ +typedef struct _GRAccessListClass GRAccessListClass; + + +/* Indique le type défini pour une liste d'accès à des registres. */ +GType g_raccess_list_get_type(void); + +/* Crée une liste d'accès à des registres. */ +GRAccessList *g_raccess_list_new(void); + +/* Intègre une liste d'accès à des registres dans une autre. */ +void g_raccess_list_merge(GRAccessList *, GRAccessList *); + +/* Compare un accès registre avec un autre. */ +int compare_reg_accesses(const reg_access *, const reg_access *); + +/* Recherche des informations existantes sur un registre. */ +reg_access *g_raccess_list_find(const GRAccessList *, GArchRegister *); + +/* Recherche des informations existantes sur un registre. */ +void g_raccess_list_add(GRAccessList *, const reg_access *); + +/* Dénombre les accès aux registres comptabilisés. */ +size_t g_raccess_list_count(const GRAccessList *); + +/* Fournit un accès donné de la liste. */ +reg_access *g_raccess_list_get(const GRAccessList *, size_t); + +/* Retire un accès donné de la liste. */ +void g_raccess_list_delete(GRAccessList *, reg_access *); + +/* Retire un accès donné de la liste. */ +void g_raccess_list_delete_by_index(GRAccessList *, size_t); + + + +#endif /* _ANALYSIS_BLOCKS_RACCESS_H */ diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c index 2385f67..584e57d 100644 --- a/src/analysis/blocks/virtual.c +++ b/src/analysis/blocks/virtual.c @@ -43,9 +43,10 @@ struct _GVirtualBlock 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 }; @@ -70,7 +71,7 @@ static void g_virtual_block_dispose(GVirtualBlock *); 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 *, vmpa_t); +static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *, vmpa_t, bool); /* Parcours le bloc d'instructions dans un ordre donné. */ static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void *); @@ -79,7 +80,7 @@ static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void static void g_virtual_block_list_all_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 *); +//static const reg_access *g_virtual_block_list_regs_accesses(const GVirtualBlock *, size_t *); @@ -132,7 +133,7 @@ static void g_virtual_block_init(GVirtualBlock *block) parent->find_by_addr = (find_by_addr_fc)g_virtual_block_find_by_addr; parent->visit_blocks = (visit_all_blocks_fc)g_virtual_block_visit; parent->list_blocks = (list_all_blocks_fc)g_virtual_block_list_all_blocks; - parent->list_regs = (list_regs_accesses_fc)g_virtual_block_list_regs_accesses; + //parent->list_regs = (list_regs_accesses_fc)g_virtual_block_list_regs_accesses; } @@ -175,9 +176,6 @@ static void g_virtual_block_dispose(GVirtualBlock *block) static void g_virtual_block_finalize(GVirtualBlock *block) { - if (block->accesses != NULL) - free(block->accesses); - if (block->children != NULL) free(block->children); @@ -213,6 +211,7 @@ GInstrBlock *g_virtual_block_new(void) * * * 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. * * * @@ -222,16 +221,25 @@ GInstrBlock *g_virtual_block_new(void) * * ******************************************************************************/ -static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *block, vmpa_t addr) +static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *block, vmpa_t 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++) - if (g_instr_block_find_by_addr(block->children[i], addr)) - result = block->children[i]; + { + ret = g_instr_block_find_by_addr(block->children[i], addr, final); + + if (ret != NULL) + { + if (final) result = ret; + else result = block->children[i]; + } + + } return result; @@ -292,7 +300,7 @@ static void g_virtual_block_list_all_blocks(const GVirtualBlock *block, GInstrBl } - +#if 0 /****************************************************************************** * * * Paramètres : block = bloc d'instructions à consulter. * @@ -313,6 +321,7 @@ static const reg_access *g_virtual_block_list_regs_accesses(const GVirtualBlock return NULL; } +#endif /****************************************************************************** diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c index f3c2265..6333216 100644 --- a/src/analysis/decomp/il.c +++ b/src/analysis/decomp/il.c @@ -34,6 +34,9 @@ /* --------------------- GESTION DES CONTEXTES DE DECOMPILATION --------------------- */ +/* Détermine les registres utilisés avant leur initialisation. */ +static bool track_used_registers(GFlowBlock *, BlockFollowPosition, GRAccessList **); + @@ -61,9 +64,144 @@ static GDecInstruction *decompiled_basic_block(GInstrBlock *, GDecContext *); /* ---------------------------------------------------------------------------------- */ +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions visité. * +* pos = indication sur la position du parcours. * +* needed = suivi de l'usage des registres entre les blocs. * +* * +* Description : Détermine les registres utilisés avant leur initialisation. * +* * +* Retour : true pour mener un parcours complet. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool track_used_registers(GFlowBlock *block, BlockFollowPosition pos, GRAccessList **needed) +{ + GRAccessList *old; /* Ancienne liste remplacée */ + const GRAccessList *accesses; /* Accès divers aux registres */ + size_t count; /* Taille d'un parcours */ + GRAccessList *awaited; /* Satisfactions des besoins */ + reg_access *access; /* Accès à un registre */ + size_t i; /* Boucle de parcours */ + reg_access *found; /* Besoin trouvé ou non */ + + switch (pos) + { + case BFP_ENTER: + g_object_set_data(G_OBJECT(block), "needed_regs", *needed); + break; + + case BFP_FOLLOW: + *needed = g_raccess_list_new(); + break; + + case BFP_BACK: + + old = *needed; + *needed = G_RACCESS_LIST(g_object_get_data(G_OBJECT(block), "needed_regs")); + + g_raccess_list_merge(*needed, old); + g_object_unref(G_OBJECT(old)); + break; + case BFP_EXIT: + g_object_set_data(G_OBJECT(block), "needed_regs", NULL); + + accesses = g_flow_block_list_regs_accesses(block); + count = g_raccess_list_count(accesses); + + awaited = g_flow_block_list_awaited_regs(block); + + for (i = 0; i < count; i++) + { + access = g_raccess_list_get(accesses, i); + + /* Enregistrement des contributions possibles */ + + found = g_raccess_list_find(*needed, access->reg); + + if (found != NULL) + { + /** + * Si un autre bloc avait déjà un besoin, on ne prend note + * qu'une seule fois ! + */ + if (g_raccess_list_find(awaited, access->reg) == NULL) + g_raccess_list_add(awaited, access); + + g_raccess_list_delete(*needed, found); + + } + + /* Ajoute les besoins du bloc */ + if (access->first_access == RAT_READ) + g_raccess_list_add(*needed, access); + + } + + /* + do + { + vmpa_t start, end; + + g_flow_block_get_boundary_addresses(block, &start, &end); + + printf(" -> flow (%d) : 0x%08x - 0x%08x | needed = %zu - provided = %zu\n", + pos, start, end, + g_raccess_list_count(*needed), g_raccess_list_count(awaited)); + + } + while (0); + */ + + break; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble des instructions d'assemblage à traiter. * +* start = adresse de départ de la routine visée. * +* * +* Description : Procède à la décompilation d'une routinée déterminée. * +* * +* Retour : Instructions créées ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDecContext *init_decomp_context(const GInstrBlock *list, vmpa_t start) +{ + GDecContext *result; /* Contexte pour la décompil. */ + GInstrBlock *first; /* Bloc de départ du flot */ + GRAccessList *needed; /* Registres inter-blocs */ + + result = NULL; + + first = g_instr_block_find_by_addr(list, start, true); + + needed = g_raccess_list_new(); + + g_flow_block_follow(G_FLOW_BLOCK(first), list, BFP_ENTER | BFP_EXIT | BFP_EXIT, + (flow_block_follow_cb)track_used_registers, &needed); + + g_object_unref(G_OBJECT(needed)); + + + return result; + +} @@ -165,14 +303,15 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon { next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_TRUE); - printf("@ 0x%08llx : true : %p\n", max, next); + //printf("@ 0x%08llx : true : %p\n", max, next); true_dinstr = NULL; if (next != NULL) { g_arch_instruction_get_location(next, NULL, NULL, &next_addr); - next_block = g_instr_block_find_by_addr(g_instr_block_get_links_block(block), next_addr); + next_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); + next_block = g_instr_block_find_by_addr(next_parent, next_addr, false); if (next_block != NULL) true_dinstr = decompiled_basic_block(next_block, ctx); @@ -181,26 +320,28 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_FALSE); - printf("@ 0x%08llx : false : %p\n", max, next); + //printf("@ 0x%08llx : false : %p\n", max, next); false_dinstr = NULL; if (next != NULL) { g_arch_instruction_get_location(next, NULL, NULL, &next_addr); - next_block = g_instr_block_find_by_addr(g_instr_block_get_links_block(block), next_addr); + next_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); + next_block = g_instr_block_find_by_addr(next_parent, next_addr, false); if (next_block != NULL) false_dinstr = decompiled_basic_block(next_block, ctx); } + /* printf(" -> ite : %p + %p\n", true_dinstr, false_dinstr); printf(" -> ite : %s + %s\n", true_dinstr ? g_type_name(G_TYPE_FROM_INSTANCE(true_dinstr)) : "none", false_dinstr ? g_type_name(G_TYPE_FROM_INSTANCE(false_dinstr)) : "none"); - + */ g_ite_instruction_set_branches(G_ITE_INSTRUCTION(decomp), true_dinstr, false_dinstr); @@ -327,6 +468,8 @@ GDecInstruction *decompiled_routine_instructions(GBinRoutine *routine, GExeForma blocks = g_binary_routine_get_basic_blocks(routine); + init_decomp_context(blocks, g_binary_routine_get_address(routine)); + result = decompiled_basic_block(blocks, context); g_object_unref(context); -- cgit v0.11.2-87-g4458