/* 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 <http://www.gnu.org/licenses/>.
 */


#include "area.h"


#include <assert.h>


#include <i18n.h>


#include "../../analysis/contents/restricted.h"
#include "../../common/bits.h"
#include "../../gui/panels/log.h"




/* Zone mémoire bien bornée */
typedef struct _mem_area_v2
{
    GBinFormat *format;                     /* Format du fichier binaire   */
    GBinContent *content;                   /* Données binaires à lire     */
    GArchProcessor *proc;                   /* Architecture du binaire     */
    SourceEndian endianness;                /* Boutisme de cette machine   */

    mrange_t range;                         /* Couverture de la zone       */

    phys_t packing_size;                    /* Granularité des découpages  */

    bitfield_t *processed;                  /* Octets traités dans la zone */
    GArchInstruction **instructions;        /* Instructions en place       */




    bool is_exec;                           /* Zone exécutable ?           */

} mem_area_v2;



/* Initialise une aire de données à partir d'une adresse donnée. */
static void init_mem_area_from_addr_v2(mem_area_v2 *, const vmpa2t *, phys_t, const GLoadedBinary *);

/* Libère d'une aire de données les ressources allouées. */
static void fini_mem_area_v2(mem_area_v2 *);

/* Indique si une zone donnée est intégralement vierge ou non. */
static bool is_range_blank_in_mem_area_v2(mem_area_v2 *, phys_t, phys_t);

/* Marque une série d'octets comme ayant été traités. */
static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *, GArchInstruction *, bool);




/* Procède au désassemblage d'un contenu binaire non exécutable. */
static void load_data_from_mem_area_v2(mem_area_v2 *, GProcContext *, const vmpa2t *, GtkStatusStack *, activity_id_t);

/* S'assure qu'une aire contient toutes ses instructions. */
static void fill_mem_area_v2(mem_area_v2 *, mem_area_v2 *, size_t, GProcContext *, GtkStatusStack *, activity_id_t);

/* Rassemble les instructions conservées dans une zone donnée. */
static GArchInstruction *get_instructions_from_mem_area_v2(const mem_area_v2 *);






/* S'assure de la présence d'un début de routine à un point. */
static void update_address_as_routine(GBinFormat *, const vmpa2t *);


/**
 * Content :: à passer en restricted.

 * Les sections croisées : pas de sens de les traiter ici, car au final une instruction sera à cheval
 * sur deux sections différentes -> incohérence au niveau de l'éditeur.
 * => régler le périmètres de segments règle donc tous les soucis.

 */








/******************************************************************************
*                                                                             *
*  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.                       *
*                binary = binaire analysé content quantités d'informations.   *
*                                                                             *
*  Description : Initialise une aire de données à partir d'une adresse donnée.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void init_mem_area_from_addr_v2(mem_area_v2 *area, const vmpa2t *addr, phys_t len, const GLoadedBinary *binary)
{
    GBinContent *content;                   /* Données binaires à lire     */

    assert(len > 0);

    area->format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));

    content = g_binary_format_get_content(area->format);

    area->proc = g_loaded_binary_get_processor(binary);
    area->endianness = g_arch_processor_get_endianness(area->proc);

    init_mrange(&area->range, addr, len);

    area->content = g_restricted_content_new(content, &area->range);

    area->packing_size = 2; /* FIXME */

    area->processed = create_bit_field(len, false);
    area->instructions = (GArchInstruction **)calloc(len, sizeof(GArchInstruction *));

}


/******************************************************************************
*                                                                             *
*  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_v2(mem_area_v2 *area)
{
    phys_t len;                             /* Etendue du parcours total   */
    phys_t i;                               /* Boucle de parcours          */

    //g_object_unref(area->format);   /* FIXME */
    g_object_unref(area->content);
    //g_object_unref(area->proc);   /* FIXME */

    delete_bit_field(area->processed);

    len = get_mrange_length(&area->range);

    for (i = 0; i < len; i++)
        if (area->instructions[i] != NULL)
            g_object_unref(G_OBJECT(area->instructions[i]));

    free(area->instructions);

}


