/* Chrysalide - Outil d'analyse de fichiers binaires
 * helper_x86.c - gestion auxiliaire de l'architecture x86
 *
 * Copyright (C) 2014-2017 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  Chrysalide 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.
 *
 *  Chrysalide 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 "helper_arm.h"


#include "elf-int.h"
#include "symbols.h"
#include "../mangling/demangler.h"








/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                relxxx = section .rel.xxx trouvée (zone à traiter).          *
*                dynsym = section .dynsym trouvée (info. dynamiques).         *
*                dynstr = section .dynstr trouvée (chaînes de caractères).    *
*                                                                             *
*  Description : Charge en mémoire la liste des symboles relogés.             *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool load_elf_arm_relocated_symbols(GElfFormat *format, const elf_shdr *relxxx, const elf_shdr *dynsym, const elf_shdr *dynstr)
{
    bool result;                            /* Bilan à retourner           */
    phys_t rel_start;                       /* Début de la zone à traiter  */
    phys_t rel_size;                        /* Taille de cette même zone   */
    phys_t iter;                            /* Boucle de parcours          */
    elf_rel reloc;                          /* Infos de relocalisation     */
    off_t index;                            /* Indice de la portion visée  */
    elf_sym sym;                            /* Définition complète         */
    const char *name;                       /* Nom du symbole trouvé       */



    virt_t virt;                            /* Adresse en mémoire virtuelle*/
    virt_t final_virt;                      /* Adresse virtuelle retenue   */
    bool status;                            /* Bilan d'une opération       */
    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   */




    result = true;



    get_elf_section_content(format, relxxx, &rel_start, &rel_size, NULL);


    for (iter = rel_start; iter < (rel_start + rel_size); )
    {
        result = read_elf_relocation(format, &iter, &reloc);
        if (!result) break;

        index = ELF_REL_SYM(format, reloc);

        if (!get_elf_symbol_by_index(format, dynsym, index, &sym))
            continue;

        name = get_elf_symbol_name(format, dynsym, dynstr, index);
        if (name == NULL)
        {
            /* FIXME */
            name = "unknown";
        }

        switch (ELF_REL_TYPE(format, reloc))
        {
            case R_ARM_JUMP_SLOT:

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

                final_virt = virt & ~0x1;

                status = g_exe_format_translate_address_into_vmpa(G_EXE_FORMAT(format), final_virt, &addr);
                if (!status) continue;

                init_mrange(&range, &addr, 0);

                routine = try_to_demangle_routine(name);

                g_binary_routine_set_range(routine, &range);

                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:
                printf("Relocation not supported (%lld) !\n", ELF_REL_TYPE(format, reloc));
                symbol = NULL;
                break;

        }

        if (symbol != NULL)
            g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);

    }

    return result;

}