diff options
Diffstat (limited to 'src/analysis/decomp')
-rw-r--r-- | src/analysis/decomp/il.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c index 64f6398..f241e46 100644 --- a/src/analysis/decomp/il.c +++ b/src/analysis/decomp/il.c @@ -2,7 +2,7 @@ /* OpenIDA - Outil d'analyse de fichiers binaires * il.h - mise en place d'un langage intermédiaire * - * Copyright (C) 2012 Cyrille Bagard + * Copyright (C) 2012-2013 Cyrille Bagard * * This file is part of OpenIDA. * @@ -27,7 +27,9 @@ #include "../blocks/flow.h" #include "../blocks/virtual.h" #include "../../decomp/expr/block.h" +#include "../../decomp/expr/immediate.h" #include "../../decomp/instr/ite.h" +#include "../../decomp/instr/switch.h" @@ -328,7 +330,7 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon GArchInstruction *first; /* Première instruction du lot */ GArchInstruction *last; /* Dernière instruction du lot */ vmpa_t max; /* Adresse de fin du bloc */ - GArchInstruction *iter; /* Boucle de parcours */ + GArchInstruction *iter; /* Boucle de parcours #1 */ GDecInstruction *decomp; /* Dernier résultat de décomp. */ GInstrBlock *sub_parent; /* Groupe des sous-branches */ GHashTable *sub_shared; /* Allocations communes */ @@ -338,6 +340,12 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon GArchInstruction *next; /* Instruction de branchement */ vmpa_t next_addr; /* Adresse de cette instruct° */ GInstrBlock *next_block; /* Sous-bloc basique direct */ + GArchInstruction **dests; /* Instr. visée par une autre */ + link_extra_info *info; /* Compléments pour les liens */ + size_t dcount; /* Nombre de liens de dest. */ + size_t i; /* Boucle de parcours #2 */ + GDecInstruction *case_dinstr; /* Décompilation 'case' */ + GDecExpression *case_value; /* Valeur d'aiguillage */ instrs = g_flow_block_get_all_instructions_list(block); g_flow_block_get_boundary(block, &first, &last); @@ -406,6 +414,45 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon } + /* switch ... case ... */ + else if (G_IS_SWITCH_INSTRUCTION(decomp)) + { + sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); + sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash, + (GEqualFunc)g_arch_register_equal, + g_object_unref, g_object_unref); + + dcount = g_arch_instruction_get_destinations(last, &dests, NULL, &info); + + for (i = 0; i < dcount; i++) + { + g_arch_instruction_get_location(dests[i], NULL, NULL, &next_addr); + next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false); + + if (next_block != NULL) + { + sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared); + case_dinstr = decompiled_basic_block(next_block, sub_ctx); + g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx); + g_object_unref(G_OBJECT(sub_ctx)); + + if (info[i].imm != NULL) + { + case_value = G_DEC_EXPRESSION(g_imm_expression_new(info[i].imm)); + g_switch_instruction_add_case(G_SWITCH_INSTRUCTION(decomp), + case_value, case_dinstr, next_addr); + } + else g_switch_instruction_set_default_case(G_SWITCH_INSTRUCTION(decomp), + case_dinstr); + + } + + } + + g_hash_table_unref(sub_shared); + + } + /* Renvoi des instructions mises en place */ return g_dec_context_get_decomp_instrs(ctx); |