/******************************************************************************
*                                                                             *
*  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.                *
*                                                                             *
*  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_v2(mem_area_v2 *area, phys_t start, phys_t len)
{
    bool result;                            /* Résultat à renvoyer         */

    if ((start + len) > get_mrange_length(&area->range))
        result = false;

    else
        result = !test_in_bit_field(area->processed, start, len);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : area  = aire représentant à contenu à parcourir.             *
*                instr = instruction à mémoriser pour la suite.               *
*                force = impose l'enregistrement de l'instruction.            *
*                                                                             *
*  Description : Marque une série d'octets comme ayant été traités.           *
*                                                                             *
*  Retour      : true si l'enregistrement a bien été réalisé, false sinon.    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool mark_range_in_mem_area_as_processed_v2(mem_area_v2 *area, GArchInstruction *instr, bool force)
{
    bool result;                            /* Bilan d'action à renvoyer   */
    const vmpa2t *start;                    /* Adresse de départ de la zone*/
    const mrange_t *range;                  /* Emplacement d'instruction   */
    const vmpa2t *addr;                     /* Début de la zone à traiter  */
    phys_t len;                             /* Taille de l'aire visée      */
    phys_t offset;                          /* Décallage de départ         */

    start = get_mrange_addr(&area->range);

    range = g_arch_instruction_get_range(instr);
    addr = get_mrange_addr(range);
    len = get_mrange_length(range);

    offset = compute_vmpa_diff(start, addr);

    result = set_atomic_in_bit_field(area->processed, offset, len);

    /* Si l'instruction était bien la première à s'inscrire... */

    result |= force;

    if (result)
        area->instructions[offset] = instr;

    return result;

}















/******************************************************************************
*                                                                             *
*  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.        *
*                status = barre de statut à actualiser.                       *
*                id     = identifiant du groupe de progression à l'affichage. *
*                                                                             *
*  Description : Procède au désassemblage d'un contenu binaire exécutable.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void load_code_from_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, const vmpa2t *start, GtkStatusStack *status, activity_id_t id)
{



    GBinFormat *format;                     /* Format du fichier binaire   */
    GArchProcessor *proc;                   /* Architecture du binaire     */
    GBinContent *content;                   /* 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 */


    bool done;                              /* Enregistrement effectué ?   */


    vmpa2t sym_addr;                        /* Adresse de nouveau symbole  */
    bool has_new_sym;                       /* Statut d'un dépilement      */

    GBinSymbol *symbol;                     /* Symbole créé en parallèle   */





    /* Récupération des informations de base */

    format = area->format;
    proc = area->proc;
    content = area->content;

    diff = compute_vmpa_diff(get_mrange_addr(&area->range), start);
    alen = get_mrange_length(&area->range);

    copy_vmpa(&pos, start);

    /* Traitement de la zone */

    printf("=== processing @ 0x%08x\n", (unsigned int)start->virtual);

    for (i = diff; i < alen; i += diff)
    {
        /**
         * On réalise un premier test informel (car non atomique) peu coûteux
         * avant de se lancer dans un désassemblage d'instruction potentiellement
         * inutile.
         */

        printf(" (%u) blank ? %d\n", (unsigned int)i, is_range_blank_in_mem_area_v2(area, i, 1));
        printf("   +1 blank ? %d\n", is_range_blank_in_mem_area_v2(area, i + 1, 1));

        if (!is_range_blank_in_mem_area_v2(area, i, 1))
            break;

        /* Décodage d'une nouvelle instruction */

        copy_vmpa(&prev, &pos);

        instr = g_arch_processor_disassemble(proc, ctx, content, &pos, G_EXE_FORMAT(format));
        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);

        /* Progression dans les traitements */

        done = mark_range_in_mem_area_as_processed_v2(area, instr, false);

        if (!done)
        {
            g_object_unref(G_OBJECT(instr));
            break;
        }

        gtk_status_stack_update_activity_value(status, id, diff);

        assert(!is_range_blank_in_mem_area_v2(area, i, diff));

        /* 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);

        /* 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);

            insert_extra_symbol_into_mem_areas_v2(list, count, symbol);

        }

        /* Rupture du flot d'exécution ? */
        if (g_arch_instruction_get_flags(instr) & AIF_RETURN_POINT)
            break;

    }

}


