summaryrefslogtreecommitdiff
path: root/src/analysis/decomp
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis/decomp')
-rw-r--r--src/analysis/decomp/il.c51
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);