/* Chrysalide - Outil d'analyse de fichiers binaires
 * symbols.c - gestion des symboles d'un ELF
 *
 * Copyright (C) 2008-2013 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 "symbols.h"


#include <assert.h>
#include <malloc.h>
#include <string.h>


#include <i18n.h>


#include "dynamic.h"
#include "elf-int.h"
#include "helper_arm.h"
#include "helper_x86.h"
#include "loading.h"
#include "program.h"
#include "section.h"
#include "../mangling/demangler.h"
#include "../../arch/raw.h"
#include "../../common/extstr.h"
#include "../../core/params.h"
#include "../../gui/panels/log.h"










/* Enregistre un point d'entrée au sein d'un binaire ELF. */
static void register_elf_entry_point(GElfFormat *, virt_t, phys_t, GBinRoutine *);

/* Enumère tous les points d'entrée principaux d'un binaire ELF. */
static bool load_all_elf_basic_entry_points(GElfFormat *);









/* -------------------------- DETAIL DES SYMBOLES INTERNES -------------------------- */


/* Assure le chargement des symboles internes ELF en différé. */
static bool do_elf_internal_symbol_loading(GElfLoading *, GElfFormat *, phys_t *);

/* Charge tous les symboles internes possibles. */
static bool load_elf_internal_symbols(GElfFormat *, wgroup_id_t, GtkStatusStack *);



/* -------------------------- DETAIL DES SYMBOLES EXTERNES -------------------------- */


/* Retrouve un élément donné dans la section dynamique. */
static bool find_elf_dynamic_item(const GElfFormat *, const elf_shdr *, int32_t, elf_dyn *);

/* Charge tous les éléments dynamiques externes possibles. */
static bool load_elf_external_symbols(GElfFormat *, const elf_shdr *);













/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
                 status = barre de statut à tenir informée.                   *
*                                                                             *
*  Description : Charge en mémoire la liste humaine des symboles.             *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool load_elf_symbols(GElfFormat *format, GtkStatusStack *status)
{
    bool result;                            /* Bilan à retourner           */
    wgroup_id_t gid;                        /* Identifiant pour les tâches */

    elf_shdr *sections;                     /* Groupe de sections trouvées */
    size_t count;                           /* Quantité de données         */

    result = true;

    gid = g_work_queue_define_work_group(get_work_queue());

    /* Symboles internes */

    result &= load_elf_internal_symbols(format, gid, status);




    /* Symboles externes */
#if 1
    if (find_elf_sections_by_type(format, SHT_DYNAMIC, &sections, &count))
    {
        log_variadic_message(LMT_INFO, _("Binary is dynamically linked"));

        result &= load_elf_external_symbols(format, &sections[0]);

        free(sections);

    }
    else log_variadic_message(LMT_INFO, _("Binary is statically linked"));
#endif
    /* Symboles internes */
    //result &= load_elf_internal_symbols(format);



    /* Symboles d'entrée, si encore besoin */

    /**
     * Le tri en préalable
     */





    result &= load_all_elf_basic_entry_points(format);

    return result;

}