/******************************************************************************
*                                                                             *
*  Paramètres  : area   = aire représentant à contenu à parcourir.            *
*                ctx    = contexte offert en soutien à un désassemblage.      *
*                start  = démarrage de l'exécution au sein de la zone.        *
*                status = barre de statut à actualiser.                       *
*                id     = identifiant du groupe de progression à l'affichage. *
*                                                                             *
*  Description : Procède au désassemblage d'un contenu binaire non exécutable.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void load_data_from_mem_area_v2(mem_area_v2 *area, GProcContext *ctx, const vmpa2t *start, GtkStatusStack *status, activity_id_t id)
{
    GBinContent *content;                   /* Données binaires à lire     */
    SourceEndian endianness;                /* Boutisme de cette machine   */
    phys_t diff;                            /* Volume de données traité    */
    phys_t alen;                            /* Taille de l'aire utilisée   */
    vmpa2t pos;                             /* Boucle de parcours          */
    phys_t i;                               /* Boucle de parcours          */
    vmpa2t prev;                            /* Boucle de parcours          */
    GArchInstruction *instr;                /* Instruction décodée         */
    mrange_t range;                         /* Couverture de l'instruction */
    bool done;                              /* Enregistrement effectué ?   */

    /* Récupération des informations de base */

    content = area->content;
    endianness = area->endianness;

    diff = compute_vmpa_diff(get_mrange_addr(&area->range), start);
    alen = get_mrange_length(&area->range);

    copy_vmpa(&pos, start);

    /* Traitement de la zone */

    for (i = diff; i < alen; i += diff)
    {
        /* On cherche à obtenir l'assurance que le traitement n'a jamais été fait */

        if (!is_range_blank_in_mem_area_v2(area, i, 1))
            break;

        instr = NULL;

        copy_vmpa(&prev, &pos);

        /* Décodage d'une nouvelle instruction, sur mesure puis minimale */

        if (get_virt_addr(&pos) % area->packing_size == 0
            && is_range_blank_in_mem_area_v2(area, i, area->packing_size))
        {
            diff = area->packing_size;

            instr = g_raw_instruction_new_array(content, MDS_FROM_BYTES(diff), 1, &pos, endianness);

            if (instr == NULL)
                copy_vmpa(&pos, &prev);

        }

        if (instr == NULL)
        {
            diff = 1;

            instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, &pos, endianness);

        }

        /* On rencontre ici un morceau déjà traité. */

        if (instr == NULL) break;

        /* Enregistrement des positions et adresses */

        assert(diff == compute_vmpa_diff(&prev, &pos));

        init_mrange(&range, &prev, diff);

        g_arch_instruction_set_range(instr, &range);

        /* Progression dans les traitements */

        done = mark_range_in_mem_area_as_processed_v2(area, instr, false);

        if (!done)
        {
            g_object_unref(G_OBJECT(instr));
            break;
        }

        gtk_status_stack_update_activity_value(status, id, diff);

        assert(!is_range_blank_in_mem_area_v2(area, i, diff));

        /* On laisse une chance au code pour se reprendre... */

        if (area->is_exec) break;

    }

}


