/* Chrysalide - Outil d'analyse de fichiers binaires
 * area.c - définition et manipulation des aires à désassembler
 *
 * Copyright (C) 2014 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 .
 */
#include "area.h"
#include 
/* Zone mémoire bien bornée */
typedef struct _mem_area
{
    mrange_t range;                         /* Couverture de la zone       */
    unsigned long *processed;               /* Octets traités dans la zone */
    GArchInstruction **instructions;        /* Instructions en place       */
    bool has_sym;                           /* Représentation via symbole ?*/
    union
    {
        bool exec;                          /* Zone exécutable ?           */
        GBinSymbol *symbol;                 /* Symbole associé à la zone   */
    };
} mem_area;
/* Initialise une aire de données à partir d'une adresse donnée. */
static void init_mem_area_from_addr(mem_area *, const vmpa2t *, phys_t);
/* Initialise une aire de données à partir d'un espace donné. */
static void init_mem_area_from_range(mem_area *, const mrange_t *);
/* Initialise une aire de données à partir d'un morceau donné. */
static void init_mem_area_from_bigger_area(mem_area *, const vmpa2t *, phys_t, const mem_area *);
/* Copie certaines propriétés d'une aire à une autre. */
static void copy_mem_area_properties(mem_area *, const mem_area *);
/* Libère d'une aire de données les ressources allouées. */
static void fini_mem_area(mem_area *);
/* Indique si une zone donnée est intégralement vierge ou non. */
static bool is_range_blank_in_mem_area(mem_area *, phys_t, phys_t, GArchInstruction *);
/* Marque une série d'octets comme ayant été traités. */
static bool mark_range_in_mem_area_as_processed(mem_area *, phys_t, phys_t, GArchInstruction *);
/* S'assure de la présence d'un début de routine à un point. */
static void update_address_as_routine(GBinFormat *, const vmpa2t *);
/* Procède au désassemblage d'un contenu binaire non exécutable. */
static void load_data_from_mem_area(mem_area *, mem_area *, size_t, const GLoadedBinary *, GProcContext *, const vmpa2t *, status_blob_info *);
/* Rassemble les instructions conservées dans une zone donnée. */
static GArchInstruction *get_instructions_from_mem_area(const mem_area *);
///////////////////////////////
/* Insère un symbole dans un découpage en aires. */
static bool insert_extra_symbol_into_mem_areas(mem_area **, size_t *, GBinSymbol *, size_t);
/* Manipule la cartographie des octets traités d'une zone. */
typedef bool (* visit_bytes_map_fc) (mem_area *, phys_t, phys_t, GArchInstruction *);
/* Manipule la cartographie des octets d'aires de données. */
static bool handle_bytes_map_in_mem_area(mem_area *, size_t, const mrange_t *, GArchInstruction *, visit_bytes_map_fc);
/* Indique si une zone donnée est intégralement vierge ou non. */
static bool is_range_blank_in_mem_areas(mem_area *, size_t, const mrange_t *);
/* Marque une série d'octets comme ayant été traités. */
static bool mark_range_in_mem_areas_as_processed(mem_area *, size_t, GArchInstruction *);
/******************************************************************************
*                                                                             *
*  Paramètres  : area = aire représentant à contenu à initialiser.            *
*                addr = adresse de départ de l'espace à mettre en place.      *
*                len  = longueur de l'espace à créer.                         *
*                                                                             *
*  Description : Initialise une aire de données à partir d'une adresse donnée.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void init_mem_area_from_addr(mem_area *area, const vmpa2t *addr, phys_t len)
{
    size_t requested;                       /* Nombre de mots à allouer    */
    init_mrange(&area->range, addr, len);
    requested = len / sizeof(unsigned long);
    if (len % sizeof(unsigned long) != 0) requested++;
    area->processed = (unsigned long *)calloc(requested, sizeof(unsigned long));
    area->instructions = (GArchInstruction **)calloc(len, sizeof(GArchInstruction *));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area  = aire représentant à contenu à initialiser.           *