/******************************************************************************
*                                                                             *
*  Paramètres  : format  = description de l'exécutable à compléter.           *
*                vaddr   = adresse virtuelle du symbole à insérer.            *
*                len     = taille de la routine à ajouter.                    *
*                routine = représentation de la fonction repérée.             *
*                                                                             *
*  Description : Enregistre un point d'entrée au sein d'un binaire ELF.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void register_elf_entry_point(GElfFormat *format, virt_t vaddr, phys_t len, GBinRoutine *routine)
{
    GBinFormat *base;                       /* Version basique du format   */
    virt_t final_vaddr;                     /* Adresse virtuelle retenue   */
    bool status;                            /* Bilan d'une opération       */
    vmpa2t addr;                            /* Localisation d'une routine  */
    mrange_t range;                         /* Couverture mémoire associée */
    GBinSymbol *symbol;                     /* Nouveau symbole construit   */

    /* Localisation complète du symbole */

	if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
		final_vaddr = vaddr & ~0x1;
    else
        final_vaddr = vaddr;

    status = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_vaddr, &addr);
    if (!status) return;

    /* Comptabilisation en tant que symbole */

    if (g_binary_format_find_symbol_at(G_BIN_FORMAT(format), &addr, &symbol))
    {
        g_object_unref(G_OBJECT(routine));

        routine = g_binary_symbol_get_routine(symbol);
        g_object_ref(G_OBJECT(routine));

        _g_binary_symbol_attach_routine(symbol, routine, STP_ENTRY_POINT);

    }
    else
    {
        base = G_BIN_FORMAT(format);

        init_mrange(&range, &addr, len);

        g_binary_routine_set_range(routine, &range);

        symbol = g_binary_symbol_new(STP_ENTRY_POINT);
        g_binary_symbol_attach_routine(symbol, routine);
        g_binary_format_add_symbol(base, symbol);

        /* Comptabilisation pour le désassemblage brut */
        g_binary_format_register_code_point(base, vaddr, true);

    }

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à consulter.            *
*                                                                             *
*  Description : Enumère tous les points d'entrée principaux d'un binaire ELF.*
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool load_all_elf_basic_entry_points(GElfFormat *format)
{
    virt_t ep;                              /* Point d'entrée détecté      */
    GBinRoutine *routine;                   /* Routine à associer à un pt. */
    elf_phdr dynamic;                       /* En-tête de programme DYNAMIC*/
    elf_dyn item_a;                         /* Premier élément DYNAMIC     */
    elf_dyn item_b;                         /* Second élément DYNAMIC      */
    const GBinContent *content;             /* Contenu binaire à lire      */
    phys_t length;                          /* Taille totale du contenu    */
    bool status;                            /* Bilan d'une opération       */
    vmpa2t pos;                             /* Tête de lecture courante    */
    uint32_t virt_32;                       /* Adresse virtuelle sur 32b   */
    uint64_t virt_64;                       /* Adresse virtuelle sur 64b   */

    /* Point d'entrée principal éventuel */

    ep = ELF_HDR(format, format->header, e_entry);

    if (ep != 0x0)
    {
        routine = try_to_demangle_routine("entry_point");
        register_elf_entry_point(format, ep, 0, routine);
    }

    /* Chargemet de l'en-tête de programme DYNAMIC */

    if (!find_elf_dynamic_program_header(format, &dynamic))
        goto laebep_exit;

    /* Détection des constructeurs & destructeurs */

    if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_INIT, &item_a))
    {
        ep = ELF_DYN(format, item_a, d_un.d_ptr);

        if (ep != 0x0)
        {
            routine = try_to_demangle_routine("init_function");
            register_elf_entry_point(format, ep, 0, routine);
        }

    }

    if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_FINI, &item_a))
    {
        ep = ELF_DYN(format, item_a, d_un.d_ptr);

        if (ep != 0x0)
        {
            routine = try_to_demangle_routine("termination_function");
            register_elf_entry_point(format, ep, 0, routine);
        }

    }

    void load_entry_points_from_array(GElfFormat *fmt, const elf_dyn *ar, const elf_dyn *sz, const char *prefix)
    {
        unsigned int i;                     /* Boucle de parcours          */
        char fullname[64];                  /* Désignation humaine         */

        assert(sizeof(fullname) >= (strlen(prefix) + sizeof(XSTR(UINT64_MAX) + 1)));

        content = G_BIN_FORMAT(fmt)->content;

        status = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format),
                                                          ELF_DYN(fmt, *ar, d_un.d_val),
                                                          &pos);
        if (!status) return;

        length = get_phy_addr(&pos) + ELF_DYN(fmt, *sz, d_un.d_val);

        for (i = 0; get_phy_addr(&pos) < length; i++)
        {
            /**
             * Selon la libc d'Android (https://www.codeaurora.org/.../android/bionic/linker/README.TXT) :
             *
             *      DT_INIT_ARRAY
             *          Points to an array of function addresses that must be
             *          called, in-order, to perform initialization. Some of
             *          the entries in the array can be 0 or -1, and should
             *          be ignored.
             *
             * On étend le principe aux sections DT_FINI_ARRAY et DT_PREINIT_ARRAY.
             */

            if (fmt->is_32b)
            {
                status = g_binary_content_read_u32(content, &pos, fmt->endian, &virt_32);
                status &= (virt_32 != 0x0 && virt_32 != 0xffffffff);
                ep = virt_32;
            }
            else
            {
                status = g_binary_content_read_u64(content, &pos, fmt->endian, &virt_64);
                status &= (virt_64 != 0x0 && virt_64 != 0xffffffffffffffff);
                ep = virt_64;
            }

            if (!status) break;

            snprintf(fullname, sizeof(fullname), "%s%u", prefix, i);

            routine = try_to_demangle_routine(fullname);
            register_elf_entry_point(fmt, ep, 0, routine);

        }

    }

    if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_INIT_ARRAY, &item_a))
    {
        if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_INIT_ARRAYSZ, &item_b))
        {
            load_entry_points_from_array(format, &item_a, &item_b, "init_array_function_");
        }

    }

    if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_FINI_ARRAY, &item_a))
    {
        if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_FINI_ARRAYSZ, &item_b))
        {
            load_entry_points_from_array(format, &item_a, &item_b, "fini_array_function_");
        }

    }

    if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_PREINIT_ARRAY, &item_a))
    {
        if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_PREINIT_ARRAYSZ, &item_b))
        {
            load_entry_points_from_array(format, &item_a, &item_b, "preinit_array_function_");
        }

    }

    /* Identification de l'entrée de la PLT */

    if (find_elf_dynamic_item_from_pheader(format, &dynamic, DT_PLTGOT, &item_a))
    {
        status = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format),
                                                          ELF_DYN(format, item_a, d_un.d_val),
                                                          &pos);

        if (status)
        {
            content = G_BIN_FORMAT(format)->content;

            /* On saute le premier élément... */
            if (format->is_32b)
                status = g_binary_content_read_u32(content, &pos, format->endian, &virt_32);
            else
                status = g_binary_content_read_u64(content, &pos, format->endian, &virt_64);

            while (1)
            {
                if (format->is_32b)
                {
                    status = g_binary_content_read_u32(content, &pos, format->endian, &virt_32);
                    ep = virt_32;
                }
                else
                {
                    status = g_binary_content_read_u64(content, &pos, format->endian, &virt_64);
                    ep = virt_64;
                }

                if (!status) break;

                if (ep != 0x0)
                {
                    routine = try_to_demangle_routine("plt_entry");
                    register_elf_entry_point(format, ep, 0, routine);
                    break;
                }

            }

        }

    }

 laebep_exit:

    return true;

}