/******************************************************************************
*                                                                             *
*  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.      *
*                status = barre de statut à actualiser.                       *
*                id     = identifiant du groupe de progression à l'affichage. *
*                                                                             *
*  Description : S'assure qu'une aire contient toutes ses instructions.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void fill_mem_area_v2(mem_area_v2 *area, mem_area_v2 *list, size_t count, GProcContext *ctx, GtkStatusStack *status, activity_id_t id)
{
    const vmpa2t *addr;                     /* Début de la zone à traiter  */
    phys_t len;                             /* Taille de la zone à remplir */
    phys_t i;                               /* Boucle de parcours          */
    vmpa2t start;                           /* Adresse de départ de combles*/

    addr = get_mrange_addr(&area->range);
    len = get_mrange_length(&area->range);

    for (i = 0; i < len; i++)
    {
        if (is_range_blank_in_mem_area_v2(area, i, 1))
        {
            copy_vmpa(&start, addr);
            advance_vmpa(&start, i);

            if (area->is_exec && get_virt_addr(&start) % area->packing_size == 0)
                load_code_from_mem_area_v2(area, list, count, ctx, &start, status, id);

            if (is_range_blank_in_mem_area_v2(area, i, 1))
                load_data_from_mem_area_v2(area, ctx, &start, status, id);

        }

        assert(!is_range_blank_in_mem_area_v2(area, i, 1));

    }

}


/******************************************************************************
*                                                                             *
*  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_v2(const mem_area_v2 *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;

    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  : 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   : -                                                            *
*                                                                             *
******************************************************************************/

mem_area_v2 *find_memory_area_by_addr_v2(mem_area_v2 *list, size_t count, const vmpa2t *addr)
{
    mem_area_v2 *result;                       /* Elément trouvé à renvoyer   */

    int find_mem_area(const vmpa2t *_addr, const mem_area_v2 *_area)
    {
        int status;                         /* Bilan à retourner           */

        if (mrange_contains_addr(&_area->range, _addr))
            status = 0;

        else
            status = cmp_vmpa(_addr, get_mrange_addr(&_area->range));

        return status;

    }

    result = bsearch(addr, list, count, sizeof(mem_area_v2), (__compar_fn_t)find_mem_area);

    return result;

}








