From d626276398a3cdd3cd6432e073a8866aa91418ce Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sat, 5 Jan 2013 13:30:19 +0000 Subject: 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 --- ChangeLog | 32 ++++++++++ src/analysis/binary.c | 6 +- src/analysis/block-int.h | 4 ++ src/analysis/block.c | 21 +++++++ src/analysis/block.h | 16 +++++ src/analysis/blocks/flow.c | 62 +++++++++++++++++-- src/analysis/blocks/flow.h | 3 + src/analysis/blocks/virtual.c | 54 +++++++++++++++++ src/analysis/blocks/virtual.h | 3 + src/analysis/decomp/decompiler.c | 2 + src/analysis/disass/macro.c | 125 ++++++++++++++++++++++++++++++--------- src/decomp/expr/immediate.c | 1 + src/gtkext/graph/layout.c | 120 ++++++++++++++++++++++++++++++++----- src/gtkext/graph/layout.h | 2 +- src/gtkext/graph/node.c | 78 ++++++++++++++++++++---- src/gtkext/graph/node.h | 13 +++- src/gtkext/gtkgraphview.c | 16 +++-- 17 files changed, 486 insertions(+), 72 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9561278..59f7fc6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +13-01-05 Cyrille Bagard + + * src/analysis/binary.c: + Restore decompilation at this level. + + * src/analysis/block.c: + * src/analysis/block.h: + * src/analysis/block-int.h: + * src/analysis/blocks/flow.c: + * src/analysis/blocks/flow.h: + * src/analysis/blocks/virtual.c: + * src/analysis/blocks/virtual.h: + Implement a visitor design pattern for basic blocks. + + * src/analysis/decomp/decompiler.c: + Disable decompilation for now. + + * src/analysis/disass/macro.c: + Refine the definition of basic blocks for easier abstract use. + + * src/decomp/expr/immediate.c: + Avoid faults by increasing a ref counter. + + * src/gtkext/graph/layout.c: + * src/gtkext/graph/layout.h: + * src/gtkext/graph/node.c: + * src/gtkext/graph/node.h: + Define new clusters using the basic blocks to group nodes. + + * src/gtkext/gtkgraphview.c: + Update code. + 13-01-02 Cyrille Bagard * src/analysis/block.c: 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, ¶ms); - 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 +#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)); -- cgit v0.11.2-87-g4458