summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
-rw-r--r--src/decomp/expr/immediate.c1
-rw-r--r--src/gtkext/graph/layout.c120
-rw-r--r--src/gtkext/graph/layout.h2
-rw-r--r--src/gtkext/graph/node.c78
-rw-r--r--src/gtkext/graph/node.h13
-rw-r--r--src/gtkext/gtkgraphview.c16
16 files changed, 454 insertions, 72 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);
}
diff --git a/src/decomp/expr/immediate.c b/src/decomp/expr/immediate.c
index a17b2a1..18af422 100644
--- a/src/decomp/expr/immediate.c
+++ b/src/decomp/expr/immediate.c
@@ -122,6 +122,7 @@ GDecInstruction *g_imm_expression_new(GImmOperand *operand)
result = g_object_new(G_TYPE_IMM_EXPRESSION, NULL);
result->operand = operand;
+ g_object_ref(G_OBJECT(operand));
return G_DEC_INSTRUCTION(result);
diff --git a/src/gtkext/graph/layout.c b/src/gtkext/graph/layout.c
index 45e3a82..2cf4a36 100644
--- a/src/gtkext/graph/layout.c
+++ b/src/gtkext/graph/layout.c
@@ -2,7 +2,7 @@
/* OpenIDA - Outil d'analyse de fichiers binaires
* layout.c - mise en place de graphique
*
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
*
* This file is part of OpenIDA.
*
@@ -33,14 +33,33 @@
#include "node.h"
#include "../gtkbufferview.h"
#include "../../analysis/binary.h"
+#include "../../analysis/blocks/flow.h"
#include "../../common/extstr.h"
+/* Taille maximale des introductions aux clusters */
+#define CLUSTER_DESC_LEN 128
+
/* Taille maximale des descriptions de liens */
#define LINKS_DESC_LEN 128
+/* Paramètres de construction des commandes */
+typedef struct _visitor_dot_params
+{
+ GGraphNode **nodes; /* Intermédiaires en place */
+ size_t count; /* Quantité de noeuds en place */
+
+ unsigned int level; /* Profondeur de la visite */
+ char *cmds; /* Description à envoyer à dot */
+
+} visitor_dot_params;
+
+
+/* Construit les commandes pour dot en parcourant les noeuds. */
+static bool register_graph_nodes(GInstrBlock *, BlockVisitOrder, visitor_dot_params *);
+
/* Etablit tous les liens entre les différents morceaux de code. */
static char *complete_graph_links(const GtkGraphView *, GtkViewPanel **, size_t, char *);
@@ -60,47 +79,118 @@ static char *complete_graph_links(const GtkGraphView *, GtkViewPanel **, size_t,
* *
******************************************************************************/
-bool build_graph_view(GtkGraphView *view, GtkViewPanel **views, size_t count)
+bool build_graph_view(GtkGraphView *view, GInstrBlock *blocks, GtkViewPanel **views, size_t count)
{
- GGraphNode **nodes; /* Intermédiaires en place */
+ visitor_dot_params params; /* Paramètres de construction */
size_t i; /* Boucle de parcours */
- char *cmds; /* Description à envoyer à dot */
graph_layout *layout; /* Graphique construit */
GtkLinkRenderer **links; /* Liens graphiques construits */
size_t links_count; /* Quantité de ces liens */
/* Création de la glue */
- nodes = (GGraphNode **)calloc(count, sizeof(GGraphNode *));
+ params.nodes = (GGraphNode **)calloc(count, sizeof(GGraphNode *));
+ params.count = count;
for (i = 0; i < count; i++)
- nodes[i] = g_graph_node_new(GTK_WIDGET(views[i]));
+ params.nodes[i] = g_graph_node_new(GTK_WIDGET(views[i]));
/* Définition du graphique */
- cmds = strdup("digraph G {\n overlap=false;\n splines=ortho;\n compound=true;\n");
+ params.level = 1;
+ params.cmds = strdup("digraph G {\n overlap=false;\n splines=ortho;\n compound=true;\n");
- for (i = 0; i < count; i++)
- cmds = g_graph_node_register_for_dot(nodes[i], cmds);
+ g_instr_block_visit(blocks, (instr_block_visitor_cb)register_graph_nodes, &params);
- cmds = complete_graph_links(view, views, count, cmds);
+ params.cmds = complete_graph_links(view, views, count, params.cmds);
- cmds = stradd(cmds, "}");
+ params.cmds = stradd(params.cmds, "}");
- layout = create_graph_layout(cmds);
+ layout = create_graph_layout(params.cmds);
/* Affichage du graphique */
- place_nodes_of_graph_layout(layout, view, nodes, count);
+ place_nodes_of_graph_layout(layout, view, params.nodes, count);
- links = create_links_from_graph_layout(layout, &links_count, nodes, count);
+ links = create_links_from_graph_layout(layout, &links_count, params.nodes, count);
gtk_graph_view_attach_links(view, links, links_count);
gtk_widget_queue_draw(GTK_WIDGET(view));
delete_graph_layout(layout);
- /* TODO : free nodes */
+ for (i = 0; i < count; i++)
+ g_object_unref(params.nodes[i]);
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : block = bloc d'instructions concerné par la visite. *
+* order = position dans la visite. *
+* params = informations à mettre à jour pour dot. *
+* *
+* Description : Construit les commandes pour dot en parcourant les noeuds. *
+* *
+* Retour : true si le parcours a été jusqu'à son terme, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool register_graph_nodes(GInstrBlock *block, BlockVisitOrder order, visitor_dot_params *params)
+{
+ char *cmds; /* Raccourci d'usage pratique */
+ vmpa_t start; /* Adresse de départ d'un bloc */
+ GGraphNode *node; /* Noeud rattaché */
+ unsigned int i; /* Boucle de parcours */
+ char buffer[CLUSTER_DESC_LEN]; /* Tampon pour les commandes */
+
+ cmds = params->cmds;
+
+ if (G_IS_FLOW_BLOCK(block))
+ {
+ g_flow_block_get_boundary_addresses(G_FLOW_BLOCK(block), &start, NULL);
+ node = find_graph_node_by_start_address(params->nodes, params->count, start);
+
+ cmds = g_graph_node_register_for_dot(node, cmds, params->level);
+
+ }
+ else
+ {
+ if (order == BVO_IN)
+ {
+ for (i = 0; i < params->level; i++)
+ cmds = stradd(cmds, DOT_IDENT);
+
+ snprintf(buffer, CLUSTER_DESC_LEN, "subgraph cluster_v%p {\n", block);
+ cmds = stradd(cmds, buffer);
+
+ params->level++;
+
+ for (i = 0; i < params->level; i++)
+ cmds = stradd(cmds, DOT_IDENT);
+
+ cmds = stradd(cmds, "style=invisible;\n");
+
+ }
+ else if (order == BVO_OUT)
+ {
+ params->level--;
+
+ for (i = 0; i < params->level; i++)
+ cmds = stradd(cmds, DOT_IDENT);
+
+ cmds = stradd(cmds, "}\n");
+
+ }
+
+ }
+
+ params->cmds = cmds;
return true;
diff --git a/src/gtkext/graph/layout.h b/src/gtkext/graph/layout.h
index ffb227f..7a3bf1e 100644
--- a/src/gtkext/graph/layout.h
+++ b/src/gtkext/graph/layout.h
@@ -34,7 +34,7 @@
/* Dispose une série de morceaux d'affichage en graphique. */
-bool build_graph_view(GtkGraphView *, GtkViewPanel **, size_t);
+bool build_graph_view(GtkGraphView *, GInstrBlock *, GtkViewPanel **, size_t);
diff --git a/src/gtkext/graph/node.c b/src/gtkext/graph/node.c
index 0d746e2..d9b0eca 100644
--- a/src/gtkext/graph/node.c
+++ b/src/gtkext/graph/node.c
@@ -2,7 +2,7 @@
/* OpenIDA - Outil d'analyse de fichiers binaires
* node.c - éléments de graphiques chez dot
*
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
*
* This file is part of OpenIDA.
*
@@ -29,6 +29,7 @@
#include <string.h>
+#include "../gtkbufferview.h"
#include "../../common/extstr.h"
@@ -60,6 +61,10 @@ struct _GGraphNodeClass
};
+/* Taille maximale des lignes de description de noeud */
+#define NODE_DESC_LEN 128
+
+
/* Initialise la classe des intermédiaires avec les noeuds dot. */
static void g_graph_node_class_init(GGraphNodeClass *);
@@ -184,8 +189,9 @@ GGraphNode *g_graph_node_new(GtkWidget *view)
/******************************************************************************
* *
-* Paramètres : node = intermédiaire à consulter. *
-* cmds = description pour dot à compléter. *
+* Paramètres : node = intermédiaire à consulter. *
+* cmds = description pour dot à compléter. *
+* level = profondeur du noeud pour l'indentation. *
* *
* Description : Déclare l'intermédiaire en tant que noeud pour dot. *
* *
@@ -195,33 +201,45 @@ GGraphNode *g_graph_node_new(GtkWidget *view)
* *
******************************************************************************/
-char *g_graph_node_register_for_dot(const GGraphNode *node, char *cmds)
+char *g_graph_node_register_for_dot(const GGraphNode *node, char *cmds, unsigned int level)
{
GtkRequisition requisition; /* Taille à l'écran requise */
- char buffer[128];
+ unsigned int i; /* Boucle de parcours */
+ char buffer[NODE_DESC_LEN]; /* Tampon pour les commandes */
gtk_widget_size_request(node->view, &requisition);
- snprintf(buffer, 128, " subgraph cluster%s {\n", node->name);
+ for (i = 0; i < level; i++)
+ cmds = stradd(cmds, DOT_IDENT);
+
+ snprintf(buffer, NODE_DESC_LEN, "subgraph cluster%s {\n", node->name);
cmds = stradd(cmds, buffer);
- cmds = stradd(cmds, " style=invisible;\n");
+ for (i = 0; i < (level + 1); i++)
+ cmds = stradd(cmds, DOT_IDENT);
+
+ cmds = stradd(cmds, "style=invisible;\n");
+
+ for (i = 0; i < (level + 1); i++)
+ cmds = stradd(cmds, DOT_IDENT);
- cmds = stradd(cmds, " ");
cmds = stradd(cmds, node->name);
cmds = stradd(cmds, " [shape=box, fixedsize ");
- snprintf(buffer, 128, ", width=\"%g\"",
+ snprintf(buffer, NODE_DESC_LEN, ", width=\"%g\"",
requisition.width / G_GRAPH_NODE_GET_CLASS(node)->dpi_x);
cmds = stradd(cmds, buffer);
- snprintf(buffer, 128, ", height=\"%g\"",
+ snprintf(buffer, NODE_DESC_LEN, ", height=\"%g\"",
requisition.height / G_GRAPH_NODE_GET_CLASS(node)->dpi_y);
cmds = stradd(cmds, buffer);
cmds = stradd(cmds, "];\n");
- cmds = stradd(cmds, " }\n");
+ for (i = 0; i < level; i++)
+ cmds = stradd(cmds, DOT_IDENT);
+
+ cmds = stradd(cmds, "}\n");
return cmds;
@@ -327,6 +345,44 @@ void g_graph_node_connect(const GGraphNode *node, gint x, gint y, GdkPoint **poi
/******************************************************************************
* *
+* Paramètres : nodes = liste de noeuds à parcourir. *
+* count = taille de la liste. *
+* addrt = adresse de début du noeud recherché. *
+* *
+* Description : Recherche un noeud donné dans une série de noeuds. *
+* *
+* Retour : Noeud trouvé ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GGraphNode *find_graph_node_by_start_address(GGraphNode **nodes, size_t count, vmpa_t addr)
+{
+ GGraphNode *result; /* Trouvaille à remonter */
+ size_t i; /* Boucle de parcours */
+ GBufferView *buffer; /* Tampon d'une partie de code */
+ vmpa_t start; /* Adresse de départ du tampon */
+
+ result = NULL;
+
+ for (i = 0; i < count && result == NULL; i++)
+ {
+ buffer = gtk_buffer_view_get_buffer(GTK_BUFFER_VIEW(nodes[i]->view));
+ g_buffer_view_get_restrictions(buffer, &start, NULL);
+
+ if (start == addr)
+ result = nodes[i];
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : nodes = liste de noeuds à parcourir. *
* count = taille de la liste. *
* target = nom du noeud recherché. *
diff --git a/src/gtkext/graph/node.h b/src/gtkext/graph/node.h
index 515c92b..57d0932 100644
--- a/src/gtkext/graph/node.h
+++ b/src/gtkext/graph/node.h
@@ -2,7 +2,7 @@
/* OpenIDA - Outil d'analyse de fichiers binaires
* node.h - prototypes pour les éléments de graphiques chez dot
*
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
*
* This file is part of OpenIDA.
*
@@ -26,6 +26,12 @@
#include "../gtkgraphview.h"
+#include "../../arch/archbase.h"
+
+
+
+/* Indentation pour l'édition des commandes */
+#define DOT_IDENT " "
@@ -53,7 +59,7 @@ GType g_graph_node_get_type(void);
GGraphNode *g_graph_node_new(GtkWidget *);
/* Déclare l'intermédiaire en tant que noeud pour dot. */
-char *g_graph_node_register_for_dot(const GGraphNode *, char *);
+char *g_graph_node_register_for_dot(const GGraphNode *, char *, unsigned int);
/* Place le morceau de code de l'intermédiaire à l'écran. */
void g_graph_node_place(GGraphNode *, GtkGraphView *, gint , gint);
@@ -67,6 +73,9 @@ void g_graph_node_connect(const GGraphNode *, gint, gint, GdkPoint **, size_t *)
/* Recherche un noeud donné dans une série de noeuds. */
+GGraphNode *find_graph_node_by_start_address(GGraphNode **, size_t, vmpa_t);
+
+/* Recherche un noeud donné dans une série de noeuds. */
GGraphNode *find_graph_node_by_name(GGraphNode **, size_t, const char *);
diff --git a/src/gtkext/gtkgraphview.c b/src/gtkext/gtkgraphview.c
index 67fb577..6aedf26 100644
--- a/src/gtkext/gtkgraphview.c
+++ b/src/gtkext/gtkgraphview.c
@@ -2,7 +2,7 @@
/* OpenIDA - Outil d'analyse de fichiers binaires
* gtkgraphview.c - affichage de morceaux de code sous forme graphique
*
- * Copyright (C) 2009-2012 Cyrille Bagard
+ * Copyright (C) 2009-2013 Cyrille Bagard
*
* This file is part of OpenIDA.
*
@@ -39,8 +39,9 @@ struct _GtkGraphView
GtkViewPanel parent; /* A laisser en premier */
GtkFixed *support; /* Support des vues en bloc */
- vmpa_t start; /* Début de la portion vue */
- vmpa_t end; /* Fin de la portion affichée */
+ GBinRoutine *routine; /* Routine en cours d'affichage*/
+ vmpa_t start; /* Début de la portion vue */ /* FIXME : à garder ? */
+ vmpa_t end; /* Fin de la portion affichée */ /* FIXME : à garder ? */
GtkViewPanel **children; /* Liste des sous-blocs */
GtkAllocation *allocs; /* Emplacements prévisibles */
@@ -380,6 +381,9 @@ static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr)
if (start <= addr && addr < end)
{
+ view->routine = routines[i];
+ g_object_ref(G_OBJECT(view->routine));
+
view->start = start;
view->end = end;
@@ -389,7 +393,8 @@ static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr)
view->allocs = (GtkAllocation *)calloc(view->children_count,
sizeof(GtkAllocation));
- build_graph_view(view, view->children, view->children_count);
+ build_graph_view(view, g_binary_routine_get_basic_blocks(view->routine),
+ view->children, view->children_count);
break;
@@ -425,7 +430,8 @@ static void gtk_graph_view_prepare_resize(GtkGraphView *view)
for (i = 0; i < view->children_count; i++)
gtk_widget_queue_resize(GTK_WIDGET(view->children[i]));
- build_graph_view(view, view->children, view->children_count);
+ build_graph_view(view, g_binary_routine_get_basic_blocks(view->routine),
+ view->children, view->children_count);
change_editor_items_current_view_content(GTK_VIEW_PANEL(view));