/******************************************************************************
*                                                                             *
*  Paramètres  : binary     = binaire analysé contenant quantités d'infos.    *
*                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_v2 *compute_memory_areas_v2(const GLoadedBinary *binary, phys_t bin_length, size_t *count)
{
    mem_area_v2 *result;                       /* Liste à renvoyer            */
    GExeFormat *format;                     /* Format de fichier associé   */
    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 */
    bool status;                            /* Bilan d'une conversion      */
    size_t i;                               /* Boucle de parcours #1       */
    const vmpa2t *border;                   /* Nouvelle bordure rencontrée */
    mem_area_v2 *area;                         /* Zone avec valeurs à éditer  */
    vmpa2t tmp;                             /* Stockage temporaire         */
    GPortionLayer *layer;                   /* Couche première de portions */
    GBinPortion **portions;                 /* Morceaux d'encadrement      */
    size_t portions_count;                  /* Taille de cette liste       */
    const vmpa2t *portion_start;            /* Point de départ de portion  */
    const vmpa2t *portion_next;             /* Départ de portion suivante  */
    size_t j;                               /* Boucle de parcours #2       */
    SymbolType type;                        /* Nature d'un symbole         */
    const mrange_t *range;                  /* Couverture d'un symbole     */
    phys_t length;                          /* Taille de ce même symbole   */
    phys_t new_length;                      /* Nouvelle taille déterminée  */

    result = NULL;
    *count = 0;

    /**
     * Le parcours n'est valide que si les zones exécutables sont triées !
     */

    format = g_loaded_binary_get_format(binary);

    exe_ranges = g_exe_format_get_x_ranges(format, &exe_count);

    symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &sym_count);

    /* Première étape : on comble les trous ! */

    status = g_exe_format_translate_offset_into_vmpa(format, 0, &last);
    assert(status);

    for (i = 0; i < exe_count; i++)
    {
        border = get_mrange_addr(&exe_ranges[i]);

        /* Zone tampon à constituer */

        if (cmp_vmpa(&last, border) < 0)
        {
            result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));

            area = &result[*count - 1];

            init_mem_area_from_addr_v2(area, &last, compute_vmpa_diff(&last, border), binary);
            area->is_exec = false;

        }

        /* Insertion d'une zone exécutable déjà définie */

        result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));

        area = &result[*count - 1];

        init_mem_area_from_addr_v2(area, get_mrange_addr(&exe_ranges[i]),
                                   get_mrange_length(&exe_ranges[i]), binary);
        area->is_exec = true;

        /* Avancée du curseur */

        compute_mrange_end_addr(&exe_ranges[i], &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_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));

        area = &result[*count - 1];

        init_mem_area_from_addr_v2(area, &tmp, bin_length - get_phy_addr(&tmp), binary);
        area->is_exec = false;

    }








    for (i = 0; i < *count; i++)
    {
        printf(" (init) AREA %zu :: 0x%x / 0x%x + 0x%x\n",
               i,
               (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)),
               (unsigned int)get_virt_addr(get_mrange_addr(&result[i].range)),
               (unsigned int)get_mrange_length(&result[i].range));

    }

    printf("--------------------\n");








    /* Seconde étape : on s'assure du découpage autour des portions pour respecter l'alignement */

    layer = g_exe_format_get_main_layer(format);

    portions = g_portion_layer_collect_all_portions(layer, &portions_count);

    for (i = 1; i < portions_count; i++)
    {
        portion_start = get_mrange_addr(g_binary_portion_get_range(portions[i]));

        printf(" [portion % 3zu] addr = 0x%x / 0x%x\n",
               i,
               (unsigned int)get_phy_addr(portion_start),
               (unsigned int)get_virt_addr(portion_start));


        /**
         * Si plusieurs portions débutent au même endroit, il ne sert
         * à rien de découper plusieurs fois.
         */
        if ((i + 1) < portions_count)
        {
            portion_next = get_mrange_addr(g_binary_portion_get_range(portions[i + 1]));

            if (cmp_vmpa(portion_start, portion_next) == 0)
                continue;

        }

        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_v2(&result[j]);

                result = (mem_area_v2 *)realloc(result, ++(*count) * sizeof(mem_area_v2));

                memmove(&result[j + 2], &result[j + 1], (*count - j - 2) * sizeof(mem_area_v2));

                status = result[j].is_exec;

                /* Première moitié */

                area = &result[j];

                copy_vmpa(&tmp, get_mrange_addr(&area->range));
                length = get_mrange_length(&area->range);

                new_length = compute_vmpa_diff(&tmp, portion_start);

                init_mem_area_from_addr_v2(area, &tmp, new_length, binary);
                area->is_exec = status;

                /* Seconde moitié */

                length -= get_mrange_length(&area->range);

                area = &result[j + 1];

                init_mem_area_from_addr_v2(area, portion_start, length, binary);
                area->is_exec = status;

            }

            j = *count;

        }

    }

    if (portions != NULL)
        free(portions);

    g_object_unref(G_OBJECT(layer));






    for (i = 0; i < *count; i++)
    {
        printf(" (fini) AREA %zu :: 0x%x / 0x%x + 0x%x\n",
               i,
               (unsigned int)get_phy_addr(get_mrange_addr(&result[i].range)),
               (unsigned int)get_virt_addr(get_mrange_addr(&result[i].range)),
               (unsigned int)get_mrange_length(&result[i].range));

    }

    printf("--------------------\n");








    /* Troisième étape : on insère les symboles existants */

    for (i = 0; i < sym_count; i++)
    {
        type = g_binary_symbol_get_target_type(symbols[i]);

        /**
         * On ne garde que les symboles renvoyant directement une ou
         * plusieurs instructions, c'est à dire les symboles valides
         * pour un appel à g_binary_symbol_get_instruction().
         *
         * Les instructions des autres symboles sont obtenues et mises
         * en place durant la procédure de désassemblage.
         */

        if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL)
            continue;

        range = g_binary_symbol_get_range(symbols[i]);

        length = get_mrange_length(range);

        if (length == 0)
            continue;

        insert_extra_symbol_into_mem_areas_v2(result, *count, symbols[i]);

    }

    /* Nettoyage final */

    if (exe_ranges != NULL)
        free(exe_ranges);

    /// FIXME g_object_unref(G_OBJECT(format));

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : areas  = liste de zones délimitant des contenus à traiter.   *
*                count  = nombre de zones à disposition.                      *
*                symbol = élément nouveau à venir insérer dans les zones.     *
*                                                                             *
*  Description : Insère un symbole dans un découpage en aires.                *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void insert_extra_symbol_into_mem_areas_v2(mem_area_v2 *areas, size_t count, const GBinSymbol *symbol)
{
    SymbolType type;                        /* Type de symbole             */
    GArchInstruction *list;                 /* Ensemble à insérer          */
    GArchInstruction *iter;                 /* Boucle de parcours          */
    const mrange_t *range;                  /* Emplacement d'instruction   */
    const vmpa2t *addr;                     /* Départ de cet emplacement   */
    mem_area_v2 *area;                         /* Zone d'accueil désignée     */
    VMPA_BUFFER(loc);                       /* Description d'un emplacement*/
    phys_t start;                           /* Point de départ             */

    type = g_binary_symbol_get_target_type(symbol);

    if (!HAS_DATA_INSTR(type))
        return;

    list = g_binary_symbol_get_instruction(symbol);

    for (iter = list; iter != NULL; iter = g_arch_instruction_get_next_iter(list, iter, ~0))
    {
        range = g_arch_instruction_get_range(iter);
        addr = get_mrange_addr(range);

        /* Une aire d'accueil existe-t-elle ? */

        area = find_memory_area_by_addr_v2(areas, count, addr);

        if (area == NULL)
        {
            vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL);

            log_variadic_message(LMT_WARNING, _("No place found for symbol located at %s."), loc);
            continue;

        }

        /* L'instruction est-elle accueillie dans son intégralité ? */

        start = compute_vmpa_diff(get_mrange_addr(&area->range), addr);

        if (start + get_mrange_length(range) > get_mrange_length(&area->range))
        {
            vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL);

            log_variadic_message(LMT_WARNING, _("The symbol located at %s is too big for one place only."), loc);
            continue;

        }

        /* Inscription d'une instruction de symbole (sans retour arrière possible :/ ) */

        mark_range_in_mem_area_as_processed_v2(area, iter, true);

        g_object_ref(G_OBJECT(iter));

    }

}


