/* Chrysalide - Outil d'analyse de fichiers binaires
* symbol.c - gestion des symboles dans un binaire
*
* Copyright (C) 2009-2012 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 "symbol.h"
#include
#include
/* Symbole d'exécutable (instance) */
struct _GBinSymbol
{
GObject parent; /* A laisser en premier */
SymbolType type; /* Type du symbole */
bool block_start; /* Début d'un bloc ? */
char *alt; /* Nom alternatif */
union
{
GArchInstruction *instr; /* Instruction correspondante */
GBinRoutine *routine; /* Compléments pour fonction */
} extra;
GDbComment *comment; /* Eventuel commentaire lié */
};
/* Symbole d'exécutable (classe) */
struct _GBinSymbolClass
{
GObjectClass parent; /* A laisser en premier */
};
/* Initialise la classe des symboles d'exécutables. */
static void g_binary_symbol_class_init(GBinSymbolClass *);
/* Initialise une instance de symbole d'exécutable. */
static void g_binary_symbol_init(GBinSymbol *);
/* Supprime toutes les références externes. */
static void g_binary_symbol_dispose(GBinSymbol *);
/* Procède à la libération totale de la mémoire. */
static void g_binary_symbol_finalize(GBinSymbol *);
/* Indique le type défini pour un symbole d'exécutable. */
G_DEFINE_TYPE(GBinSymbol, g_binary_symbol, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des symboles d'exécutables. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_symbol_class_init(GBinSymbolClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_symbol_dispose;
object->finalize = (GObjectFinalizeFunc)g_binary_symbol_finalize;
}
/******************************************************************************
* *
* Paramètres : symbol = instance à initialiser. *
* *
* Description : Initialise une instance de symbole d'exécutable. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_symbol_init(GBinSymbol *symbol)
{
}
/******************************************************************************
* *
* Paramètres : symbol = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_symbol_dispose(GBinSymbol *symbol)
{
/* TODO... */
G_OBJECT_CLASS(g_binary_symbol_parent_class)->dispose(G_OBJECT(symbol));
}
/******************************************************************************
* *
* Paramètres : symbol = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_symbol_finalize(GBinSymbol *symbol)
{
free(symbol->alt);
G_OBJECT_CLASS(g_binary_symbol_parent_class)->finalize(G_OBJECT(symbol));
}
/******************************************************************************
* *
* Paramètres : type = type de symbole à créer. *
* *
* Description : Crée un nouveau symbole d'exécutable. *
* *
* Retour : Adresse de l'instance mise en place ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinSymbol *g_binary_symbol_new(SymbolType type)
{
GBinSymbol *result; /* Nouveau symbole à renvoyer */
result = g_object_new(G_TYPE_BIN_SYMBOL, NULL);
result->type = type;
return result;
}
/******************************************************************************
* *
* Paramètres : a = premier symbole à analyser. *
* b = second symbole à analyser. *
* *
* Description : Compare deux symboles d'exécutable selon leurs propriétés. *
* *
* Retour : Bilan de la comparaison : -1, 0 ou 1 (-1 par défaut). *
* *
* Remarques : - *
* *
******************************************************************************/
int g_binary_symbol_cmp(const GBinSymbol **a, const GBinSymbol **b)
{
int result; /* Bilan à retourner */
const mrange_t *ra; /* Emplacement du symbole A */
const mrange_t *rb; /* Emplacement du symbole B */
ra = g_binary_symbol_get_range(*a);
rb = g_binary_symbol_get_range(*b);
if (ra == NULL && rb == NULL)
result = 0;
else if (ra != NULL && rb == NULL)
result = 1;
else if (ra == NULL && rb != NULL)
result = -1;
else
result = cmp_mrange(ra, rb);
return result;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* *
* Description : Fournit le type du symbole. *
* *
* Retour : Type de symbole représenté. *
* *
* Remarques : - *
* *
******************************************************************************/
SymbolType g_binary_symbol_get_target_type(const GBinSymbol *symbol)
{
return symbol->type;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir compléter. *
* start = indication quant à la nature du symbole. *
* *
* Description : Définit si un symbole est susceptible de démarrer un bloc. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_symbol_define_as_block_start(GBinSymbol *symbol, bool start)
{
symbol->block_start = start;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* *
* Description : Indique si un symbole est susceptible de démarrer un bloc. *
* *
* Retour : Capacité de rassemblement du symbole. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_binary_symbol_is_block_start(GBinSymbol *symbol)
{
bool result; /* Statut à retourner */
switch (g_binary_symbol_get_target_type(symbol))
{
case STP_ROUTINE:
case STP_OBJECT:
case STP_FUNCTION:
case STP_ENTRY_POINT:
case STP_STRING:
case STP_RO_STRING:
result = true;
break;
default:
result = false;
break;
}
result |= symbol->block_start;
return result;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* *
* Description : Fournit un étiquette pour viser un symbole. *
* *
* Retour : Chaîne de caractères renvoyant au symbole. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *g_binary_symbol_get_label(const GBinSymbol *symbol)
{
const char *result; /* Etiquette à retourner */
if (symbol->alt != NULL)
return symbol->alt;
result = NULL;
switch (symbol->type)
{
case STP_ROUTINE:
case STP_ENTRY_POINT:
case STP_CODE_LABEL:
result = g_binary_routine_get_declarator(symbol->extra.routine, false);
break;
default:
result = NULL;
break;
}
return result;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* alt = désignation humaine alternative à favoriser. *
* *
* Description : Définit un autre nom pour le symbole. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_symbol_set_alt_label(GBinSymbol *symbol, const char *alt)
{
if (symbol->alt != NULL)
free(symbol->alt);
if (alt == NULL)
symbol->alt = NULL;
else
symbol->alt = strdup(alt);
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir mettre à jour. *
* full = adresse dont la définition est complète. *
* *
* Description : Raffine la définition de l'emplacement d'un symbole. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_symbol_fix_range(GBinSymbol *symbol, const vmpa2t *full)
{
GArchInstruction *instr; /* Instruction associée */
mrange_t range; /* Plage à manipuler */
GBinRoutine *routine; /* Routine associée */
switch (symbol->type)
{
case STP_DATA:
case STP_RO_STRING:
instr = g_binary_symbol_get_instruction(symbol);
copy_mrange(&range, g_arch_instruction_get_range(instr));
assert(cmp_vmpa(get_mrange_addr(&range), full) == 0);
copy_vmpa(get_mrange_addr(&range), full);
g_arch_instruction_set_range(instr, &range);
break;
case STP_ROUTINE:
case STP_ENTRY_POINT:
case STP_CODE_LABEL:
routine = g_binary_symbol_get_routine(symbol);
copy_mrange(&range, g_binary_routine_get_range(routine));
assert(cmp_vmpa(get_mrange_addr(&range), full) == 0);
copy_vmpa(get_mrange_addr(&range), full);
g_binary_routine_set_range(routine, &range);
break;
default:
break;
}
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* *
* Description : Fournit l'emplacement où se situe un symbole. *
* *
* Retour : Zone mémoire couverte par le symbole. *
* *
* Remarques : - *
* *
******************************************************************************/
const mrange_t *g_binary_symbol_get_range(const GBinSymbol *symbol)
{
const mrange_t *result; /* Plage à retourner */
result = NULL;
switch (symbol->type)
{
case STP_DATA:
case STP_RO_STRING:
result = g_arch_instruction_get_range(symbol->extra.instr);
break;
case STP_ROUTINE:
case STP_ENTRY_POINT:
case STP_CODE_LABEL:
result = g_binary_routine_get_range(symbol->extra.routine);
break;
default:
/* FIXME : assert(0); */
result = NULL;
break;
}
return result;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* routine = prototype de la fonction représentée. *
* type = (nouveau) type du symbole attaché. *
* *
* Description : Attache la routine associée au symbole. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void _g_binary_symbol_attach_routine(GBinSymbol *symbol, GBinRoutine *routine, SymbolType type)
{
if (symbol->extra.routine != NULL)
g_object_unref(G_OBJECT(symbol->extra.routine));
symbol->type = type;
symbol->extra.routine = routine;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* routine = prototype de la fonction représentée. *
* *
* Description : Attache la routine associée au symbole. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_symbol_attach_routine(GBinSymbol *symbol, GBinRoutine *routine)
{
_g_binary_symbol_attach_routine(symbol, routine, symbol->type);
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir manipuler. *
* instr = représentation du symbole associé. *
* *
* Description : Attache l'instruction associée au symbole. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_symbol_attach_instruction(GBinSymbol *symbol, GArchInstruction *instr)
{
if (symbol->type != STP_RO_STRING)
symbol->type = STP_DATA;
symbol->extra.instr = instr;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* *
* Description : Fournit l'éventuelle routine associée au symbole. *
* *
* Retour : Instance GLib en place ou NULL si aucune. *
* *
* Remarques : Il n'y a pas de transfert de propriété ici ! *
* *
******************************************************************************/
GBinRoutine *g_binary_symbol_get_routine(const GBinSymbol *symbol)
{
/* TODO : rajouter des assert() sur le type de symbole */
return symbol->extra.routine;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* *
* Description : Fournit l'éventuelle instruction associée au symbole. *
* *
* Retour : Instance GLib en place ou NULL si aucune. *
* *
* Remarques : Il n'y a pas de transfert de propriété ici ! *
* *
******************************************************************************/
GArchInstruction *g_binary_symbol_get_instruction(const GBinSymbol *symbol)
{
/* TODO : rajouter des assert() sur le type de symbole */
return symbol->extra.instr;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir manipuler. *
* comment = commentaire construit à propos du symbole. *
* *
* Description : Ajoute un commentaire facultatif au symbole. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_symbol_set_comment(GBinSymbol *symbol, GDbComment *comment)
{
symbol->comment = comment;
}
/******************************************************************************
* *
* Paramètres : symbol = symbole à venir consulter. *
* *
* Description : Fournit l'éventuel commentaire associé au symbole. *
* *
* Retour : Instance GLib en place ou NULL si aucune. *
* *
* Remarques : Il n'y a pas de transfert de propriété ici ! *
* *
******************************************************************************/
GDbComment *g_binary_symbol_get_comment(const GBinSymbol *symbol)
{
return symbol->comment;
}