From 221bcaeeb06415d501f9abbb9bc4b7d8339af1fe Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 10 Jan 2013 22:47:37 +0000 Subject: Simplified the decompilation process by using links between basic blocks. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@322 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 19 +++++++ src/analysis/block-int.h | 2 + src/analysis/block.c | 46 ++++++++++++++++ src/analysis/block.h | 6 +++ src/analysis/blocks/virtual.c | 3 +- src/analysis/decomp/il.c | 30 +++++------ src/analysis/disass/macro.c | 121 ++++++++++++++++++++++++------------------ src/decomp/instr/ite.c | 21 +++++++- 8 files changed, 175 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index b081ee7..74e3608 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +13-01-10 Cyrille Bagard + + * src/analysis/block.c: + * src/analysis/block.h: + * src/analysis/block-int.h: + Create a link between basic blocks. + + * src/analysis/blocks/virtual.c: + Return the first [parent] block found, not the final one. + + * src/analysis/decomp/il.c: + Simplify the decompilation process by using links between basic blocks. + + * src/analysis/disass/macro.c: + Attach the conditional blocks with their origin. Fix a bug for exceptions. + + * src/decomp/instr/ite.c: + Inverse the condition if the 'true' branch is empty. + 13-01-09 Cyrille Bagard * src/analysis/decomp/decompiler.c: diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h index 355c1ee..f016e35 100644 --- a/src/analysis/block-int.h +++ b/src/analysis/block-int.h @@ -53,6 +53,8 @@ struct _GInstrBlock list_all_blocks_fc list_blocks; /* Liste de tous les blocs */ list_regs_accesses_fc list_regs; /* Liste des accès registres */ + GInstrBlock *links_block; /* Lieu des blocs attachés */ + }; /* Description d'un bloc d'instructions (classe) */ diff --git a/src/analysis/block.c b/src/analysis/block.c index 62b56ab..1ec9804 100644 --- a/src/analysis/block.c +++ b/src/analysis/block.c @@ -131,6 +131,9 @@ static void g_instr_block_init(GInstrBlock *block) static void g_instr_block_dispose(GInstrBlock *block) { + if (block->links_block != NULL) + g_object_unref(G_OBJECT(block->links_block)); + G_OBJECT_CLASS(g_instr_block_parent_class)->dispose(G_OBJECT(block)); } @@ -215,3 +218,46 @@ void g_instr_block_list_all_blocks(const GInstrBlock *block, GInstrBlock ***list block->list_blocks(block, list, count); } + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions à mettre à jour. * +* links = bloc contenant les blocs liés au bloc. * +* * +* Description : Définit l'ensemble contenant les blocs liés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_instr_block_set_links_block(GInstrBlock *block, GInstrBlock *links) +{ + if (block->links_block != NULL) + g_object_unref(G_OBJECT(block->links_block)); + + g_object_ref(G_OBJECT(links)); + block->links_block = links; + +} + + +/****************************************************************************** +* * +* Paramètres : block = bloc d'instructions à mettre à jour. * +* * +* Description : Fournit l'ensemble contenant les blocs liés. * +* * +* Retour : Bloc contenant les blocs liés au bloc. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GInstrBlock *g_instr_block_get_links_block(const GInstrBlock *block) +{ + return block->links_block; + +} diff --git a/src/analysis/block.h b/src/analysis/block.h index 1574dc1..125ff0e 100644 --- a/src/analysis/block.h +++ b/src/analysis/block.h @@ -104,6 +104,12 @@ 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 *); +/* Définit l'ensemble contenant les blocs liés. */ +void g_instr_block_set_links_block(GInstrBlock *, GInstrBlock *); + +/* Fournit l'ensemble contenant les blocs liés. */ +GInstrBlock *g_instr_block_get_links_block(const GInstrBlock *); + #endif /* _ANALYSIS_BLOCK_H */ diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c index 71a6d06..2385f67 100644 --- a/src/analysis/blocks/virtual.c +++ b/src/analysis/blocks/virtual.c @@ -230,7 +230,8 @@ static GInstrBlock *g_virtual_block_find_by_addr(const GVirtualBlock *block, vmp result = NULL; for (i = 0; i < block->children_count && result == NULL; i++) - result = g_instr_block_find_by_addr(block->children[i], addr); + if (g_instr_block_find_by_addr(block->children[i], addr)) + result = block->children[i]; return result; diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c index c2bc0be..f3c2265 100644 --- a/src/analysis/decomp/il.c +++ b/src/analysis/decomp/il.c @@ -46,7 +46,7 @@ static GDecInstruction *merge_decompiled_instructions(GDecInstruction *, GDecInstruction *); /* Procède à la décompilation d'un bloc déterminé. */ -static GDecInstruction *decompiled_instructions_block(GFlowBlock *, GVirtualBlock *, GDecContext *); +static GDecInstruction *decompiled_instructions_block(GFlowBlock *, GDecContext *); /* Procède à la décompilation d'un ensemble de blocs déterminé. */ static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *, GDecContext *); @@ -111,9 +111,8 @@ static GDecInstruction *merge_decompiled_instructions(GDecInstruction *group, GD /****************************************************************************** * * -* Paramètres : block = ensemble des instructions d'assemblage à traiter. * -* parent = groupe de blocs d'appartenance. * -* ctx = contexte de soutien à associer à l'opération. * +* Paramètres : block = ensemble des instructions d'assemblage à traiter. * +* ctx = contexte de soutien à associer à l'opération. * * * * Description : Procède à la décompilation d'un bloc déterminé. * * * @@ -123,7 +122,7 @@ static GDecInstruction *merge_decompiled_instructions(GDecInstruction *group, GD * * ******************************************************************************/ -static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtualBlock *parent, GDecContext *ctx) +static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecContext *ctx) { GDecInstruction *res; @@ -137,7 +136,8 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtua GDecInstruction *false_dinstr; /* Décompilation 'cond fausse' */ GArchInstruction *next; /* Instruction de branchement */ vmpa_t next_addr; /* Adresse de cette instruct° */ - GInstrBlock *next_block; /* Bloc basique correspondant */ + GInstrBlock *next_parent; /* Bloc basique correspondant */ + GInstrBlock *next_block; /* Sous-bloc basique direct */ instrs = g_flow_block_get_all_instructions_list(block); g_flow_block_get_boundary(block, &first, &last); @@ -172,13 +172,10 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtua if (next != NULL) { g_arch_instruction_get_location(next, NULL, NULL, &next_addr); - next_block = g_instr_block_find_by_addr(G_INSTR_BLOCK(parent), next_addr); + next_block = g_instr_block_find_by_addr(g_instr_block_get_links_block(block), next_addr); if (next_block != NULL) - { - next_block = g_instr_block_find_by_addr(next_block, next_addr); true_dinstr = decompiled_basic_block(next_block, ctx); - } } @@ -191,21 +188,18 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GVirtua if (next != NULL) { g_arch_instruction_get_location(next, NULL, NULL, &next_addr); - next_block = g_instr_block_find_by_addr(G_INSTR_BLOCK(parent), next_addr); + next_block = g_instr_block_find_by_addr(g_instr_block_get_links_block(block), next_addr); if (next_block != NULL) - { - next_block = g_instr_block_find_by_addr(next_block, next_addr); false_dinstr = decompiled_basic_block(next_block, ctx); - } } printf(" -> ite : %p + %p\n", true_dinstr, false_dinstr); printf(" -> ite : %s + %s\n", - g_type_name(G_TYPE_FROM_INSTANCE(true_dinstr)), - g_type_name(G_TYPE_FROM_INSTANCE(false_dinstr))); + 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); @@ -259,7 +253,7 @@ static GDecInstruction *decompiled_instructions_blocks(GVirtualBlock *block, GDe /* FIXME */ g_dec_context_set_decomp_instrs(ctx, NULL); - dinstrs = decompiled_instructions_block(G_FLOW_BLOCK(sub_block), block, ctx); + dinstrs = decompiled_instructions_block(G_FLOW_BLOCK(sub_block), ctx); result = merge_decompiled_instructions(result, dinstrs); } @@ -294,7 +288,7 @@ static GDecInstruction *decompiled_basic_block(GInstrBlock *block, GDecContext * else { - result = decompiled_instructions_block(G_FLOW_BLOCK(block), NULL, ctx); + result = decompiled_instructions_block(G_FLOW_BLOCK(block), ctx); if (!G_IS_EXPR_BLOCK(result)) result = merge_decompiled_instructions(NULL, result); diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c index 2e5c0ee..8652b27 100644 --- a/src/analysis/disass/macro.c +++ b/src/analysis/disass/macro.c @@ -288,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 *parent; /* Mémorisation pour les liens */ GInstrBlock *group; /* Regroupement de blocs */ branch_info *cases_branches; /* Branches d'un aiguillage */ size_t cases_count; /* Nombre d'aiguillages */ @@ -375,7 +376,6 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta case ILT_EXEC_FLOW: case ILT_JUMP: - block = g_flow_block_new(instrs, first, iter); MACRO_MARK_AS_PROCESSED(first); first = NULL; @@ -428,21 +428,23 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta /* Post-traitements de ILT_CASE_JUMP */ if (cases_count > 0) { - if (first != NULL) - { - block = g_flow_block_new(instrs, first, iter); - MACRO_MARK_AS_PROCESSED(first); - first = NULL; - - DELAYED_BLOCK_ADDING(result, result_cached, block); + /** + * On doit clôturer le bloc renvoyant vers les branches de cas ici. + * Les sauts conditionnels sont normalement présents de façon exclusive, + * sauf pour les exceptions, qui sont traitées après. + */ + block = g_flow_block_new(instrs, first, iter); + MACRO_MARK_AS_PROCESSED(first); + first = NULL; - } + DELAYED_BLOCK_ADDING(result, result_cached, block); //printf(" --- cases --- start\n"); next_addr = compute_first_common_addr_in_group(cases_branches, cases_count); //printf(" stop :: 0x%08llx\n", next_addr); + parent = block; group = g_virtual_block_new(); for (j = 0; j < cases_count; j++) @@ -460,7 +462,10 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta } if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0) + { DELAYED_BLOCK_ADDING(result, result_cached, group); + g_instr_block_set_links_block(parent, group); + } else g_object_unref(G_OBJECT(group)); @@ -471,38 +476,6 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta } - /* Post-traitements de ILT_CATCH_EXCEPTION */ - if (excep_count > 0) - { - if (first != NULL) - { - block = g_flow_block_new(instrs, first, iter); - MACRO_MARK_AS_PROCESSED(first); - first = NULL; - - DELAYED_BLOCK_ADDING(result, result_cached, block); - - } - - for (j = 0; j < excep_count; j++) - { - stop_addr = compute_first_common_addr(&main_branch, &excep_branches[j]); - //next_addr = MIN(next_addr, end); - - block = build_instruction_block(instrs, excep_branches[j].jumps[0], end, stop_addr); - - if (block != NULL) - - g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block); - - free(excep_branches[j].jumps); - - } - - free(excep_branches); - - } - if (next_addr == VMPA_MAX) { iter = g_arch_instruction_get_next_iter(instrs, iter, end); @@ -514,16 +487,18 @@ 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 (first != NULL) - { - block = g_flow_block_new(instrs, first, iter); - MACRO_MARK_AS_PROCESSED(first); - first = NULL; - - DELAYED_BLOCK_ADDING(result, result_cached, block); + /** + * On doit clôturer le bloc renvoyant vers les branches 'true' et 'false' ici. + * Les sauts conditionnels sont normalement présents de façon exclusive, + * sauf pour les exceptions, qui sont traitées après. + */ + block = g_flow_block_new(instrs, first, iter); + MACRO_MARK_AS_PROCESSED(first); + first = NULL; - } + DELAYED_BLOCK_ADDING(result, result_cached, block); + parent = block; group = g_virtual_block_new(); block = build_instruction_block(instrs, true_branch.jumps[0], end, next_addr); @@ -535,7 +510,10 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block); if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(group)) > 0) + { DELAYED_BLOCK_ADDING(result, result_cached, group); + g_instr_block_set_links_block(parent, group); + } else g_object_unref(G_OBJECT(group)); @@ -546,6 +524,38 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta } + /* Post-traitements de ILT_CATCH_EXCEPTION */ + if (excep_count > 0) + { + if (first != NULL) + { + block = g_flow_block_new(instrs, first, iter); + MACRO_MARK_AS_PROCESSED(first); + first = NULL; + + DELAYED_BLOCK_ADDING(result, result_cached, block); + + } + + for (j = 0; j < excep_count; j++) + { + stop_addr = compute_first_common_addr(&main_branch, &excep_branches[j]); + //next_addr = MIN(next_addr, end); + + block = build_instruction_block(instrs, excep_branches[j].jumps[0], end, stop_addr); + + if (block != NULL) + + DELAYED_BLOCK_ADDING(result, result_cached, block); + + free(excep_branches[j].jumps); + + } + + free(excep_branches); + + } + /* Détermination du prochain point de chute */ iter = g_arch_instruction_find_by_address(instrs, next_addr, true); @@ -581,6 +591,7 @@ static bool print_blocks(GInstrBlock *blk, BlockVisitOrder order, int *pad) { int i; vmpa_t start, end; + GInstrBlock *links; if (order != BVO_OUT) for (i = 0; i < *pad; i++) @@ -589,7 +600,13 @@ static bool print_blocks(GInstrBlock *blk, BlockVisitOrder order, int *pad) 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); + links = g_instr_block_get_links_block(blk); + + if (links != NULL) + printf(" - flow %p : 0x%08lx -> 0x%08lx (links = %p)\n", blk, start, end, links); + else + printf(" - flow %p : 0x%08lx -> 0x%08lx\n", blk, start, end); + } else { @@ -638,14 +655,14 @@ void group_routines_instructions(GArchInstruction *list, GBinRoutine **routines, end = start + g_binary_routine_get_size(routines[i]); - //printf("==== %s ====\n", g_binary_routine_to_string(routines[i])); + printf("==== %s ====\n", g_binary_routine_to_string(routines[i])); 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 }); + 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/instr/ite.c b/src/decomp/instr/ite.c index 7c68031..c12d314 100644 --- a/src/decomp/instr/ite.c +++ b/src/decomp/instr/ite.c @@ -33,6 +33,8 @@ struct _GITEInstruction { GDecInstruction parent; /* A laisser en premier */ + bool inverse; /* Condition inversée */ + GDecExpression *cond; /* Condition prise en compte */ GDecInstruction *true_branch; /* Condition vérifiée */ @@ -165,8 +167,20 @@ GDecInstruction *g_ite_instruction_new(GDecExpression *cond, vmpa_t if_true, vmp void g_ite_instruction_set_branches(GITEInstruction *expr, GDecInstruction *true_branch, GDecInstruction *false_branch) { - expr->true_branch = true_branch; - expr->false_branch = false_branch; + + if (true_branch == NULL) + { + expr->inverse = true; + + expr->true_branch = false_branch; + expr->false_branch = true_branch; + + } + else + { + expr->true_branch = true_branch; + expr->false_branch = false_branch; + } } @@ -192,6 +206,9 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "if ", 3, RTT_KEY_WORD); + if (expr->inverse) + g_buffer_line_insert_text(line /* FIXME */, BLC_ASSEMBLY_HEAD, "!", 1, RTT_KEY_WORD); + result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->cond), buffer, line, output); -- cgit v0.11.2-87-g4458