/******************************************************************************
*                                                                             *
*  Paramètres  : 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.      *
*                status = barre de statut à actualiser.                       *
*                id     = identifiant du groupe de progression à l'affichage. *
*                                                                             *
*  Description : S'assure que l'ensemble des aires est entièrement décodé.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void ensure_all_mem_areas_are_filled(mem_area_v2 *list, size_t count, GProcContext *ctx, GtkStatusStack *status, activity_id_t id)
{
    size_t i;                               /* Boucle de parcours          */

    for (i = 0; i < count; i++)
        fill_mem_area_v2(&list[i], list, count, ctx, status, id);

}


/******************************************************************************
*                                                                             *
*  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_v2(const mem_area_v2 *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_v2(&list[i]);
        g_arch_instruction_merge_lists(&result, &instr);
    }

    return result;

}















//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////
//////////////////////////////////::://////////////////////////////////////////////////////////////////////




/* 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éé     */
    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_find_symbol_at(format, addr, &symbol);

    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 && wrong_type))
    {
        init_mrange(&range, addr, 0);

        vmpa2_virt_to_string(addr, MDS_UNDEFINED, loc, NULL);
        snprintf(name, sizeof(name), "sub_%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);
            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     */
    GBinContent *content;                   /* 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);
    content = g_binary_format_get_content(format);
    /* TODO : unref */

    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));



    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, content, &pos, G_EXE_FORMAT(format));

        /* TODO : valider que la taille de l'instruction obtenue ne dépasse pas la zone */

        //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);

        assert(diff == 4 || diff == 2); /* FIXME */

        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(!is_range_blank_in_mem_areas(*list, *count, &range));


        if (g_arch_instruction_get_flags(instr) & AIF_RETURN_POINT)
            printf("BREAK @ 0x%08x\n", (unsigned int)get_virt_addr(&prev));

        //continue;

        /* Rupture du flot d'exécution ? */
        if (g_arch_instruction_get_flags(instr) & AIF_RETURN_POINT)
            break;

    }


    printf("\n");


    g_object_unref(G_OBJECT(content));

    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   */
    GBinContent *content;                   /* Données binaires à lire     */
    GArchProcessor *proc;                   /* Architecture du binaire     */
    SourceEndian endianness;                /* Boutisme de cette machine   */
    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));
    content = g_binary_format_get_content(format);
    /* TODO g_object_unref(G_OBJECT(format)); */

    proc = g_loaded_binary_get_processor(binary);
    endianness = g_arch_processor_get_endianness(proc);
    g_object_unref(G_OBJECT(proc));

    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(content, MDS_32_BITS, 1, &pos, 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(content, MDS_16_BITS, 1, &pos, 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(content, MDS_8_BITS, 1, &pos, 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;



    }

    g_object_unref(G_OBJECT(content));

}


/******************************************************************************
*                                                                             *
*  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  */

    area = (*list) + *index;

    /* 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) % 4/*2 - FIXME */ == 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       */
    SymbolType type;                        /* Nature d'un symbole         */
    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 = NULL;//g_exe_format_get_portions_at_level(format, -1, &portions_count);
    portions_count = 0;


    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));

    }




    /* Troisième étape : on insère les symboles existants */

    j = 0;

    for (i = 0; i < *count; i++)
    {
        /* Sélection et écartement des symboles */

        range = NULL;   /* Pour GCC */
        length = 0;     /* Pour GCC */

        for (; j < sym_count; j++)
        {
            type = g_binary_symbol_get_target_type(symbols[j]);

            /**
             * On ne garde que les symboles renvoyant directement une ou
             * plusieurs instructions, c'est à dire les symboles valides
             * pour un appel à g_binary_symbol_get_instruction().
             *
             * Les instructions des autres symboles sont obtenues et mises
             * en place durant la procédure de désassemblage.
             */

            if (type == STP_ROUTINE || type == STP_ENTRY_POINT || type == STP_CODE_LABEL)
                continue;

            range = g_binary_symbol_get_range(symbols[j]);

            length = get_mrange_length(range);

            if (length > 0)
                break;

        }

        if (j == sym_count)
            break;

        start = get_mrange_addr(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++;

        }

    }

    if (exe_ranges != NULL)
        free(exe_ranges);

    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)
    {
        assert(false);

        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));

        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      */
    mem_area *found;                        /* Elément trouvé éventuel     */

    int find_mem_area(const vmpa2t *addr, const mem_area *area)
    {
        int status;                         /* Bilan à retourner           */

        if (mrange_contains_addr(&area->range, addr))
            status = 0;

        else
            status = cmp_vmpa(addr, get_mrange_addr(&area->range));

        return status;

    }

    found = bsearch(addr, list, count, sizeof(mem_area), (__compar_fn_t)find_mem_area);

    result = (found != NULL ? found - list : count);

    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;

}