summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/blocks/flow.c2
-rw-r--r--src/analysis/decomp/il.c51
-rw-r--r--src/analysis/disass/macro.c14
3 files changed, 58 insertions, 9 deletions
diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c
index 49b9c6b..4df729c 100644
--- a/src/analysis/blocks/flow.c
+++ b/src/analysis/blocks/flow.c
@@ -510,7 +510,7 @@ bool g_flow_block_follow(GFlowBlock *block, const GInstrBlock *list, BlockFollow
if (mask & BFP_ENTER)
result = callback(block, BFP_ENTER, data);
- dcount = g_arch_instruction_get_destinations(block->last, &dests, &types);
+ dcount = g_arch_instruction_get_destinations(block->last, &dests, &types, NULL);
for (i = 0; i < dcount && result; i++)
switch (types[i])
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);
diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c
index 0fef9a0..14dad95 100644
--- a/src/analysis/disass/macro.c
+++ b/src/analysis/disass/macro.c
@@ -150,7 +150,7 @@ static void find_next_jumps(GArchInstruction *instrs, vmpa_t start, vmpa_t end,
if (!g_arch_instruction_has_destinations(iter))
continue;
- dcount = g_arch_instruction_get_destinations(iter, &dests, &types);
+ dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL);
for (i = 0; i < dcount; i++)
switch (types[i])
@@ -360,7 +360,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
/* Adaptations en fonction du type de bifurcation */
- dcount = g_arch_instruction_get_destinations(iter, &dests, &types);
+ dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL);
next_addr = 0;
cases_branches = NULL;
@@ -439,20 +439,22 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
DELAYED_BLOCK_ADDING(result, result_cached, block);
- //printf(" --- cases --- start\n");
+ printf(" --- cases --- start\n");
next_addr = compute_first_common_addr_in_group(cases_branches, cases_count);
- //printf(" stop :: 0x%08llx\n", next_addr);
+ printf(" stop :: 0x%08llx\n", next_addr);
parent = block;
group = g_virtual_block_new();
for (j = 0; j < cases_count; j++)
{
- //printf(" ## %zu\n", j);
+ printf(" ## %zu...", j);
block = build_instruction_block(instrs, cases_branches[j].jumps[0], end, next_addr);
+ printf(" %p\n", block);
+
if (block != NULL)
g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
@@ -469,7 +471,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
else
g_object_unref(G_OBJECT(group));
- //printf(" --- cases --- end\n");
+ printf(" --- cases --- end\n");
free(cases_branches);