summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2013-01-05 13:30:19 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2013-01-05 13:30:19 (GMT)
commitd626276398a3cdd3cd6432e073a8866aa91418ce (patch)
tree15e4b325ebb0636b26058cd39fda3e1e87b534cc /src/analysis
parentbfd81d1f289913f4d6e09cd8d99f4aaeed98436b (diff)
Refined the definition of basic blocks and used them to build extra clusters for dot.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@317 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/binary.c6
-rw-r--r--src/analysis/block-int.h4
-rw-r--r--src/analysis/block.c21
-rw-r--r--src/analysis/block.h16
-rw-r--r--src/analysis/blocks/flow.c62
-rw-r--r--src/analysis/blocks/flow.h3
-rw-r--r--src/analysis/blocks/virtual.c54
-rw-r--r--src/analysis/blocks/virtual.h3
-rw-r--r--src/analysis/decomp/decompiler.c2
-rw-r--r--src/analysis/disass/macro.c125
10 files changed, 258 insertions, 38 deletions
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 61f826a..e3b3e9d 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -2,7 +2,7 @@
/* OpenIDA - Outil d'analyse de fichiers binaires
* binary.c - traitement des flots de code binaire
*
- * Copyright (C) 2008-2012 Cyrille Bagard
+ * Copyright (C) 2008-2013 Cyrille Bagard
*
* This file is part of OpenIDA.
*
@@ -797,10 +797,10 @@ void ack_completed_disassembly(GDelayedDisassembly *disass, GLoadedBinary *binar
if (binary->decbuf_count > 0)
{
binary->dec_buffers = (GCodeBuffer **)calloc(binary->decbuf_count, sizeof(GCodeBuffer *));
- /*
+
for (i = 0; i < binary->decbuf_count; i++)
binary->dec_buffers[i] = decompile_all_from_file(binary, files[i]);
- */
+
}
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h
index e194ace..ba84fcb 100644
--- a/src/analysis/block-int.h
+++ b/src/analysis/block-int.h
@@ -29,6 +29,9 @@
+/* Parcours tous les blocs d'instructions dans un ordre donné. */
+typedef bool (* visit_all_blocks_fc) (GInstrBlock *, instr_block_visitor_cb, void *);
+
/* Etablit la liste de tous les blocs présents. */
typedef void (* list_all_blocks_fc) (const GInstrBlock *, GInstrBlock ***, size_t *);
@@ -42,6 +45,7 @@ struct _GInstrBlock
{
GObject parent; /* A laisser en premier */
+ 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 */
diff --git a/src/analysis/block.c b/src/analysis/block.c
index 3093a98..3b3eaf3 100644
--- a/src/analysis/block.c
+++ b/src/analysis/block.c
@@ -157,6 +157,27 @@ static void g_instr_block_finalize(GInstrBlock *block)
/******************************************************************************
* *
+* Paramètres : block = bloc d'instructions démarrant la visite. *
+* callback = ensemble de blocs à parcourir. *
+* data = donnée utilisateur à associer au parcours. *
+* *
+* Description : Parcours tous les blocs d'instructions dans un ordre donné. *
+* *
+* Retour : true si le parcours a été jusqu'à son terme, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_instr_block_visit(GInstrBlock *block, instr_block_visitor_cb callback, void *data)
+{
+ return block->visit_blocks(block, callback, data);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : block = bloc d'instructions à consulter. *
* list = ensemble de blocs à compléter. [OUT] *
* count = nombre de blocs au total. [OUT] *
diff --git a/src/analysis/block.h b/src/analysis/block.h
index 9e136a3..a85e4aa 100644
--- a/src/analysis/block.h
+++ b/src/analysis/block.h
@@ -79,9 +79,25 @@ typedef struct _GInstrBlock GInstrBlock;
typedef struct _GInstrBlockClass GInstrBlockClass;
+/* Position au cours d'une visite */
+typedef enum _BlockVisitOrder
+{
+ BVO_IN, /* Entrée dans un gros bloc */
+ BVO_PENDING, /* Visite d'un bloc simple */
+ BVO_OUT /* Sortie d'un gros bloc */
+
+} BlockVisitOrder;
+
+/* Rappel à chaque bloc visité */
+typedef bool (* instr_block_visitor_cb) (GInstrBlock *, BlockVisitOrder, void *);
+
+
/* Indique le type défini pour un bloc d'instructions. */
GType g_instr_block_get_type(void);
+/* Parcours tous les blocs d'instructions dans un ordre donné. */
+bool g_instr_block_visit(GInstrBlock *, instr_block_visitor_cb, void *);
+
/* Etablit la liste de tous les blocs présents. */
void g_instr_block_list_all_blocks(const GInstrBlock *, GInstrBlock ***, size_t *);
diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c
index f80b7c8..85d98ee 100644
--- a/src/analysis/blocks/flow.c
+++ b/src/analysis/blocks/flow.c
@@ -65,15 +65,18 @@ static void g_flow_block_dispose(GFlowBlock *);
/* Procède à la libération totale de la mémoire. */
static void g_flow_block_finalize(GFlowBlock *);
+/* Parcours le bloc d'instructions dans un ordre donné. */
+static bool g_flow_block_visit(GFlowBlock *, instr_block_visitor_cb, void *);
+
+/* Etablit la liste de tous les blocs présents. */
+static void g_flow_block_list_all_blocks(const GFlowBlock *, GInstrBlock ***, size_t *);
+
/* Prend note de l'usage d'un registre, au besoin. */
static void g_flow_block_memorize_access(GFlowBlock *, GArchRegister *, RegAccessType, vmpa_t);
/* Note les différents accès aux registres. */
static void g_flow_block_compute_regs_access(GFlowBlock *);
-/* Etablit la liste de tous les blocs présents. */
-static void g_flow_block_list_all_blocks(const GFlowBlock *, GInstrBlock ***, size_t *);
-
/* Fournit les différents accès aux registres. */
static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *, size_t *);
@@ -125,6 +128,7 @@ static void g_flow_block_init(GFlowBlock *block)
parent = G_INSTR_BLOCK(block);
+ 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;
@@ -199,7 +203,7 @@ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first,
{
GFlowBlock *result; /* Structure à retourner */
- vmpa_t addr; /* Adresse de la destination */
+ //vmpa_t addr; /* Adresse de la destination */
result = g_object_new(G_TYPE_FLOW_BLOCK, NULL);
@@ -232,6 +236,27 @@ GInstrBlock *g_flow_block_new(GArchInstruction *instrs, GArchInstruction *first,
/******************************************************************************
* *
+* Paramètres : block = bloc d'instructions concerné par la visite. *
+* callback = ensemble de blocs à parcourir. *
+* data = donnée utilisateur à associer au parcours. *
+* *
+* Description : Parcours le bloc d'instructions dans un ordre donné. *
+* *
+* Retour : true si le parcours a été jusqu'à son terme, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_flow_block_visit(GFlowBlock *block, instr_block_visitor_cb callback, void *data)
+{
+ return callback(G_INSTR_BLOCK(block), BVO_PENDING, data);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : block = bloc d'instructions à consulter. *
* list = ensemble de blocs à compléter. [OUT] *
* count = nombre de blocs au total. [OUT] *
@@ -394,6 +419,28 @@ static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *block
/******************************************************************************
* *
* Paramètres : block = bloc d'instructions à consulter. *
+* first = instruction de départ du bloc. [OUT] *
+* last = dernière instruction du bloc. [OUT] *
+* *
+* Description : Fournit les instructions limites d'un bloc d'exécution. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_flow_block_get_boundary(const GFlowBlock *block, GArchInstruction **first, GArchInstruction **last)
+{
+ *first = block->first;
+ *last = block->last;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : block = bloc d'instructions à consulter. *
* start = adresse de départ du bloc. [OUT] *
* end = dernière adresse du bloc. [OUT] *
* *
@@ -407,7 +454,10 @@ static const reg_access *g_flow_block_list_regs_accesses(const GFlowBlock *block
void g_flow_block_get_boundary_addresses(const GFlowBlock *block, vmpa_t *start, vmpa_t *end)
{
- g_arch_instruction_get_location(block->first, NULL, NULL, start);
- g_arch_instruction_get_location(block->last, NULL, NULL, end);
+ if (start != NULL)
+ g_arch_instruction_get_location(block->first, NULL, NULL, start);
+
+ if (end != NULL)
+ g_arch_instruction_get_location(block->last, NULL, NULL, end);
}
diff --git a/src/analysis/blocks/flow.h b/src/analysis/blocks/flow.h
index 14f49ec..8bd7257 100644
--- a/src/analysis/blocks/flow.h
+++ b/src/analysis/blocks/flow.h
@@ -55,6 +55,9 @@ GType g_flow_block_get_type(void);
/* Crée un bloc d'exécution d'instructions. */
GInstrBlock *g_flow_block_new(GArchInstruction *, GArchInstruction *, GArchInstruction *);
+/* Fournit les instructions limites d'un bloc d'exécution. */
+void g_flow_block_get_boundary(const GFlowBlock *, GArchInstruction **, GArchInstruction **);
+
/* Fournit les adresses limites d'un bloc d'exécution. */
void g_flow_block_get_boundary_addresses(const GFlowBlock *, vmpa_t *, vmpa_t *);
diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c
index c981ece..90bccca 100644
--- a/src/analysis/blocks/virtual.c
+++ b/src/analysis/blocks/virtual.c
@@ -69,6 +69,9 @@ static void g_virtual_block_dispose(GVirtualBlock *);
/* Procède à la libération totale de la mémoire. */
static void g_virtual_block_finalize(GVirtualBlock *);
+/* Parcours le bloc d'instructions dans un ordre donné. */
+static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void *);
+
/* Etablit la liste de tous les blocs présents. */
static void g_virtual_block_list_all_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *);
@@ -123,6 +126,7 @@ static void g_virtual_block_init(GVirtualBlock *block)
parent = G_INSTR_BLOCK(block);
+ 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;
@@ -203,6 +207,37 @@ GInstrBlock *g_virtual_block_new(void)
/******************************************************************************
* *
+* Paramètres : block = bloc d'instructions concerné par la visite. *
+* callback = ensemble de blocs à parcourir. *
+* data = donnée utilisateur à associer au parcours. *
+* *
+* Description : Parcours le bloc d'instructions dans un ordre donné. *
+* *
+* Retour : true si le parcours a été jusqu'à son terme, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_virtual_block_visit(GVirtualBlock *block, instr_block_visitor_cb callback, void *data)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours */
+
+ result = callback(G_INSTR_BLOCK(block), BVO_IN, data);
+
+ for (i = 0; i < block->children_count && result; i++)
+ result = g_instr_block_visit(block->children[i], callback, data);
+
+ result &= callback(G_INSTR_BLOCK(block), BVO_OUT, data);
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : block = bloc d'instructions à consulter. *
* list = ensemble de blocs à compléter. [OUT] *
* count = nombre de blocs au total. [OUT] *
@@ -270,3 +305,22 @@ void g_virtual_block_add_child(GVirtualBlock *block, GInstrBlock *child)
g_object_ref(G_OBJECT(child));
}
+
+
+/******************************************************************************
+* *
+* Paramètres : block = bloc d'instructions à consulter. *
+* *
+* Description : Compte le nombre de blocs contenus dans le groupe courant. *
+* *
+* Retour : Quantité normalement non nulle. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t g_virtual_block_count_children(GVirtualBlock *block)
+{
+ return block->children_count;
+
+}
diff --git a/src/analysis/blocks/virtual.h b/src/analysis/blocks/virtual.h
index f1f559f..5e8ddcd 100644
--- a/src/analysis/blocks/virtual.h
+++ b/src/analysis/blocks/virtual.h
@@ -58,6 +58,9 @@ GInstrBlock *g_virtual_block_new(void);
/* Ajoute un bloc au groupe courant. */
void g_virtual_block_add_child(GVirtualBlock *, GInstrBlock *);
+/* Compte le nombre de blocs contenus dans le groupe courant. */
+size_t g_virtual_block_count_children(GVirtualBlock *);
+
#endif /* _ANALYSIS_BLOCKS_VIRTUAL_H */
diff --git a/src/analysis/decomp/decompiler.c b/src/analysis/decomp/decompiler.c
index 1ac177a..c824697 100644
--- a/src/analysis/decomp/decompiler.c
+++ b/src/analysis/decomp/decompiler.c
@@ -217,6 +217,7 @@ GCodeBuffer *decompile_all_from_file(const GLoadedBinary *binary, const char *fi
build_decomp_prologue(result, filename);
+ /*
prepare_all_routines_for_decomp(binary, filename);
@@ -224,6 +225,7 @@ GCodeBuffer *decompile_all_from_file(const GLoadedBinary *binary, const char *fi
format = g_loaded_binary_get_format(binary);
g_binary_format_decompile(G_BIN_FORMAT(format), result, filename);
+ */
return result;
diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c
index 46dc0d3..2e5c0ee 100644
--- a/src/analysis/disass/macro.c
+++ b/src/analysis/disass/macro.c
@@ -277,6 +277,7 @@ static vmpa_t compute_first_common_addr_in_group(const branch_info *list, size_t
static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t start, vmpa_t end, vmpa_t stop)
{
GInstrBlock *result; /* Regroupement à retourner */
+ GInstrBlock *result_cached; /* Temporisation pour unicité */
branch_info main_branch; /* Flot d'exécution complet */
GArchInstruction *first; /* Première instruction */
GArchInstruction *last; /* Dernière instruction */
@@ -287,6 +288,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
size_t dcount; /* Nombre de liens de dest. */
size_t i; /* Boucle de parcours #1 */
GInstrBlock *block; /* Nouveau bloc mis en place */
+ GInstrBlock *group; /* Regroupement de blocs */
branch_info *cases_branches; /* Branches d'un aiguillage */
size_t cases_count; /* Nombre d'aiguillages */
branch_info true_branch; /* Branche 'condition vraie' */
@@ -298,6 +300,32 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
vmpa_t stop_addr; /* Adresse de fin de bloc */
result = NULL;
+ result_cached = NULL;
+
+ /**
+ * Procédure d'ajout de blocs : pour le premier, on conserve le bloc en mémoire
+ * et on attend. Si rien ne suit, il constitura l'unique retour. Sinon, on
+ * l'ajoute à partir de la sauvegarde, et le reste suit.
+ */
+#define DELAYED_BLOCK_ADDING(res, cache, blk) \
+ do \
+ { \
+ if (res == NULL) \
+ { \
+ if (cache == NULL) \
+ cache = blk; \
+ else \
+ { \
+ res = g_virtual_block_new(); \
+ g_virtual_block_add_child(G_VIRTUAL_BLOCK(res), cache); \
+ } \
+ } \
+ \
+ if (res != NULL) \
+ g_virtual_block_add_child(G_VIRTUAL_BLOCK(res), blk); \
+ \
+ } \
+ while (0)
first = NULL;
last = NULL;
@@ -347,14 +375,13 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
case ILT_EXEC_FLOW:
case ILT_JUMP:
- if (result == NULL)
- result = g_virtual_block_new();
block = g_flow_block_new(instrs, first, iter);
MACRO_MARK_AS_PROCESSED(first);
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
first = NULL;
+ DELAYED_BLOCK_ADDING(result, result_cached, block);
+
g_arch_instruction_get_location(dests[i], NULL, NULL, &next_addr);
break;
@@ -401,15 +428,14 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
/* Post-traitements de ILT_CASE_JUMP */
if (cases_count > 0)
{
- if (result == NULL)
- result = g_virtual_block_new();
-
if (first != NULL)
{
block = g_flow_block_new(instrs, first, iter);
MACRO_MARK_AS_PROCESSED(first);
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
first = NULL;
+
+ DELAYED_BLOCK_ADDING(result, result_cached, block);
+
}
//printf(" --- cases --- start\n");
@@ -417,6 +443,8 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
next_addr = compute_first_common_addr_in_group(cases_branches, cases_count);
//printf(" stop :: 0x%08llx\n", next_addr);
+ group = g_virtual_block_new();
+
for (j = 0; j < cases_count; j++)
{
//printf(" ## %zu\n", j);
@@ -425,12 +453,17 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
if (block != NULL)
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+ g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
free(cases_branches[j].jumps);
}
+ if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0)
+ DELAYED_BLOCK_ADDING(result, result_cached, group);
+ else
+ g_object_unref(G_OBJECT(group));
+
//printf(" --- cases --- end\n");
@@ -441,15 +474,14 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
/* Post-traitements de ILT_CATCH_EXCEPTION */
if (excep_count > 0)
{
- if (result == NULL)
- result = g_virtual_block_new();
-
if (first != NULL)
{
block = g_flow_block_new(instrs, first, iter);
MACRO_MARK_AS_PROCESSED(first);
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
first = NULL;
+
+ DELAYED_BLOCK_ADDING(result, result_cached, block);
+
}
for (j = 0; j < excep_count; j++)
@@ -482,28 +514,30 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
next_addr = compute_first_common_addr(&true_branch, &false_branch);
next_addr = MIN(next_addr, end);
- if (result == NULL)
- result = g_virtual_block_new();
-
if (first != NULL)
{
block = g_flow_block_new(instrs, first, iter);
MACRO_MARK_AS_PROCESSED(first);
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
first = NULL;
- }
- block = build_instruction_block(instrs, true_branch.jumps[0], end, next_addr);
+ DELAYED_BLOCK_ADDING(result, result_cached, block);
- if (block != NULL)
+ }
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+ group = g_virtual_block_new();
- block = build_instruction_block(instrs, false_branch.jumps[0], end, next_addr);
+ block = build_instruction_block(instrs, true_branch.jumps[0], end, next_addr);
+ if (block != NULL)
+ g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
- if (block != NULL)
+ block = build_instruction_block(instrs, false_branch.jumps[0], end, next_addr);
+ if (block != NULL)
+ g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+ if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0)
+ DELAYED_BLOCK_ADDING(result, result_cached, group);
+ else
+ g_object_unref(G_OBJECT(group));
free(true_branch.jumps);
free(false_branch.jumps);
@@ -526,21 +560,51 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
MACRO_MARK_AS_PROCESSED(first);
//printf("--close!--\n");
- if (result == NULL)
- result = block;
- else
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+ DELAYED_BLOCK_ADDING(result, result_cached, block);
+
}
}
- if (result == NULL)
+ if ((result != NULL ? result : result_cached) == NULL)
{
//printf("WARNING :: null !\n");
//exit(0);
}
- return result;
+ return (result != NULL ? result : result_cached);
+
+}
+
+
+static bool print_blocks(GInstrBlock *blk, BlockVisitOrder order, int *pad)
+{
+ int i;
+ vmpa_t start, end;
+
+ if (order != BVO_OUT)
+ for (i = 0; i < *pad; i++)
+ printf(" ");
+
+ if (G_IS_FLOW_BLOCK(blk))
+ {
+ g_flow_block_get_boundary_addresses(G_FLOW_BLOCK(blk), &start, &end);
+ printf(" - flow %p : 0x%08lx -> 0x%08lx\n", blk, start, end);
+ }
+ else
+ {
+ if (order != BVO_OUT)
+ {
+ printf(" - virtual %p\n", blk);
+ *pad += 1;
+ }
+ else *pad -= 1;
+
+ }
+
+ fflush(NULL);
+
+ return true;
}
@@ -580,6 +644,9 @@ void group_routines_instructions(GArchInstruction *list, GBinRoutine **routines,
block = build_instruction_block(list, start, end, VMPA_MAX);
g_binary_routine_set_basic_blocks(routines[i], block);
+
+ //g_instr_block_visit(block, (instr_block_visitor_cb)print_blocks, (int []){ 0 });
+
gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
}