/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à consulter.            *
*                sym    = section comprenant les symboles à venir lire.       *
*                index  = indice de l'entrée à venir lire.                    *
*                symbol = ensemble d'informations lues. [OUT]                 *
*                                                                             *
*  Description : Récupère la définition complète d'un symbole donné.          *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool get_elf_symbol_by_index(GElfFormat *format, const elf_shdr *sym, off_t index, elf_sym *symbol)
{
    phys_t sym_start;                       /* Début de section            */
    phys_t sym_size;                        /* Taille de section           */
    phys_t offset;                          /* Emplacement à venir lire    */

    get_elf_section_content(format, sym, &sym_start, &sym_size, NULL);

    offset = sym_start + index * ELF_SIZEOF_SYM(format);
    if ((offset + ELF_SIZEOF_SYM(format)) > (sym_start + sym_size)) return NULL;

    return read_elf_symbol(format, &offset, symbol);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à consulter.            *
*                sym    = section comprenant les symboles à venir lire.       *
*                str    = section de chaînes de caractères pour les noms.     *
*                index  = indice de l'entrée à venir lire.                    *
*                                                                             *
*  Description : Récupère la désignation d'un symbole donné.                  *
*                                                                             *
*  Retour      : Nom du symbole trouvé, ou NULL si erreur ou non adapté.      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

const char *get_elf_symbol_name(GElfFormat *format, const elf_shdr *sym, const elf_shdr *str, off_t index)
{
    const char *result;                     /* Résultat à retourner        */
    elf_sym symbol;                         /* Symbole aux infos visées    */

    result = NULL;

    if (get_elf_symbol_by_index(format, sym, index, &symbol))
        result = extract_name_from_elf_string_section(format, str, ELF_SYM(format, symbol, st_name));

    return result;

}



/* ---------------------------------------------------------------------------------- */
/*                            DETAIL DES SYMBOLES INTERNES                            */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : loading = chargement de symboles internes en cours.          *
*                format  = format ELF à compléter.                            *
*                iter    = tête de lecture évoluant avec le temps. [OUT]      *
*                                                                             *
*  Description : Assure le chargement des symboles internes ELF en différé.   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool do_elf_internal_symbol_loading(GElfLoading *loading, GElfFormat *format, phys_t *iter)
{
    bool result;                            /* Bilan à retourner           */
    elf_sym sym;                            /* Symbole aux infos visées    */
    virt_t virt;                            /* Adresse virtuelle           */
    const elf_shdr *section;                /* Groupe de sections trouvées */
    bool use_virt;                          /* Choix de construction de nom*/
    const elf_shdr *strtab;                 /* Section .strtab trouvée     */
    bool has_strtab;                        /* Présence de cette section   */
    phys_t first;                           /* Position du premier élément */
    const char *name;                       /* Nom du symbole trouvé       */
    GBinFormat *base;                       /* Version basique du format   */
    vmpa2t addr;                            /* Localisation d'une routine  */
    GBinSymbol *symbol;                     /* Nouveau symbole construit   */
    char alt_name[6 + VMPA_MAX_LEN];        /* Nom abstrait de substitution*/
    virt_t final_virt;                      /* Adresse virtuelle retenue   */
    mrange_t range;                         /* Couverture mémoire associée */
    GBinRoutine *routine;                   /* Nouvelle routine trouvée    */

    result = read_elf_symbol(format, iter, &sym);
    if (!result) goto geslp_done;

    /* On rejette les symboles qui ne sont pas définis au sein du binaire */

    if (ELF_SYM(format, sym, st_shndx) == 0) goto geslp_done;

    /* Résolution précise d'adresse */

    virt = ELF_SYM(format, sym, st_value);
    if (virt == 0) goto geslp_done;


    /* TODO */

    //init_vmpa(&addr, VMPA_NO_PHYSICAL, ELF_SYM(format, sym, st_value));


    //init_mrange(&range, &addr, 0);


    /* Première ébauche de nom */

    g_elf_loading_get_internal_info(loading, &section, &use_virt, &strtab, &has_strtab, &first);

    if (!has_strtab)
        name = NULL;

    else
        name = get_elf_symbol_name(format, section, strtab,
                                   ((*iter - first) / ELF_SIZEOF_SYM(format)) - 1);

    /* Traitements particuliers */

    base = G_BIN_FORMAT(format);

    switch (ELF_ST_TYPE(format, sym))
    {
        case STT_OBJECT:

            /* Ajustement de la position */

            if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), virt, &addr))
            {
                symbol = NULL;
                break;
            }

            /* Création d'un nom unique ? */

            if (name == NULL)
            {
                strcpy(alt_name, "obj_");

                if (use_virt)
                    vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);
                else
                    vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 4, NULL);

                name = alt_name;

            }


            /* TODO */

            symbol = NULL;


            break;

        case STT_FUNC:

            /* Ajustement de la position */

            if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
                final_virt = virt & ~0x1;
            else
                final_virt = virt;

            if (!g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_virt, &addr))
            {
                symbol = NULL;
                break;
            }

            init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));

            /* Création d'un nom unique ? */

            if (name == NULL)
            {
                strcpy(alt_name, "func_");

                if (use_virt)
                    vmpa2_virt_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);
                else
                    vmpa2_phys_to_string(&addr, MDS_UNDEFINED, alt_name + 5, NULL);

                name = alt_name;

            }

            /* Routine */

            routine = try_to_demangle_routine(name);

            g_binary_routine_set_range(routine, &range);

            /* Symbole uniquement */

            symbol = g_binary_symbol_new(STP_ROUTINE);
            g_binary_symbol_attach_routine(symbol, routine);

            /* Comptabilisation pour le désassemblage brut */

            g_binary_format_register_code_point(G_BIN_FORMAT(format), virt, false);

            break;

        default:
            symbol = NULL;
            break;

    }

    if (symbol != NULL)
        g_binary_format_add_symbol(base, symbol);

 geslp_done:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                gid    = groupe de travail impliqué.                         *
                 status = barre de statut à tenir informée.                   *
