summaryrefslogtreecommitdiff
path: root/src/analysis
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2013-02-02 18:51:02 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2013-02-02 18:51:02 (GMT)
commit5b89c8369d2a26089f22be7c482e8254244ebc8c (patch)
treefdd7a23a256a0841f0d0d32a0ce33ceeb54e671e /src/analysis
parent0936f64aac6a4fa9ebc08962bc9cac663f210c00 (diff)
Closed some switch cases with a 'break' keyword.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@336 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/analysis')
-rw-r--r--src/analysis/block-int.h5
-rw-r--r--src/analysis/block.c21
-rw-r--r--src/analysis/block.h3
-rw-r--r--src/analysis/blocks/flow.c27
-rw-r--r--src/analysis/blocks/virtual.c27
-rw-r--r--src/analysis/decomp/il.c373
-rw-r--r--src/analysis/disass/macro.c97
7 files changed, 445 insertions, 108 deletions
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h
index 419a8b0..069b50c 100644
--- a/src/analysis/block-int.h
+++ b/src/analysis/block-int.h
@@ -38,6 +38,10 @@ typedef bool (* visit_all_blocks_fc) (GInstrBlock *, instr_block_visitor_cb, voi
/* Etablit la liste de tous les blocs présents. */
typedef void (* list_all_blocks_fc) (const GInstrBlock *, GInstrBlock ***, size_t *);
+/* Etablit la liste de tous les blocs terminaux. */
+typedef void (* list_leafs_blocks_fc) (const GInstrBlock *, GInstrBlock ***, size_t *);
+
+
/* Fournit les différents accès aux registres. */
//typedef const reg_access * (* list_regs_accesses_fc) (const GInstrBlock *, size_t *);
@@ -51,6 +55,7 @@ struct _GInstrBlock
find_by_addr_fc find_by_addr; /* Recherche par adresse */
visit_all_blocks_fc visit_blocks; /* Visite des différents blocs */
list_all_blocks_fc list_blocks; /* Liste de tous les blocs */
+ list_leafs_blocks_fc list_leafs; /* Liste des blocs terminaux */
//list_regs_accesses_fc list_regs; /* Liste des accès registres */
GInstrBlock *links_block; /* Lieu des blocs attachés */
diff --git a/src/analysis/block.c b/src/analysis/block.c
index 50d5644..d8d906a 100644
--- a/src/analysis/block.c
+++ b/src/analysis/block.c
@@ -202,6 +202,27 @@ void g_instr_block_list_all_blocks(const GInstrBlock *block, GInstrBlock ***list
/******************************************************************************
* *
+* Paramètres : block = bloc d'instructions à consulter. *
+* list = ensemble de blocs à compléter. [OUT] *
+* count = nombre de blocs au total. [OUT] *
+* *
+* Description : Etablit la liste de tous les blocs terminaux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_instr_block_list_leafs_blocks(const GInstrBlock *block, GInstrBlock ***list, size_t *count)
+{
+ block->list_leafs(block, list, count);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : block = bloc d'instructions à mettre à jour. *
* links = bloc contenant les blocs liés au bloc. *
* *
diff --git a/src/analysis/block.h b/src/analysis/block.h
index 7786ce5..d4e5a2b 100644
--- a/src/analysis/block.h
+++ b/src/analysis/block.h
@@ -74,6 +74,9 @@ 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 *);
+/* Etablit la liste de tous les blocs terminaux. */
+void g_instr_block_list_leafs_blocks(const GInstrBlock *, GInstrBlock ***, size_t *);
+
/* Définit l'ensemble contenant les blocs liés. */
void g_instr_block_set_links_block(GInstrBlock *, GInstrBlock *);
diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c
index 4df729c..0b68a14 100644
--- a/src/analysis/blocks/flow.c
+++ b/src/analysis/blocks/flow.c
@@ -74,6 +74,9 @@ static bool g_flow_block_visit(GFlowBlock *, instr_block_visitor_cb, void *);
/* Etablit la liste de tous les blocs présents. */
static void g_flow_block_list_all_blocks(const GFlowBlock *, GInstrBlock ***, size_t *);
+/* Etablit la liste de tous les blocs terminaux. */
+static void g_flow_block_list_leafs_blocks(const GFlowBlock *, GInstrBlock ***, size_t *);
+
/* Prend note de l'usage d'un registre, au besoin. */
static void g_flow_block_memorize_access(GFlowBlock *, GArchRegister *, RegAccessType, vmpa_t);
@@ -134,6 +137,7 @@ static void g_flow_block_init(GFlowBlock *block)
parent->find_by_addr = (find_by_addr_fc)g_flow_block_find_by_addr;
parent->visit_blocks = (visit_all_blocks_fc)g_flow_block_visit;
parent->list_blocks = (list_all_blocks_fc)g_flow_block_list_all_blocks;
+ parent->list_leafs = (list_leafs_blocks_fc)g_flow_block_list_leafs_blocks;
//parent->list_regs = (list_regs_accesses_fc)g_flow_block_list_regs_accesses;
block->regs = g_raccess_list_new();
@@ -315,6 +319,29 @@ static void g_flow_block_list_all_blocks(const GFlowBlock *block, GInstrBlock **
/******************************************************************************
* *
+* Paramètres : block = bloc d'instructions à consulter. *
+* list = ensemble de blocs à compléter. [OUT] *
+* count = nombre de blocs au total. [OUT] *
+* *
+* Description : Etablit la liste de tous les blocs terminaux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_flow_block_list_leafs_blocks(const GFlowBlock *block, GInstrBlock ***list, size_t *count)
+{
+ (*list) = (GInstrBlock **)realloc(*list, ++(*count) * sizeof(GInstrBlock *));
+
+ (*list)[*count - 1] = G_INSTR_BLOCK(block);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : block = bloc d'instructions à mettre à jour. *
* reg = registre visé par l'opération. *
* type = type d'accès à l'opérande. *
diff --git a/src/analysis/blocks/virtual.c b/src/analysis/blocks/virtual.c
index 42492e9..0cc6a0d 100644
--- a/src/analysis/blocks/virtual.c
+++ b/src/analysis/blocks/virtual.c
@@ -79,6 +79,9 @@ static bool g_virtual_block_visit(GVirtualBlock *, instr_block_visitor_cb, void
/* Etablit la liste de tous les blocs présents. */
static void g_virtual_block_list_all_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *);
+/* Etablit la liste de tous les blocs terminaux. */
+static void g_virtual_block_list_leafs_blocks(const GVirtualBlock *, GInstrBlock ***, size_t *);
+
/* Fournit les différents accès aux registres. */
//static const reg_access *g_virtual_block_list_regs_accesses(const GVirtualBlock *, size_t *);
@@ -133,6 +136,7 @@ static void g_virtual_block_init(GVirtualBlock *block)
parent->find_by_addr = (find_by_addr_fc)g_virtual_block_find_by_addr;
parent->visit_blocks = (visit_all_blocks_fc)g_virtual_block_visit;
parent->list_blocks = (list_all_blocks_fc)g_virtual_block_list_all_blocks;
+ parent->list_leafs = (list_leafs_blocks_fc)g_virtual_block_list_leafs_blocks;
//parent->list_regs = (list_regs_accesses_fc)g_virtual_block_list_regs_accesses;
}
@@ -300,6 +304,29 @@ static void g_virtual_block_list_all_blocks(const GVirtualBlock *block, GInstrBl
}
+
+/******************************************************************************
+* *
+* Paramètres : block = bloc d'instructions à consulter. *
+* list = ensemble de blocs à compléter. [OUT] *
+* count = nombre de blocs au total. [OUT] *
+* *
+* Description : Etablit la liste de tous les blocs terminaux. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_virtual_block_list_leafs_blocks(const GVirtualBlock *block, GInstrBlock ***list, size_t *count)
+{
+ if (block->children_count > 0)
+ g_instr_block_list_leafs_blocks(block->children[block->children_count - 1], list, count);
+
+}
+
+
#if 0
/******************************************************************************
* *
diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c
index f241e46..9e235a6 100644
--- a/src/analysis/decomp/il.c
+++ b/src/analysis/decomp/il.c
@@ -24,11 +24,15 @@
#include "il.h"
+#include <malloc.h>
+
+
#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/keyword.h"
#include "../../decomp/instr/switch.h"
@@ -67,6 +71,20 @@ static GDecInstruction *decompiled_basic_block(GInstrBlock *, GDecContext *);
+/* --------------------------- DECOMPILATIONS SPECIFIQUES --------------------------- */
+
+
+/* Procède à la décompilation des éléments d'un 'if then else'. */
+static void build_ite_branches(GITEInstruction *, GFlowBlock *, GDecContext *);
+
+/* Termine le traitement d'un cas de 'switch'. */
+static void close_case_decomp_instructions(GDecInstruction *, GInstrBlock *, GArchInstruction **, size_t, size_t);
+
+/* Procède à la décompilation des éléments d'un 'switch'. */
+static void build_switch_branches(GSwitchInstruction *, GFlowBlock *, GDecContext *);
+
+
+
/* ---------------------------------------------------------------------------------- */
/* GESTION DES CONTEXTES DE DECOMPILATION */
/* ---------------------------------------------------------------------------------- */
@@ -328,27 +346,12 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon
{
GArchInstruction *instrs; /* Liste d'instructions natives*/
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 #1 */
GDecInstruction *decomp; /* Dernier résultat de décomp. */
- GInstrBlock *sub_parent; /* Groupe des sous-branches */
- GHashTable *sub_shared; /* Allocations communes */
- GDecContext *sub_ctx; /* Sous-contexte pour branche */
- GDecInstruction *true_dinstr; /* Décompilation 'cond vraie' */
- GDecInstruction *false_dinstr; /* Décompilation 'cond fausse' */
- 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);
+ g_flow_block_get_boundary(block, &first, NULL);
g_flow_block_get_boundary_addresses(block, NULL, &max);
max++;
@@ -366,92 +369,11 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon
/* if ... then ... else ... */
if (G_IS_ITE_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);
-
- true_dinstr = NULL;
-
- next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_TRUE);
- if (next != NULL)
- {
- g_arch_instruction_get_location(next, 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);
- true_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));
- }
-
- }
-
- false_dinstr = NULL;
-
- next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_FALSE);
- if (next != NULL)
- {
- g_arch_instruction_get_location(next, 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);
- false_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));
- }
-
- }
-
- g_ite_instruction_set_branches(G_ITE_INSTRUCTION(decomp), true_dinstr, false_dinstr);
-
- g_hash_table_unref(sub_shared);
-
- }
+ build_ite_branches(G_ITE_INSTRUCTION(decomp), block, ctx);
/* 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);
-
- }
+ build_switch_branches(G_SWITCH_INSTRUCTION(decomp), block, ctx);
/* Renvoi des instructions mises en place */
@@ -578,3 +500,256 @@ GDecInstruction *decompiled_routine_instructions(GBinRoutine *routine, GExeForma
return result;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* DECOMPILATIONS SPECIFIQUES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : decomp = instruction 'if ... then ... else' à compléter. *
+* block = ensemble des instructions d'assemblage traitées. *
+* ctx = contexte de soutien à associer à l'opération. *
+* *
+* Description : Procède à la décompilation des éléments d'un 'if then else'. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void build_ite_branches(GITEInstruction *decomp, GFlowBlock *block, GDecContext *ctx)
+{
+ GArchInstruction *last; /* Dernière instruction du lot */
+ GInstrBlock *sub_parent; /* Groupe des sous-branches */
+ GHashTable *sub_shared; /* Allocations communes */
+ GDecContext *sub_ctx; /* Sous-contexte pour branche */
+ GDecInstruction *true_dinstr; /* Décompilation 'cond vraie' */
+ GDecInstruction *false_dinstr; /* Décompilation 'cond fausse' */
+ GArchInstruction *next; /* Instruction de branchement */
+ vmpa_t next_addr; /* Adresse de cette instruct° */
+ GInstrBlock *next_block; /* Sous-bloc basique direct */
+
+ g_flow_block_get_boundary(block, NULL, &last);
+
+ 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);
+
+ true_dinstr = NULL;
+ false_dinstr = NULL;
+
+ /* Branche 'true' */
+ next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_TRUE);
+ if (next != NULL)
+ {
+ g_arch_instruction_get_location(next, 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);
+ true_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));
+ }
+
+ }
+
+ /* Branche 'false' */
+ next = g_arch_instruction_get_given_destination(last, ILT_JUMP_IF_FALSE);
+ if (next != NULL)
+ {
+ g_arch_instruction_get_location(next, 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);
+ false_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));
+ }
+
+ }
+
+ g_ite_instruction_set_branches(decomp, true_dinstr, false_dinstr);
+
+ g_hash_table_unref(sub_shared);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : case_dinstr = instructions d'un cas de 'switch' décompilées. *
+* case_block = bloc d'instructions assembleur correspondantes.*
+* cases = listes des instructions des différents cas. *
+* current = indice du cas courant. *
+* ccount = nombre de cas présents dans le 'switch'. *
+* *
+* Description : Termine le traitement d'un cas de 'switch'. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void close_case_decomp_instructions(GDecInstruction *case_dinstr, GInstrBlock *case_block, GArchInstruction **cases, size_t current, size_t ccount)
+{
+ vmpa_t *cases_addr; /* Adresses des cas du 'switch'*/
+ size_t i; /* Boucle de parcours #1 */
+ GInstrBlock **leafs; /* Blocs terminaux du cas */
+ size_t lcount; /* Nombre de blocs terminaux */
+ vmpa_t common_addr; /* Adresse commune de suite */
+ bool is_common; /* Suite commune ? */
+ GArchInstruction *last; /* Dernière instruction de bloc*/
+ GArchInstruction **dests; /* Instr. visée par une autre */
+ size_t dcount; /* Nombre de liens de dest. */
+ size_t j; /* Boucle de parcours #2 */
+ vmpa_t addr; /* Adresse d'une instruction */
+ bool jump_to_case; /* Suite dans le cas suivant ? */
+
+ /* Etablit la liste des adresses des cas */
+
+ cases_addr = (vmpa_t *)calloc(ccount, sizeof(vmpa_t));
+
+ for (i = 0; i < ccount; i++)
+ g_arch_instruction_get_location(cases[i], NULL, NULL, &cases_addr[i]);
+
+ /* Récupère la (les) fin(s) du cas présent */
+
+ leafs = NULL;
+ lcount = 0;
+
+ g_instr_block_list_leafs_blocks(case_block, &leafs, &lcount);
+
+ /* Procède à une première analyse de la suite */
+
+ common_addr = VMPA_MAX;
+ is_common = true;
+
+ for (i = 0; i < lcount && is_common; i++)
+ {
+ g_flow_block_get_boundary(G_FLOW_BLOCK(leafs[i]), NULL, &last);
+ dcount = g_arch_instruction_get_destinations(last, &dests, NULL, NULL);
+
+ for (j = 0; j < dcount && is_common; j++)
+ {
+ g_arch_instruction_get_location(dests[j], NULL, NULL, &addr);
+
+ if (common_addr == VMPA_MAX)
+ common_addr = addr;
+ else
+ is_common = (common_addr == addr);
+
+ }
+
+ }
+
+ /* La sortie du cas est unique ! */
+ if (is_common)
+ {
+ if (common_addr == VMPA_MAX)
+ goto ecdi_exit;
+
+ jump_to_case = false;
+
+ for (i = 0; i < ccount && !jump_to_case; i++)
+ if (i != current)
+ jump_to_case = (cases_addr[i] == common_addr);
+
+ if (!jump_to_case)
+ g_expr_block_add_item(G_EXPR_BLOCK(case_dinstr), g_keyword_instruction_new(DKW_BREAK));
+
+ }
+
+ /* ... ou il faut suivre les différentes branches... */
+ else
+ {
+
+ /* TODO */
+
+ }
+
+ ecdi_exit:
+
+ free(cases_addr);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : decomp = instruction 'switch' à compléter. *
+* block = ensemble des instructions d'assemblage traitées. *
+* ctx = contexte de soutien à associer à l'opération. *
+* *
+* Description : Procède à la décompilation des éléments d'un 'switch'. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void build_switch_branches(GSwitchInstruction *decomp, GFlowBlock *block, GDecContext *ctx)
+{
+ GArchInstruction *last; /* Dernière instruction du lot */
+ GInstrBlock *sub_parent; /* Groupe des sous-branches */
+ GHashTable *sub_shared; /* Allocations communes */
+ GDecContext *sub_ctx; /* Sous-contexte pour branche */
+ 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 */
+
+ g_flow_block_get_boundary(block, NULL, &last);
+
+ 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));
+
+ close_case_decomp_instructions(case_dinstr, next_block, dests, i, dcount);
+
+ 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);
+
+}
diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c
index 14dad95..993f70f 100644
--- a/src/analysis/disass/macro.c
+++ b/src/analysis/disass/macro.c
@@ -52,7 +52,7 @@ typedef struct _branch_info
/* Indique si une adresse est retenue comme point de passage. */
-static bool is_addr_in_branch(const branch_info *, const vmpa_t *, bool);
+static bool is_addr_in_branch(const branch_info *, const vmpa_t *, bool, size_t *);
/* Identifie les différents points de passage d'une branche. */
static void find_next_jumps(GArchInstruction *, vmpa_t, vmpa_t, branch_info *);
@@ -73,6 +73,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *, vmpa_t, vmpa_t,
* Paramètres : info = informations à consulter. *
* addr = adresse à rechercher. *
* fast = autorise une recherche rapide. *
+* pos = enregistrement de la position de la trouvaille. [OUT] *
* *
* Description : Indique si une adresse est retenue comme point de passage. *
* *
@@ -82,7 +83,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *, vmpa_t, vmpa_t,
* *
******************************************************************************/
-static bool is_addr_in_branch(const branch_info *info, const vmpa_t *addr, bool fast)
+static bool is_addr_in_branch(const branch_info *info, const vmpa_t *addr, bool fast, size_t *pos)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
@@ -92,12 +93,20 @@ static bool is_addr_in_branch(const branch_info *info, const vmpa_t *addr, bool
if (!fast)
for (i = 0; i < info->count && !result; i++)
+ {
result = (info->jumps[i] == *addr);
+ if (result && pos != NULL)
+ *pos = i;
+ }
else
{
ptr = bsearch(addr, info->jumps, info->count, sizeof(vmpa_t), (__compar_fn_t)compare_vmpa);
result = (ptr != NULL);
+
+ if (result && pos != NULL)
+ *pos = (ptr - ((void *)info->jumps)) / sizeof(vmpa_t);
+
}
return result;
@@ -130,7 +139,7 @@ static void find_next_jumps(GArchInstruction *instrs, vmpa_t start, vmpa_t end,
vmpa_t addr; /* Adresse de la destination */
/* On évite de boucler... */
- if (is_addr_in_branch(info, &start, false))
+ if (is_addr_in_branch(info, &start, false, NULL))
return;
info->jumps = (vmpa_t *)realloc(info->jumps, ++(info->count) * sizeof(vmpa_t));
@@ -174,7 +183,7 @@ static void find_next_jumps(GArchInstruction *instrs, vmpa_t start, vmpa_t end,
}
/* Si on termine... */
- if (iter != NULL && !is_addr_in_branch(info, &end, false))
+ if (iter != NULL && !is_addr_in_branch(info, &end, false, NULL))
{
info->jumps = (vmpa_t *)realloc(info->jumps, ++(info->count) * sizeof(vmpa_t));
info->jumps[info->count - 1] = end;
@@ -208,7 +217,7 @@ static vmpa_t compute_first_common_addr(branch_info *a, branch_info *b)
//qsort(b->jumps, b->count, sizeof(vmpa_t), (__compar_fn_t)compare_vmpa);
for (i = 0; i < a->count && result == VMPA_MAX; i++)
- if (is_addr_in_branch(b, &a->jumps[i], false))
+ if (is_addr_in_branch(b, &a->jumps[i], false, NULL))
result = a->jumps[i];
return result;
@@ -247,7 +256,7 @@ static vmpa_t compute_first_common_addr_in_group(const branch_info *list, size_t
keep = true;
for (j = 1; j < count && keep; j++)
- keep = is_addr_in_branch(&list[j], &list[0].jumps[i], false);
+ keep = is_addr_in_branch(&list[j], &list[0].jumps[i], false, NULL);
if (keep)
result = list[0].jumps[i];
@@ -259,6 +268,51 @@ static vmpa_t compute_first_common_addr_in_group(const branch_info *list, size_t
}
+
+
+
+/******************************************************************************
+* *
+* Paramètres : list = liste d'ensembles de jalons à parcourir. *
+* count = taille de cette liste. *
+* *
+* Description : Retrouve le point de ralliement entre un groupe de branches. *
+* *
+* Retour : Adresse commune aux branches. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static vmpa_t avoid_cases_common_part(const branch_info *list, size_t cur, size_t count, vmpa_t max)
+{
+ vmpa_t result; /* Adresse trouvée à retourner */
+ size_t found_pos; /* Plus petit tronc commun */
+ size_t i; /* Boucle de parcours */
+ size_t pos; /* Emplacement du cas commun */
+
+ result = max;
+
+ found_pos = list[cur].count;
+
+ for (i = 0; i < count; i++)
+ {
+ if (i == cur) continue;
+
+ if (is_addr_in_branch(&list[cur], &list[i].jumps[0], false, &pos))
+ {
+ if (pos < found_pos)
+ result = list[i].jumps[0];
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
/******************************************************************************
* *
* Paramètres : instrs = ensemble des instructions d'assemblage. *
@@ -447,13 +501,38 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
parent = block;
group = g_virtual_block_new();
+ do
+ {
+ size_t _i, _j;
+
+ for (_i = 0; _i < cases_count; _i++)
+ {
+ printf(" [case %d] : ", _i);
+
+ for (_j = 0; _j < cases_branches[_i].count; _j++)
+ printf("0x%08lx ", cases_branches[_i].jumps[_j]);
+
+ printf("\n");
+
+ }
+
+ } while (0);
+
+
for (j = 0; j < cases_count; j++)
{
- printf(" ## %zu...", j);
+ printf(" ## %zu start=0x%08lx (0x%08lx)...\n", j, cases_branches[j].jumps[0],
+ next_addr);
+
+ //block = build_instruction_block(instrs, cases_branches[j].jumps[0], end, next_addr);
+
+ //next_addr = avoid_cases_common_part(cases_branches, j, cases_count, next_addr);
- block = build_instruction_block(instrs, cases_branches[j].jumps[0], end, next_addr);
+ block = build_instruction_block(instrs, cases_branches[j].jumps[0], end,
+ avoid_cases_common_part(cases_branches, j, cases_count, next_addr));
- printf(" %p\n", block);
+ printf(" %p (0x%08lx)\n", block,
+ avoid_cases_common_part(cases_branches, j, cases_count, next_addr));
if (block != NULL)