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/disass | |
| 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/disass')
| -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  | 