*                                                                             *
*  Description : Charge tous les symboles internes possibles.                 *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool load_elf_internal_symbols(GElfFormat *format, wgroup_id_t gid, GtkStatusStack *status)
{
    bool result;                            /* Bilan à retourner           */
    bool no_name;                           /* Choix de construction de nom*/
    activity_id_t msg;                      /* Message de progression      */
    GWorkQueue *queue;                      /* Gestionnaire de différés    */
    elf_shdr *dynsym_sections;              /* Groupe de sections trouvées */
    size_t count;                           /* Quantité de données         */
    elf_shdr *symtab_sections;              /* Groupe de sections trouvées */
    size_t i;                               /* Boucle de parcours          */

    result = true;

    /* Charge tous les symboles définis dans une section */
    void add_all_symbols_from_section(const elf_shdr *section, bool use_virt, GWorkQueue *wq, activity_id_t id)
    {
        phys_t start;                       /* Début de la zone à traiter  */
        phys_t size;                        /* Taille de cette même zone   */
        phys_t sym_size;                    /* Taille de chaque symbole lu */
        guint runs_count;                   /* Qté d'exécutions parallèles */
        phys_t run_size;                    /* Volume réparti par exécution*/
        guint i;                            /* Boucle de parcours          */
        phys_t begin;                       /* Début de zone de traitement */
        phys_t end;                         /* Fin d'un zone de traitement */
        GElfLoading *loading;               /* Tâche de chargement à lancer*/

        get_elf_section_content(format, section, &start, &size, NULL);

        sym_size = ELF_SIZEOF_SYM(format);

        runs_count = g_get_num_processors();

        run_size = size / (sym_size * runs_count);

        gtk_status_stack_extend_activity(status, id, size / sym_size);

        for (i = 0; i < runs_count; i++)
        {
            begin = start + i * run_size * sym_size;

            if ((i + 1) == runs_count)
                end = start + size;
            else
                end = begin + run_size * sym_size;

            loading = g_elf_loading_new(format, section, use_virt, start, begin, end,
                                        id, do_elf_internal_symbol_loading);

            g_work_queue_schedule_work(wq, G_DELAYED_WORK(loading), gid);

        }

    }

    if (!g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &no_name))
        return false;

    msg = gtk_status_stack_add_activity(status, _("Loading internal symbols..."), 0);

    queue = get_work_queue();

    if (find_elf_sections_by_type(format, SHT_DYNSYM, &dynsym_sections, &count))
        for (i = 0; i < count; i++)
            add_all_symbols_from_section(&dynsym_sections[i], no_name, queue, msg);

    if (find_elf_sections_by_type(format, SHT_SYMTAB, &symtab_sections, &count))
        for (i = 0; i < count; i++)
            add_all_symbols_from_section(&symtab_sections[i], no_name, queue, msg);

    g_work_queue_wait_for_completion(get_work_queue(), gid);

    gtk_status_stack_remove_activity(status, msg);

    if (dynsym_sections != NULL) free(dynsym_sections);
    if (symtab_sections != NULL) free(symtab_sections);

    return result;

}



