/* 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 .
 */
#include "symbols.h"
#include 
#include 
#include 
#include "elf-int.h"
#include "helper_arm.h"
#include "helper_x86.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"
/* Récupère la définition complète d'un symbole donné. */
bool get_elf_symbol_by_index(GElfFormat *, const elf_shdr *, off_t, elf_sym *);
/* Récupère la désignation d'un symbole donné. */
const char *get_elf_symbol_name(GElfFormat *, const elf_shdr *, const elf_shdr *, off_t);
/* ------------------------ CHARGEMENT DE SYMBOLES DU FORMAT ------------------------ */
/* Charge tous les symboles de l'en-tête ELF. */
static bool annotate_elf_header(GElfFormat *);
/* Charge tous les symboles liés aux en-têtes de programme ELF. */
static bool annotate_elf_program_header_table(GElfFormat *);
/* Charge tous les symboles liés aux en-têtes de section ELF. */
static bool annotate_elf_section_header_table(GElfFormat *);
/* -------------------------- DETAIL DES SYMBOLES INTERNES -------------------------- */
/* Charge tous les symboles internes possibles. */
static bool load_elf_internal_symbols(GElfFormat *);
/* -------------------------- 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 *);
#include 
/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                                                                             *
*  Description : Charge en mémoire la liste humaine des symboles.             *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
bool load_elf_symbols(GElfFormat *format)
{
    bool result;                            /* Bilan à retourner           */
	virt_t entry_point;
        vmpa2t addr;                        /* Localisation d'une routine  */
        mrange_t range;                     /* Couverture mémoire associée */
        GBinRoutine *routine;               /* Nouvelle routine trouvée    */
        GBinSymbol *symbol;                 /* Nouveau symbole construit   */
    elf_shdr *sections;                     /* Groupe de sections trouvées */
    size_t count;                           /* Quantité de données         */
    result = true;
#if 1
    annotate_elf_header(format);
    annotate_elf_program_header_table(format);
    annotate_elf_section_header_table(format);
#endif
    /* Symboles internes */
#if 0
    result = load_elf_internal_symbols(format);
#endif
    entry_point = ELF_HDR(format, format->header, e_entry);
    G_BIN_FORMAT(format)->entry_point = entry_point;
    printf("E_ENTRY : 0x%08lx\n", (unsigned long)entry_point);
	if (ELF_HDR(format, format->header, e_machine) == EM_ARM)
		entry_point &= ~0x1;
	init_vmpa(&addr, VMPA_NO_PHYSICAL, entry_point);
	init_mrange(&range, &addr, 0);
	routine = try_to_demangle_routine("entry_point");
	g_binary_routine_set_range(routine, &range);
	symbol = g_binary_symbol_new(STP_ROUTINE, "entry_point", ~0);
	g_binary_symbol_attach_routine(symbol, routine);
	g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);
    /* Symboles externes */
#if 1
    if (find_elf_sections_by_type(format, SHT_DYNAMIC, §ions, &count))
    {
        log_variadic_message(LMT_INFO, _("Binary is dynamically linked"));
        result &= load_elf_external_symbols(format, §ions[0]);
        free(sections);
    }
    else log_variadic_message(LMT_INFO, _("Binary is statically linked"));
#endif
    /* Symboles internes */
    //result &= load_elf_internal_symbols(format);
	qsort(G_BIN_FORMAT(format)->symbols, G_BIN_FORMAT(format)->symbols_count,
		  sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp);
#if 0
    const vmpa2t *saddr;                    /* Adresse de symbole          */
    size_t i;                               /* Boucle de parcours #2       */
    GBinSymbol **symbols;                   /* Symboles à représenter      */
	symbols = G_BIN_FORMAT(format)->symbols;
	for (i = 0; i < G_BIN_FORMAT(format)->symbols_count; i++)
	{
		saddr = get_mrange_addr(g_binary_symbol_get_range(symbols[i]));
		if (saddr == NULL) continue;
		//if (g_binary_symbol_to_string(symbols[i]) == NULL) continue;
		printf("  '% 22s'-> 0x%08lx  0x%08lx\n",
			   i,
			   g_binary_symbol_to_string(symbols[i]),
			   saddr->physical,
			   saddr->virtual);
	}
	//exit(0);
