diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2015-10-15 19:18:31 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2015-10-15 19:18:31 (GMT) |
commit | 83dccba3a9b6c18d6fe7b6f30794a16336803962 (patch) | |
tree | 982e6ec5d7eae20020315936cbfbd9494bc9111e /src/analysis | |
parent | c9449c389834c580196527c4e1cb010a701e7a32 (diff) |
Detected loops as introduced in the book "Compilers: Principles, Techniques, and Tools".
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@596 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src/analysis')
-rw-r--r-- | src/analysis/disass/area.c | 6 | ||||
-rw-r--r-- | src/analysis/disass/loop.c | 595 |
2 files changed, 600 insertions, 1 deletions
diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c index b45e7fc..de2c742 100644 --- a/src/analysis/disass/area.c +++ b/src/analysis/disass/area.c @@ -554,6 +554,8 @@ bool load_code_from_mem_area(mem_area **list, size_t *count, size_t *index, cons diff = compute_vmpa_diff(&prev, &pos); + assert(diff == 4 || diff == 2); /* FIXME */ + init_mrange(&range, &prev, diff); g_arch_instruction_set_range(instr, &range); @@ -840,7 +842,7 @@ void fill_mem_area(mem_area **list, size_t *count, size_t *index, const GLoadedB copy_vmpa(&start, get_mrange_addr(&area->range)); advance_vmpa(&start, i); - if (area->exec && get_virt_addr(&start) % 2 == 0) + if (area->exec && get_virt_addr(&start) % 4/*2 - FIXME */ == 0) { refresh = load_code_from_mem_area(list, count, index, binary, ctx, &start, info); @@ -1396,6 +1398,8 @@ static bool insert_extra_symbol_into_mem_areas(mem_area **list, size_t *count, G /* Si le symbole est construit avec une localisation partielle, on complète ! */ if (get_phy_addr(&sym_pos) == VMPA_NO_PHYSICAL || get_virt_addr(&sym_pos) == VMPA_NO_VIRTUAL) { + assert(false); + diff = compute_vmpa_diff(&area_pos, &sym_pos); copy_vmpa(&sym_pos, &area_pos); diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c index 5f97981..d9a3f2d 100644 --- a/src/analysis/disass/loop.c +++ b/src/analysis/disass/loop.c @@ -24,6 +24,592 @@ #include "loop.h" +#include <assert.h> +#include <malloc.h> + + +#include "../../common/bits.h" + + + +/* Description de noeud, en référence à "Compilers: Principles, Techniques, and Tools" */ +typedef struct _dragon_node +{ + GArchInstruction *first; /* Arrivée d'un lien (début) */ + GArchInstruction *last; /* Départ d'un lien (fin) */ + + bitfield_t *bits; /* Représentation par masque */ + +} dragon_node; + + +/* Définition des blocs d'allocation */ +#define NODE_ALLOC_SIZE 100 + + +/* Dénombre le nombre de noeuds présents dans une routine. */ +static dragon_node *create_dragon_nodes(const GArchProcessor *, const instr_coverage *, const mrange_t *, const vmpa2t *, size_t *); + +/* Termine l'initialisation de noeuds trouvés dans une routine. */ +static void define_mask_for_nodes(dragon_node *, size_t); + +/* Supprime de la mémoire tous les noeuds détectés. */ +static void delete_dragon_nodes(dragon_node *, size_t); + +/* Recherche un noeud selon son intruction de départ. */ +static dragon_node *find_node_for_instruction(dragon_node *, size_t, bool, const GArchInstruction *); + +/* Détermine toute la chaîne hiérarchique de domination. */ +static void compute_all_dominators(dragon_node *, size_t); + +/* 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 *); + + + +/****************************************************************************** +* * +* 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. * +* count = taille de la liste de noeuds retournés. [OUT] * +* * +* Description : Dénombre le nombre de noeuds présents dans une routine. * +* * +* Retour : Liste de noeuds initialisés de façon incomplète. * +* * +* Remarques : - * +* * +******************************************************************************/ + +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 */ + GArchInstruction *last; /* Mémorisation du passé */ + GArchInstruction *iter; /* Boucle de parcours */ + const mrange_t *irange; /* Emplacement d'instruction */ + InstructionLinkType *types; /* Type de lien entre instr. */ + size_t scount; /* Nombre de liens de dest. */ + size_t i; /* Boucle de parcours */ + dragon_node *new; /* Nouvel élément à créer */ + + result = NULL; + *count = 0; + + allocated = 0; + + for (last = NULL, iter = g_arch_processor_find_covered_instr_by_address(proc, coverage, start); + iter != NULL; + last = iter, 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; + + /* Analyse des sources */ + + if (result == NULL) + { + (*count)++; + + if (*count >= allocated) + { + allocated += NODE_ALLOC_SIZE; + result = (dragon_node *)realloc(result, allocated * sizeof(dragon_node)); + } + + new = &result[*count - 1]; + + new->first = iter; + + } + else + { + scount = g_arch_instruction_get_sources(iter, NULL, &types); + if (scount == 0) continue; + + for (i = 0; i < scount; 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: + + if (*count > 0) + result[*count - 1].last = last; + + (*count)++; + i = scount; + + if (*count >= allocated) + { + allocated += NODE_ALLOC_SIZE; + result = (dragon_node *)realloc(result, allocated * sizeof(dragon_node)); + } + + new = &result[*count - 1]; + + new->first = iter; + + break; + + default: + break; + + } + + } + + } + + if (*count > 0) + result[*count - 1].last = last; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : nodes = liste de noeuds détectés dans une routine. * +* count = taille de cette liste de noeuds à traiter. * +* * +* Description : Termine l'initialisation de noeuds trouvés dans une routine. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void define_mask_for_nodes(dragon_node *nodes, size_t count) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < count; i++) + nodes[i].bits = create_bit_field(count, i > 0); + + set_in_bit_field(nodes[0].bits, 0, 1); + +} + + +/****************************************************************************** +* * +* Paramètres : nodes = liste de noeuds détectés dans une routine. * +* count = taille de cette liste de noeuds à traiter. * +* * +* Description : Supprime de la mémoire tous les noeuds détectés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +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].bits); + + free(nodes); + +} + + +/****************************************************************************** +* * +* Paramètres : nodes = liste de noeuds détectés dans une routine. * +* count = taille de cette liste de noeuds à parcourir. * +* 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 : - * +* * +******************************************************************************/ + +static dragon_node *find_node_for_instruction(dragon_node *nodes, size_t count, bool final, const GArchInstruction *instr) +{ + dragon_node *result; /* Résultat des recherches */ + const mrange_t *irange; /* Emplacement d'instruction */ + + int find_node_from_range(const mrange_t *range, const dragon_node *node) + { + int status; /* Bilan à retourner */ + const mrange_t *nrange; /* Emplacement de noeud */ + + nrange = g_arch_instruction_get_range(final ? node->last : node->first); + + status = cmp_mrange(range, nrange); + + return status; + + } + + irange = g_arch_instruction_get_range(instr); + + result = bsearch(irange, nodes, count, sizeof(dragon_node), (__compar_fn_t)find_node_from_range); + + return result; + +} + + +/****************************************************************************** +* * +* 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 : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void compute_all_dominators(dragon_node *nodes, size_t count) +{ + bitfield_t *inter; /* Intersection de dominations */ + bool changed; /* Note un changement qq part */ + size_t k; /* Boucle de parcours #1 */ + dragon_node *node; /* Noeud à traiter */ + dragon_node *predecessor; /* Noeud prédécesseur direct */ + GArchInstruction **srcs; /* Instructions d'origine */ + InstructionLinkType *types; /* Type de lien entre instr. */ + size_t scount; /* Nombre de liens de source */ + size_t i; /* Boucle de parcours #2 */ + + inter = create_bit_field(count, false); + + do + { + changed = false; + + for (k = 1; k < count; k++) + { + node = &nodes[k]; + + set_all_in_bit_field(inter); + + scount = g_arch_instruction_get_sources(node->first, &srcs, &types); + assert(scount > 0); + + for (i = 0; i < scount; 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: + + 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; + + and_bit_field(inter, predecessor->bits); + break; + + default: + break; + + } + + set_in_bit_field(inter, k, 1); + + if (!is_bit_field_equal_to(node->bits, inter)) + { + copy_bit_field(node->bits, inter); + changed = true; + } + + } + + } + while (changed); + + delete_bit_field(inter); + +} + + + +/****************************************************************************** +* * +* Paramètres : nodes = liste de noeuds détectés dans une routine. * +* count = taille de cette liste de noeuds à traiter. * +* * +* Description : Matérialise les liens de retour arrière en tant que boucles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void detect_back_edges(dragon_node *nodes, size_t count) +{ + size_t k; /* Boucle de parcours #1 */ + dragon_node *node; /* Noeud à traiter */ + 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 */ + dragon_node *target; /* Noeud référencé à tester */ + size_t id; /* Indice du bit associé */ + + + + printf("-----------------------------------------------------------------\n"); + + for (k = 0; k < count; k++) + { + node = &nodes[k]; + + printf("#[ node %zu ]# @ 0x%08x / 0x%08x - mask = 0x%08lx\n", k, + (unsigned int)g_arch_instruction_get_range(node->first)->addr.virtual, + (unsigned int)g_arch_instruction_get_range(node->last)->addr.virtual, + gfw(node->bits)); + + } + + printf("\n"); + + + + for (k = 1; k < count; k++) + { + node = &nodes[k]; + + dcount = g_arch_instruction_get_destinations(node->last, &dests, &types, NULL); + if (dcount == 0) continue; + + 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: + + target = find_node_for_instruction(nodes, count, false, dests[i]); + if (target == NULL) break; + + id = (target - nodes); + + if (test_in_bit_field(node->bits, id, 1)) + { + + printf("BACKEDGE :: 0x%08lx -> 0x%08lx\n", + (unsigned int)g_arch_instruction_get_range(node->last)->addr.virtual, + (unsigned int)g_arch_instruction_get_range(dests[i])->addr.virtual); + + + /* status = */g_arch_instruction_change_link(node->last, dests[i], types[i], ILT_LOOP); + + + } + + break; + + default: + break; + + } + + } + +} + + + +/****************************************************************************** +* * +* 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) +{ + dragon_node *nodes; /* Liste des noeuds détectés */ + size_t count; /* Taille de cette liste */ + + nodes = create_dragon_nodes(proc, coverage, range, start, &count); + assert(nodes != NULL); + + printf("nodes count :: %d\n", (int)count); + + define_mask_for_nodes(nodes, count); + + compute_all_dominators(nodes, count); + + detect_back_edges(nodes, count); + + delete_dragon_nodes(nodes, count); + +} + + +/****************************************************************************** +* * +* 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> @@ -193,6 +779,8 @@ void detect_loops_in_code(const GArchProcessor *proc, GBinRoutine **routines, si for (i = 0; i < count; i++) { + + range = g_binary_routine_get_range(routines[i]); start = get_mrange_addr(range); @@ -207,3 +795,10 @@ void detect_loops_in_code(const GArchProcessor *proc, GBinRoutine **routines, si } } + + + + + + +#endif |