*                range = espace limitant à associer à l'aire de données.      *
*                                                                             *
*  Description : Initialise une aire de données à partir d'un espace donné.   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void init_mem_area_from_range(mem_area *area, const mrange_t *range)
{
    phys_t len;                             /* Taille de la zone courante  */
    size_t requested;                       /* Nombre de mots à allouer    */
    copy_mrange(&area->range, range);
    len = get_mrange_length(range);
    requested = len / sizeof(unsigned long);
    if (len % sizeof(unsigned long) != 0) requested++;
    area->processed = (unsigned long *)calloc(requested, sizeof(unsigned long));
    area->instructions = (GArchInstruction **)calloc(len, sizeof(GArchInstruction *));
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area  = aire représentant à contenu à initialiser.           *
*                addr = adresse de départ de l'espace à mettre en place.      *
*                len  = longueur de l'espace à créer.                         *
*                ref   = aire de référence avant découpage.                   *
*                                                                             *
*  Description : Initialise une aire de données à partir d'un morceau donné.  *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : On considère que la zone de destination est inclue dans      *
*                celle de référence.                                          *
*                                                                             *
******************************************************************************/
static void init_mem_area_from_bigger_area(mem_area *area, const vmpa2t *addr, phys_t len, const mem_area *ref)
{
    phys_t start;                           /* Point de départ de la copie */
    phys_t i;                               /* Boucle de parcours          */
    size_t index;                           /* Cellule de tableau visée #1 */
    unsigned int remaining;                 /* Nombre de bits restants #1  */
    size_t ref_index;                       /* Cellule de tableau visée #2 */
    unsigned int ref_remaining;             /* Nombre de bits restants #2  */
    printf(" INIT_FROM (0x%08x / 0x%08x | 0x%x) : area (0x%08x / 0x%08x) len = 0x%x\n",
           (unsigned int)ref->range.addr.physical, (unsigned int)ref->range.addr.virtual,
           (unsigned int)ref->range.length,
           (unsigned int)addr->physical, (unsigned int)addr->virtual,
           (unsigned int)len);
    init_mem_area_from_addr(area, addr, len);
    assert(mrange_contains_mrange(&ref->range, &area->range));
    start = compute_vmpa_diff(get_mrange_addr(&ref->range), get_mrange_addr(&area->range));
    for (i = 0; i < len; i++)
    {
        index = i / (sizeof(unsigned long) * 8);
        remaining = i % (sizeof(unsigned long) * 8);
        ref_index = (start + i) / (sizeof(unsigned long) * 8);
        ref_remaining = (start + i) % (sizeof(unsigned long) * 8);
        if (ref->processed[ref_index] & (1ul << ref_remaining))
            area->processed[index] |= (1ul << remaining);
        area->instructions[i] = ref->instructions[start + i];
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : dest = aire délimitée représentant des données.              *
*                src  = aire délimitée contenant les informations à copier.   *
*                                                                             *
*  Description : Copie certaines propriétés d'une aire à une autre.           *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void copy_mem_area_properties(mem_area *dest, const mem_area *src)
{
    dest->has_sym = src->has_sym;
    if (src->has_sym)
        dest->symbol = src->symbol;
    else
        dest->exec = src->exec;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area = aire représentant à contenu à nettoyer en mémoire.    *
*                                                                             *
*  Description : Libère d'une aire de données les ressources allouées.        *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void fini_mem_area(mem_area *area)
{
    free(area->processed);
#if 0
    if (area->has_sym)
        g_object_unref(area->symbol);   /* FIXME ?! */
#endif
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area  = aire représentant à contenu à parcourir.             *
*                start = début de la zone à manipuler.                        *
*                len   = taille de cette même aire de données.                *
*                instr = instruction à mémoriser pour la suite.               *
*                                                                             *
*  Description : Indique si une zone donnée est intégralement vierge ou non.  *
*                                                                             *
*  Retour      : true si l'aire visée n'a jamais été traitée, false sinon.    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool is_range_blank_in_mem_area(mem_area *area, phys_t start, phys_t len, GArchInstruction *instr)
{
    bool result;                            /* Bilan à renvoyer            */
    phys_t max;                             /* Point d'arrêt de la boucle  */
    phys_t i;                               /* Boucle de parcours          */
    size_t index;                           /* Cellule de tableau visée    */
    unsigned int remaining;                 /* Nombre de bits restants     */
    if (area->has_sym)
        return false;
    max = start + len;
    assert(max <= get_mrange_length(&area->range));
    result = true;
    for (i = start; i < max && result; i++)
    {
        index = i / (sizeof(unsigned long) * 8);
        remaining = i % (sizeof(unsigned long) * 8);
        result &= ((area->processed[index] & (1ul << remaining)) == 0);
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area  = aire représentant à contenu à parcourir.             *
*                start = début de la zone à manipuler.                        *
*                len   = taille de cette même aire de données.                *
*                instr = instruction à mémoriser pour la suite.               *
*                                                                             *
*  Description : Marque une série d'octets comme ayant été traités.           *
*                                                                             *
*  Retour      : true.                                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool mark_range_in_mem_area_as_processed(mem_area *area, phys_t start, phys_t len, GArchInstruction *instr)
{
    phys_t max;                             /* Point d'arrêt de la boucle  */
    phys_t i;                               /* Boucle de parcours          */
    size_t index;                           /* Cellule de tableau visée    */
    unsigned int remaining;                 /* Nombre de bits restants     */
    max = start + len;
    assert(max <= get_mrange_length(&area->range));
    for (i = start; i < max; i++)
    {
        index = i / (sizeof(unsigned long) * 8);
        remaining = i % (sizeof(unsigned long) * 8);
        //assert((area->processed[index] & (1ul << remaining)) == 0);
        area->processed[index] |= (1ul << remaining);
    }
    //assert(area->instructions[start] == NULL);
    area->instructions[start] = instr;
    return true;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : format = format binaire en cours de traitement.              *
*                addr   = adresse d'une instruction présentée comme première. *
*                                                                             *
*  Description : S'assure de la présence d'un début de routine à un point.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void update_address_as_routine(GBinFormat *format, const vmpa2t *addr)
{
    GBinSymbol *symbol;                     /* Symbole présent ou créé     */
    phys_t offset;                          /* Décallage trouvé            */
    bool found;                             /* Détection de symbole        */
    SymbolType sym_type;                    /* Type de symbole en place    */
    bool wrong_type;                        /* Analyse plus fine de ce type*/
    mrange_t range;                         /* Etendue du symbole à créer  */
    VMPA_BUFFER(loc);                       /* Traduction de l'adresse     */
    char name[5 + VMPA_MAX_LEN];            /* Nom de symbole nouveau      */
    GBinRoutine *routine;                   /* Nouvelle routine trouvée    */
    found = g_binary_format_resolve_symbol(format, addr, &symbol, &offset);
    if (found)
    {
        sym_type = g_binary_symbol_get_target_type(symbol);
        wrong_type = (sym_type != STP_ROUTINE && sym_type != STP_ENTRY_POINT);
    }
    if (!found || (found && offset == 0 && wrong_type))
    {
        init_mrange(&range, addr, 0);
        vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL);
        snprintf(name, sizeof(name), "ZZZ_%s", loc + 2);
        routine = g_binary_routine_new();
        g_binary_routine_set_name(routine, strdup(name));
        g_binary_routine_set_range(routine, &range);
        if (!found)
        {
            symbol = g_binary_symbol_new(STP_ROUTINE, NULL, ~0);
            g_binary_symbol_attach_routine(symbol, routine);
            g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);
        }
        else _g_binary_symbol_attach_routine(symbol, routine, STP_ROUTINE);
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area   = aire représentant à contenu à parcourir.            *
*                list   = liste de zones délimitant des contenus à traiter.   *
*                count  = nombre de zones à disposition.                      *
*                index  = indice de l'aire à considérer pendant l'opération.  *
*                binary = représentation de binaire chargé.                   *
*                ctx    = contexte offert en soutien à un désassemblage.      *
*                start  = démarrage de l'exécution au sein de la zone.        *
*                info   = indications quant à la progression à afficher.      *
*                                                                             *
*  Description : Procède au désassemblage d'un contenu binaire exécutable.    *
*                                                                             *
*  Retour      : Recalcul de rafraîchissement de l'aire de travail requis ?   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool load_code_from_mem_area(mem_area **list, size_t *count, size_t *index, const GLoadedBinary *binary, GProcContext *ctx, const vmpa2t *start, status_blob_info *info)
{
    bool result;                            /* Besoin à retourner          */
    mem_area *area;                         /* Zone de désassemblage       */
    GBinFormat *format;                     /* Format du fichier binaire   */
    GArchProcessor *proc;                   /* Architecture du binaire     */
    off_t bin_length;                       /* Taille des données à lire   */
    bin_t *bin_data;                        /* Données binaires à lire     */
    phys_t diff;                            /* Volume de données traité    */
    phys_t alen;                            /* Taille de l'aire utilisée   */
    phys_t i;                               /* Boucle de parcours          */
    vmpa2t pos;                             /* Boucle de parcours          */
    vmpa2t prev;                            /* Boucle de parcours          */
    GArchInstruction *instr;                /* Instruction décodée         */
    mrange_t range;                             /* Couverture de l'instruction */
    vmpa2t sym_addr;                        /* Adresse de nouveau symbole  */
    bool has_new_sym;                       /* Statut d'un dépilement      */
    GBinSymbol *symbol;                     /* Symbole créé en parallèle   */
    bool refresh;                           /* Besoin de rafraîchissement  */
    result = false;
    /* On cherche à obtenir l'assurance que le traitement n'a jamais été fait */
    init_mrange(&range, start, 1);
    if (!is_range_blank_in_mem_areas(*list, *count, &range)) return false;
    /* Récupération des informations de base */
    format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
    proc = g_loaded_binary_get_processor(binary);
    bin_data = g_loaded_binary_get_data(binary, &bin_length);
    area = (*list) + *index;
    diff = compute_vmpa_diff(get_mrange_addr(&area->range), start);
    alen = get_mrange_length(&area->range);
    /**
     * On copie la position courante à partir de l'aire plutôt que du
     * point de départ car cette première est potentiellement plus complète.
     */
    copy_vmpa(&pos, get_mrange_addr(&area->range));
    advance_vmpa(&pos, diff);
    //printf(" [%p] CODE start @ %u (len=%u)\n", area, (unsigned int)diff, (unsigned int)alen);
    printf(" START @ 0x%08x\n", (unsigned int)get_virt_addr(&pos));
    bin_length = (get_phy_addr(get_mrange_addr(&area->range)) + alen);
    for (i = diff; i < alen; i += diff)
    {
        /* S'il y a eu un point d'entrée en milieu de zone, on s'arrête ! */
        if (!is_range_blank_in_mem_area(area, i, 1, NULL)) break;
        /* Décodage d'une nouvelle instruction */
        copy_vmpa(&prev, &pos);
        instr = g_arch_processor_disassemble(proc, ctx, bin_data, &pos, bin_length);
        //printf(" @ 0x%08x -> %p\n", (uint32_t)get_virt_addr(&prev), instr);
        if (instr == NULL) break;
        /* Enregistrement des positions et adresses */
        diff = compute_vmpa_diff(&prev, &pos);
        init_mrange(&range, &prev, diff);
        g_arch_instruction_set_range(instr, &range);
        /* Enregistrement d'un éventuel début de routine */
        if (g_arch_instruction_get_flags(instr) & AIF_ROUTINE_START)
            update_address_as_routine(format, &prev);
        /* Eventuel renvoi vers d'autres adresses */
        g_arch_instruction_call_hook(instr, IPH_FETCH, proc, ctx, format);
        /* Progression dans les traitements */
        mark_range_in_mem_areas_as_processed(*list, *count, instr);
        inc_progessive_status(info, diff);
        assert(!is_range_blank_in_mem_areas(*list, *count, &range));
        /* Insertion des symboles découverts en parallèle */
        for (has_new_sym = g_proc_context_pop_new_symbol_at(ctx, &sym_addr);
             has_new_sym;
             has_new_sym = g_proc_context_pop_new_symbol_at(ctx, &sym_addr))
        {
            has_new_sym = g_binary_format_find_symbol_at(format, &sym_addr, &symbol);
            assert(has_new_sym);
            refresh = insert_extra_symbol_into_mem_areas(list, count, symbol, *index);
            result |= refresh;
            /**
             * Si une insertion a été réalisée dans la même zone que celle courante ou avant,
             * en l'absence d'indication sur les localisations exactes, le plus simple
             * est de tout recharger.
             */
            if (refresh)
            {
                *index = find_memory_area_by_addr(*list, *count, &pos);
                area = (*list) + *index;
                diff = compute_vmpa_diff(get_mrange_addr(&area->range), &pos);
                alen = get_mrange_length(&area->range);
                i = 0;
            }
            /**
             * Si la zone modifiée se trouve bien après la zone courante, l'emplacement de la liste
             * peut potentiellement avoir évolué. Donc on ne recharge ici que le minimum.
             */
            else area = (*list) + *index;
        }
        assert(1 && !is_range_blank_in_mem_areas(*list, *count, &range));
        if (g_arch_instruction_is_return(instr))
            printf("BREAK @ 0x%08x\n", (unsigned int)get_virt_addr(&prev));
        //continue;
        /* Rupture du flot d'exécution ? */
        if (g_arch_instruction_is_return(instr))
            break;
    }
    printf("\n");
    g_object_unref(G_OBJECT(proc));
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area   = aire représentant à contenu à parcourir.            *
*                list   = liste de zones délimitant des contenus à traiter.   *
*                count  = nombre de zones à disposition.                      *
*                binary = représentation de binaire chargé.                   *
*                ctx    = contexte offert en soutien à un désassemblage.      *
*                start  = démarrage de l'exécution au sein de la zone.        *
*                info   = indications quant à la progression à afficher.      *
*                                                                             *
*  Description : Procède au désassemblage d'un contenu binaire non exécutable.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void load_data_from_mem_area(mem_area *area, mem_area *list, size_t count, const GLoadedBinary *binary, GProcContext *ctx, const vmpa2t *start, status_blob_info *info)
{
    GBinFormat *format;                     /* Format du fichier binaire   */
    GArchProcessor *proc;                   /* Architecture du binaire     */
    SourceEndian endianness;                /* Boutisme de cette machine   */
    off_t bin_length;                       /* Taille des données à lire   */
    bin_t *bin_data;                        /* Données binaires à lire     */
    phys_t diff;                            /* Volume de données traité    */
    phys_t alen;                            /* Taille de l'aire utilisée   */
    phys_t i;                               /* Boucle de parcours          */
    vmpa2t pos;                             /* Boucle de parcours          */
    vmpa2t prev;                            /* Boucle de parcours          */
    GArchInstruction *instr;                /* Instruction décodée         */
    mrange_t range;                         /* Couverture de l'instruction */
    /* On cherche à obtenir l'assurance que le traitement n'a jamais été fait */
    init_mrange(&range, start, 1);
    if (!is_range_blank_in_mem_areas(list, count, &range)) printf("DATA OK ! @ 0x%08x\n", (unsigned int)get_phy_addr(get_mrange_addr(&area->range)));
    if (!is_range_blank_in_mem_areas(list, count, &range)) return;
    /* Récupération des informations de base */
    format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
    proc = g_loaded_binary_get_processor(binary);
    endianness = g_arch_processor_get_endianness(proc);
    g_object_unref(G_OBJECT(proc));
    bin_data = g_loaded_binary_get_data(binary, &bin_length);
    diff = compute_vmpa_diff(get_mrange_addr(&area->range), start);
    alen = get_mrange_length(&area->range);
    /**
     * On copie la position courante à partir de l'aire plutôt que du
     * point de départ car cette première est potentiellement plus complète.
     */
    copy_vmpa(&pos, get_mrange_addr(&area->range));
    advance_vmpa(&pos, diff);
    /*
    printf(" [%p] DATA start @ 0x%08x -> %u (len=%u) => 0x%08x <-> 0x%08x\n",
           area, (unsigned int)get_phy_addr(&pos), (unsigned int)diff, (unsigned int)alen,
           (unsigned int)get_virt_addr(&pos), (unsigned int)(get_virt_addr(&pos) + alen));
    */
    for (i = diff; i < alen; i += diff)
    {
        /* Décodage d'une nouvelle instruction, sur mesure */
        copy_vmpa(&prev, &pos);
        instr = NULL;
        /*
        if (instr == NULL && (i + 4) <= alen)
        {
            init_mrange(&range, &pos, 4);
            if (is_range_blank_in_mem_areas(list, count, &range))
                instr = g_raw_instruction_new_array_old(bin_data, MDS_32_BITS, 1, &pos, bin_length, endianness);
        }
        */
        if (instr == NULL && (i + 2) <= alen)
        {
            copy_vmpa(&pos, &prev);
            init_mrange(&range, &pos, 2);
            if (is_range_blank_in_mem_areas(list, count, &range))
                instr = g_raw_instruction_new_array_old(bin_data, MDS_16_BITS, 1, &pos, bin_length, endianness);
        }
        if (instr == NULL/* && (i + 1) <= alen*/)
        {
            copy_vmpa(&pos, &prev);
            init_mrange(&range, &pos, 1);
            if (is_range_blank_in_mem_areas(list, count, &range))
                instr = g_raw_instruction_new_array_old(bin_data, MDS_8_BITS, 1, &pos, bin_length, endianness);
            else
            {
                /**
                 * On rencontre ici un morceau déjà traité.
                 * On recherche donc la fin de cette partie à sauter, si elle existe.
                 */
                //////////////
                return;
                for (i++; i < alen; i++)
                {
                    advance_vmpa(&pos, 1);
                    init_mrange(&range, &pos, 1);
                    if (is_range_blank_in_mem_areas(list, count, &range))
                        break;
                }
                diff = 0;
                continue; 
            }
        }
        assert(instr != NULL);
        /* Enregistrement des positions et adresses */
        diff = compute_vmpa_diff(&prev, &pos);
        init_mrange(&range, &prev, diff);
        g_arch_instruction_set_range(instr, &range);
        /* Progression dans les traitements */
        mark_range_in_mem_areas_as_processed(list, count, instr);
        inc_progessive_status(info, diff);
        assert(!is_range_blank_in_mem_areas(list, count, &range));
        if (area->exec) break;
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area   = aire représentant à contenu à parcourir.            *
*                list   = liste de zones délimitant des contenus à traiter.   *
*                count  = nombre de zones à disposition.                      *
*                index  = indice de l'aire à considérer pendant l'opération.  *
*                binary = représentation de binaire chargé.                   *
*                ctx    = contexte offert en soutien à un désassemblage.      *
*                info   = indications quant à la progression à afficher.      *
*                                                                             *
*  Description : S'assure qu'une aire contient toutes ses instructions.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void fill_mem_area(mem_area **list, size_t *count, size_t *index, const GLoadedBinary *binary, GProcContext *ctx, status_blob_info *info)
{
    mem_area *area;                         /* Zone de désassemblage       */
    phys_t len;                             /* Taille de la zone à remplir */
    phys_t i;                               /* Boucle de parcours          */
    vmpa2t start;                           /* Adresse de départ de combles*/
    bool refresh;                           /* Besoin de rafraîchissement  */
    size_t k;
    for (k = 0; k < *count; k++) 
   {
        printf(" (filled) AREA %zu :: 0x%08x + %u\n",
               k,
               (unsigned int)get_phy_addr(get_mrange_addr(&(*list)[k].range)),
               (unsigned int)get_mrange_length(&(*list)[k].range));
    }
    area = (*list) + *index;
    printf(" === FILLING (%zu) | 0x%08x // 0x%08x <-> 0x%08x...\n", *index,
           (unsigned int)get_phy_addr(get_mrange_addr(&area->range)),
           (unsigned int)get_virt_addr(get_mrange_addr(&area->range)),
           (unsigned int)(get_virt_addr(get_mrange_addr(&area->range)) + get_mrange_length(&area->range)));
    /* Les symboles se doivent d'être indépendants ! */
    if (area->has_sym) return;
    len = get_mrange_length(&area->range);
    for (i = 0; i < len; i++)
    {
        if (is_range_blank_in_mem_area(area, i, 1, NULL))
        {
            copy_vmpa(&start, get_mrange_addr(&area->range));
            advance_vmpa(&start, i);
            if (area->exec && get_virt_addr(&start) % 2 == 0)
            {
                refresh = load_code_from_mem_area(list, count, index, binary, ctx, &start, info);
                /**
                 * Mêmes commentaires que dans load_code_from_mem_area() :
                 *  - en cas de décalage avéré, on recharge tout.
                 *  - sinon, la liste a potentiellement été déplacée, donc on recharge un minimum.
                 */
                if (refresh)
                {
                    area = (*list) + *index;
                    len = get_mrange_length(&area->range);
                    i = compute_vmpa_diff(get_mrange_addr(&area->range), &start);
                }
                else area = (*list) + *index;
            }
            if (is_range_blank_in_mem_area(area, i, 1, NULL))
                load_data_from_mem_area(area, *list, *count, binary, ctx, &start, info);
        }
        assert(!is_range_blank_in_mem_area(area, i, 1, NULL));
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : area = aire représentant à contenu à parcourir.              *
*                                                                             *
*  Description : Rassemble les instructions conservées dans une zone donnée.  *
*                                                                             *
*  Retour      : Liste d'instructions prêtes à emploi.                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static GArchInstruction *get_instructions_from_mem_area(const mem_area *area)
{
    GArchInstruction *result;               /* Liste d'instr. à renvoyer   */
    phys_t len;                             /* Nombre d'instructions au max*/
    phys_t i;                               /* Boucle de parcours          */
    GArchInstruction *instr;                /* Instruction décodée         */
    result = NULL;
    if (area->has_sym)
        switch (g_binary_symbol_get_target_type(area->symbol))
        {
            case STP_DATA:
            case STP_RO_STRING:
                result = g_binary_symbol_get_instruction(area->symbol);
                g_object_ref(G_OBJECT(result));
                break;
            case STP_ROUTINE:
                assert(false);
                //instr = load_code_binary(binary, start, end, statusbar, id);
                // + fill
                break;
            default:
                assert(false);
                break;
        }
    else
    {
        len = get_mrange_length(&area->range);
        for (i = 0; i < len; i++)
        {
            instr = area->instructions[i];
            if (instr != NULL)
            {
                g_object_ref(G_OBJECT(instr));
                g_arch_instruction_add_to_list(&result, instr);
            }
        }
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : format     = format d'un exécutable à consulter.             *
*                bin_length = quantité d'octets à traiter au total.           *
*                count      = nombre de zones mises en place. [OUT]           *
*                                                                             *
*  Description : Détermine une liste de zones contigües à traiter.            *
*                                                                             *
*  Retour      : Liste de zones mémoire à libérer après usage.                *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
mem_area *compute_memory_areas(GExeFormat *format, phys_t bin_length, size_t *count)
{
    mem_area *result;                       /* Liste à renvoyer            */
    mrange_t *exe_ranges;                   /* Liste de zones exécutables  */
    size_t exe_count;                       /* Nombre de ces zones         */
    GBinSymbol **symbols;                   /* Symboles à représenter      */
    size_t sym_count;                       /* Qté de symboles présents    */
    vmpa2t *last;                           /* Dernière bordure rencontrée */
    size_t i;                               /* Boucle de parcours #1       */
    vmpa2t *border;                         /* Nouvelle bordure rencontrée */
    mem_area *area;                         /* Zone avec valeurs à éditer  */
    vmpa2t tmp;                             /* Stockage temporaire         */
    GBinPortion **portions;                 /* Morceaux d'encadrement      */
    size_t portions_count;                  /* Taille de cette liste       */
    const vmpa2t *portion_start;            /* Point de départ de portion  */
    size_t j;                               /* Boucle de parcours #2       */
    const mrange_t *range;                  /* Couverture d'un symbole     */
    const vmpa2t *start;                    /* Point de départ du symbole  */
    phys_t length;                          /* Taille de ce même symbole   */
    bool included;                          /* Inclusion dans une zone ?   */
    mem_area orig;                          /* Copie de la zone réduite    */
    phys_t old_length;                      /* Taille de zone originelle   */
    phys_t new_length;                      /* Nouvelle taille déterminée  */
    size_t next;                            /* Indice de zone suivante     */
    result = NULL;
    *count = 0;
    /**
     * Le parcours n'est valide que si les listes, symboles et zones exécutables,
     * sont triées !
     */
    exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);
    symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);
    for (i = 0; i < exe_count; i++)
    {
        printf(" (init) AREA %zu :: 0x%08x + %u\n",
               i,
               (unsigned int)get_phy_addr(get_mrange_addr(&exe_ranges[i])),
               (unsigned int)get_mrange_length(&exe_ranges[i]));
    }
    printf("----------------\n");
    /* Première étape : on comble les trous ! */
    last = make_vmpa(0, VMPA_NO_VIRTUAL);
    for (i = 0; i < exe_count; i++)
    {
        border = get_mrange_addr(&exe_ranges[i]);
        /* Zone tampon à constituer */
        if (cmp_vmpa_by_phy(last, border) < 0)
        {
            result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
            area = &result[*count - 1];
            init_mem_area_from_addr(area, last, compute_vmpa_diff(last, border));
            area->has_sym = false;
            area->exec = false;
        }
        /* Insertion d'une zone exécutable déjà définie */
        result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
        area = &result[*count - 1];
        init_mem_area_from_range(area, &exe_ranges[i]);
        area->has_sym = false;
        area->exec = true;
        /* Avancée du curseur */
        copy_vmpa(last, border);
        advance_vmpa(last, get_mrange_length(&exe_ranges[i]));
    }
    delete_vmpa(last);
    /* Extension finale complémentaire ? */
    area = &result[*count - 1];
    copy_vmpa(&tmp, get_mrange_addr(&area->range));
    advance_vmpa(&tmp, get_mrange_length(&area->range));
    if (get_phy_addr(&tmp) < bin_length)
    {
        result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
        area = &result[*count - 1];
        init_mem_area_from_addr(area, &tmp, bin_length - get_phy_addr(&tmp));
        area->has_sym = false;
        area->exec = false;
    }
    /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */
    for (i = 0; i < *count; i++)
    {
        printf(" (fini) AREA %zu :: 0x%08x + %u\n",
               i,
               (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)),
               (unsigned int)get_mrange_length(&result[i].range));
    }
    printf("--------------------\n");
    portions = g_exe_format_get_portions_at_level(format, -1, &portions_count);
    for (i = 1; i < portions_count; i++)
    {
        portion_start = get_mrange_addr(g_binary_portion_get_range(portions[i]));
        for (j = 0; j < *count; j++)
        {
            area = &result[j];
            if (!mrange_contains_addr(&area->range, portion_start))
                continue;
            /* Si le déccoupage actuel ne correspond pas au besoin des portions... */
            if (cmp_vmpa(get_mrange_addr(&area->range), portion_start) != 0)
            {
                fini_mem_area(&result[j]);
                result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
                memmove(&result[j + 2], &result[j + 1], (*count - j - 2) * sizeof(mem_area));
                copy_mem_area_properties(&result[j + 1], &result[j]);
                /* Première moitié */
                area = &result[j];
                copy_vmpa(&tmp, get_mrange_addr(&area->range));
                length = get_mrange_length(&area->range);
                init_mem_area_from_addr(area, &tmp, compute_vmpa_diff(&tmp, portion_start));
                /* Seconde moitié */
                length -= get_mrange_length(&area->range);
                area = &result[j + 1];
                init_mem_area_from_addr(area, portion_start, length);
            }
            j = *count;
        }
    }
    for (i = 0; i < *count; i++)
    {
        printf(" (sect) AREA %zu :: 0x%08x + %u\n",
               i,
               (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)),
               (unsigned int)get_mrange_length(&result[i].range));
    }
    //exit(0);
    /* Troisième étape : on insère les symboles existants */
    j = 0;
#define SKIP_EMPTY_SYMBOLS                                  \
    for (; j < sym_count; j++)                              \
    {                                                       \
        range = g_binary_symbol_get_range(symbols[j]);      \
                                                            \
        length = get_mrange_length(range);                  \
        if (length > 0) break;                              \
                                                            \
    }                                                       \
    SKIP_EMPTY_SYMBOLS
    for (i = 0; i < *count && j < sym_count; i++)
    {
        range = g_binary_symbol_get_range(symbols[j]);
        start = get_mrange_addr(range);
        length = get_mrange_length(range);
        /* Si un découpage s'impose... */
        if (mrange_contains_addr(&result[i].range, start))
        {
            copy_vmpa(&tmp, start);
            advance_vmpa(&tmp, length);
            included = mrange_contains_addr(&result[i].range, &tmp);
            memcpy(&orig, &result[i], sizeof(mem_area));
            fini_mem_area(&orig);
            /* Réduction de la zone de départ */
            copy_vmpa(&tmp, get_mrange_addr(&result[i].range));
            old_length = get_mrange_length(&result[i].range);
            new_length = compute_vmpa_diff(get_mrange_addr(&result[i].range), start);
            if (new_length == 0)
            {
                memmove(&result[i], &result[i + 1], (*count - i - 1) * sizeof(mem_area));
                (*count)--;
                next = i;
            }
            else
            {
                init_mem_area_from_addr(&result[i], &tmp, new_length);
                next = i + 1;
            }
            /* Insertion de la zone du symbole */
            result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
            memmove(&result[next + 1], &result[next], (*count - next - 1) * sizeof(mem_area));
            area = &result[next];
            init_mem_area_from_range(area, range);
            area->has_sym = true;
            area->symbol = symbols[j];
            /* Jointure finale... */
            if (included)
            {
                /* Simple extension pour rattraper la fin originelle */
                if ((old_length - new_length - length) > 0)
                {
                    result = (mem_area *)realloc(result, ++(*count) * sizeof(mem_area));
                    memmove(&result[next + 2], &result[next + 1], (*count - next - 2) * sizeof(mem_area));
                    area = &result[next + 1];
                    copy_vmpa(&tmp, start);
                    advance_vmpa(&tmp, length);
                    init_mem_area_from_addr(area, &tmp, old_length - new_length - length);
                    copy_mem_area_properties(area, &orig);
                }
                i = next;
            }
            else
            {
                /* Suppression des éventuelles zones totalement recouvertes */
                /* Réduction de la zone d'arrivée */
            }
            j++;
            SKIP_EMPTY_SYMBOLS
        }
    }
    if (exe_ranges != NULL)
        free(exe_ranges);
    //exit(0);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : list    = liste de zones délimitant des contenus à traiter.  *
*                count   = nombre de zones à disposition.                     *
*                symbol  = élément nouveau à venir insérer dans les zones.    *
*                working = indice de l'aire de travail courante.              *
*                                                                             *
*  Description : Insère un symbole dans un découpage en aires.                *
*                                                                             *
*  Retour      : Recalcul de rafraîchissement de l'aire de travail requis ?   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool insert_extra_symbol_into_mem_areas(mem_area **list, size_t *count, GBinSymbol *symbol, size_t working)
{
    bool result;                            /* Besoin à renvoyer           */
    const mrange_t *sym_range;              /* Emplacement du symbole      */
    size_t index;                           /* Zone trouvée à scinder      */
    mem_area *area;                         /* Aire en cours de traitement */
    mem_area saved;                         /* Aire aux données copiées    */
    mrange_t area_range;                    /* Emplacement d'une aire      */
    vmpa2t area_pos;                        /* Position relative à une aire*/
    vmpa2t sym_pos;                         /* Position pour un symbole    */
    phys_t diff;                            /* Décalage entre localisation */
    phys_t new_length;                      /* Nouvelle taille de zone     */
    sym_range = g_binary_symbol_get_range(symbol);
    index = find_memory_area_by_addr(*list, *count, get_mrange_addr(sym_range));
    assert(index < *count);
    result = (working >= index);
    area = &(*list)[index];
    do
    {
        size_t i;
        printf("--- INDEX = %zu   OLD_INDEX = %zu\n", index, working);
        printf("--- comment '%s'...\n",
               g_db_comment_get_text(g_binary_symbol_get_comment(symbol)));
        printf("--- insert @ 0x%04x + %u\n",
               get_phy_addr(get_mrange_addr(sym_range)), get_mrange_length(sym_range));
        for (i = 0; i < 3; i++)
            printf("area [ %zu ]  <=>  0x%04x + %u (sym ? %d)\n",
                   index - 1 + i,
                   get_phy_addr(get_mrange_addr(&(&(*list)[index - 1 + i])->range)),
                   get_mrange_length(&(&(*list)[index - 1 + i])->range),
                   (&(*list)[index - 1 + i])->has_sym);
    }
    while (0);
    if (area->has_sym) return false;
    assert(!area->has_sym);
    saved = *area;
    copy_mrange(&area_range, &area->range);
    copy_vmpa(&area_pos, get_mrange_addr(&area_range));
    copy_vmpa(&sym_pos, get_mrange_addr(sym_range));
    /* 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)
    {
        diff = compute_vmpa_diff(&area_pos, &sym_pos);
        copy_vmpa(&sym_pos, &area_pos);
        advance_vmpa(&sym_pos, diff);
        g_binary_symbol_fix_range(symbol, &sym_pos);
    }
    /* Si le symbole a une taille identique à la zone qui le contient, on remplace simplement... */
    if (get_mrange_length(&area_range) == get_mrange_length(sym_range))
    {
        assert((cmp_vmpa(&area_pos, &sym_pos) == 0));
        init_mem_area_from_range(area, sym_range);
        area->has_sym = true;
        area->symbol = symbol;
        goto iesima_done;
    }
    /* Si le symbole se trouve en début de zone... */
    if (cmp_vmpa(&area_pos, &sym_pos) == 0)
    {
        *list = (mem_area *)realloc(*list, ++(*count) * sizeof(mem_area));
        memmove(&(*list)[index + 1], &(*list)[index], (*count - index - 1) * sizeof(mem_area));
        /* Aire du symbole */
        area = &(*list)[index];
        init_mem_area_from_range(area, sym_range);
        area->has_sym = true;
        area->symbol = symbol;
        /* Aire raccourcie */
        copy_vmpa(&area_pos, get_mrange_addr(&saved.range));
        advance_vmpa(&area_pos, get_mrange_length(sym_range));
        //compute_mrange_end_addr(sym_range, &area_pos);
        new_length = get_mrange_length(&area_range) - get_mrange_length(sym_range);
        area = &(*list)[index + 1];
        init_mem_area_from_bigger_area(area, &area_pos, new_length, &saved);
        goto iesima_done;
    }
    compute_mrange_end_addr(&area->range, &area_pos);
    compute_mrange_end_addr(sym_range, &sym_pos);
    /* Si le symbole se trouve en fin de zone... */
    if (cmp_vmpa(&area_pos, &sym_pos) == 0)
    {
        *list = (mem_area *)realloc(*list, ++(*count) * sizeof(mem_area));
        memmove(&(*list)[index + 1], &(*list)[index], (*count - index - 1) * sizeof(mem_area));
        /* Aire raccourcie */
        copy_vmpa(&area_pos, get_mrange_addr(&area_range));
        new_length = get_mrange_length(&area_range) - get_mrange_length(sym_range);
        area = &(*list)[index];
        init_mem_area_from_bigger_area(area, &area_pos, new_length, &saved);
        /* Aire du symbole */
        area = &(*list)[index + 1];
        init_mem_area_from_range(area, sym_range);
        area->has_sym = true;
        area->symbol = symbol;
    }
    /* Sinon il se trouve au milieu et on découpe en trois... */
    else
    {
        *count += 2;
        *list = (mem_area *)realloc(*list, *count * sizeof(mem_area));
        memmove(&(*list)[index + 2], &(*list)[index], (*count - index - 2) * sizeof(mem_area));
        /* Aire raccourcie #1 */
        copy_vmpa(&area_pos, get_mrange_addr(&area_range));
        new_length = compute_vmpa_diff(&area_pos, get_mrange_addr(sym_range));
        assert(new_length != 0);    /* Symbole non présent au début */
        area = &(*list)[index];
        init_mem_area_from_bigger_area(area, &area_pos, new_length, &saved);
        /* Aire du symbole */
        area = &(*list)[index + 1];
        init_mem_area_from_range(area, sym_range);
        area->has_sym = true;
        area->symbol = symbol;
        /* Aire raccourcie #2 */
        copy_vmpa(&area_pos, get_mrange_addr(&saved.range));
        advance_vmpa(&area_pos, get_mrange_length(&(*list)[index].range));
        advance_vmpa(&area_pos, get_mrange_length(sym_range));
        //compute_mrange_end_addr(sym_range, &area_pos);
        new_length = get_mrange_length(&area_range) - get_mrange_length(sym_range) \
            - get_mrange_length(&(*list)[index].range);
        assert(new_length != 0);    /* Symbole non présent à la fin */
        area = &(*list)[index + 2];
        init_mem_area_from_bigger_area(area, &area_pos, new_length, &saved);
    }
    fini_mem_area(&saved);
 iesima_done:
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : list  = listes de zones utable à consulter.                  *
*                count = nombre de zones mises en place.                      *
*                addr  = adresse à retrouver dans les aires présentes.        *
*                                                                             *
*  Description : Détermine une liste de zones contigües à traiter.            *
*                                                                             *
*  Retour      : Indice de la zone trouvée, ou nombre d'aires en cas d'échec. *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
size_t find_memory_area_by_addr(mem_area *list, size_t count, const vmpa2t *addr)
{
    size_t result;                          /* Trouvaille à retourner      */
    for (result = 0; result < count; result++)
        if (mrange_contains_addr(&list[result].range, addr))
            break;
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : list    = liste de zones délimitant des contenus à traiter.  *
*                count   = nombre de zones à disposition.                     *
*                range   = aire des octets à manipuler.                       *
*                visitor = fonction opérationnelle finale à appeler.          *
*                                                                             *
*  Description : Manipule la cartographie des octets d'aires de données.      *
*                                                                             *
*  Retour      : valeur retournée par le visiteur, voire false si erreur.     *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool handle_bytes_map_in_mem_area(mem_area *list, size_t count, const mrange_t *range, GArchInstruction *instr, visit_bytes_map_fc visitor)
{
    bool result;                            /* Bilan à retourner           */
    size_t found;                           /* Indice de la zone trouvée   */
    mem_area *area;                         /* Aire à traiter trouvée      */
    phys_t offset;                          /* Point de départ dans l'aire */
    phys_t remaining;                       /* Quantité restant à traiter  */
    phys_t processed;                       /* Quantité traitée            */
    vmpa2t start;                           /* Point de départ suivant     */
    result = false;
    found = find_memory_area_by_addr(list, count, get_mrange_addr(range));
    if (found == count) return false;
    area = list + found;
    offset = compute_vmpa_diff(get_mrange_addr(&area->range), get_mrange_addr(range));
    remaining = get_mrange_length(range);
    /* Traitement intégral dans la zone trouvée */
    if ((offset + remaining) <= get_mrange_length(&area->range))
        result = visitor(area, offset, remaining, instr);
    else
    {
        printf("BUG_ON | off=%u remaining=%u length=%u\n",
               (unsigned int)offset,
               (unsigned int)remaining,
               (unsigned int)get_mrange_length(&area->range));
        printf("BUG_ON @ 0x%08x + %d\n",
               (unsigned int)get_virt_addr(get_mrange_addr(range)),
               (int)get_mrange_length(range)
               );
        assert(0);
        /* Traitement de la fin de la première aire */
        processed = get_mrange_length(&area->range) - offset;
        result = visitor(area, offset, processed, instr);
        /* Traitement des zones adjacentes suivantes */
        copy_vmpa(&start, get_mrange_addr(range));
        for (remaining -= processed; remaining > 0 && result; remaining -= processed)
        {
            advance_vmpa(&start, processed);
            found = find_memory_area_by_addr(list, count, &start);
            if (found == count)
            {
                result = false;
                break;
            }
            area = list + found;
            processed = get_mrange_length(&area->range);
            if (remaining < processed) processed = remaining;
            result = visitor(area, 0, processed, instr);
        }
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : list  = liste de zones délimitant des contenus à traiter.    *
*                count = nombre de zones à disposition.                       *
*                range = aire des octets à manipuler.                         *
*                                                                             *
*  Description : Indique si une zone donnée est intégralement vierge ou non.  *
*                                                                             *
*  Retour      : true si l'aire visée n'a jamais été traitée, false sinon.    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool is_range_blank_in_mem_areas(mem_area *list, size_t count, const mrange_t *range)
{
    return handle_bytes_map_in_mem_area(list, count,
                                        range, NULL,
                                        is_range_blank_in_mem_area);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : list  = liste de zones délimitant des contenus à traiter.    *
*                count = nombre de zones à disposition.                       *
*                instr = instruction désassemblée à conserver en mémoire.     *
*                                                                             *
*  Description : Marque une série d'octets comme ayant été traités.           *
*                                                                             *
*  Retour      : true.                                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool mark_range_in_mem_areas_as_processed(mem_area *list, size_t count, GArchInstruction *instr)
{
    return handle_bytes_map_in_mem_area(list, count,
                                        g_arch_instruction_get_range(instr), instr,
                                        mark_range_in_mem_area_as_processed);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : areas = série d'aires représentant à contenu à parcourir.    *
*                count = nombre de ces zones présentes.                       *
*                                                                             *
*  Description : Rassemble les instructions conservées dans des zones données.*
*                                                                             *
*  Retour      : Liste d'instructions prêtes à emploi.                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GArchInstruction *collect_instructions_from_mem_areas(mem_area *list, size_t count)
{
    GArchInstruction *result;               /* Liste d'instr. à renvoyer   */
    size_t i;                               /* Boucle de parcours          */
    GArchInstruction *instr;                /* Instruction(s) à insérer    */
    result = NULL;
    for (i = 0; i < count; i++)
    {
        instr = get_instructions_from_mem_area(&list[i]);
        g_arch_instruction_merge_lists(&result, &instr);
    }
    return result;
}