#endif
    return result;
}
/******************************************************************************
*                                                                             *
*  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)
{
    off_t sym_start;                        /* Début de section            */
    off_t sym_size;                         /* Taille de section           */
    off_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;
}
/* ---------------------------------------------------------------------------------- */
/*                          CHARGEMENT DE SYMBOLES DU FORMAT                          */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                                                                             *
*  Description : Charge tous les symboles de l'en-tête ELF.                   *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool annotate_elf_header(GElfFormat *format)
{
    const bin_t *content;                   /* Contenu binaire à lire      */
    off_t length;                           /* Taille totale du contenu    */
    vmpa2t *pos;                            /* Localisation des symboles   */
    const char *text;                       /* Texte constant à insérer    */
    GArchInstruction *instr;                /* Instruction décodée         */
    GArchOperand *operand;                  /* Opérande à venir modifier   */
    GDbComment *comment;                    /* Définition de commentaire   */
    GBinSymbol *symbol;                     /* Symbole à intégrer          */
    content = G_BIN_FORMAT(format)->content;
    length = G_BIN_FORMAT(format)->length;
    pos = make_vmpa(0, 0x123);
    /* ELFMAG (0) */
    instr = g_raw_instruction_new_array(content, MDS_8_BITS, 4, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 1, IOD_CHAR);
    SET_IMM_DISPLAY(instr, operand, 2, IOD_CHAR);
    SET_IMM_DISPLAY(instr, operand, 3, IOD_CHAR);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("ELF magic number"));
    /* EI_CLASS (4) */
    switch (format->header.hdr32.e_ident[EI_CLASS])
    {
        case EV_NONE:
            text = _("File class: invalid");
            break;
        case ELFCLASS32:
            text = _("File class: 32-bit objects");
            break;
        case ELFCLASS64:
            text = _("File class: 64-bit objects");
            break;
        default:
            text = _("File class: unknown");
            break;
    }
    instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
    /* EI_DATA (5) */
    switch (format->header.hdr32.e_ident[EI_DATA])
    {
        case ELFDATANONE:
            text = _("Data encoding: invalid");
            break;
        case ELFDATA2LSB:
            text = _("Data encoding: 2's complement, little endian");
            break;
        case ELFDATA2MSB:
            text = _("Data encoding: 2's complement, big endian");
            break;
        default:
            text = _("Data encoding: unknown");
            break;
    }
    instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
    /* EI_VERSION (6) */
    switch (format->header.hdr32.e_ident[EI_VERSION])
    {
        case EV_NONE:
            text = _("File version: invalid");
            break;
        case EV_CURRENT:
            text = _("File version: current");
            break;
        default:
            text = _("File version: unknown");
            break;
    }
    instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
    /* EI_OSABI (7) */
    switch (format->header.hdr32.e_ident[EI_OSABI])
    {
        case ELFOSABI_SYSV:
            text = _("OS ABI: UNIX System V");
            break;
        case ELFOSABI_HPUX:
            text = _("OS ABI: HP-UX");
            break;
        case ELFOSABI_NETBSD:
            text = _("OS ABI: NetBSD");
            break;
        case ELFOSABI_GNU:
            text = _("OS ABI: object uses GNU ELF extensions");
            break;
        case ELFOSABI_SOLARIS:
            text = _("OS ABI: Sun Solaris");
            break;
        case ELFOSABI_AIX:
            text = _("OS ABI: IBM AIX");
            break;
        case ELFOSABI_IRIX:
            text = _("OS ABI: SGI Irix");
            break;
        case ELFOSABI_FREEBSD:
            text = _("OS ABI: FreeBSD");
            break;
        case ELFOSABI_TRU64:
            text = _("OS ABI: Compaq TRU64 UNIX");
            break;
        case ELFOSABI_MODESTO:
            text = _("OS ABI: Novell Modesto");
            break;
        case ELFOSABI_OPENBSD:
            text = _("OS ABI: OpenBSD");
            break;
        case ELFOSABI_ARM_AEABI:
            text = _("OS ABI: ARM EABI");
            break;
        case ELFOSABI_ARM:
            text = _("OS ABI: ARM");
            break;
        case ELFOSABI_STANDALONE:
            text = _("OS ABI: standalone (embedded) application");
            break;
        default:
            text = _("OS ABI: unknown");
            break;
    }
    instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
    /* EI_ABIVERSION (8) */
    instr = g_raw_instruction_new_array(content, MDS_8_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("ABI version"));
    /* Padding */
    instr = g_raw_instruction_new_array(content, MDS_8_BITS, 7, pos, length, format->endian);
    g_raw_instruction_mark_as_padding(G_RAW_INSTRUCTION(instr), true);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Padding"));
    /* Champ "e_type" */
    switch (format->header.hdr32.e_ident[EI_DATA])
    {
        case ET_NONE:
            text = _("Object file type: no file type");
            break;
        case ET_REL:
            text = _("Object file type: relocatable file");
            break;
        case ET_EXEC:
            text = _("Object file type: executable file");
            break;
        case ET_DYN:
            text = _("Object file type: shared object file");
            break;
        case ET_CORE:
            text = _("Object file type: core file");
            break;
        case ET_LOOS ... ET_HIOS:
            text = _("Object file type: OS-specific");
            break;
        case ET_LOPROC ... ET_HIPROC:
            text = _("Object file type: processor-specific");
            break;
        default:
            text = _("Object file type: unkown");
            break;
    }
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
    /* Champ "e_machine" */
    switch (format->header.hdr32.e_machine)
    {
        case EM_NONE:		text = _("Architecture: No machine"); break;
        case EM_M32:		text = _("Architecture: AT&T WE 32100"); break;
        case EM_SPARC:		text = _("Architecture: SUN SPARC"); break;
        case EM_386:		text = _("Architecture: Intel 80386"); break;
        case EM_68K:		text = _("Architecture: Motorola m68k family"); break;
        case EM_88K:		text = _("Architecture: Motorola m88k family"); break;
        case EM_860:		text = _("Architecture: Intel 80860"); break;
        case EM_MIPS:		text = _("Architecture: MIPS R3000 big-endian"); break;
        case EM_S370:	    text = _("Architecture: IBM System/370"); break;
        case EM_MIPS_RS3_LE:text = _("Architecture: MIPS R3000 little-endian"); break;
        case EM_PARISC:		text = _("Architecture: HPPA"); break;
        case EM_VPP500:		text = _("Architecture: Fujitsu VPP500"); break;
        case EM_SPARC32PLUS:text = _("Architecture: Sun's \"v8plus\""); break;
        case EM_960:		text = _("Architecture: Intel 80960"); break;
        case EM_PPC:		text = _("Architecture: PowerPC"); break;
        case EM_PPC64:		text = _("Architecture: PowerPC 64-bit"); break;
        case EM_S390:		text = _("Architecture: IBM S390"); break;
        case EM_V800:		text = _("Architecture: NEC V800 series"); break;
        case EM_FR20:		text = _("Architecture: Fujitsu FR20"); break;
        case EM_RH32:		text = _("Architecture: TRW RH-32"); break;
        case EM_RCE:		text = _("Architecture: Motorola RCE"); break;
        case EM_ARM:		text = _("Architecture: ARM"); break;
        case EM_FAKE_ALPHA: text = _("Architecture: Digital Alpha"); break;
        case EM_SH:		    text = _("Architecture: Hitachi SH"); break;
        case EM_SPARCV9:	text = _("Architecture: SPARC v9 64-bit"); break;
        case EM_TRICORE:	text = _("Architecture: Siemens Tricore"); break;
        case EM_ARC:		text = _("Architecture: Argonaut RISC Core"); break;
        case EM_H8_300:		text = _("Architecture: Hitachi H8/300"); break;
        case EM_H8_300H:	text = _("Architecture: Hitachi H8/300H"); break;
        case EM_H8S:		text = _("Architecture: Hitachi H8S"); break;
        case EM_H8_500:		text = _("Architecture: Hitachi H8/500"); break;
        case EM_IA_64:		text = _("Architecture: Intel Merced"); break;
        case EM_MIPS_X:		text = _("Architecture: Stanford MIPS-X"); break;
        case EM_COLDFIRE:	text = _("Architecture: Motorola Coldfire"); break;
        case EM_68HC12:		text = _("Architecture: Motorola M68HC12"); break;
        case EM_MMA:		text = _("Architecture: Fujitsu MMA Multimedia Accelerator"); break;
        case EM_PCP:		text = _("Architecture: Siemens PCP"); break;
        case EM_NCPU:		text = _("Architecture: Sony nCPU embeeded RISC"); break;
        case EM_NDR1:		text = _("Architecture: Denso NDR1 microprocessor"); break;
        case EM_STARCORE:	text = _("Architecture: Motorola Start*Core processor"); break;
        case EM_ME16:		text = _("Architecture: Toyota ME16 processor"); break;
        case EM_ST100:		text = _("Architecture: STMicroelectronic ST100 processor"); break;
        case EM_TINYJ:		text = _("Architecture: Advanced Logic Corp. Tinyj emb.fam"); break;
        case EM_X86_64:		text = _("Architecture: AMD x86-64 architecture"); break;
        case EM_PDSP:		text = _("Architecture: Sony DSP Processor"); break;
        case EM_FX66:		text = _("Architecture: Siemens FX66 microcontroller"); break;
        case EM_ST9PLUS:	text = _("Architecture: STMicroelectronics ST9+ 8/16 mc"); break;
        case EM_ST7:		text = _("Architecture: STmicroelectronics ST7 8 bit mc"); break;
        case EM_68HC16:		text = _("Architecture: Motorola MC68HC16 microcontroller"); break;
        case EM_68HC11:		text = _("Architecture: Motorola MC68HC11 microcontroller"); break;
        case EM_68HC08:		text = _("Architecture: Motorola MC68HC08 microcontroller"); break;
        case EM_68HC05:		text = _("Architecture: Motorola MC68HC05 microcontroller"); break;
        case EM_SVX:		text = _("Architecture: Silicon Graphics SVx"); break;
        case EM_ST19:		text = _("Architecture: STMicroelectronics ST19 8 bit mc"); break;
        case EM_VAX:		text = _("Architecture: Digital VAX"); break;
        case EM_CRIS:		text = _("Architecture: Axis Communications 32-bit embedded processor"); break;
        case EM_JAVELIN:	text = _("Architecture: Infineon Technologies 32-bit embedded processor"); break;
        case EM_FIREPATH:	text = _("Architecture: Element 14 64-bit DSP Processor"); break;
        case EM_ZSP:		text = _("Architecture: LSI Logic 16-bit DSP Processor"); break;
        case EM_MMIX:		text = _("Architecture: Donald Knuth's educational 64-bit processor"); break;
        case EM_HUANY:		text = _("Architecture: Harvard University machine-independent object files"); break;
        case EM_PRISM:		text = _("Architecture: SiTera Prism"); break;
        case EM_AVR:		text = _("Architecture: Atmel AVR 8-bit microcontroller"); break;
        case EM_FR30:		text = _("Architecture: Fujitsu FR30"); break;
        case EM_D10V:		text = _("Architecture: Mitsubishi D10V"); break;
        case EM_D30V:		text = _("Architecture: Mitsubishi D30V"); break;
        case EM_V850:		text = _("Architecture: NEC v850"); break;
        case EM_M32R:		text = _("Architecture: Mitsubishi M32R"); break;
        case EM_MN10300:	text = _("Architecture: Matsushita MN10300"); break;
        case EM_MN10200:	text = _("Architecture: Matsushita MN10200"); break;
        case EM_PJ:		    text = _("Architecture: picoJava"); break;
        case EM_OPENRISC:	text = _("Architecture: OpenRISC 32-bit embedded processor"); break;
        case EM_ARC_A5:		text = _("Architecture: ARC Cores Tangent-A5"); break;
        case EM_XTENSA:		text = _("Architecture: Tensilica Xtensa Architecture"); break;
        case EM_AARCH64:	text = _("Architecture: ARM AARCH64"); break;
        case EM_TILEPRO:	text = _("Architecture: Tilera TILEPro"); break;
        case EM_MICROBLAZE:	text = _("Architecture: Xilinx MicroBlaze"); break;
        case EM_TILEGX:		text = _("Architecture: Tilera TILE-Gx"); break;
        default:		    text = _("Architecture: unknown"); break;
    }
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
    /* Champ "e_version" */
    instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Object file version"));
    if (format->header.hdr32.e_ident[EI_CLASS] == ELFCLASS32)
    {
        /* Champ "e_entry" */
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry point virtual address"));
        /* Champ "e_phoff" */
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table file offset"));
        /* Champ "e_shoff" */
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table file offset"));
    }
    else if (format->header.hdr32.e_ident[EI_CLASS] == ELFCLASS64)
    {
        /* Champ "e_entry" */
        instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry point virtual address"));
        /* Champ "e_phoff" */
        instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table file offset"));
        /* Champ "e_shoff" */
        instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table file offset"));
    }
    else return false;
    /* Champ "e_flags" */
    instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
    //SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Processor-specific flags"));
    /* Champ "e_ehsize" */
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("ELF header size in bytes"));
    /* Champ "e_phentsize" */
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table entry size"));
    /* Champ "e_phnum" */
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Program header table entry count"));
    /* Champ "e_shentsize" */
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table entry size"));
    /* Champ "e_shnum" */
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header table entry count"));
    /* Champ "e_shstrndx" */
    instr = g_raw_instruction_new_array(content, MDS_16_BITS, 1, pos, length, format->endian);
    SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
    ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section header string table index"));
    return true;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                                                                             *
