/* Chrysalide - Outil d'analyse de fichiers binaires
 * executable.c - support des formats d'exécutables
 *
 * Copyright (C) 2009-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 "executable.h"


#include <malloc.h>
#include <stdlib.h>


#include "executable-int.h"
#include "format.h"



/* Initialise la classe des formats d'exécutables génériques. */
static void g_executable_format_class_init(GExeFormatClass *);

/* Initialise une instance de format d'exécutable générique. */
static void g_executable_format_init(GExeFormat *);



/* Indique le type défini pour un format d'exécutable générique. */
G_DEFINE_TYPE(GExeFormat, g_executable_format, G_TYPE_BIN_FORMAT);


/******************************************************************************
*                                                                             *
*  Paramètres  : klass = classe à initialiser.                                *
*                                                                             *
*  Description : Initialise la classe des formats d'exécutables génériques.   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_executable_format_class_init(GExeFormatClass *klass)
{

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = instance à initialiser.                             *
*                                                                             *
*  Description : Initialise une instance de format d'exécutable générique.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_executable_format_init(GExeFormat *format)
{

}











/******************************************************************************
*                                                                             *
*  Paramètres  : format = informations chargées à consulter.                  *
*                                                                             *
*  Description : Indique le type d'architecture visée par le format.          *
*                                                                             *
*  Retour      : Identifiant de l'architecture ciblée par le format.          *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

const char *g_exe_format_get_target_machine(const GExeFormat *format)
{
    return format->get_machine(format);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à consulter.            *
*                                                                             *
*  Description : Décrit les différentes portions qui composent le binaire.    *
*                                                                             *
*  Retour      : Défintions de zones.                                         *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GBinPortion *g_exe_format_get_portions(GExeFormat *format)
{
    vmpa2t addr;                            /* Emplacement vide de sens    */

    if (format->portions == NULL)
    {
        format->portions = g_binary_portion_new(BPC_RAW);

        init_vmpa(&addr, 0, VMPA_NO_VIRTUAL);
        g_binary_portion_set_values(format->portions, &addr, G_BIN_FORMAT(format)->length);

        if (format->refine_portions != NULL)
            format->refine_portions(format, format->portions);

    }

    return format->portions;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à consulter.            *
*                level  = étage des portions à considérer ou -1 pour tous.    *
*                count  = nombre de portions trouvées et renvoyées. [OUT]     *
*                                                                             *
*  Description : Fournit une liste choisie de portions d'un binaire.          *
*                                                                             *
*  Retour      : Liste de définitins de zones à libérer après usage.          *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GBinPortion **g_exe_format_get_portions_at_level(GExeFormat *format, unsigned int level, size_t *count)
{
    GBinPortion **result;                   /* Liste à retourner           */

    typedef struct _portions_list
    {
        unsigned int required;
        GBinPortion **portions;
        size_t length;

    } portions_list;

    portions_list list;                     /* Sauvegarde de la liste      */

    bool visit_for_level(GBinPortion *portion, portions_list *list)
    {
        if (list->required == -1 || g_binary_portion_get_level(portion) == list->required)
        {
            list->portions = (GBinPortion **)realloc(list->portions, ++list->length * sizeof(GBinPortion *));
            list->portions[list->length - 1] = portion;
        }

        return true;

    }

    list.required = level;
    list.portions = NULL;
    list.length = 0;

    g_binary_portion_visit(g_exe_format_get_portions(format), (visit_portion_fc)visit_for_level, &list);

    result = list.portions;
    *count = list.length;

    qsort(result, *count, sizeof(GBinPortion *), (__compar_fn_t)g_binary_portion_compare);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = informations chargées à consulter.                  *
*                count  = quantité de zones listées. [OUT]                    *
*                                                                             *
*  Description : Fournit les espaces mémoires des portions exécutables.       *
*                                                                             *
*  Retour      : Liste de zones binaires exécutables à libérer après usage.   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

mrange_t *g_exe_format_get_x_ranges(GExeFormat *format, size_t *count)
{
    mrange_t *result;                       /* Liste à retourner           */

    typedef struct _x_ranges
    {
        mrange_t *list;
        size_t length;

    } x_ranges;

    x_ranges tmp;                           /* Sauvegarde de la liste      */

    bool visit_for_x(GBinPortion *portion, x_ranges *ranges)
    {
        const mrange_t *range;

        if (g_binary_portion_get_rights(portion) & PAC_EXEC)
        {
            range = g_binary_portion_get_range(portion);

            ranges->list = (mrange_t *)realloc(ranges->list, ++ranges->length * sizeof(mrange_t));
            copy_mrange(&ranges->list[ranges->length - 1], range);

        }

        return true;

    }

    tmp.list = NULL;
    tmp.length = 0;

    g_binary_portion_visit(g_exe_format_get_portions(format), (visit_portion_fc)visit_for_x, &tmp);

    result = tmp.list;
    *count = tmp.length;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à consulter.            *
*                off    = position physique à retrouver.                      *
*                pos    = position correspondante. [OUT]                      *
*                                                                             *
*  Description : Fournit l'emplacement correspondant à une position physique. *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool g_exe_format_translate_offset_into_vmpa(const GExeFormat *format, phys_t off, vmpa2t *pos)
{
    bool result;                            /* Bilan à retourner           */

    result = G_EXE_FORMAT_GET_CLASS(format)->translate_phys(format, off, pos);

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : format = description de l'exécutable à consulter.            *
*                addr   = adresse virtuelle à retrouver.                      *
*                pos    = position correspondante. [OUT]                      *
*                                                                             *
*  Description : Fournit l'emplacement correspondant à une adresse virtuelle. *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool g_exe_format_translate_address_into_vmpa(const GExeFormat *format, virt_t addr, vmpa2t *pos)
{
    bool result;                            /* Bilan à retourner           */

    result = G_EXE_FORMAT_GET_CLASS(format)->translate_virt(format, addr, pos);

    return result;

}