/* ---------------------------------------------------------------------------------- */
/*                            DETAIL DES SYMBOLES EXTERNES                            */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : format  = informations chargées à consulter.                 *
*                dynamic = section de type SHT_DYNAMIC.                       *
*                type    = sorte d'élément recherché.                         *
*                item    = élément retrouvé dans la section. [OUT]            *
*                                                                             *
*  Description : Retrouve un élément donné dans la section dynamique.         *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool find_elf_dynamic_item(const GElfFormat *format, const elf_shdr *section, int32_t type, elf_dyn *item)
{
    bool result;                            /* Bilan à retourner           */
    const GBinContent *content;             /* Contenu binaire à lire      */
    phys_t pos;                             /* Position de lecture         */
    vmpa2t tmp;                             /* Position écrasable          */
    int32_t tag32;                          /* Type de l'entrée (32 bits)  */
    int64_t tag64;                          /* Type de l'entrée (64 bits)  */

    result = true;

    content = G_BIN_FORMAT(format)->content;

    for (pos = ELF_SHDR(format, *section, sh_offset);
         result;
         pos += ELF_SIZEOF_DYN(format))
    {
        init_vmpa(&tmp, pos, VMPA_NO_VIRTUAL);

        if (format->is_32b)
        {
            result = g_binary_content_read_s32(content, &tmp, format->endian, &tag32);
            if (tag32 == type) break;
        }
        else
        {
            result = g_binary_content_read_s64(content, &tmp, format->endian, &tag64);
            if (tag64 == type) break;
        }

    }

    if (result)
    {
        init_vmpa(&tmp, pos, VMPA_NO_VIRTUAL);

        if (format->is_32b)
        {
            result = g_binary_content_read_s32(content, &tmp, format->endian, &item->dyn32.d_tag);
            result &= g_binary_content_read_s32(content, &tmp, format->endian, &item->dyn32.d_un.d_val);
        }
        else
        {
            result = g_binary_content_read_s64(content, &tmp, format->endian, &item->dyn64.d_tag);
            result &= g_binary_content_read_s64(content, &tmp, format->endian, &item->dyn64.d_un.d_val);
        }

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format  = informations chargées à consulter.                 *
*                dynamic = section de type SHT_DYNAMIC.                       *
*                                                                             *
*  Description : Charge tous les éléments dynamiques externes possibles.      *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static bool load_elf_external_symbols(GElfFormat *format, const elf_shdr *section)
{
    bool result;                            /* Bilan à retourner           */

    elf_dyn item;                           /* Elément dynamique           */
    elf_shdr relxxx;                        /* Section .rel.xxx trouvée    */
    elf_shdr dynsym;                        /* Section .dynsym trouvée     */
    elf_shdr dynstr;                        /* Section .dynstr trouvée     */
    elf_shdr plt;                           /* Section .plt trouvée        */

    result = true;






    /* Section .rel.plt */
    if (find_elf_dynamic_item(format, section, DT_JMPREL, &item))
    {
        result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx);

        if (result)
            result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_link), &dynsym);

        if (result)
            result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr);

        if (result)
            switch (ELF_HDR(format, format->header, e_machine))
            {
                case EM_ARM:
                    result = load_elf_arm_relocated_symbols(format, &relxxx, &dynsym, &dynstr);
                    break;

                case EM_386:
                    result = load_elf_x86_relocated_symbols(format, &relxxx, &dynsym, &dynstr);
                    break;

                default:
                    break;

            }

    }

#if 0

    /* Entrées équivalentes dans le binaire */
    if (find_elf_dynamic_item(format, section, DT_SYMTAB, &item))
    {
        result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &dynsym);

        if (result)
            result = find_elf_section_by_index(format, ELF_SHDR(format, dynsym, sh_link), &dynstr);

        if (result)
            switch (g_exe_format_get_target_machine(G_EXE_FORMAT(format)))
            {
                case FTM_MIPS:
                    //result = find_elf_mips_dynamic_symbols(format, &dynsym, &dynstr);
                    break;

                case FTM_386:

                    if (find_elf_dynamic_item(format, section, DT_JMPREL, &item))
                    {
                        result &= find_elf_section_by_virtual_address(format, ELF_DYN(format, item, d_un.d_ptr), &relxxx);


                        printf("VMA :: 0x%08llx\n", ELF_DYN(format, item, d_un.d_ptr));



                        if (result)
                            result = find_elf_section_by_index(format, ELF_SHDR(format, relxxx, sh_info), &plt);

                        if (result)
                            result = find_elf_x86_dynamic_symbols(format, &plt, &relxxx, &dynsym, &dynstr);

                    }

                    break;

                default:
                    break;

            }

    }

#endif

    return result;

}