/* Chrysalide - Outil d'analyse de fichiers binaires
 * helper_x86.c - gestion auxiliaire de l'architecture x86
 *
 * Copyright (C) 2009-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_x86.h"



bool load_elf_x86_relocated_symbols(GElfFormat *a, const elf_shdr *b, const elf_shdr *c, const elf_shdr *d)
{
    return false;
}

/* Déduit les adresses effectives des appels externes. */
bool find_elf_x86_dynamic_symbols(GElfFormat *a, const elf_shdr *b, const elf_shdr *c, const elf_shdr *d, const elf_shdr *e)
{
    return false;
}






#if 0

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


#include "elf-int.h"
#include "../symbol.h"
#include "../mangling/demangler.h"
#include "../../arch/immediate.h"
#include "../../arch/processor.h"
#include "../../arch/x86/instruction.h"


// Désactivation
#define g_x86_instruction_get_opcode(i) 0


/* symbols.c : Récupère la désignation d'un symbole donné. */
extern const char *get_elf_symbol_name(GElfFormat *, const elf_shdr *, const elf_shdr *, off_t);


/* Décode les instructions liées à la relocalisation. */
GArchInstruction **decode_elf_relocations(GElfFormat *, const elf_shdr *, size_t *);

/* Déduit les adresses effectives des relocalisations. */
void translate_exe_elf_relocations(GElfFormat *, GArchInstruction **, size_t);

/* Déduit les adresses effectives des relocalisations. */
void translate_dyn_elf_relocations(GElfFormat *, GArchInstruction **, size_t, const elf_shdr *, const elf_shdr *, const elf_shdr *);