*  Description : Charge tous les symboles liés aux en-têtes de programme ELF. *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool annotate_elf_program_header_table(GElfFormat *format)
{
    const bin_t *content;                   /* Contenu binaire à lire      */
    off_t length;                           /* Taille totale du contenu    */
    off_t offset;                           /* Tête de lecture du bbinaire */
    vmpa2t *pos;                            /* Localisation des symboles   */
    uint16_t e_phnum;                       /* Nombre d'éléments 'Program' */
    uint16_t i;                             /* Boucle de parcours          */
    elf_phdr phdr;                          /* En-tête de programme ELF    */
    ImmOperandDisplay disp;                 /* Afficahge de valeur         */
    const char *text;                       /* Texte constant à insérer    */
    GArchInstruction *instr;                /* Instruction décodée         */
    GArchOperand *operand;                  /* Opérande à venir modifier   */
    GDbComment *comment;                    /* Définition de commentaire   */
    GBinSymbol *symbol;                     /* Symbole à intégrer          */
    char *dtext;                            /* Texte dynamique à créer     */
    bool filled;                            /* Suivi de mise en place      */
    content = G_BIN_FORMAT(format)->content;
    length = G_BIN_FORMAT(format)->length;
    offset = ELF_HDR(format, format->header, e_phoff);
    pos = make_vmpa(offset, 0x5500);
    e_phnum = ELF_HDR(format, format->header, e_phnum);
    for (i = 0; i < e_phnum; i++)
    {
        if (!read_elf_program_header(format, &offset, &phdr))
            break;
        /* Champ "p_type" */
        disp = IOD_DEC;
        switch (ELF_PHDR(format, phdr, p_type))
        {
            case PT_NULL:
                text = _("Segment type: unused");
                break;
            case PT_LOAD:
                text = _("Segment type: loadable program segment");
                break;
            case PT_DYNAMIC:
                text = _("Segment type: dynamic linking information");
                break;
            case PT_INTERP:
                text = _("Segment type: program interpreter");
                break;
            case PT_NOTE:
                text = _("Segment type: auxiliary information");
                break;
            case PT_SHLIB:
                text = _("Segment type: reserved");
                break;
            case PT_PHDR:
                text = _("Segment type: entry for header table itself");
                break;
            case PT_TLS:
                text = _("Segment type: thread-local storage segment");
                break;
            case PT_LOOS ... PT_HIOS:
                disp = IOD_HEX;
                switch (ELF_PHDR(format, phdr, p_type))
                {
                    case PT_GNU_EH_FRAME:
                        text = _("Segment type: GCC .eh_frame_hdr segment");
                        break;
                    case PT_GNU_STACK:
                        text = _("Segment type: indicates stack executability");
                        break;
                    case PT_GNU_RELRO:
                        text = _("Segment type: read-only after relocation");
                        break;
                    case PT_LOSUNW ... PT_HISUNW:
                        switch (ELF_PHDR(format, phdr, p_type))
                        {
                            case PT_SUNWSTACK:
                                text = _("Segment type: Sun Stack segment");
                                break;
                            default:
                                text = _("Segment type: Sun specific segment");
                                break;
                        }
                        break;
                    default:
                        text = _("Segment type: OS-specific");
                        break;
                }
                break;
            case PT_LOPROC ... PT_HIPROC:
                disp = IOD_HEX;
                text = _("Segment type: processor-specific");
                break;
            default:
                disp = IOD_HEX;
                text = _("Segment type: unknown");
                break;
        }
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        SET_IMM_DISPLAY(instr, operand, 0, disp);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
        if (format->is_32b)
        {
            /* Champ "p_offset" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment file offset"));
            /* Champ "p_vaddr" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment virtual address"));
            /* Champ "p_paddr" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment physical address"));
            /* Champ "p_filesz" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in file"));
            /* Champ "p_memsz" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in memory"));
            /* Champ "p_flags" */
            dtext = strdup(_("Segment flags: "));
            filled = false;
            if (ELF_PHDR(format, phdr, p_flags) & PF_R)
            {
                dtext = stradd(dtext, "R");
                filled = true;
            }
            if (ELF_PHDR(format, phdr, p_flags) & PF_W)
            {
                dtext = stradd(dtext, "W");
                filled = true;
            }
            if (ELF_PHDR(format, phdr, p_flags) & PF_X)
            {
                dtext = stradd(dtext, "X");
                filled = true;
            }
            if (ELF_PHDR(format, phdr, p_flags) & PF_MASKOS)
                /* TODO */;
            if (ELF_PHDR(format, phdr, p_flags) & PF_MASKPROC)
                /* TODO */;
            if (!filled)
                dtext = stradd(dtext, _("none"));
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
            free(dtext);
            /* Champ "p_align" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment alignment"));
        }
        else
        {
            /* Champ "p_flags" */
            dtext = strdup(_("Segment flags: "));
            filled = false;
            if (ELF_PHDR(format, phdr, p_flags) & PF_R)
            {
                dtext = stradd(dtext, "R");
                filled = true;
            }
            if (ELF_PHDR(format, phdr, p_flags) & PF_W)
            {
                dtext = stradd(dtext, "W");
                filled = true;
            }
            if (ELF_PHDR(format, phdr, p_flags) & PF_X)
            {
                dtext = stradd(dtext, "X");
                filled = true;
            }
            if (ELF_PHDR(format, phdr, p_flags) & PF_MASKOS)
                /* TODO */;
            if (ELF_PHDR(format, phdr, p_flags) & PF_MASKPROC)
                /* TODO */;
            if (!filled)
                dtext = stradd(dtext, _("none"));
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
            free(dtext);
            /* Champ "p_offset" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment file offset"));
            /* Champ "p_vaddr" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment virtual address"));
            /* Champ "p_paddr" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment physical address"));
            /* Champ "p_filesz" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in file"));
            /* Champ "p_memsz" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment size in memory"));
            /* Champ "p_align" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Segment alignment"));
        }
    }
    return true;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                                                                             *
*  Description : Charge tous les symboles liés aux en-têtes de section ELF.   *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool annotate_elf_section_header_table(GElfFormat *format)
{
    const bin_t *content;                   /* Contenu binaire à lire      */
    off_t length;                           /* Taille totale du contenu    */
    off_t offset;                           /* Tête de lecture du bbinaire */
    elf_shdr strings;                       /* Section des descriptions    */
    vmpa2t *pos;                            /* Localisation des symboles   */
    uint16_t e_shnum;                       /* Nombre d'éléments 'Program' */
    uint16_t i;                             /* Boucle de parcours          */
    elf_shdr shdr;                          /* En-tête de programme ELF    */
    const char *secname;                    /* Nom d'une section analysée  */
    ImmOperandDisplay disp;                 /* Afficahge de valeur         */
    const char *text;                       /* Texte constant à insérer    */
    GArchInstruction *instr;                /* Instruction décodée         */
    GArchOperand *operand;                  /* Opérande à venir modifier   */
    GDbComment *comment;                    /* Définition de commentaire   */
    GBinSymbol *symbol;                     /* Symbole à intégrer          */
    char *dtext;                            /* Texte dynamique à créer     */
    bool filled;                            /* Suivi de mise en place      */
    content = G_BIN_FORMAT(format)->content;
    length = G_BIN_FORMAT(format)->length;
    if (!find_elf_section_by_index(format, ELF_HDR(format, format->header, e_shstrndx), &strings))
        return false;
    offset = ELF_HDR(format, format->header, e_shoff);
    pos = make_vmpa(offset, 0x9900);
    e_shnum = ELF_HDR(format, format->header, e_shnum);
    for (i = 0; i < e_shnum; i++)
    {
        if (!read_elf_section_header(format, get_phy_addr(pos), &shdr))
            break;
        /* Champ "sh_name" */
        secname = extract_name_from_elf_string_section(format, &strings,
                                                       ELF_SHDR(format, shdr, sh_name));
        if (secname == NULL)
            dtext = strdup(_("Section name: "));
        else
        {
            dtext = strdup(_("Section name: '"));
            dtext = stradd(dtext, secname);
            dtext = stradd(dtext, "'");
        }
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
        free(dtext);
        /* Champ "sh_type" */
        disp = IOD_DEC;
        switch (ELF_SHDR(format, shdr, sh_type))
        {
            case SHT_NULL:
                text = _("Section type: unused");
                break;
            case SHT_PROGBITS:
                text = _("Section type: program data");
                break;
            case SHT_SYMTAB:
                text = _("Section type: symbol table");
                break;
            case SHT_STRTAB:
                text = _("Section type: string table");
                break;
            case SHT_RELA:
                text = _("Section type: relocation entries with addends");
                break;
            case SHT_HASH:
                text = _("Section type: symbol hash table");
                break;
            case SHT_DYNAMIC:
                text = _("Section type: dynamic linking information");
                break;
            case SHT_NOTE:
                text = _("Section type: notes");
                break;
            case SHT_NOBITS:
                text = _("Section type: program space with no data (bss)");
                break;
            case SHT_REL:
                text = _("Section type: relocation entries, no addends");
                break;
            case SHT_SHLIB:
                text = _("Section type: reserved");
                break;
            case SHT_DYNSYM:
                text = _("Section type: dynamic linker symbol table");
                break;
            case SHT_INIT_ARRAY:
                text = _("Section type: array of constructors");
                break;
            case SHT_FINI_ARRAY:
                text = _("Section type: array of destructors");
                break;
            case SHT_PREINIT_ARRAY:
                text = _("Section type: array of pre-constructors");
                break;
            case SHT_GROUP:
                text = _("Section type: section group");
                break;
            case SHT_SYMTAB_SHNDX:
                text = _("Section type: extended section indeces");
                break;
            case SHT_LOOS ... SHT_HIOS:
                disp = IOD_HEX;
                switch (ELF_SHDR(format, shdr, sh_type))
                {
                    case SHT_GNU_ATTRIBUTES:
                        text = _("Section type: object attributes");
                        break;
                    case SHT_GNU_HASH:
                        text = _("Section type: GNU-style hash table");
                        break;
                    case SHT_GNU_LIBLIST:
                        text = _("Section type: prelink library list");
                        break;
                    case SHT_CHECKSUM:
                        text = _("Section type: checksum for DSO content");
                        break;
                    case SHT_LOSUNW ... SHT_HISUNW:
                        switch (ELF_SHDR(format, shdr, sh_type))
                        {
                            case SHT_SUNW_move:
                                text = _("Section type: SHT_SUNW_move");
                                break;
                            case SHT_SUNW_COMDAT:
                                text = _("Section type: SHT_SUNW_COMDAT");
                                break;
                            case SHT_SUNW_syminfo:
                                text = _("Section type: SHT_SUNW_syminfo");
                                break;
                            case SHT_GNU_verdef:
                                text = _("Section type: version definition section");
                                break;
                            case SHT_GNU_verneed:
                                text = _("Section type: version needs section");
                                break;
                            case SHT_GNU_versym:
                                text = _("Section type: version symbol table");
                                break;
                            default:
                                text = _("Section type: Sun-specific");
                                break;
                        }
                        break;
                    default:
                        text = _("Section type: OS-specific");
                        break;
                }
                break;
            case SHT_LOPROC ... SHT_HIPROC:
                disp = IOD_HEX;
                text = _("Section type: processor-specific");
                break;
            case SHT_LOUSER ... SHT_HIUSER:
                disp = IOD_HEX;
                text = _("Section type: application-specific");
                break;
            default:
                disp = IOD_HEX;
                text = _("Section type: unknown");
                break;
        }
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        SET_IMM_DISPLAY(instr, operand, 0, disp);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, text);
        /* Champ "sh_flags"... */
        dtext = strdup(_("Section flags: "));
        filled = false;
        if (ELF_SHDR(format, shdr, sh_type) & SHF_WRITE)
        {
            dtext = stradd(dtext, "W");
            filled = true;
        }
        if (ELF_SHDR(format, shdr, sh_type) & SHF_ALLOC)
        {
            dtext = stradd(dtext, "A");
            filled = true;
        }
        if (ELF_SHDR(format, shdr, sh_type) & SHF_EXECINSTR)
        {
            dtext = stradd(dtext, "X");
            filled = true;
        }
        if (ELF_SHDR(format, shdr, sh_type) & SHF_MERGE)
        {
            dtext = stradd(dtext, "M");
            filled = true;
        }
        if (ELF_SHDR(format, shdr, sh_type) & SHF_LINK_ORDER)
        {
            dtext = stradd(dtext, "L");
            filled = true;
        }
        if (ELF_SHDR(format, shdr, sh_type) & SHF_TLS)
        {
            dtext = stradd(dtext, "T");
            filled = true;
        }
        if (!filled)
            dtext = stradd(dtext, _("none"));
        if (format->is_32b)
        {
            /* Champ "sh_flags" (suite) */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
            free(dtext);
            /* Champ "sh_addr" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section virtual addr at execution"));
            /* Champ "sh_offset" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section file offset"));
            /* Champ "sh_size" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section size in bytes"));
        }
        else
        {
            /* Champ "sh_flags" (suite) */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, dtext);
            free(dtext);
            /* Champ "sh_addr" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section virtual addr at execution"));
            /* Champ "sh_offset" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section file offset"));
            /* Champ "sh_size" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section size in bytes"));
        }
        /* Champ "sh_link" */
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Link to another section"));
        /* Champ "sh_info" */
        instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
        ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Additional section information"));
        if (format->is_32b)
        {
            /* Champ "sh_addralign" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section alignment"));
            /* Champ "sh_entsize" */
            instr = g_raw_instruction_new_array(content, MDS_32_BITS, 1, pos, length, format->endian);
            SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry size if section holds table"));
        }
        else
        {
            /* Champ "sh_addralign" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Section alignment"));
            /* Champ "sh_entsize" */
            instr = g_raw_instruction_new_array(content, MDS_64_BITS, 1, pos, length, format->endian);
            SET_IMM_DISPLAY(instr, operand, 0, IOD_DEC);
            ADD_RAW_AS_SYM(format, symbol, pos, instr, comment, _("Entry size if section holds table"));
        }
    }
    return true;
}
/* ---------------------------------------------------------------------------------- */
/*                            DETAIL DES SYMBOLES INTERNES                            */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                                                                             *
*  Description : Charge tous les symboles internes possibles.                 *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static bool load_elf_internal_symbols(GElfFormat *format)
{
    bool result;                            /* Bilan à retourner           */
    bool no_name;                           /* Choix de construction de nom*/
    elf_shdr *sections;                      /* Groupe de sections trouvées */
    size_t count;                           /* Quantité de données         */
    size_t i;                               /* Boucle de parcours          */
    result = true;
    /* Charge tous les symboles définis dans une section */
    bool add_all_symbols_from_section(GElfFormat *format, const elf_shdr *section, bool use_virt)
    {
        elf_shdr strtab;                    /* Section .strtab trouvée     */
        bool has_strtab;                    /* Présence de cette section   */
        off_t start;                        /* Début de la zone à traiter  */
        off_t size;                         /* Taille de cette même zone   */
        off_t iter;                         /* Boucle de parcours          */
        elf_sym sym;                        /* Symbole aux infos visées    */
        vmpa2t addr;                        /* Localisation d'une routine  */
        mrange_t range;                     /* Couverture mémoire associée */
        const char *name;                   /* Nom du symbole trouvé       */
        char alt_name[5 + VMPA_MAX_LEN];    /* Nom abstrait de substitution*/
        GBinRoutine *routine;               /* Nouvelle routine trouvée    */
        GBinSymbol *symbol;                 /* Nouveau symbole construit   */
        has_strtab = find_elf_section_by_index(format, ELF_SHDR(format, *section, sh_link), &strtab);
        get_elf_section_content(format, section, &start, &size, NULL);
        for (iter = start; iter < (start + size); )
        {
            result = read_elf_symbol(format, &iter, &sym);
            if (!result) break;
            if (ELF_SYM(format, sym, st_value) == 0) continue;
            /* Résolution précise d'adresse */
            /* TODO */
            init_vmpa(&addr, ELF_SYM(format, sym, st_value), VMPA_NO_VIRTUAL);
            init_mrange(&range, &addr, ELF_SYM(format, sym, st_size));
            /* Première ébauche de nom */
            if (!has_strtab) name = NULL;
            else name = get_elf_symbol_name(format, section, &strtab,
                                            ((iter - start) / ELF_SIZEOF_SYM(format)) - 1);
            /* Traitements particuliers */
            switch (ELF_ST_TYPE(format, sym))
            {
                case STT_OBJECT:
                    /* 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);
                    }
                    /* TODO */
                    symbol = NULL;
                    break;
                case STT_FUNC:
                    /* 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);
                    }
                    /* Routine */
					printf("ADDING>> '%s'\n", name);
                    routine = try_to_demangle_routine(name);
                    g_binary_routine_set_range(routine, &range);
                    /* Symbole uniquement */
                    symbol = g_binary_symbol_new(STP_ROUTINE, name, ~0);
                    g_binary_symbol_attach_routine(symbol, routine);
                    break;
                default:
                    symbol = NULL;
                    break;
            }
            if (symbol != NULL)
                g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);
        }
        return true;
    }
    if (!g_generic_config_get_value(get_main_configuration(), MPK_FORMAT_NO_NAME, &no_name))
        return false;
    if (find_elf_sections_by_type(format, SHT_DYNSYM, §ions, &count))
        for (i = 0; i < count && result; i++)
            result = add_all_symbols_from_section(format, §ions[i], no_name);
    if (find_elf_sections_by_type(format, SHT_SYMTAB, §ions, &count))
        for (i = 0; i < count && result; i++)
            result = add_all_symbols_from_section(format, §ions[i], no_name);
    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 bin_t *content;                   /* Contenu binaire à lire      */
    off_t length;                           /* Taille totale du contenu    */
    off_t pos;                              /* Position de lecture         */
    off_t 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;
    length = G_BIN_FORMAT(format)->length;
    for (pos = ELF_SHDR(format, *section, sh_offset);
         pos < length/* FIXME !! + xploit */ && result;
         pos += ELF_SIZEOF_DYN(format))
    {
        tmp = pos;
        if (format->is_32b)
        {
            result = read_s32(&tag32, content, &tmp, length, format->endian);
            if (tag32 == type) break;
        }
        else
        {
            result = read_s64(&tag64, content, &tmp, length, format->endian);
            if (tag64 == type) break;
        }
    }
    result &= (pos < length);
    if (result)
    {
        if (format->is_32b)
        {
            result = read_s32(&item->dyn32.d_tag, content, &pos, length, format->endian);
            result &= read_s32(&item->dyn32.d_un.d_val, content, &pos, length, format->endian);
        }
        else
        {
            result = read_s64(&item->dyn64.d_tag, content, &pos, length, format->endian);
            result &= read_s64(&item->dyn64.d_un.d_val, content, &pos, length, format->endian);
        }
    }
    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 (g_exe_format_get_target_machine(G_EXE_FORMAT(format)))
            {
                case FTM_ARM:
                    result = load_elf_arm_relocated_symbols(format, &relxxx, &dynsym, &dynstr);
                    break;
                case FTM_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;
}