summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2016-04-02 07:47:13 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2016-04-02 07:47:13 (GMT)
commit36a5b2577d67ab7c9f2c5817f6dba7a9601d1f20 (patch)
tree8b326546f84c5ca82bbff2b41ef967ba3b0c0745
parent33906ce366efc053dee0b76d5bd668797b99071e (diff)
Handled all routines disassembling processing in one place.
-rw-r--r--ChangeLog31
-rw-r--r--src/analysis/blocks/flow.c6
-rw-r--r--src/analysis/disass/Makefile.am3
-rw-r--r--src/analysis/disass/disassembler.c114
-rw-r--r--src/analysis/disass/dragon.c214
-rw-r--r--src/analysis/disass/dragon.h20
-rw-r--r--src/analysis/disass/loop.c389
-rw-r--r--src/analysis/disass/loop.h6
-rw-r--r--src/analysis/disass/macro.c1542
-rw-r--r--src/analysis/disass/macro.h7
-rw-r--r--src/analysis/disass/output.c5
-rw-r--r--src/analysis/disass/rank.c29
-rw-r--r--src/analysis/disass/rank.h3
-rw-r--r--src/analysis/disass/routines.c278
-rw-r--r--src/analysis/disass/routines.h55
-rw-r--r--src/common/bits.c22
-rw-r--r--src/common/bits.h4
17 files changed, 981 insertions, 1747 deletions
diff --git a/ChangeLog b/ChangeLog
index 846bc0a..6b45152 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+16-04-02 Cyrille Bagard <nocbos@gmail.com>
+
+ * src/analysis/blocks/flow.c:
+ Disable usage of any processor.
+
+ * src/analysis/disass/Makefile.am:
+ Add the 'routines.[ch]' files to libanalysisdisass_la_SOURCES.
+
+ * src/analysis/disass/disassembler.c:
+ Clean the code.
+
+ * src/analysis/disass/dragon.c:
+ * src/analysis/disass/dragon.h:
+ Compute execution paths to follow the control flow.
+
+ * src/analysis/disass/loop.c:
+ * src/analysis/disass/loop.h:
+ * src/analysis/disass/macro.c:
+ * src/analysis/disass/macro.h:
+ * src/analysis/disass/rank.c:
+ * src/analysis/disass/rank.h:
+ Clean the code.
+
+ * src/analysis/disass/routines.c:
+ * src/analysis/disass/routines.h:
+ New entries: handle all routines disassembling processing in one place.
+
+ * src/common/bits.c:
+ * src/common/bits.h:
+ Init a copied bit field with a given value.
+
16-03-27 Cyrille Bagard <nocbos@gmail.com>
* src/analysis/project.c:
diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c
index 85edad6..9eb9de8 100644
--- a/src/analysis/blocks/flow.c
+++ b/src/analysis/blocks/flow.c
@@ -164,7 +164,7 @@ static void g_flow_block_init(GFlowBlock *block)
static void g_flow_block_dispose(GFlowBlock *block)
{
- g_object_unref(G_OBJECT(block->proc));
+ //g_object_unref(G_OBJECT(block->proc));
g_object_unref(G_OBJECT(block->first));
g_object_unref(G_OBJECT(block->last));
@@ -215,11 +215,13 @@ GInstrBlock *g_flow_block_new(GArchProcessor *proc, GArchInstruction *first, GAr
result = g_object_new(G_TYPE_FLOW_BLOCK, NULL);
+ /* FIXME : proc non utilisé ! */
+
result->proc = proc;
result->first = first;
result->last = last;
- g_object_ref(G_OBJECT(result->proc));
+ //g_object_ref(G_OBJECT(result->proc));
g_object_ref(G_OBJECT(result->first));
g_object_ref(G_OBJECT(result->last));
diff --git a/src/analysis/disass/Makefile.am b/src/analysis/disass/Makefile.am
index 3231749..e901570 100644
--- a/src/analysis/disass/Makefile.am
+++ b/src/analysis/disass/Makefile.am
@@ -11,7 +11,8 @@ libanalysisdisass_la_SOURCES = \
loop.h loop.c \
macro.h macro.c \
output.h output.c \
- rank.h rank.c
+ rank.h rank.c \
+ routines.h routines.c
libanalysisdisass_la_LDFLAGS =
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index 0fcc7f3..4e6a13c 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -39,6 +39,7 @@
#include "macro.h"
#include "output.h"
#include "rank.h"
+#include "routines.h"
#include "../../decomp/lang/asm.h"
#include "../../format/format.h"
#include "../../glibext/delayed-int.h"
@@ -196,15 +197,11 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta
GArchProcessor *proc; /* Architecture du binaire */
- unsigned int valid; /* Instructions traduites */
- unsigned int db; /* Instructions non décodées */
- unsigned int valid_sum; /* Instructions traduites */
- unsigned int instr_sum; /* Instructions totales */
- size_t i; /* Boucle de parcours */
+ //size_t i; /* Boucle de parcours */
GBinRoutine **routines; /* Liste des routines trouvées */
size_t routines_count; /* Nombre de ces routines */
- bstatus_id_t id; /* Identifiant de statut */
+ activity_id_t id; /* Identifiant de statut */
//GArchProcessor *proc; /* Architecture du binaire */
@@ -341,9 +338,9 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta
//qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare);
- limit_all_routines(disass->format, proc, routines, routines_count, gid, id);
+ limit_all_routines(disass->format, proc, routines, routines_count, gid, 0/*id*/);
- gtk_extended_status_bar_remove(statusbar, id);
+ gtk_extended_status_bar_remove(statusbar, 0/*id*/);
//run_plugins_on_binary(disass->binary, PGA_BINARY_BOUNDED, true);
@@ -354,9 +351,6 @@ static void g_delayed_disassembly_process(GDelayedDisassembly *disass, GtkExtSta
-
-
-
/* Troisième étape */
id = gtk_extended_status_bar_push(statusbar, _("Establishing links..."), true);
@@ -372,9 +366,9 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
*/
- establish_links_between_instructions(*disass->instrs, G_BIN_FORMAT(disass->format), statusbar, id);
+ establish_links_between_instructions(*disass->instrs, G_BIN_FORMAT(disass->format), statusbar, 0/*id*/);
- gtk_extended_status_bar_remove(statusbar, id);
+ gtk_extended_status_bar_remove(statusbar, 0/*id*/);
//run_plugins_on_binary(disass->binary, PGA_BINARY_LINKED, true);
@@ -389,16 +383,82 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
/* Quatrième étape */
- id = gtk_extended_status_bar_push(statusbar, _("Detecting loops..."), true);
+ // -- old -- id = gtk_extended_status_bar_push(statusbar, _("Detecting loops..."), true);
- detect_loops_in_code(proc, routines, routines_count, statusbar, id);
+ // -- old -- detect_loops_in_code(proc, routines, routines_count, statusbar, 0/*id*/);
- gtk_extended_status_bar_remove(statusbar, id);
+ // -- old -- gtk_extended_status_bar_remove(statusbar, 0/*id*/);
///
// plugins //////////////////////////
- process_disassembly_event(PGA_DISASSEMBLY_LOOPS, disass->binary);
+ // -- old -- process_disassembly_event(PGA_DISASSEMBLY_LOOPS, disass->binary);
+
+
+
+
+
+
+
+
+
+
+ //////////////////////////////////////
+
+
+ // Control-flow analysis...
+
+
+
+
+
+
+
+
+ mrange_t *exe_ranges; /* Liste de zones exécutables */
+ size_t exe_count; /* Nombre de ces zones */
+ guint runs_count; /* Qté d'exécutions parallèles */
+ size_t run_size; /* Volume réparti par exécution*/
+ GWorkQueue *queue; /* Gestionnaire de différés */
+ guint i; /* Boucle de parcours */
+ size_t begin; /* Début de bloc de traitement */
+ size_t end; /* Fin d'un bloc de traitement */
+ GRoutinesStudy *study; /* Tâche d'étude à programmer */
+
+ exe_ranges = g_exe_format_get_x_ranges(disass->format, &exe_count);
+
+ runs_count = g_get_num_processors();
+
+ run_size = routines_count / runs_count;
+
+ queue = get_work_queue();
+
+ for (i = 0; i < runs_count; i++)
+ {
+ begin = i * run_size;
+
+ if ((i + 1) < runs_count)
+ end = routines_count - begin;
+ else
+ end = begin + run_size;
+
+ study = g_routines_study_new(proc, exe_ranges, exe_count, routines, routines_count, begin, end, id);
+
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(study), gid);
+
+ }
+
+ g_work_queue_wait_for_completion(queue, gid);
+
+ if (exe_ranges != NULL)
+ free(exe_ranges);
+
+
+
+
+
+
+
@@ -406,18 +466,18 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
/* Cinquième étape */
- id = gtk_extended_status_bar_push(statusbar, _("Grouping routines instructions..."), true);
+ // -- old -- id = gtk_extended_status_bar_push(statusbar, _("Grouping routines instructions..."), true);
//qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare);
- group_routines_instructions(proc, routines, routines_count, statusbar, id);
+ // -- old -- group_routines_instructions(proc, routines, routines_count, statusbar, 0/*id*/);
- gtk_extended_status_bar_remove(statusbar, id);
+ // -- old -- gtk_extended_status_bar_remove(statusbar, 0/*id*/);
//run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true);
- process_disassembly_event(PGA_DISASSEMBLY_GROUPED, disass->binary);
+ // -- old -- process_disassembly_event(PGA_DISASSEMBLY_GROUPED, disass->binary);
@@ -425,18 +485,18 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
/* Sixième étape */
- id = gtk_extended_status_bar_push(statusbar, _("Ranking each instructions block..."), true);
+ // -- old -- id = gtk_extended_status_bar_push(statusbar, _("Ranking each instructions block..."), true);
//qsort(routines, routines_count, sizeof(GBinRoutine *), (__compar_fn_t)g_binary_routine_rcompare);
- rank_routines_blocks(routines, routines_count, statusbar, id);
+ // -- old -- rank_routines_blocks(routines, routines_count, statusbar, 0/*id*/);
- gtk_extended_status_bar_remove(statusbar, id);
+ // -- old -- gtk_extended_status_bar_remove(statusbar, 0/*id*/);
//run_plugins_on_binary(disass->binary, PGA_BINARY_GROUPED, true);
- process_disassembly_event(PGA_DISASSEMBLY_RANKED, disass->binary);
+ // -- old -- process_disassembly_event(PGA_DISASSEMBLY_RANKED, disass->binary);
@@ -450,7 +510,7 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
proc = g_loaded_binary_get_processor(disass->binary);
print_disassembled_instructions(disass->buffer, disass->format, proc, *disass->instrs,
- routines, routines_count, statusbar, id);
+ routines, routines_count, statusbar, 0/*id*/);
g_object_unref(G_OBJECT(proc));
@@ -464,7 +524,7 @@ G_BIN_FORMAT(g_loaded_binary_get_format(disass->binary)
printf("---fin\n");
- //gtk_extended_status_bar_remove(statusbar, id);
+ //gtk_extended_status_bar_remove(statusbar, 0/*id*/);
//run_plugins_on_binary(disass->binary, PGA_BINARY_PRINTED, true);
diff --git a/src/analysis/disass/dragon.c b/src/analysis/disass/dragon.c
index 2fcf830..fbdecd8 100644
--- a/src/analysis/disass/dragon.c
+++ b/src/analysis/disass/dragon.c
@@ -38,6 +38,7 @@ struct _dragon_node
GArchInstruction *first; /* Arrivée d'un lien (début) */
GArchInstruction *last; /* Départ d'un lien (fin) */
+ bitfield_t *paths_bits; /* Masque de noeuds accessibles*/
bitfield_t *bits; /* Représentation par masque */
};
@@ -91,11 +92,12 @@ struct _dragon_knight
* Remarques : - *
* *
******************************************************************************/
-
+#include "../../arch/instruction-int.h"
static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_coverage *coverage, const mrange_t *range, const vmpa2t *start, size_t *count)
{
dragon_node *result; /* Liste à créer et renvoyer */
size_t allocated; /* Dimensionnement en mémoire */
+ bool need_alloc; /* Besoin d'une extension ? */
GArchInstruction *last; /* Mémorisation du passé */
GArchInstruction *iter; /* Boucle de parcours */
const mrange_t *irange; /* Emplacement d'instruction */
@@ -108,6 +110,7 @@ static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_
*count = 0;
allocated = 0;
+ need_alloc = true;
for (last = NULL, iter = g_arch_processor_find_covered_instr_by_address(proc, coverage, start);
iter != NULL;
@@ -122,8 +125,10 @@ static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_
/* Analyse des sources */
- if (result == NULL)
+ if (need_alloc)
{
+ need_alloc = false;
+
(*count)++;
if (*count >= allocated)
@@ -137,6 +142,8 @@ static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_
new->first = iter;
}
+
+
else
{
scount = g_arch_instruction_get_sources(iter, NULL, &types);
@@ -154,6 +161,15 @@ static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_
if (*count > 0)
result[*count - 1].last = last;
+
+ /*
+ printf(" %% ?jmp? %% cut @ %zu ; last = 0x%08x ; iter = 0x%08x\n", *count - 1,
+ (unsigned int)last->range.addr.virtual,
+ (unsigned int)iter->range.addr.virtual);
+ fflush(NULL);
+ */
+
+
(*count)++;
i = scount;
@@ -176,6 +192,25 @@ static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_
}
+
+
+ if (g_arch_instruction_get_flags(iter) & AIF_RETURN_POINT)
+ {
+ if (*count > 0)
+ result[*count - 1].last = iter;
+
+ /*
+ printf(" %% return %% cut @ %zu ; addr = 0x%08x\n", *count - 1,
+ (unsigned int)iter->range.addr.virtual);
+ fflush(NULL);
+ */
+
+ need_alloc = true;
+
+ }
+
+
+
}
if (*count > 0)
@@ -204,7 +239,10 @@ static void delete_dragon_nodes(dragon_node *nodes, size_t count)
size_t i; /* Boucle de parcours */
for (i = 0; i < count; i++)
+ {
+ delete_bit_field(nodes[i].paths_bits);
delete_bit_field(nodes[i].bits);
+ }
free(nodes);
@@ -229,7 +267,10 @@ static void init_mask_for_nodes(dragon_node *nodes, size_t count)
size_t i; /* Boucle de parcours */
for (i = 0; i < count; i++)
+ {
+ nodes[i].paths_bits = create_bit_field(count, false);
nodes[i].bits = create_bit_field(count, i > 0);
+ }
set_in_bit_field(nodes[0].bits, 0, 1);
@@ -347,6 +388,84 @@ dragon_node *find_node_for_instruction(dragon_node *nodes, size_t count, bool fi
* Paramètres : nodes = liste de noeuds détectés dans une routine. *
* count = taille de cette liste de noeuds à traiter. *
* *
+* Description : Marque tous les noeuds accessibles pour chaque noeud de code.*
+* *
+* Retour : - *
+* *
+* Remarques : Les chemins issus de boucles ne sont pas pris en compte. *
+* On cherche à construire une hiérarchie, pas une réalité. *
+* *
+******************************************************************************/
+
+void compute_all_paths(dragon_node *nodes, size_t count)
+{
+ void follow_flow_in_nodes(dragon_node *node)
+ {
+ GArchInstruction **dests; /* Instr. visée par une autre */
+ InstructionLinkType *types; /* Type de lien entre lignes */
+ size_t dcount; /* Nombre de liens de dest. */
+ size_t i; /* Boucle de parcours */
+ dragon_node *next; /* Noeud suivant dans le code */
+ size_t id; /* Indice du bit associé */
+
+ dcount = g_arch_instruction_get_destinations(node->last, &dests, &types, NULL);
+
+ for (i = 0; i < dcount; i++)
+ switch (types[i])
+ {
+ case ILT_EXEC_FLOW:
+ case ILT_JUMP:
+ case ILT_CASE_JUMP:
+ case ILT_JUMP_IF_TRUE:
+ case ILT_JUMP_IF_FALSE:
+
+ next = find_node_for_instruction(nodes, count, false, dests[i]);
+ if (next == NULL) break;
+
+ id = get_dragon_node_index(nodes, next);
+ set_in_bit_field(node->paths_bits, id, 1);
+
+ follow_flow_in_nodes(next);
+ or_bit_field(node->paths_bits, next->paths_bits);
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ follow_flow_in_nodes(&nodes[0]);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud représentant une portion de code à consulter. *
+* *
+* Description : Fournit la liste des noeuds accessibles depuis un autre. *
+* *
+* Retour : Champ de bits en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const bitfield_t *get_paths_bits(const dragon_node *node)
+{
+ return node->paths_bits;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : nodes = liste de noeuds détectés dans une routine. *
+* count = taille de cette liste de noeuds à traiter. *
+* *
* Description : Détermine toute la chaîne hiérarchique de domination. *
* *
* Retour : - *
@@ -380,7 +499,7 @@ void compute_all_dominators(dragon_node *nodes, size_t count)
set_all_in_bit_field(inter);
scount = g_arch_instruction_get_sources(node->first, &srcs, &types);
- assert(scount > 0);
+ //assert(scount > 0); // un 'ret' coupe, le suivant n'a pas de source
for (i = 0; i < scount; i++)
switch (types[i])
@@ -393,12 +512,12 @@ void compute_all_dominators(dragon_node *nodes, size_t count)
predecessor = find_node_for_instruction(nodes, count, true, srcs[i]);
-
+ /*
printf(" -- finding pred @ 0x%08x -> 0x%08x :: %p\n",
(unsigned int)g_arch_instruction_get_range(node->first)->addr.virtual,
(unsigned int)g_arch_instruction_get_range(srcs[i])->addr.virtual,
predecessor);
-
+ */
if (predecessor == NULL) break;
@@ -449,9 +568,6 @@ const bitfield_t *get_domination_bits(const dragon_node *node)
-
-
-
/* ---------------------------------------------------------------------------------- */
/* ENCAPSULATION DES NOEUDS */
/* ---------------------------------------------------------------------------------- */
@@ -522,8 +638,8 @@ void end_dragon_knight(dragon_knight *knight)
/******************************************************************************
* *
* Paramètres : knight = données représentant une complexité à considérer. *
-* nodes = noeuds de code associés à récupérer. [OUT] *
-* count = taille de cette liste de noeuds. [OUT] *
+* nodes = noeuds de code associés à récupérer ou NULL. [OUT] *
+* count = taille de cette liste de noeuds ou NULL. [OUT] *
* *
* Description : Fournit les éléments utiles à un traitement de blocs de code.*
* *
@@ -533,9 +649,81 @@ void end_dragon_knight(dragon_knight *knight)
* *
******************************************************************************/
-void get_dragon_knight_content(dragon_knight *knight, dragon_node **nodes, size_t *count)
+void get_dragon_knight_content(const dragon_knight *knight, dragon_node **nodes, size_t *count)
+{
+ if (nodes != NULL) *nodes = knight->nodes;
+ if (count != NULL) *count = knight->count;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : knight = données représentant une complexité à considérer. *
+* *
+* Description : Fournit un noeud particulier à partir d'une liste. *
+* *
+* Retour : Noeud ciblé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+dragon_node *get_dragon_knight_node(const dragon_knight *knight, size_t index)
{
- *nodes = knight->nodes;
- *count = knight->count;
+ assert(index < knight->count);
+
+ return knight->nodes + index;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : knight = données représentant une complexité à considérer. *
+* node = noeud ciblé au sein de cette liste. *
+* *
+* Description : Fournit l'indice d'un noeud particulier à partir d'une liste.*
+* *
+* Retour : Indice du noeud ciblé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+size_t get_dragon_knight_node_index(const dragon_knight *knight, dragon_node *node)
+{
+ size_t result; /* Indice à retourner */
+
+ result = (node - knight->nodes);
+
+ assert(result < knight->count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : knight = données représentant une complexité à considérer. *
+* final = précise si l'instruction visée est la première. *
+* instr = instruction à retrouver en tant que début de noeud. *
+* *
+* Description : Recherche un noeud selon son intruction de départ. *
+* *
+* Retour : Noeud trouvé ou NULL si aucune trouvaille. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+dragon_node *find_knight_node_for_instruction(const dragon_knight *knight, bool final, const GArchInstruction *instr)
+{
+ dragon_node *result; /* Résultat des recherches */
+
+ result = find_node_for_instruction(knight->nodes, knight->count, final, instr);
+
+ return result;
}
diff --git a/src/analysis/disass/dragon.h b/src/analysis/disass/dragon.h
index c6f6fd5..3449e6f 100644
--- a/src/analysis/disass/dragon.h
+++ b/src/analysis/disass/dragon.h
@@ -49,6 +49,12 @@ size_t get_dragon_node_index(dragon_node *, dragon_node *);
/* Recherche un noeud selon son intruction de départ. */
dragon_node *find_node_for_instruction(dragon_node *, size_t, bool, const GArchInstruction *);
+/* Marque tous les noeuds accessibles pour chaque noeud de code. */
+void compute_all_paths(dragon_node *, size_t);
+
+/* Fournit la liste des noeuds accessibles depuis un autre. */
+const bitfield_t *get_paths_bits(const dragon_node *);
+
/* Détermine toute la chaîne hiérarchique de domination. */
void compute_all_dominators(dragon_node *, size_t);
@@ -57,9 +63,6 @@ const bitfield_t *get_domination_bits(const dragon_node *);
-
-
-
/* ---------------------------- ENCAPSULATION DES NOEUDS ---------------------------- */
@@ -74,7 +77,16 @@ dragon_knight *begin_dragon_knight(const GArchProcessor *, const instr_coverage
void end_dragon_knight(dragon_knight *);
/* Fournit les éléments utiles à un traitement de blocs de code. */
-void get_dragon_knight_content(dragon_knight *, dragon_node **, size_t *);
+void get_dragon_knight_content(const dragon_knight *, dragon_node **, size_t *);
+
+/* Fournit un noeud particulier à partir d'une liste. */
+dragon_node *get_dragon_knight_node(const dragon_knight *, size_t);
+
+/* Fournit l'indice d'un noeud particulier à partir d'une liste. */
+size_t get_dragon_knight_node_index(const dragon_knight *, dragon_node *);
+
+/* Recherche un noeud selon son intruction de départ. */
+dragon_node *find_knight_node_for_instruction(const dragon_knight *, bool, const GArchInstruction *);
diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c
index dd0b661..e7dbbd7 100644
--- a/src/analysis/disass/loop.c
+++ b/src/analysis/disass/loop.c
@@ -24,27 +24,10 @@
#include "loop.h"
-#include <assert.h>
-#include <malloc.h>
-
-
-#include "dragon.h"
-
-
-
-
-
-
-
/* Matérialise les liens de retour arrière en tant que boucles. */
static void detect_back_edges(dragon_node *, size_t);
-/* Suit un flot d'exécution à la recherche de boucles. */
-static void track_loops_in_code(const GArchProcessor *, const instr_coverage *, const mrange_t *, const vmpa2t *, memfield_t *);
-
-
-
/******************************************************************************
@@ -70,33 +53,9 @@ static void detect_back_edges(dragon_node *nodes, size_t count)
InstructionLinkType *types; /* Type de lien entre lignes */
size_t dcount; /* Nombre de liens de dest. */
size_t i; /* Boucle de parcours #2 */
- dragon_node *target; /* Noeud référencé à tester */
+ dragon_node *target; /* Noeud référence à tester */
size_t id; /* Indice du bit associé */
-
-
- printf("-----------------------------------------------------------------\n");
-
- for (k = 0; k < count; k++)
- {
- GArchInstruction *first;
-
- node = get_dragon_node(nodes, k);
-
- dominators = get_domination_bits(node);
-
- get_dragon_node_bounding_instructions(node, &first, &last);
-
-
- printf("#[ node %zu ]# @ 0x%08x / 0x%08x - mask = 0x%08lx\n", k,
- (unsigned int)g_arch_instruction_get_range(first)->addr.virtual,
- (unsigned int)g_arch_instruction_get_range(last)->addr.virtual,
- gfw(dominators));
-
- }
-
- printf("\n");
-
for (k = 1; k < count; k++)
{
node = get_dragon_node(nodes, k);
@@ -125,10 +84,11 @@ static void detect_back_edges(dragon_node *nodes, size_t count)
if (test_in_bit_field(dominators, id, 1))
{
+ /*
printf("BACKEDGE :: 0x%08lx -> 0x%08lx\n",
(unsigned int)g_arch_instruction_get_range(last)->addr.virtual,
(unsigned int)g_arch_instruction_get_range(dests[i])->addr.virtual);
-
+ */
/* status = */g_arch_instruction_change_link(last, dests[i], types[i], ILT_LOOP);
@@ -147,16 +107,11 @@ static void detect_back_edges(dragon_node *nodes, size_t count)
}
-
/******************************************************************************
* *
-* Paramètres : proc = ensemble d'instructions à parcourir. *
-* coverage = zone de couverture où rechercher des instructions.*
-* range = zone de couverture de la routine analysée. *
-* start = adresse du début de l'analyse. *
-* flow = ensemble des jalons de l'exécution du code. *
+* Paramètres : knight = informations quant à la complexité gérée du code. *
* *
-* Description : Suit un flot d'exécution à la recherche de boucles. *
+* Description : Détecte les boucles dans du code machine. *
* *
* Retour : - *
* *
@@ -164,347 +119,15 @@ static void detect_back_edges(dragon_node *nodes, size_t count)
* *
******************************************************************************/
-static void track_loops_in_code(const GArchProcessor *proc, const instr_coverage *coverage, const mrange_t *range, const vmpa2t *start, memfield_t *flow)
+void detect_loops_in_code(dragon_knight *knight)
{
- dragon_knight *knight; /* Complexité de code posée */
dragon_node *nodes; /* Liste des noeuds détectés */
size_t count; /* Taille de cette liste */
- knight = begin_dragon_knight(proc, coverage, range, start);
-
- if (knight == NULL) return;
-
- assert(knight != NULL);
-
-
-
get_dragon_knight_content(knight, &nodes, &count);
-
- printf("nodes count :: %d\n", (int)count);
-
compute_all_dominators(nodes, count);
detect_back_edges(nodes, count);
-
- end_dragon_knight(knight);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : proc = ensemble d'instructions à relier. *
-* routines = prototypes existants à insérer. *
-* count = quantité de ces prototypes. *
-* statusbar = barre de statut avec progression à mettre à jour.*
-* id = identifiant du message affiché à l'utilisateur. *
-* *
-* Description : Détecte les boucles dans du code machine. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void detect_loops_in_code(const GArchProcessor *proc, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, bstatus_id_t id)
-{
- size_t i; /* Boucle de parcours */
- const mrange_t *range; /* Couverture d'une routine */
- const vmpa2t *start; /* Adresse de départ */
- const instr_coverage *coverage; /* Instructions couvertes */
- memfield_t *flow; /* Flot d'exécution à suivre */
-
- //for (i = 286; i == 286; i++)
- for (i = 0; i < count; i++)
- {
-
-
- range = g_binary_routine_get_range(routines[i]);
- start = get_mrange_addr(range);
-
-
- printf("====== '%s' @ 0x%08x\n",
- g_binary_routine_get_name(routines[i]),
- start->virtual);
-
-
- coverage = g_arch_processor_find_coverage_by_address(proc, start);
-
- flow = NULL;//create_mem_field(range);
- track_loops_in_code(proc, coverage, range, start, flow);
- //delete_mem_field(flow);
-
- gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
-
- }
-
-
- printf("done\n\n");
- //exit(0);
-
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-
-#if 0
-
-
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-#include "../../common/bits.h"
-
-
-
-/* Suit un flot d'exécution à la recherche de boucles. */
-static void track_loops_in_code(const GArchProcessor *, const instr_coverage *, const mrange_t *, const vmpa2t *, memfield_t *);
-
-
-
-/******************************************************************************
-* *
-* Paramètres : proc = ensemble d'instructions à parcourir. *
-* coverage = zone de couverture où rechercher des instructions.*
-* range = zone de couverture de la routine analysée. *
-* start = adresse du début de l'analyse. *
-* flow = ensemble des jalons de l'exécution du code. *
-* *
-* Description : Suit un flot d'exécution à la recherche de boucles. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void track_loops_in_code(const GArchProcessor *proc, const instr_coverage *coverage, const mrange_t *range, const vmpa2t *start, memfield_t *flow)
-{
- bool exit_track; /* Détermine la fin du parcours*/
- GArchInstruction *iter; /* Boucle de parcours */
- const mrange_t *irange; /* Emplacement d'instruction */
- GArchInstruction **dests; /* Instr. visée par une autre */
- InstructionLinkType *types; /* Type de lien entre lignes */
- size_t dcount; /* Nombre de liens de dest. */
- size_t i; /* Boucle de parcours */
- const vmpa2t *addr; /* Prochaine adresse de saut */
- memfield_t *next_flow; /* Suite de l'exécution */
-
- set_in_mem_field(flow, start);
-
- exit_track = false;
-
- for (iter = g_arch_processor_find_covered_instr_by_address(proc, coverage, start);
- iter != NULL && !exit_track;
- iter = g_arch_instruction_get_next_iter(iter /* FIXME : list*/, iter, ~0))
- {
- /* L'instruction sort-elle des clous ? */
-
- irange = g_arch_instruction_get_range(iter);
-
- if (!mrange_contains_mrange(range, irange))
- break;
-
- /* Fin de parcours ? */
-
- if (g_arch_instruction_get_flags(iter) & AIF_RETURN_POINT)
- break;
-
- /**
- * Afin de détecter les boucles le plus en aval possible,
- * on marque toutes les arrivées potentielles de boucles comme jalons.
- * Ainsi la détection se réalise sur l'ultime saut qui boucle effectivement.
- */
- if (g_arch_instruction_has_sources(iter))
- {
- addr = get_mrange_addr(irange);
-
- if (!test_in_mem_field(flow, addr))
- set_in_mem_field(flow, start);
-
- }
-
- /* Analyse des destinations */
-
- dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL);
- if (dcount == 0) continue;
-
- for (i = 0; i < dcount; i++)
- switch (types[i])
- {
- case ILT_LOOP:
- /**
- * On est déjà passé par là, donc on peut arrêter le parcours courant.
- */
- exit_track = true;
- break;
-
- case ILT_CATCH_EXCEPTION:
-
- irange = g_arch_instruction_get_range(dests[i]);
- addr = get_mrange_addr(irange);
-
- next_flow = create_mem_field_from(flow);
- track_loops_in_code(proc, coverage, range, addr, next_flow);
- delete_mem_field(next_flow);
-
- break;
-
- case ILT_EXEC_FLOW:
- case ILT_JUMP:
- case ILT_CASE_JUMP:
- case ILT_JUMP_IF_TRUE:
- case ILT_JUMP_IF_FALSE:
-
- /**
- * On se lance dans d'autres suivis qui vont parcourir le reste des
- * instructions, donc on peut arrêter le parcours courant ici.
- */
- exit_track = true;
-
- irange = g_arch_instruction_get_range(dests[i]);
-
- if (!mrange_contains_mrange(range, irange))
- break;
-
- addr = get_mrange_addr(irange);
-
- if (test_in_mem_field(flow, addr))
- /* status = */g_arch_instruction_change_link(iter, dests[i], types[i], ILT_LOOP);
-
- else
- {
- next_flow = dup_mem_field(flow);
- track_loops_in_code(proc, coverage, range, addr, next_flow);
- delete_mem_field(next_flow);
- }
-
- break;
-
- default:
- break;
-
- }
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : proc = ensemble d'instructions à relier. *
-* routines = prototypes existants à insérer. *
-* count = quantité de ces prototypes. *
-* statusbar = barre de statut avec progression à mettre à jour.*
-* id = identifiant du message affiché à l'utilisateur. *
-* *
-* Description : Détecte les boucles dans du code machine. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void detect_loops_in_code(const GArchProcessor *proc, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, bstatus_id_t id)
-{
- size_t i; /* Boucle de parcours */
- const mrange_t *range; /* Couverture d'une routine */
- const vmpa2t *start; /* Adresse de départ */
- const instr_coverage *coverage; /* Instructions couvertes */
- memfield_t *flow; /* Flot d'exécution à suivre */
-
- for (i = 0; i < count; i++)
- {
-
-
- range = g_binary_routine_get_range(routines[i]);
- start = get_mrange_addr(range);
-
- coverage = g_arch_processor_find_coverage_by_address(proc, start);
-
- flow = create_mem_field(range);
- track_loops_in_code(proc, coverage, range, start, flow);
- delete_mem_field(flow);
-
- gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
-
- }
-
-}
-
-
-
-
-
-
-#endif
diff --git a/src/analysis/disass/loop.h b/src/analysis/disass/loop.h
index f4b05cf..0d2f730 100644
--- a/src/analysis/disass/loop.h
+++ b/src/analysis/disass/loop.h
@@ -25,14 +25,12 @@
#define _ANALYSIS_DISASS_LOOP_H
-#include "../routine.h"
-#include "../../arch/processor.h"
-#include "../../gtkext/gtkextstatusbar.h"
+#include "dragon.h"
/* Détecte les boucles dans du code machine. */
-void detect_loops_in_code(const GArchProcessor *, GBinRoutine **, size_t, GtkExtStatusBar *, bstatus_id_t);
+void detect_loops_in_code(dragon_knight *);
diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c
index acb210a..d9d20ee 100644
--- a/src/analysis/disass/macro.c
+++ b/src/analysis/disass/macro.c
@@ -25,8 +25,6 @@
#include <assert.h>
-#include <malloc.h>
-#include <stdlib.h>
#include "../blocks/flow.h"
@@ -34,115 +32,6 @@
-/* ------------------------ COUVERTURE D'UNE ZONE A DECOUPER ------------------------ */
-
-
-/* Bornes d'une zone à couvrir */
-typedef struct _code_coverage
-{
- bool initial; /* Couverture racine ? */
-
- mrange_t range; /* Couverture totale */
-
- vmpa2t start; /* Position butoir de début */
-
- vmpa2t *ends; /* Positions butoir de fin */
- size_t ends_count; /* Quantité de fins possibles */
-
- unsigned long *processed; /* Octets traités dans la zone */
- size_t allocated; /* Taille de la cartographie */
-
-} code_coverage;
-
-
-/* Met en place les délimitations d'une zone de code. */
-static code_coverage *create_code_coverage(const mrange_t *);
-
-/* Crée une copie d'une couverture de zone de code. */
-static code_coverage *dup_code_coverage(const code_coverage *, const vmpa2t *);
-
-/* Détruit des délimitations d'une zone de code. */
-static void delete_code_coverage(code_coverage *);
-
-/* Précise la position de départ courante pour une analyse. */
-static const vmpa2t *get_code_coverage_start_addr(const code_coverage *);
-
-/* Indique si une adresse est hors zone ou non. */
-static bool code_coverage_stop_here(const code_coverage *coverage, const vmpa2t *);
-
-/* Ajoute une adresse butoir pour la zone à couvrir. */
-static bool add_ending_address_code_coverage(code_coverage *, const vmpa2t *);
-
-/* Indique si une zone donnée n'a jamais été traitée ou non. */
-static bool is_range_processed_in_coverage(const code_coverage *, const mrange_t *);
-
-/* Marque une série d'octets comme ayant été traités. */
-static void mark_range_as_processed_in_coverage(code_coverage *, const GArchInstruction *);
-
-
-
-/* ------------------------- SUIVI DES FLOTS D'INSTRUCTIONS ------------------------- */
-
-
-/* Indications sur une branche */
-typedef struct _branch_info
-{
- vmpa2t *hops; /* Jalons de la branche */
- size_t count; /* Quantité de ces jalons */
-
- vmpa2t entry; /* Valeur du jalon d'entrée */
-
-} branch_info;
-
-
-/* Initialise le suivi d'une branche de flot d'exécution. */
-static void init_branch_info(branch_info *);
-
-/* Acte la fin d'un suivi d'une branche de flot d'exécution. */
-static void clean_branch_info(branch_info *);
-
-/* Indique si une adresse est retenue comme point de passage. */
-static bool is_addr_in_branch(const branch_info *, const vmpa2t *);
-
-/* Ajoute un nouveau jalon dans l'exécution d'une branche. */
-static bool add_hop_into_branch(branch_info *, const vmpa2t *);
-
-/* Retourne le premier point d'exécution d'une branche donnée. */
-static const vmpa2t *get_entry_to_branch(const branch_info *);
-
-/* Identifie les différents points de passage d'une branche. */
-static void find_next_hops(GArchProcessor *, const vmpa2t *, const code_coverage *, branch_info *);
-
-/* Retrouve le point de ralliement entre deux branches. */
-static bool compute_first_common_addr(const branch_info *, const branch_info *, vmpa2t *);
-
-
-/* Groupement de branches et d'indications */
-typedef struct _branch_group
-{
- branch_info *branches; /* Liste des branches */
- size_t count; /* Taille de cette liste */
-
-} branch_group;
-
-
-/* Initialise le suivi d'un ensemble de branches. */
-static void init_branch_group(branch_group *);
-
-/* Acte la fin d'un suivi d'un ensemble de branches. */
-static void clean_branch_group(branch_group *);
-
-/* Ajoute une branche à un ensemble de branches en place. */
-static branch_info *extend_branch_group(branch_group *);
-
-/* Retrouve le point de ralliement entre un groupe de branches. */
-static bool compute_first_common_addr_in_group(const branch_group *, vmpa2t *);
-
-
-
-/* --------------------------- DECOUPAGE EN BLOCS DE CODE --------------------------- */
-
-
/**
* Procédure d'ajout de blocs : pour le premier, on conserve le bloc en mémoire
* et on attend. Si rien ne suit, il constitura l'unique retour. Sinon, on
@@ -169,389 +58,64 @@ static bool compute_first_common_addr_in_group(const branch_group *, vmpa2t *);
while (0)
-/* Procède à la création d'un bloc d'instructions simple. */
-static GInstrBlock *build_instruction_block_simple(GArchProcessor *, code_coverage *, GArchInstruction **, GArchInstruction *);
-
-/* Procède à la définition d'un bloc d'instructions selectif. */
-static GInstrBlock *build_instruction_blocks_case(GArchProcessor *, code_coverage *, const branch_group *, vmpa2t *);
-
-/* Procède à la définition d'un bloc d'instruction if/then/else. */
-static GInstrBlock *build_instruction_blocks_ite(GArchProcessor *, code_coverage *, const branch_info *, const branch_info *, vmpa2t *);
-
-/* Procède à la définition d'un bloc d'instructions d'exception. */
-static void add_instruction_blocks_except(GInstrBlock **, GInstrBlock **, GArchProcessor *, code_coverage *, const branch_group *, const branch_info *);
+/* Détermine la couverture d'un ensemble de chemins. */
+static bitfield_t *compute_other_paths_mask(const dragon_knight *, GArchInstruction **, InstructionLinkType *, size_t, size_t);
/* Procède à la définition de bloc regroupant des instructions. */
-static GInstrBlock *build_instruction_blocks(GArchProcessor *, code_coverage *);
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* COUVERTURE D'UNE ZONE A DECOUPER */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : range = définition de la zone à couvrir. *
-* *
-* Description : Met en place les délimitations d'une zone de code. *
-* *
-* Retour : Couverture d'une zone de code. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static code_coverage *create_code_coverage(const mrange_t *range)
-{
- code_coverage *result; /* Couverture à retourner */
- phys_t length; /* Taille de la zone couverte */
- size_t requested; /* Nombre de mots à allouer */
+static GInstrBlock *build_instruction_blocks(GArchProcessor *, const dragon_knight *, dragon_node *, const bitfield_t *, bitfield_t *, size_t *);
- result = (code_coverage *)calloc(1, sizeof(code_coverage));
-
- result->initial = true;
-
- copy_mrange(&result->range, range);
-
- copy_vmpa(&result->start, get_mrange_addr(range));
-
- result->ends = (vmpa2t *)calloc(1, sizeof(vmpa2t));
- result->ends_count = 1;
-
- compute_mrange_end_addr(range, &result->ends[0]);
-
- length = get_mrange_length(range);
-
- requested = length / sizeof(unsigned long);
- if (length % sizeof(unsigned long) != 0) requested++;
-
- result->processed = (unsigned long *)calloc(requested, sizeof(unsigned long));
- result->allocated = requested;
-
- return result;
-
-}
/******************************************************************************
* *
-* Paramètres : src = informations de couverture à consulter. *
-* new = nouvelle position de début, plus profonde. *
+* Paramètres : knight = représentation de la complexité du code. *
+* dests = instructions pointées à consulter. *
+* types = types associés aux destinations. *
+* dcount = nombre de destinations. *
+* current = indice de la destionation courante. *
* *
-* Description : Crée une copie d'une couverture de zone de code. *
+* Description : Détermine la couverture d'un ensemble de chemins. *
* *
-* Retour : Couverture d'une zone de code copiée. *
+* Retour : Champ de bits mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
-static code_coverage *dup_code_coverage(const code_coverage *src, const vmpa2t *new)
+static bitfield_t *compute_other_paths_mask(const dragon_knight *knight, GArchInstruction **dests, InstructionLinkType *types, size_t dcount, size_t current)
{
- code_coverage *result; /* Couverture à retourner */
+ bitfield_t *result; /* Couverture à retourner */
+ size_t length; /* Taille du champ de bits */
+ InstructionLinkType target; /* Type de noeud à cibler */
size_t i; /* Boucle de parcours */
+ dragon_node *node; /* Noeud à considérer */
- result = (code_coverage *)calloc(1, sizeof(code_coverage));
-
- result->initial = false;
-
- copy_mrange(&result->range, &src->range);
-
- copy_vmpa(&result->start, new);
-
- result->ends = (vmpa2t *)calloc(src->ends_count, sizeof(vmpa2t));
- result->ends_count = src->ends_count;
-
- for (i = 0; i < result->ends_count; i++)
- copy_vmpa(&result->ends[i], &src->ends[i]);
-
- /**
- * Les blocs produits par le découpage sont à accès global, et ne sont donc pas
- * la propriété d'une branche particulière.
- * Il ne faut donc pas créer deux blocs identiques à partir de deux chemins
- * différents ; aussi on partage la couverture de code plutôt que la copier.
- * Et, par ailleurs, c'est plus simple & efficace.
- */
-
- result->processed = src->processed;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : coverage = structure à libérer de la mémoire. *
-* *
-* Description : Détruit des délimitations d'une zone de code. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void delete_code_coverage(code_coverage *coverage)
-{
- free(coverage->ends);
-
- if (coverage->initial)
- free(coverage->processed);
-
- free(coverage);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : coverage = informations de couverture à consulter. *
-* *
-* Description : Précise la position de départ courante pour une analyse. *
-* *
-* Retour : Position de départ pour une analyse d'une portion de zone. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static const vmpa2t *get_code_coverage_start_addr(const code_coverage *coverage)
-{
- return &coverage->start;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : coverage = informations de couverture à consulter. *
-* addr = localisation à tester. *
-* *
-* Description : Indique si une adresse est hors zone ou non. *
-* *
-* Retour : true si l'adresse ne doit pas être couverte, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool code_coverage_stop_here(const code_coverage *coverage, const vmpa2t *addr)
-{
- void *ptr; /* Résultat des recherches */
-
- if (!mrange_contains_addr(&coverage->range, addr))
- return true;
-
- ptr = bsearch(addr, coverage->ends, coverage->ends_count,
- sizeof(vmpa2t), (__compar_fn_t)cmp_vmpa);
-
- return (ptr != NULL);
-
-}
+ get_dragon_knight_content(knight, NULL, &length);
+ result = create_bit_field(length, false);
-/******************************************************************************
-* *
-* Paramètres : coverage = informations de couverture à compléter. *
-* addr = localisation à ajouter. *
-* *
-* Description : Ajoute une adresse butoir pour la zone à couvrir. *
-* *
-* Retour : true si une insertion a été effectuée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ target = types[current];
-static bool add_ending_address_code_coverage(code_coverage *coverage, const vmpa2t *addr)
-{
- bool result; /* Bilan à retourner */
+ if (target == ILT_JUMP_IF_TRUE)
+ target = ILT_JUMP_IF_FALSE;
+ else if (target == ILT_JUMP_IF_FALSE)
+ target = ILT_JUMP_IF_TRUE;
- result = !code_coverage_stop_here(coverage, addr);
+ assert(target == ILT_CASE_JUMP || target == ILT_JUMP_IF_TRUE || target == ILT_JUMP_IF_FALSE);
- if (result)
+ for (i = 0; i < dcount; i++)
{
- coverage->ends = (vmpa2t *)realloc(coverage->ends, ++coverage->ends_count * sizeof(vmpa2t));
-
- copy_vmpa(&coverage->ends[coverage->ends_count - 1], addr);
-
- qsort(coverage->ends, coverage->ends_count, sizeof(vmpa2t), (__compar_fn_t)cmp_vmpa);
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : coverage = informations de couverture à consulter. *
-* range = zone à interroger. *
-* *
-* Description : Indique si une zone donnée n'a jamais été traitée ou non. *
-* *
-* Retour : true si l'aire visée est vierge, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool is_range_processed_in_coverage(const code_coverage *coverage, const mrange_t *range)
-{
- bool result; /* Bilan à renvoyer */
- phys_t diff; /* Décalage à appliquer */
- size_t index; /* Cellule de tableau visée */
- unsigned int remaining; /* Nombre de bits restants */
-
- diff = compute_vmpa_diff(get_mrange_addr(&coverage->range), get_mrange_addr(range));
- assert(diff < get_mrange_length(&coverage->range));
-
- index = diff / (sizeof(unsigned long) * 8);
- remaining = diff % (sizeof(unsigned long) * 8);
-
- result = ((coverage->processed[index] & (1ul << remaining)) != 0);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : coverage = informations de couverture à consulter. *
-* instr = instruction couvrant la zone à interroger. *
-* *
-* Description : Marque une série d'octets comme ayant été traités. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void mark_range_as_processed_in_coverage(code_coverage *coverage, const GArchInstruction *instr)
-{
- const mrange_t *range; /* Emplacement d'instruction */
- phys_t diff; /* Décalage à appliquer */
- size_t index; /* Cellule de tableau visée */
- unsigned int remaining; /* Nombre de bits restants */
-
- range = g_arch_instruction_get_range(instr);
-
- diff = compute_vmpa_diff(get_mrange_addr(&coverage->range), get_mrange_addr(range));
- assert(diff < get_mrange_length(&coverage->range));
-
- index = diff / (sizeof(unsigned long) * 8);
- remaining = diff % (sizeof(unsigned long) * 8);
-
- coverage->processed[index] |= (1ul << remaining);
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* SUIVI DES FLOTS D'INSTRUCTIONS */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-* *
-* Paramètres : info = informations à initialiser. *
-* *
-* Description : Initialise le suivi d'une branche de flot d'exécution. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void init_branch_info(branch_info *info)
-{
- memset(info, 0, sizeof(branch_info));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : info = informations à nettoyer. *
-* *
-* Description : Acte la fin d'un suivi d'une branche de flot d'exécution. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void clean_branch_info(branch_info *info)
-{
- if (info->hops != NULL)
- free(info->hops);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : info = informations à consulter. *
-* addr = position à rechercher. *
-* *
-* Description : Indique si une adresse est retenue comme point de passage. *
-* *
-* Retour : true si le jalon est déjà dans la liste, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool is_addr_in_branch(const branch_info *info, const vmpa2t *addr)
-{
- void *ptr; /* Résultat des recherches */
-
- ptr = bsearch(addr, info->hops, info->count,
- sizeof(vmpa2t), (__compar_fn_t)cmp_vmpa);
-
- return (ptr != NULL);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : info = informations de flot à compléter. *
-* addr = localisation à ajouter. *
-* *
-* Description : Ajoute un nouveau jalon dans l'exécution d'une branche. *
-* *
-* Retour : true si une insertion a été effectuée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool add_hop_into_branch(branch_info *info, const vmpa2t *addr)
-{
- bool result; /* Bilan à retourner */
-
- result = !is_addr_in_branch(info, addr);
-
- if (result)
- {
- if (info->count == 0)
- copy_vmpa(&info->entry, addr);
+ if (i == current)
+ continue;
- info->hops = (vmpa2t *)realloc(info->hops, ++info->count * sizeof(vmpa2t));
+ if (types[i] == target)
+ {
+ node = find_knight_node_for_instruction(knight, false, dests[i]);
+ if (node == NULL) continue;
- copy_vmpa(&info->hops[info->count - 1], addr);
+ or_bit_field(result, get_paths_bits(node));
- qsort(info->hops, info->count, sizeof(vmpa2t), (__compar_fn_t)cmp_vmpa);
+ }
}
@@ -562,983 +126,413 @@ static bool add_hop_into_branch(branch_info *info, const vmpa2t *addr)
/******************************************************************************
* *
-* Paramètres : info = informations de flot à consulter. *
-* *
-* Description : Retourne le premier point d'exécution d'une branche donnée. *
-* *
-* Retour : Point de départ d'une branche. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static const vmpa2t *get_entry_to_branch(const branch_info *info)
-{
- return &info->entry;
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : proc = ensemble des instructions d'assemblage. *
-* start = position du début de bloc. *
-* coverage = liste des adresses de fin butoir. *
-* count = nombre de sauts détectés. [OUT] *
+* coverage = délimitations de la zone à couvrir. *
* *
-* Description : Identifie les différents points de passage d'une branche. *
+* Description : Procède à la définition de bloc regroupant des instructions. *
* *
-* Retour : Jalons dans le flot d'exécution. *
+* Retour : Bloc créé et enregistré, ou NULL si erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-static void find_next_hops(GArchProcessor *proc, const vmpa2t *start, const code_coverage *coverage, branch_info *info)
+static GInstrBlock *build_instruction_blocks(GArchProcessor *proc, const dragon_knight *knight, dragon_node *node, const bitfield_t *stop, bitfield_t *converted, size_t *next)
{
- GArchInstruction *iter; /* Boucle de parcours #1 */
- const mrange_t *range; /* Emplacement d'instruction */
+ GInstrBlock *result; /* Regroupement à retourner */
+ GInstrBlock *result_cached; /* Temporisation pour unicité */
+ size_t id; /* Indice du bit associé */
+ GArchInstruction *first; /* Première instruction de bloc*/
+ GArchInstruction *last; /* Dernière instruction de bloc*/
+ GInstrBlock *block; /* Nouveau bloc mis en place */
+ bitfield_t *local_stop; /* Arrêts pour les sous-blocs */
+ bitfield_t *others; /* Couvertures des autres */
GArchInstruction **dests; /* Instr. visée par une autre */
InstructionLinkType *types; /* Type de lien entre lignes */
size_t dcount; /* Nombre de liens de dest. */
- size_t i; /* Boucle de parcours #2 */
- size_t not_handled; /* Nombre d'éléments écartés */
+ size_t i; /* Boucle de parcours */
+ dragon_node *target; /* Noeud suivant à traiter */
+ GInstrBlock *group; /* Regroupement à retourner */
+ GInstrBlock *group_cached ; /* Temporisation pour unicité */
- printf(" ---- FN [ %p ] ---------------------------\n", info);
+ result = NULL;
+ result_cached = NULL;
- printf("CONTAINS ? %d\n", mrange_contains_addr(&coverage->range, start));
- /* Si la position est déjà présente, on évite de boucler... */
- if (!add_hop_into_branch(info, start))
- {
- printf(" ++ !add 0x%08x\n", (unsigned int)start->virtual);
- return;
- }
- else
- printf(" ++ add 0x%08x\n", (unsigned int)start->virtual);
- /* On suit le flot jusqu'à la prochaine bifurcation */
- for (iter = g_arch_processor_find_instr_by_address(proc, start);
- iter != NULL;
- iter = g_arch_processor_get_next_instr(proc, iter))
+ while (1)
{
- range = g_arch_instruction_get_range(iter);
+ id = get_dragon_knight_node_index(knight, node);
-
- if (code_coverage_stop_here(coverage, get_mrange_addr(range)))
- printf(" ++ stop here 0x%08x\n", (unsigned int)range->addr.virtual);
-
- if (code_coverage_stop_here(coverage, get_mrange_addr(range)))
- break;
+ /**
+ * Si on traite une des branches Vrai/Faux et que cette branche est vide,
+ * on doit s'arrêter.
+ */
- if (g_arch_instruction_has_sources(iter))
- add_hop_into_branch(info, get_mrange_addr(range));
+ //printf("=== [%d] PROCESSING NODE %u (0x%x) in 0x%08x\n", fff, id, 1 << id, gfw(stop));
+ if (test_in_bit_field(stop, id, 1))
+ {
+ //printf(" -- STOP\n");
+ *next = id;
+ break;
+ }
- if (g_arch_instruction_get_flags(iter) & AIF_RETURN_POINT)
- printf(" ++ return 0x%08x\n", (unsigned int)range->addr.virtual);
+ /**
+ * Si le bloc a déjà été converti, on arrête la conversion pour la branche courante.
+ *
+ * Cela peut correspondre à la situation suivante quand on revient sur le bloc
+ * inférieur droit :
+ *
+ * ======
+ * / \
+ * === |
+ * / \ |
+ * | `.|
+ * | ||
+ * === ===
+ */
- if (g_arch_instruction_get_flags(iter) & AIF_RETURN_POINT)
+ if (test_in_bit_field(converted, id, 1))
{
- iter = NULL;
+ //printf(" HALT\n");
+
+ *next = 0;
break;
}
+ /* Constitution et ajout d'un bloc */
+
+ get_dragon_node_bounding_instructions(node, &first, &last);
+
/*
- if (!g_arch_instruction_has_destinations(iter))
- printf(" ++ no dest 0x%08x\n", (unsigned int)range->addr.virtual);
+ printf(" -- [%d] process block %u @ 0x%08x <-> 0x%08x\n",
+ fff, (unsigned int)id,
+ (unsigned int)first->range.addr.virtual,
+ (unsigned int)last->range.addr.virtual);
*/
- if (!g_arch_instruction_has_destinations(iter))
- continue;
+ block = g_flow_block_new(proc, first, last);
+ DELAYED_BLOCK_ADDING(result, result_cached, block);
- printf(" ++ dcount 0x%08x\n", (unsigned int)range->addr.virtual);
+ set_in_bit_field(converted, id, 1);
- dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL);
+ /* Détermination du prochain arrêt */
- not_handled = 0;
+ local_stop = create_bit_field_from(stop, true);
- for (i = 0; i < dcount; i++)
- {
- range = g_arch_instruction_get_range(dests[i]);
+ others = NULL;
+ dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL);
+
+ for (i = 0; i < dcount && others == NULL; i++)
switch (types[i])
{
case ILT_EXEC_FLOW:
case ILT_JUMP:
- case ILT_CASE_JUMP:
- case ILT_JUMP_IF_TRUE:
- case ILT_JUMP_IF_FALSE:
- find_next_hops(proc, get_mrange_addr(range), coverage, info);
break;
case ILT_LOOP:
- add_hop_into_branch(info, get_mrange_addr(range));
break;
- default:
- not_handled++;
- break;
-
- }
-
- }
-
- if (not_handled < dcount)
- break;
+ case ILT_CASE_JUMP:
+ case ILT_JUMP_IF_TRUE:
+ case ILT_JUMP_IF_FALSE:
- }
+ target = find_knight_node_for_instruction(knight, false, dests[i]);
+ if (target == NULL) break;
- /* Si on termine... */
- if (iter != NULL) add_hop_into_branch(info, get_mrange_addr(range));
+ id = get_dragon_knight_node_index(knight, target);
- printf(" ------- [ %p ] ---\n", info);
+ others = compute_other_paths_mask(knight, dests, types, dcount, i);
-}
+ /**
+ * Si une patte est contenue dans une autre, on place la branche
+ * incluse comme borne de fin.
+ */
+ if (test_in_bit_field(others, id, 1))
+ {
+ reset_all_in_bit_field(others);
+ set_in_bit_field(others, id, 1);
+ }
+ /**
+ * Sinon la borne de fin est la sortie commune.
+ */
+ else
+ {
+ delete_bit_field(others);
+ others = NULL;
-/******************************************************************************
-* *
-* Paramètres : a = premier ensemble de jalons à parcourir. *
-* b = second ensemble de jalons à parcourir. *
-* c = éventuelle adresse commune à deux branches. *
-* *
-* Description : Retrouve le point de ralliement entre deux branches. *
-* *
-* Retour : true si une position commune a pu être trouvée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ and_bit_field(local_stop, get_paths_bits(target));
-static bool compute_first_common_addr(const branch_info *a, const branch_info *b, vmpa2t *c)
-{
- bool result; /* Bilan à retourner */
- size_t i; /* Boucle de parcours */
-
- result = false;
+ }
+ break;
- printf("....................\n");
+ case ILT_CATCH_EXCEPTION:
+ break;
- printf(" A :: ");
- for (i = 0; i < a->count; i++)
- printf("0x%08x ", a->hops[i].virtual);
- printf("\n");
+ default:
+ //assert(false);
+ break;
- printf(" B :: ");
- for (i = 0; i < b->count; i++)
- printf("0x%08x ", b->hops[i].virtual);
- printf("\n");
+ }
- for (i = 0; i < a->count && !result; i++)
- if (is_addr_in_branch(b, &a->hops[i]))
+ if (others != NULL)
{
- result = true;
- copy_vmpa(c, &a->hops[i]);
+ //printf(" HO \n");
+ delete_bit_field(local_stop);
+ local_stop = others;
}
- if (result)
- printf(" N :: 0x%08x\n", (unsigned int)c->virtual);
- else
- printf(" N :: ----\n");
-
- printf("....................\n");
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : group = informations à initialiser. *
-* *
-* Description : Initialise le suivi d'un ensemble de branches. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void init_branch_group(branch_group *group)
-{
- memset(group, 0, sizeof(branch_group));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : group = informations à nettoyer. *
-* *
-* Description : Acte la fin d'un suivi d'un ensemble de branches. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void clean_branch_group(branch_group *group)
-{
- size_t i; /* Boucle de parcours */
-
- for (i = 0; i < group->count; i++)
- clean_branch_info(&group->branches[i]);
-
- if (group->branches != NULL)
- free(group->branches);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : group = liste d'ensembles de jalons à agrandir. *
-* *
-* Description : Ajoute une branche à un ensemble de branches en place. *
-* *
-* Retour : Nouvel élément rajouté et initialisé. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static branch_info *extend_branch_group(branch_group *group)
-{
- branch_info *result; /* Nouveauté à retourner */
- group->branches = (branch_info *)realloc(group->branches,
- ++group->count * sizeof(branch_info));
- result = &group->branches[group->count];
+ //printf(" -- [%d] common :: 0x%08x\n", fff, gfw(local_stop));
- init_branch_info(result);
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : group = liste d'ensembles de jalons à parcourir. *
-* common = éventuelle adresse commune à branches. *
-* *
-* Description : Retrouve le point de ralliement entre un groupe de branches. *
-* *
-* Retour : true si une position commune a pu être trouvée, false sinon. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ //or_bit_field(local_stop, stop);
-static bool compute_first_common_addr_in_group(const branch_group *group, vmpa2t *common)
-{
- vmpa_t result; /* Adresse trouvée à retourner */
- branch_info *list; /* Raccourci de confort */
- size_t i; /* Boucle de parcours #1 */
- bool keep; /* Candidate à garder ? */
- size_t j; /* Boucle de parcours #2 */
- result = false;
+ //printf(" -- [%d] common :: 0x%08x\n", fff, gfw(local_stop));
- list = group->branches;
- for (i = 0; i < list[0].count && !result; i++)
- {
- keep = true;
+ /* Récupération des sous-blocs */
- for (j = 1; j < group->count && keep; j++)
- keep = is_addr_in_branch(&list[j], &list[0].hops[i]);
+ *next = 0;
- if (keep)
- copy_vmpa(common, &list[0].hops[i]);
+ group = NULL;
+ group_cached = NULL;
- }
+ for (i = 0; i < dcount; i++)
+ switch (types[i])
+ {
+ case ILT_EXEC_FLOW:
+ case ILT_JUMP:
- return result;
+ /* Il ne peut y en avoir qu'un ! */
+ assert(*next == 0);
-}
+ target = find_knight_node_for_instruction(knight, false, dests[i]);
+ if (target == NULL) break;
+ *next = get_dragon_knight_node_index(knight, target);
+ break;
+ case ILT_LOOP:
+ break;
-/* ---------------------------------------------------------------------------------- */
-/* DECOUPAGE EN BLOCS DE CODE */
-/* ---------------------------------------------------------------------------------- */
+ case ILT_CASE_JUMP:
+ case ILT_JUMP_IF_TRUE:
+ case ILT_JUMP_IF_FALSE:
+ target = find_knight_node_for_instruction(knight, false, dests[i]);
+ if (target == NULL) break;
-/******************************************************************************
-* *
-* Paramètres : proc = ensemble des instructions d'assemblage. *
-* coverage = délimitations de la zone à couvrir. *
-* first = première instruction d'un bloc préliminaire. *
-* cur = instruction courante dans le traitement. *
-* *
-* Description : Procède à la création d'un bloc d'instructions simple. *
-* *
-* Retour : Bloc créé ou NULL. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-#include "../../arch/instruction-int.h"
-static GInstrBlock *build_instruction_block_simple(GArchProcessor *proc, code_coverage *coverage, GArchInstruction **first, GArchInstruction *cur)
-{
- GInstrBlock *result; /* Regroupement à retourner */
-
- if (*first != NULL)
- {
- result = g_flow_block_new(proc, *first, cur);
+ /*
+ printf(" -- call %d -> %zu -> %zu\n",
+ fff,
+ get_dragon_knight_node_index(knight, node),
+ get_dragon_knight_node_index(knight, target));
+ */
- mark_range_as_processed_in_coverage(coverage, *first);
+ block = build_instruction_blocks(proc, knight, target, local_stop, converted, &id);
- *first = NULL;
+ //printf(" -> next id = %zu\n", id);
- }
- else result = NULL;
- return result;
-}
+ /* Le premier passage crée la référence */
+ if (*next == 0)
+ *next = id;
+ /**
+ * Une patte, première ou nom, peut se terminer alors que
+ * ses voisines continuent.
+ *
+ * Il y a donc plusieurs valeurs pour l'indice suivant :
+ * un nul et un strictement positif.
+ *
+ * Le cas typique est le suivant :
+ *
+ * ======
+ * / \
+ * | |
+ * ret |
+ * |
+ * ===
+ */
-/******************************************************************************
-* *
-* Paramètres : proc = ensemble des instructions d'assemblage. *
-* coverage = délimitations de la zone à couvrir. *
-* cases = branches conditionnelles des situations. *
-* next = localisation de l'instruction de reprise. *
-* *
-* Description : Procède à la définition d'un bloc d'instructions selectif. *
-* *
-* Retour : Bloc créé et enregistré, ou NULL si erreur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ else if (id > 0)
+ {
+ //printf(" NEXT :: %u vs %u\n", *next, id);
+ assert(*next == id);
+ }
-static GInstrBlock *build_instruction_blocks_case(GArchProcessor *proc, code_coverage *coverage, const branch_group *cases, vmpa2t *next)
-{
- GInstrBlock *result; /* Regroupement à retourner */
- bool has_common; /* Fin commune ? */
- size_t i; /* Boucle de parcours #1 */
- code_coverage *sub_coverage; /* Couverture pour les suivants*/
- size_t j; /* Boucle de parcours #2 */
- GInstrBlock *block; /* Nouveau bloc mis en place */
+ if (block != NULL)
+ DELAYED_BLOCK_ADDING(group, group_cached, block);
- has_common = compute_first_common_addr_in_group(cases, next);
- if (!has_common) return NULL;
+ break;
- result = g_virtual_block_new();
+ case ILT_CATCH_EXCEPTION:
+ break;
- for (i = 0; i < cases->count; i++)
- {
- sub_coverage = dup_code_coverage(coverage, get_entry_to_branch(&cases->branches[i]));
+ default:
+ //assert(false);
+ break;
- add_ending_address_code_coverage(sub_coverage, next);
+ }
- for (j = 0; j < cases->count; j++)
- add_ending_address_code_coverage(sub_coverage, get_entry_to_branch(&cases->branches[j]));
+ if (/*group != NULL || */group_cached != NULL)
+ DELAYED_BLOCK_ADDING(result, result_cached, group != NULL ? group : group_cached);
- block = build_instruction_blocks(proc, sub_coverage);
+ delete_bit_field(local_stop);
- if (block != NULL)
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+ /* On passe au noeud suivant */
- delete_code_coverage(sub_coverage);
+ if (*next == 0)
+ break;
- }
+ node = get_dragon_knight_node(knight, *next);
- if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(result)) == 0)
- {
- g_object_unref(G_OBJECT(result));
- result = NULL;
}
- return result;
+ return (result != NULL ? result : result_cached);
}
/******************************************************************************
* *
-* Paramètres : proc = ensemble des instructions d'assemblage. *
-* coverage = délimitations de la zone à couvrir. *
-* true_branch = branche conditionnelle correspondant à true. *
-* false_branch = branche conditionnelle correspondant à false. *
-* next = localisation de l'instruction de reprise. *
+* Paramètres : routine = routine en code exécutable à traiter. *
+* knight = rassemblement des complexités de code. *
* *
-* Description : Procède à la définition d'un bloc d'instruction if/then/else.*
+* Description : Procède à la définition de blocs regroupant des instructions.*
* *
-* Retour : Bloc créé et enregistré, ou NULL si erreur. *
+* Retour : Blocs créés et enregistrés, ou NULL si erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-static GInstrBlock *build_instruction_blocks_ite(GArchProcessor *proc, code_coverage *coverage, const branch_info *true_branch, const branch_info *false_branch, vmpa2t *next)
+void group_routine_instructions(GBinRoutine *routine, const dragon_knight *knight)
{
- GInstrBlock *result; /* Regroupement à retourner */
- bool has_common; /* Fin commune ? */
- GInstrBlock *block; /* Nouveau bloc mis en place */
-
- has_common = compute_first_common_addr(true_branch, false_branch, next);
-
-
- if (!has_common)
- {
- code_coverage *_sub_coverage; /* Couverture pour les suivants*/
-
-
- result = g_virtual_block_new();
-
-
- /* Branche 'true' */
-
- _sub_coverage = dup_code_coverage(coverage, get_entry_to_branch(true_branch));
-
- block = build_instruction_blocks(proc, _sub_coverage);
-
- delete_code_coverage(_sub_coverage);
-
- printf("===> !TRUE_BRANCH = %p\n", block);
-
- if (block != NULL)
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
- /* Branche 'false' */
- _sub_coverage = dup_code_coverage(coverage, get_entry_to_branch(false_branch));
-
- block = build_instruction_blocks(proc, _sub_coverage);
-
- delete_code_coverage(_sub_coverage);
+ dragon_node *nodes; /* Liste des noeuds détectés */
+ size_t count; /* Taille de cette liste */
+ dragon_node *node; /* Noeud à traiter */
+ bitfield_t *stop; /* Bloc d'arrêt de l'analyse */
+ bitfield_t *converted; /* Cartographie des traitements*/
+ GInstrBlock *blocks; /* Blocs basiques construits */
- printf("===> !FALSE_BRANCH = %p\n", block);
- if (block != NULL)
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
- /* Conclusion */
- if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(result)) == 0)
- {
- g_object_unref(G_OBJECT(result));
- result = NULL;
- }
- return result;
+ get_dragon_knight_content(knight, &nodes, &count);
+ compute_all_paths(nodes, count);
- }
- assert(has_common);
+#if 0
+ size_t k;
- if (!has_common) printf(" === nothing in common\n");
- if (!has_common) return NULL;
-
- result = g_virtual_block_new();
-
- /**
- * Encapsulation des branches conditionnelles.
- */
-
- GInstrBlock *build_instr_block_bi(GArchProcessor *proc, const code_coverage *coverage, const branch_info *br0, const branch_info *br1, const vmpa2t *next)
+ for (k = 0; k < count; k++)
{
- GInstrBlock *result; /* Bloc construit à renvoyer */
- code_coverage *sub_coverage; /* Couverture pour les suivants*/
-
- result = NULL;
-
- if (br0->count > 0)
- {
- sub_coverage = dup_code_coverage(coverage, get_entry_to_branch(br0));
-
- add_ending_address_code_coverage(sub_coverage, next);
+ GArchInstruction *first;
+ GArchInstruction *last;
+ const bitfield_t *paths;
- if (br1->count > 0)
- add_ending_address_code_coverage(sub_coverage, get_entry_to_branch(br1));
+ node = get_dragon_node(nodes, k);
- result = build_instruction_blocks(proc, sub_coverage);
+ paths = get_paths_bits(node);
- delete_code_coverage(sub_coverage);
+ get_dragon_node_bounding_instructions(node, &first, &last);
- }
- return result;
+ printf("#[ node %zu ]# @ 0x%08x / 0x%08x - mask = 0x%08lx\n", k,
+ (unsigned int)g_arch_instruction_get_range(first)->addr.virtual,
+ (unsigned int)g_arch_instruction_get_range(last)->addr.virtual,
+ gfw(paths));
}
+#endif
- /* Branche 'true' */
-
- block = build_instr_block_bi(proc, coverage, true_branch, false_branch, next);
-
- printf("===> TRUE_BRANCH = %p\n", block);
-
- if (block != NULL)
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
- /* Branche 'false' */
- block = build_instr_block_bi(proc, coverage, false_branch, true_branch, next);
- printf("===> FALSE_BRANCH = %p\n", block);
+ node = get_dragon_node(nodes, 0);
- if (block != NULL)
- g_virtual_block_add_child(G_VIRTUAL_BLOCK(result), block);
+ stop = create_bit_field(count, false);
+ converted = create_bit_field(count, false);
- /* Conclusion */
-
- if (g_virtual_block_count_children(G_VIRTUAL_BLOCK(result)) == 0)
- {
- g_object_unref(G_OBJECT(result));
- result = NULL;
- }
-
- return result;
+ blocks = build_instruction_blocks(NULL, knight, node, stop, converted, (size_t []) { 0 });
-}
+ delete_bit_field(stop);
-/******************************************************************************
-* *
-* Paramètres : result = liste générale résultante du découpage. [OUT] *
-* cached = emplacement pour le cache des résultats. [OUT] *
-* proc = ensemble des instructions d'assemblage. *
-* coverage = délimitations de la zone à couvrir. *
-* exceptions = branche conditionnelle correspondant à true. *
-* main_branch = branche principale avec son flot d'exécution. *
-* *
-* Description : Procède à la définition d'un bloc d'instructions d'exception.*
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-static void add_instruction_blocks_except(GInstrBlock **result, GInstrBlock **cached, GArchProcessor *proc, code_coverage *coverage, const branch_group *exceptions, const branch_info *main_branch)
-{
- size_t i; /* Boucle de parcours */
- vmpa2t stop_addr; /* Adresse de fin de bloc */
- bool has_stop; /* Fin commune ? */
- code_coverage *sub_coverage; /* Couverture pour les suivants*/
- GInstrBlock *block; /* Nouveau bloc mis en place */
- for (i = 0; i < exceptions->count; i++)
+#if 0
+ bool visit_block(GInstrBlock *blk, BlockVisitOrder order, int *indent)
{
- has_stop = compute_first_common_addr(main_branch, &exceptions->branches[i], &stop_addr);
- if (!has_stop) continue;
-
- sub_coverage = dup_code_coverage(coverage, get_entry_to_branch(&exceptions->branches[i]));
- add_ending_address_code_coverage(sub_coverage, &stop_addr);
-
- block = build_instruction_blocks(proc, sub_coverage);
+ int i;
- if (block != NULL)
- DELAYED_BLOCK_ADDING(*result, *cached, block);
-
- delete_code_coverage(sub_coverage);
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : proc = ensemble des instructions d'assemblage. *
-* coverage = délimitations de la zone à couvrir. *
-* *
-* Description : Procède à la définition de bloc regroupant des instructions. *
-* *
-* Retour : Bloc créé et enregistré, ou NULL si erreur. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-#include "../../arch/instruction-int.h"
-static GInstrBlock *build_instruction_blocks(GArchProcessor *proc, code_coverage *coverage)
-{
- GInstrBlock *result; /* Regroupement à retourner */
- GInstrBlock *result_cached; /* Temporisation pour unicité */
- branch_info main_branch; /* Flot d'exécution complet */
- GArchInstruction *first; /* Première instruction */
- GArchInstruction *last; /* Dernière instruction */
- GArchInstruction *iter; /* Boucle de parcours */
- const mrange_t *range; /* Emplacement d'instruction */
- const vmpa2t *addr; /* Adresse de la destination */
- GArchInstruction **dests; /* Instr. visée par une autre */
- InstructionLinkType *types; /* Type de lien entre lignes */
- size_t dcount; /* Nombre de liens de dest. */
- size_t i; /* Boucle de parcours #1 */
- GInstrBlock *block; /* Nouveau bloc mis en place */
- GInstrBlock *group; /* Regroupement de blocs */
- size_t not_handled; /* Quantité de liens non gérés */
- vmpa2t next_addr; /* Prochaine instruction visée */
- branch_group cases_branches; /* Branches d'un aiguillage */
- branch_info true_branch; /* Branche 'condition vraie' */
- branch_info false_branch; /* Branche 'condition fausse' */
- branch_group excep_branches; /* Branches d'exceptions */
- branch_info *branch; /* Branche à suivre */
-
- result = NULL;
- result_cached = NULL;
-
- first = NULL;
- last = NULL;
-
- init_branch_info(&main_branch);
- find_next_hops(proc, get_code_coverage_start_addr(coverage), coverage, &main_branch);
-
-
- printf("//////////////////////////\n");
- printf("/// Cutting for 0x%08x -> %p\n",
- get_code_coverage_start_addr(coverage)->virtual,
- g_arch_processor_find_instr_by_address(proc, get_code_coverage_start_addr(coverage)));
- printf("//////////////////////////\n");
-
-
- for (iter = g_arch_processor_find_instr_by_address(proc, get_code_coverage_start_addr(coverage));
- iter != NULL;
- )
- {
- range = g_arch_instruction_get_range(iter);
- addr = get_mrange_addr(range);
-
- if (code_coverage_stop_here(coverage, addr)) break;
-
- /* On s'arrête si l'instruction est déjà décompilée */
- if (is_range_processed_in_coverage(coverage, range)) break;
-
- if (first == NULL)
- first = iter;
-
- last = iter;
-
- /**
- * On s'arrête également en fin de procédure.
- * L'expérience montre qu'il peut y avoir plusieurs fins dans une routine,
- * et donc des fins en milieu de couverture de cette même routine.
- */
- if (g_arch_instruction_get_flags(iter) & AIF_RETURN_POINT) break;
-
- /* On n'approfondit que les chemins qui se séparent */
- if (!g_arch_instruction_has_destinations(iter))
+ switch (order)
{
- iter = g_arch_processor_get_next_instr(proc, iter);
- continue;
- }
-
- /* Adaptations en fonction du type de bifurcation */
+ case BVO_IN:
+ case BVO_PENDING:
- dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL);
+ for (i = 0; i < *indent; i++)
+ printf(" ");
- not_handled = 0;
- init_vmpa(&next_addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+ printf("%p '%s'", blk, G_OBJECT_TYPE_NAME(blk));
- init_branch_group(&cases_branches);
- init_branch_info(&true_branch);
- init_branch_info(&false_branch);
- init_branch_group(&excep_branches);
-
- for (i = 0; i < dcount; i++)
- {
- branch = NULL;
-
- switch (types[i])
+ if (G_IS_FLOW_BLOCK(blk))
{
- case ILT_EXEC_FLOW:
- case ILT_JUMP:
-
-
- //break;
- {
- GArchInstruction *_saved0;
-
- _saved0 = first;
-
- block = build_instruction_block_simple(proc, coverage, &first, iter);
- printf(" -- simple block JMP -- @ 0x%08x <-> 0x%08x\n",
- (unsigned int)(_saved0 ? _saved0->range.addr.virtual : ~0),
- (unsigned int)iter->range.addr.virtual);
- fflush(NULL);
- }
- DELAYED_BLOCK_ADDING(result, result_cached, block);
-
- /**
- * La prochaine adresse d'analyse est celle visée par l'instruction !
- * Pour les sauts naturels, ça ne change rien ; ce n'est pas le cas
- * pour les sauts explicites.
- */
- range = g_arch_instruction_get_range(dests[i]);
- copy_vmpa(&next_addr, get_mrange_addr(range));
-
- first = NULL;
-
- break;
-
- case ILT_LOOP:
- /**
- * Lorsque l'on désassemble un flot d'instructions et que l'on rencontre
- * une amorce de boucle, il y a deux cas de figure :
- *
- * - soit il s'agit d'un ancien JUMP, et la reprise du désassemblage
- * se fera à partir de l'adresse ciblée.
- *
- * - soit il s'agit d'un branchement conditionnel dont une des branches
- * conduit à un rebouclage. Le désassemblage s'arrête alors pour la
- * partie en boucle car il n'y a plus d'adresse commune pour la suite.
- *
- * Il reste donc à forcer une coupure dans le cas suivant :
- *
- * ...
- * jmp xxxx
- * loc:
- * ...
- *
- * Il suffit de ne pas initialiser 'next_addr' et de laisser la main à d'éventuelles
- * autres destinations voisines.
- */
- break;
-
- case ILT_CASE_JUMP:
- branch = extend_branch_group(&cases_branches);
- break;
-
- case ILT_JUMP_IF_TRUE:
- printf("FIND TRUE BRANCH @ 0x%08x\n", (unsigned int)iter->range.addr.virtual);
- branch = &true_branch;
- break;
-
- case ILT_JUMP_IF_FALSE:
- printf("FIND FALSE BRANCH @ 0x%08x\n", (unsigned int)iter->range.addr.virtual);
- branch = &false_branch;
- break;
-
- case ILT_CATCH_EXCEPTION:
- branch = extend_branch_group(&excep_branches);
-
- /**
- * Les deux cas sont les seuls à ne pas conduire à une définition de
- * next_addr, donc on les comptabilise sur un pied d'égalité !
- */
- /* break; */
+ vmpa2t start;
+ vmpa2t end;
- default:
- not_handled++;
- break;
+ g_flow_block_get_boundary_addresses(G_FLOW_BLOCK(blk), &start, &end);
- }
-
- /* Si on a une branche à compléter... */
- if (branch != NULL)
- {
- range = g_arch_instruction_get_range(dests[i]);
- addr = get_mrange_addr(range);
-
- printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
- printf("BUILD @ 0x%08x\n", (unsigned int)addr->virtual);
- find_next_hops(proc, addr, coverage, branch);
- printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
+ printf(" 0x%08x -> 0x%08x",
+ (unsigned int)start.virtual,
+ (unsigned int)end.virtual);
}
- }
-
- /* Post-traitements de ILT_CASE_JUMP */
- if (cases_branches.count > 0)
- {
- block = build_instruction_block_simple(proc, coverage, &first, iter);
- DELAYED_BLOCK_ADDING(result, result_cached, block);
+ printf("\n");
- group = build_instruction_blocks_case(proc, coverage, &cases_branches, &next_addr);
-
- if (group != NULL)
- {
- DELAYED_BLOCK_ADDING(result, result_cached, group);
- g_instr_block_set_links_block(block, group);
- }
-
- }
-
- /* Post-traitements de ILT_JUMP_IF_TRUE / ILT_JUMP_IF_FALSE */
- else if (true_branch.count > 0 || false_branch.count > 0)
- {
- block = build_instruction_block_simple(proc, coverage, &first, iter);
-
- GArchInstruction *_saved1;
-
- _saved1 = first;
-
-
-
- printf(" -- branches -- %d vs %d\n", (int)true_branch.count, (int)false_branch.count);
-
- printf(" -- simple block ITE -- @ 0x%08x <-> 0x%08x\n",
- (unsigned int)(_saved1 ? _saved1->range.addr.virtual : ~0),
- (unsigned int)iter->range.addr.virtual);
- fflush(NULL);
- DELAYED_BLOCK_ADDING(result, result_cached, block);
-
- group = build_instruction_blocks_ite(proc, coverage, &true_branch, &false_branch, &next_addr);
-
- printf(" --> group = %p - next = 0x%08x\n", group, next_addr.virtual);
-
- if (group != NULL)
- {
- DELAYED_BLOCK_ADDING(result, result_cached, group);
- g_instr_block_set_links_block(block, group);
- }
-
- }
-
- /* Post-traitements de ILT_CATCH_EXCEPTION */
- if (excep_branches.count > 0)
- {
- block = build_instruction_block_simple(proc, coverage, &first, iter);
- if (block != NULL) DELAYED_BLOCK_ADDING(result, result_cached, block);
+ if (order == BVO_IN) (*indent)++;
+ break;
- add_instruction_blocks_except(&result, &result_cached, proc, coverage,
- &excep_branches, &main_branch);
+ case BVO_OUT:
+ (*indent)--;
+ break;
}
- clean_branch_group(&cases_branches);
- clean_branch_info(&true_branch);
- clean_branch_info(&false_branch);
- clean_branch_group(&excep_branches);
-
- /* Détermination du prochain point de chute */
-
- if (not_handled == dcount)
- iter = g_arch_processor_get_next_instr(proc, iter);
- else
- iter = g_arch_processor_find_instr_by_address(proc, &next_addr);
-
- }
-
- if (first != NULL && last != NULL)
- {
- range = g_arch_instruction_get_range(first);
-
- if (!is_range_processed_in_coverage(coverage, range))
- {
- block = build_instruction_block_simple(proc, coverage, &first, last);
- DELAYED_BLOCK_ADDING(result, result_cached, block);
- }
+ return true;
}
- clean_branch_info(&main_branch);
-
- return (result != NULL ? result : result_cached);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : proc = processeur rassemblant les instructions à relier.*
-* routines = prototypes existants à insérer. *
-* count = quantité de ces prototypes. *
-* statusbar = barre de statut avec progression à mettre à jour.*
-* id = identifiant du message affiché à l'utilisateur. *
-* *
-* Description : Regroupe les instructions par blocs. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void group_routines_instructions(GArchProcessor *proc, GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, bstatus_id_t id)
-{
- size_t i; /* Boucle de parcours */
- const mrange_t *range; /* Emplacement de routine */
- code_coverage *coverage; /* Couverture de zone de code */
- GInstrBlock *block; /* Regroupement d'instructions */
-
- for (i = 0; i < count; i++)
- {
- range = g_binary_routine_get_range(routines[i]);
-
- printf("===== BLOCK(S) for 0x%08x ======\n", range->addr.virtual);
-
- coverage = create_code_coverage(range);
-
- block = build_instruction_blocks(proc, coverage);
-
-
- if (block == NULL) continue;
-
-
- g_binary_routine_set_basic_blocks(routines[i], block);
-
-
- bool visit_block(GInstrBlock *blk, BlockVisitOrder order, int *indent)
- {
- int i;
-
- switch (order)
- {
- case BVO_IN:
- case BVO_PENDING:
-
- for (i = 0; i < *indent; i++)
- printf(" ");
-
- printf("%p '%s'", blk, G_OBJECT_TYPE_NAME(blk));
-
- if (G_IS_FLOW_BLOCK(blk))
- {
- vmpa2t start;
- vmpa2t end;
-
- g_flow_block_get_boundary_addresses(G_FLOW_BLOCK(blk), &start, &end);
-
- printf(" 0x%08x -> 0x%08x",
- (unsigned int)start.virtual,
- (unsigned int)end.virtual);
-
- }
-
- printf("\n");
-
- if (order == BVO_IN) (*indent)++;
- break;
-
- case BVO_OUT:
- (*indent)--;
- break;
-
- }
-
- return true;
-
- }
-
- g_instr_block_visit(block, (instr_block_visitor_cb)visit_block, (int []){ 0 });
-
- printf("\n");
+ g_instr_block_visit(blocks, (instr_block_visitor_cb)visit_block, (int []){ 0 });
+ printf("\n");
+#endif
- delete_code_coverage(coverage);
+ //if (blocks != NULL)
- gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
- }
+ g_binary_routine_set_basic_blocks(routine, blocks);
}
diff --git a/src/analysis/disass/macro.h b/src/analysis/disass/macro.h
index 2c03520..e607260 100644
--- a/src/analysis/disass/macro.h
+++ b/src/analysis/disass/macro.h
@@ -25,14 +25,13 @@
#define _ANALYSIS_DISASS_MACRO_H
+#include "dragon.h"
#include "../routine.h"
-#include "../../arch/instruction.h"
-#include "../../gtkext/gtkextstatusbar.h"
-/* Regroupe les instructions par blocs. */
-void group_routines_instructions(GArchProcessor *, GBinRoutine **, size_t, GtkExtStatusBar *, bstatus_id_t);
+/* Procède à la définition de blocs regroupant des instructions. */
+void group_routine_instructions(GBinRoutine *, const dragon_knight *);
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index 51b0a04..dce5497 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -232,6 +232,11 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form
line = g_arch_instruction_print(iter, buffer, msize, content, ASX_INTEL);
+
+ if (g_arch_instruction_get_flags(iter) & AIF_RETURN_POINT)
+ g_buffer_line_add_flag(line, BLF_BOOKMARK);
+
+
if (sym_index < sym_count)
{
iaddr = get_mrange_addr(g_arch_instruction_get_range(iter));
diff --git a/src/analysis/disass/rank.c b/src/analysis/disass/rank.c
index 2ad1cdf..9b9f29e 100644
--- a/src/analysis/disass/rank.c
+++ b/src/analysis/disass/rank.c
@@ -177,11 +177,7 @@ static bool rank_flow_block(GFlowBlock *block, BlockVisitOrder order, const GIns
/******************************************************************************
* *
-* Paramètres : list = ensemble d'instructions à relier. *
-* routines = prototypes existants à insérer. *
-* count = quantité de ces prototypes. *
-* statusbar = barre de statut avec progression à mettre à jour.*
-* id = identifiant du message affiché à l'utilisateur. *
+* Paramètres : routine = routine regroupant les blocs à traiter. *
* *
* Description : Classe les blocs des routines. *
* *
@@ -191,24 +187,22 @@ static bool rank_flow_block(GFlowBlock *block, BlockVisitOrder order, const GIns
* *
******************************************************************************/
-void rank_routines_blocks(GBinRoutine **routines, size_t count, GtkExtStatusBar *statusbar, bstatus_id_t id)
+void rank_routine_blocks(GBinRoutine *routine)
{
- size_t i; /* Boucle de parcours */
GInstrBlock *main_block; /* Ensemble des blocs d'instr. */
- for (i = 0; i < count; i++)
- {
- main_block = g_binary_routine_get_basic_blocks(routines[i]);
+ main_block = g_binary_routine_get_basic_blocks(routine);
- if (main_block == NULL) continue;
+ if (main_block == NULL) return;
- g_instr_block_visit(main_block, (instr_block_visitor_cb)rank_flow_block, main_block);
+ g_instr_block_visit(main_block, (instr_block_visitor_cb)rank_flow_block, main_block);
+#if 0
- printf("===== BLOCK(S) xXXx ======\n");
+ printf("===== BLOCK(S) xXXx ======\n");
bool visit_ranked_block(GInstrBlock *blk, BlockVisitOrder order, int *indent)
@@ -259,16 +253,9 @@ void rank_routines_blocks(GBinRoutine **routines, size_t count, GtkExtStatusBar
printf("\n");
+#endif
-
-
-
-
-
-
- }
-
}
diff --git a/src/analysis/disass/rank.h b/src/analysis/disass/rank.h
index a4c62bb..182885e 100644
--- a/src/analysis/disass/rank.h
+++ b/src/analysis/disass/rank.h
@@ -26,12 +26,11 @@
#include "../routine.h"
-#include "../../gtkext/gtkextstatusbar.h"
/* Classe les blocs des routines. */
-void rank_routines_blocks(GBinRoutine **, size_t, GtkExtStatusBar *, bstatus_id_t);
+void rank_routine_blocks(GBinRoutine *);
diff --git a/src/analysis/disass/routines.c b/src/analysis/disass/routines.c
new file mode 100644
index 0000000..280757a
--- /dev/null
+++ b/src/analysis/disass/routines.c
@@ -0,0 +1,278 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * routines.c - étude des flots d'exécution dans les routines
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "routines.h"
+
+
+#include "dragon.h"
+#include "loop.h"
+#include "macro.h"
+#include "rank.h"
+#include "../../glibext/delayed-int.h"
+
+
+
+/* Fraction de routines à limiter (instance) */
+struct _GRoutinesStudy
+{
+ GDelayedWork parent; /* A laisser en premier */
+
+ const GArchProcessor *proc; /* Processeurs avec ses instr. */
+
+ mrange_t *exe_ranges; /* Liste de zones exécutables */
+ size_t exe_count; /* Nombre de ces zones */
+
+ GBinRoutine **routines; /* Liste de routines à traiter */
+ size_t count; /* Taille de cette liste */
+ size_t begin; /* Point de départ du parcours */
+ size_t end; /* Point d'arrivée exclu */
+
+ activity_id_t id; /* Identifiant pour messages */
+
+};
+
+/* Fraction de routines à limiter (classe) */
+struct _GRoutinesStudyClass
+{
+ GDelayedWorkClass parent; /* A laisser en premier */
+
+};
+
+
+/* Indique le type défini pour les tâches d'étude de routines. */
+GType g_routines_study_get_type(void);
+
+/* Initialise la classe des tâches d'étude de routines. */
+static void g_routines_study_class_init(GRoutinesStudyClass *);
+
+/* Initialise une tâche d'étude de routines. */
+static void g_routines_study_init(GRoutinesStudy *);
+
+/* Supprime toutes les références externes. */
+static void g_routines_study_dispose(GRoutinesStudy *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_routines_study_finalize(GRoutinesStudy *);
+
+/* Assure l'étude des routines en différé. */
+static void g_routines_study_process(GRoutinesStudy *, GtkStatusStack *);
+
+
+
+/* Indique le type défini pour les tâches d'étude de routines. */
+G_DEFINE_TYPE(GRoutinesStudy, g_routines_study, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des tâches d'étude de routines. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_routines_study_class_init(GRoutinesStudyClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GDelayedWorkClass *work; /* Version en classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_routines_study_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_routines_study_finalize;
+
+ work = G_DELAYED_WORK_CLASS(klass);
+
+ work->run = (run_task_fc)g_routines_study_process;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : computing = instance à initialiser. *
+* *
+* Description : Initialise une tâche d'étude de routines. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_routines_study_init(GRoutinesStudy *study)
+{
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : computing = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_routines_study_dispose(GRoutinesStudy *computing)
+{
+ G_OBJECT_CLASS(g_routines_study_parent_class)->dispose(G_OBJECT(computing));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : computing = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_routines_study_finalize(GRoutinesStudy *computing)
+{
+ G_OBJECT_CLASS(g_routines_study_parent_class)->finalize(G_OBJECT(computing));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : proc = ensemble d'instructions désassemblées. *
+* routines = prototypes existants à insérer. *
+* count = quantité de ces prototypes. *
+* begin = point de départ du parcours de liste. *
+* end = point d'arrivée exclu du parcours. *
+* id = identifiant du message affiché à l'utilisateur. *
+* *
+* Description : Crée une tâche d'étude de routines différée. *
+* *
+* Retour : Tâche créée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GRoutinesStudy *g_routines_study_new(const GArchProcessor *proc, mrange_t *exe_ranges, size_t exe_count, GBinRoutine **routines, size_t count, size_t begin, size_t end, activity_id_t id)
+{
+ GRoutinesStudy *result; /* Tâche à retourner */
+
+ result = g_object_new(G_TYPE_ROUTINES_STUDY, NULL);
+
+ result->proc = proc;
+
+ result->exe_ranges = exe_ranges;
+ result->exe_count = exe_count;
+
+ result->routines = routines;
+ result->count = count;
+ result->begin = begin;
+ result->end = end;
+
+ result->id = id;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : study = étude de routines à mener. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Assure l'étude des routines en différé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_routines_study_process(GRoutinesStudy *study, GtkStatusStack *status)
+{
+ size_t i; /* Boucle de parcours */
+ GBinRoutine *routine; /* Routine en traitement */
+ const mrange_t *range; /* Couverture d'une routine */
+ const vmpa2t *start; /* Adresse de départ */
+ const instr_coverage *coverage; /* Instructions couvertes */
+ dragon_knight *knight; /* Complexité de code posée */
+ //dragon_node *nodes; /* Liste des noeuds détectés */
+ //size_t count; /* Taille de cette liste */
+
+ for (i = study->begin; i < study->end; i++)
+ {
+ //gtk_extended_status_bar_update_activity(statusbar, id, (i + 1) * 1.0 / count);
+
+ routine = study->routines[i];
+
+ /* Préparatifs communs */
+
+ range = g_binary_routine_get_range(routine);
+ start = get_mrange_addr(range);
+
+ coverage = g_arch_processor_find_coverage_by_address(study->proc, start);
+
+ knight = begin_dragon_knight(study->proc, coverage, range, start);
+
+
+
+
+ detect_loops_in_code(knight);
+
+
+
+ /* Phase AAAA : regroupement des instructions par blocs */
+
+
+
+
+ group_routine_instructions(routine, knight);
+
+
+
+
+
+ rank_routine_blocks(routine);
+
+
+
+ /* Nettoyage final */
+
+ end_dragon_knight(knight);
+
+ }
+
+}
diff --git a/src/analysis/disass/routines.h b/src/analysis/disass/routines.h
new file mode 100644
index 0000000..7e01928
--- /dev/null
+++ b/src/analysis/disass/routines.h
@@ -0,0 +1,55 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * routines.h - prototypes pour l'étude des flots d'exécution dans les routines
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * OpenIDA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenIDA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_DISASS_ROUTINES_H
+#define _ANALYSIS_DISASS_ROUTINES_H
+
+
+#include "../routine.h"
+#include "../../arch/processor.h"
+#include "../../format/executable.h"
+#include "../../gtkext/gtkstatusstack.h"
+
+
+
+#define G_TYPE_ROUTINES_STUDY g_routines_study_get_type()
+#define G_ROUTINES_STUDY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_routines_study_get_type(), GRoutinesStudy))
+#define G_IS_ROUTINES_STUDY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_routines_study_get_type()))
+#define G_ROUTINES_STUDY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ROUTINES_STUDY, GRoutinesStudyClass))
+#define G_IS_ROUTINES_STUDY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ROUTINES_STUDY))
+#define G_ROUTINES_STUDY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ROUTINES_STUDY, GRoutinesStudyClass))
+
+
+/* Fraction de routines à limiter (instance) */
+typedef struct _GRoutinesStudy GRoutinesStudy;
+
+/* Fraction de routines à limiter (classe) */
+typedef struct _GRoutinesStudyClass GRoutinesStudyClass;
+
+
+/* Crée une tâche d'étude de routines différée. */
+GRoutinesStudy *g_routines_study_new(const GArchProcessor *, mrange_t *, size_t, GBinRoutine **, size_t, size_t, size_t, activity_id_t);
+
+
+
+#endif /* _ANALYSIS_DISASS_ROUTINES_H */
diff --git a/src/common/bits.c b/src/common/bits.c
index 90cb098..925c1b7 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -52,7 +52,7 @@ struct _bitfield_t
static bitfield_t *_create_bit_field(size_t, bool, size_t);
/* Crée une copie de champ de bits initialisé à zéro. */
-static bitfield_t *_create_bit_field_from(const bitfield_t *, size_t);
+static bitfield_t *_create_bit_field_from(const bitfield_t *, bool, size_t);
/* Crée une copie d'un champ de bits classique. */
static bitfield_t *_dup_bit_field(const bitfield_t *, size_t);
@@ -113,7 +113,7 @@ static bitfield_t *_create_bit_field(size_t length, bool state, size_t extra)
* Paramètres : length = nom de bits du champ à représenter. *
* state = état initial de chaque des bits. *
* *
-* Description : Crée un champ de bits initialisé à zéro. *
+* Description : Crée un champ de bits initialisé. *
* *
* Retour : Champ de bits mis en place. *
* *
@@ -130,8 +130,9 @@ bitfield_t *create_bit_field(size_t length, bool state)
/******************************************************************************
* *
-* extra = espace mémoire supplémentaire à ajouter au final. *
-* Paramètres : length = nom de bits du champ à représenter. *
+* Paramètres : field = champde bits à prendre pour modèle. *
+* state = état initial de chaque des bits. *
+* extra = espace mémoire supplémentaire à ajouter au final. *
* *
* Description : Crée une copie de champ de bits initialisé à zéro. *
* *
@@ -141,16 +142,17 @@ bitfield_t *create_bit_field(size_t length, bool state)
* *
******************************************************************************/
-static bitfield_t *_create_bit_field_from(const bitfield_t *field, size_t extra)
+static bitfield_t *_create_bit_field_from(const bitfield_t *field, bool state, size_t extra)
{
- return _create_bit_field(field->length, false, extra);
+ return _create_bit_field(field->length, state, extra);
}
/******************************************************************************
* *
-* Paramètres : length = nom de bits du champ à représenter. *
+* Paramètres : field = champde bits à prendre pour modèle. *
+* state = état initial de chaque des bits. *
* *
* Description : Crée une copie de champ de bits initialisé à zéro. *
* *
@@ -160,9 +162,9 @@ static bitfield_t *_create_bit_field_from(const bitfield_t *field, size_t extra)
* *
******************************************************************************/
-bitfield_t *create_bit_field_from(const bitfield_t *field)
+bitfield_t *create_bit_field_from(const bitfield_t *field, bool state)
{
- return _create_bit_field_from(field, 0);
+ return _create_bit_field_from(field, state, 0);
}
@@ -594,7 +596,7 @@ memfield_t *create_mem_field_from(const memfield_t *field)
{
bitfield_t *result; /* Création à retourner */
- result = _create_bit_field_from((bitfield_t *)field, sizeof(vmpa2t));
+ result = _create_bit_field_from((bitfield_t *)field, false, sizeof(vmpa2t));
copy_vmpa((vmpa2t *)result->tail, (vmpa2t *)field->tail);
diff --git a/src/common/bits.h b/src/common/bits.h
index 6d8ea5b..f2e1399 100644
--- a/src/common/bits.h
+++ b/src/common/bits.h
@@ -36,11 +36,11 @@
typedef struct _bitfield_t bitfield_t;
-/* Crée un champ de bits initialisé à zéro. */
+/* Crée un champ de bits initialisé. */
bitfield_t *create_bit_field(size_t, bool);
/* Crée une copie de champ de bits initialisé à zéro. */
-bitfield_t *create_bit_field_from(const bitfield_t *);
+bitfield_t *create_bit_field_from(const bitfield_t *, bool);
/* Supprime de la mémoire un champ de bits donné. */
void delete_bit_field(bitfield_t *);