diff options
| -rw-r--r-- | ChangeLog | 26 | ||||
| -rw-r--r-- | src/analysis/block-int.h | 6 | ||||
| -rw-r--r-- | src/analysis/block.c | 26 | ||||
| -rw-r--r-- | src/analysis/block.h | 36 | ||||
| -rwxr-xr-x | src/analysis/blocks/Makefile.am | 1 | ||||
| -rw-r--r-- | src/analysis/blocks/flow.c | 200 | ||||
| -rw-r--r-- | src/analysis/blocks/flow.h | 24 | ||||
| -rw-r--r-- | src/analysis/blocks/raccess.c | 387 | ||||
| -rw-r--r-- | src/analysis/blocks/raccess.h | 105 | ||||
| -rw-r--r-- | src/analysis/blocks/virtual.c | 31 | ||||
| -rw-r--r-- | src/analysis/decomp/il.c | 153 | 
11 files changed, 851 insertions, 144 deletions
| @@ -1,3 +1,29 @@ +13-01-13  Cyrille Bagard <nocbos@gmail.com> + +	* 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 <nocbos@gmail.com>  	* 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 <glib.h>  #include <glib-object.h> +#include <stdbool.h> -#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 <glib-object.h> +#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 <http://www.gnu.org/licenses/>. + */ + + +#include "raccess.h" + + +#include <malloc.h> +#include <stdlib.h> +#include <string.h> + + + +/* 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 <http://www.gnu.org/licenses/>. + */ + + +#ifndef _ANALYSIS_BLOCKS_RACCESS_H +#define _ANALYSIS_BLOCKS_RACCESS_H + + +#include <glib.h> +#include <glib-object.h> + +#include <stdbool.h> + + +#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); | 
