summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog26
-rw-r--r--src/analysis/block-int.h6
-rw-r--r--src/analysis/block.c26
-rw-r--r--src/analysis/block.h36
-rwxr-xr-xsrc/analysis/blocks/Makefile.am1
-rw-r--r--src/analysis/blocks/flow.c200
-rw-r--r--src/analysis/blocks/flow.h24
-rw-r--r--src/analysis/blocks/raccess.c387
-rw-r--r--src/analysis/blocks/raccess.h105
-rw-r--r--src/analysis/blocks/virtual.c31
-rw-r--r--src/analysis/decomp/il.c153
11 files changed, 851 insertions, 144 deletions
diff --git a/ChangeLog b/ChangeLog
index 74e3608..31709b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);