diff options
Diffstat (limited to 'src/analysis')
-rw-r--r-- | src/analysis/blocks/flow.c | 6 | ||||
-rw-r--r-- | src/analysis/disass/Makefile.am | 3 | ||||
-rw-r--r-- | src/analysis/disass/disassembler.c | 114 | ||||
-rw-r--r-- | src/analysis/disass/dragon.c | 214 | ||||
-rw-r--r-- | src/analysis/disass/dragon.h | 20 | ||||
-rw-r--r-- | src/analysis/disass/loop.c | 389 | ||||
-rw-r--r-- | src/analysis/disass/loop.h | 6 | ||||
-rw-r--r-- | src/analysis/disass/macro.c | 1542 | ||||
-rw-r--r-- | src/analysis/disass/macro.h | 7 | ||||
-rw-r--r-- | src/analysis/disass/output.c | 5 | ||||
-rw-r--r-- | src/analysis/disass/rank.c | 29 | ||||
-rw-r--r-- | src/analysis/disass/rank.h | 3 | ||||
-rw-r--r-- | src/analysis/disass/routines.c | 278 | ||||
-rw-r--r-- | src/analysis/disass/routines.h | 55 |
14 files changed, 936 insertions, 1735 deletions
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 */ |