summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2013-01-10 22:47:37 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2013-01-10 22:47:37 (GMT)
commit221bcaeeb06415d501f9abbb9bc4b7d8339af1fe (patch)
tree243a1709589d3733d6525b0a143ecf0c539caae7
parentc455057e634b30c3214a49db009bad5fd0c631ff (diff)
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
-rw-r--r--ChangeLog19
-rw-r--r--src/analysis/block-int.h2
-rw-r--r--src/analysis/block.c46
-rw-r--r--src/analysis/block.h6
-rw-r--r--src/analysis/blocks/virtual.c3
-rw-r--r--src/analysis/decomp/il.c30
-rw-r--r--src/analysis/disass/macro.c121
-rw-r--r--src/decomp/instr/ite.c21
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 <nocbos@gmail.com>
+
+ * 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 <nocbos@gmail.com>
* 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);