/******************************************************************************
*                                                                             *
*  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 dynamiques.          *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

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




    result = true;



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


    printf("rel :: %d -> %d\n", rel_start, rel_start + rel_size);



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

        switch (ELF_REL_TYPE(format, reloc))
        {
            case R_386_NONE:
                break;

            case R_386_JMP_SLOT:

                index = ELF_REL_SYM(format, reloc);
                name = get_elf_symbol_name(format, dynsym, dynstr, index);


                //printf("got a jump ! >> %d - %s\n", index, name);


                if (name == NULL)
                {
                    /* FIXME */
                    name = "unknown";
                }

                symbol = g_binary_symbol_new(NULL, STP_ROUTINE);
                g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);

                break;

            default:
                printf("Relocation not supported (%lld) !\n", ELF_REL_TYPE(format, reloc));
                break;

        }

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                plt    = section .plt trouvée (points d'entrées dynamiques). *
*                rel    = section .rel.plt présentant la table des symboles.  *
*                dynsym = section listant tous les symboles.                  *
*                dynstr = section contenant le nom de ces symboles.           *
*                                                                             *
*  Description : Déduit les adresses effectives des appels externes.          *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool find_elf_x86_dynamic_symbols(GElfFormat *format, const elf_shdr *plt, const elf_shdr *rel, const elf_shdr *dynsym, const elf_shdr *dynstr)
{
    GArchInstruction **instructions;        /* Instructions décodées       */
    size_t count;                           /* Quantité d'instructions     */
    size_t i;                               /* Boucle de parcours          */

    instructions = decode_elf_relocations(format, plt, &count);

    switch (ELF_HDR(format, format->header, e_type))
    {
        case ET_EXEC:
            translate_exe_elf_relocations(format, instructions, count);
            break;

        case ET_DYN:
            translate_dyn_elf_relocations(format, instructions, count, rel, dynsym, dynstr);
            break;

    }

    for (i = 0; i < count; i++)
        /* TODO : free instructions[i] */;

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

    return true;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à compléter.            *
*                plt    = section .plt trouvée (points d'entrées dynamiques). *
*                count  = nombre d'instructions lues. [OUT]                   *
*                                                                             *
*  Description : Décode les instructions liées à la relocalisation.           *
*                                                                             *
*  Retour      : Liste des instructions décodées ou NULL.                     *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GArchInstruction **decode_elf_relocations(GElfFormat *format, const elf_shdr *plt, size_t *count)
{
    GArchInstruction **result;              /* Liste à renvoyer            */
    off_t plt_start;                        /* Début de section            */
    off_t plt_size;                         /* Taille de section           */
    vmpa_t plt_address;                     /* Adresse virtuelle associée  */
    GArchProcessor *proc;                   /* Processeur pour le décodage */
    off_t pos;                              /* Tête de lecture             */
    vmpa_t address;                         /* Adresse virtuelle courante  */
    GArchInstruction *instr;                /* Instruction décodée         */

    result = NULL;
    *count = 0;

    get_elf_section_content(format, plt, &plt_start, &plt_size, &plt_address);

    proc = NULL;//get_arch_processor_for_type(APT_386);

    for (pos = 0; pos < plt_size; )
    {
        address = plt_address + pos;

#if 0
        instr = g_arch_processor_decode_instruction(proc, NULL /*FIXME*/, &G_BIN_FORMAT(format)->content[plt_start],
                                                    &pos, plt_size, address, NULL /*FIXME*/);
#endif

        result = (GArchInstruction **)realloc(result, ++(*count) * sizeof(GArchInstruction *));
        result[*count - 1] = instr;

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format       = description de l'exécutable à compléter.      *
*                instructions = listes des instructions à interpréter.        *
*                count        = nombre d'instructions lues.                   *
*                                                                             *
*  Description : Déduit les adresses effectives des relocalisations.          *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void translate_exe_elf_relocations(GElfFormat *format, GArchInstruction **instructions, size_t count)
{
    size_t i;                               /* Boucle de parcours #1       */
    X86Opcodes opcode_n0;                   /* Opcode de l'instruction n   */
    X86Opcodes opcode_n1;                   /* Opcode de l'instruction n+1 */
    X86Opcodes opcode_n2;                   /* Opcode de l'instruction n+2 */
    const GArchOperand *operand;            /* Valeur du saut              */
    vmpa_t address;                         /* Adresse virtuelle finale    */
    GBinSymbol **symbols;                   /* Liste des symboles existants*/
    size_t symbols_count;                   /* Taille de cette liste       */
    size_t j;                               /* Boucle de parcours #2       */
    size_t new_len;                         /* Taille du nouveau nom       */
    char *new_name;                         /* Nom avec suffixe @plt       */
    GBinRoutine *routine;                   /* Nouvelle routine déduite    */
    GBinSymbol *symbol;                     /* Nouveau symbole construit   */

    for (i = 0; (i + 2) < count; )
    {
        opcode_n0 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i]));
        opcode_n1 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i + 1]));
        opcode_n2 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i + 2]));

        if (opcode_n0 == XOP_JMP_RM1632
            && opcode_n1 == XOP_PUSH_IMM1632
            && opcode_n2 == XOP_JMP_REL1632)
        {
            operand = g_arch_instruction_get_operand(instructions[i], 0);

            if (g_imm_operand_to_vmpa_t(G_IMM_OPERAND(operand), &address))
            {
                symbols = g_binary_format_get_symbols(G_BIN_FORMAT(format), &symbols_count);

                for (j = 0; j < symbols_count; j++)
                    if (0 /* FIXME g_binary_symbol_get_address(symbols[j]) == address*/)
                    {
                        /* Nom final */

                        new_len = strlen(g_binary_symbol_get_label(symbols[j])) + 4 + 1;
                        new_name = calloc(new_len, sizeof(char));
                        snprintf(new_name, new_len, "%s@plt", g_binary_symbol_get_label(symbols[j]));

                        g_arch_instruction_get_location(instructions[i], NULL, NULL, &address);

                        /* Routine */

                        routine = try_to_demangle_routine(g_binary_symbol_get_label(symbols[j]));

                        ///g_binary_routine_set_address(routine, address);

                        ///// reactiver g_binary_format_add_routine(G_BIN_FORMAT(format), routine);

                        /* Symbole uniquement */

                        symbol = g_binary_symbol_new(NULL, STP_ROUTINE);

                        g_binary_symbol_attach_routine(symbol, routine);

                        g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);

                        break;

                    }

            }

            i += 3;

        }
        else i++;

    }

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format       = description de l'exécutable à compléter.      *
*                instructions = listes des instructions à interpréter.        *
*                count        = nombre d'instructions lues.                   *
*                                                                             *
*  Description : Déduit les adresses effectives des relocalisations.          *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void translate_dyn_elf_relocations(GElfFormat *format, GArchInstruction **instructions, size_t count, const elf_shdr *rel, const elf_shdr *dynsym, const elf_shdr *dynstr)
{
    off_t rel_start;                        /* Début de la zone à traiter  */
    off_t rel_size;                         /* Taille de cette même zone   */
    size_t i;                               /* Boucle de parcours #1       */
    X86Opcodes opcode_n0;                   /* Opcode de l'instruction n   */
    X86Opcodes opcode_n1;                   /* Opcode de l'instruction n+1 */
    X86Opcodes opcode_n2;                   /* Opcode de l'instruction n+2 */
    const GArchOperand *operand;            /* Valeur du saut              */
    off_t pos;                              /* Tête de lecture             */
    bool negative;                          /* Tête de lecture invalide ?  */
    elf_rel reloc;                          /* Infos de relocalisation     */
    off_t index;                            /* Indice de la portion visée  */
    const char *name;                       /* Nom du symbole trouvé       */
    size_t new_len;                         /* Taille du nouveau nom       */
    char *new_name;                         /* Nom avec suffixe @plt       */
    vmpa_t address;                         /* Adresse virtuelle finale    */
    GBinRoutine *routine;                   /* Nouvelle routine déduite    */
    GBinSymbol *symbol;                     /* Nouveau symbole construit   */

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

    for (i = 0; (i + 2) < count; )
    {
        opcode_n0 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i]));
        opcode_n1 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i + 1]));
        opcode_n2 = g_x86_instruction_get_opcode(G_X86_INSTRUCTION(instructions[i + 2]));

        if (opcode_n0 == XOP_JMP_RM1632
            && opcode_n1 == XOP_PUSH_IMM1632
            && opcode_n2 == XOP_JMP_REL1632)
        {
            operand = g_arch_instruction_get_operand(instructions[i + 1], 0);

            if (!g_imm_operand_to_off_t(G_IMM_OPERAND(operand), &pos, &negative))
                goto next_op;

            if ((pos + ELF_SIZEOF_REL(format)) > rel_size)
                goto next_op;

            pos += rel_start;

            if (!false/*read_elf_relocation(format, &pos, &reloc)*/)
                goto next_op;

            index = ELF_REL_SYM(format, reloc);
            name = get_elf_symbol_name(format, dynsym, dynstr, index);

            if (name == NULL)
            {
                /* FIXME */
                name = "unknown";
            }

            /* Nom final */

            new_len = strlen(name) + 4 + 1;
            new_name = calloc(new_len, sizeof(char));
            snprintf(new_name, new_len, "%s@plt", name);

            g_arch_instruction_get_location(instructions[i], NULL, NULL, &address);

            /* Routine */

            routine = try_to_demangle_routine(name);

            ////g_binary_routine_set_address(routine, address);

            ///// reactiver g_binary_format_add_routine(G_BIN_FORMAT(format), routine);

            /* Symbole uniquement */

            symbol = g_binary_symbol_new(NULL, STP_ROUTINE);

            g_binary_symbol_attach_routine(symbol, routine);

            g_binary_format_add_symbol(G_BIN_FORMAT(format), symbol);

 next_op:

            i += 3;

        }
        else i++;

    }

}

#endif