/* Chrysalide - Outil d'analyse de fichiers binaires
* symbol.c - gestion des symboles dans un binaire
*
* 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 .
*/
#include "symbol.h"
#include
#include
#include "../glibext/linegen-int.h"
/* --------------------- FONCTIONNALITES BASIQUES POUR SYMBOLES --------------------- */
/* 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 *);
/* Procède à l'initialisation de l'interface de génération. */
static void g_binary_symbol_interface_init(GLineGeneratorInterface *);
/* 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 *);
/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_binary_symbol_count_lines(const GBinSymbol *);
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_binary_symbol_compute_addr(const GBinSymbol *, gint, vmpa2t *, size_t, size_t);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_binary_symbol_contains_addr(const GBinSymbol *, const vmpa2t *, size_t, size_t);
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_binary_symbol_get_flags(const GBinSymbol *, size_t, size_t);
/* Imprime dans une ligne de rendu le contenu représenté. */
static void g_binary_symbol_print(GBinSymbol *, GBufferLine *, size_t, size_t);
/* ---------------------------------------------------------------------------------- */
/* FONCTIONNALITES BASIQUES POUR SYMBOLES */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour un symbole d'exécutable. */
G_DEFINE_TYPE_WITH_CODE(GBinSymbol, g_binary_symbol, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_binary_symbol_interface_init));
/******************************************************************************
* *
* 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 : iface = interface GLib à initialiser. *
* *
* Description : Procède à l'initialisation de l'interface de génération. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_symbol_interface_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_binary_symbol_count_lines;
iface->compute = (linegen_compute_fc)g_binary_symbol_compute_addr;
iface->contains = (linegen_contains_fc)g_binary_symbol_contains_addr;
iface->get_flags = (linegen_get_flags_fc)g_binary_symbol_get_flags;
iface->print = (linegen_print_fc)g_binary_symbol_print;
}
/******************************************************************************
* *
* 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 à analyser. *
* addr = localisation à venir comparer à celle du symbole. *
* *
* Description : Compare un symbole et une localisation. *
* *
* Retour : Bilan de la comparaison : -1, 0 ou 1 (-1 par défaut). *
* *
* Remarques : - *
* *
******************************************************************************/
int g_binary_symbol_cmp_with_vmpa(const GBinSymbol *symbol, const vmpa2t *addr)
{
int result; /* Bilan à retourner */
const mrange_t *range; /* Emplacement du symbole */
range = g_binary_symbol_get_range(symbol);
if (range == NULL)
result = 1;
else
result = cmp_mrange_with_vmpa(range, addr);
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_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 */
/* TODO : ref() */
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 */
/* TODO : ref() */
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)
{
#ifndef NDEBUG
const vmpa2t *saddr; /* Adresse du symbole */
const vmpa2t *caddr; /* Adresse du commentaire */
#endif
#ifndef NDEBUG
saddr = get_mrange_addr(g_binary_symbol_get_range(symbol));
caddr = g_db_comment_get_address(comment);
assert(cmp_vmpa(saddr, caddr) == 0);
#endif
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;
}
/* ---------------------------------------------------------------------------------- */
/* OFFRE DE CAPACITES DE GENERATION */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : symbol = générateur à consulter pour futur usage. *
* *
* Description : Détermine si un symbole pour faire office de générateur. *
* *
* Retour : Instance de générateur si les capacités sont là. *
* *
* Remarques : - *
* *
******************************************************************************/
GLineGenerator *g_binary_symbol_produce_label(GBinSymbol *symbol)
{
GLineGenerator *result; /* Instance à retourner */
const char *label; /* Etiquette à insérer */
label = g_binary_symbol_get_label(symbol);
result = (label != NULL ? G_LINE_GENERATOR(symbol) : NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : symbol = générateur à consulter. *
* *
* Description : Indique le nombre de ligne prêtes à être générées. *
* *
* Retour : Nombre de lignes devant apparaître au final. *
* *
* Remarques : - *
* *
******************************************************************************/
static size_t g_binary_symbol_count_lines(const GBinSymbol *symbol)
{
return 1;
}
/******************************************************************************
* *
* Paramètres : symbol = générateur à consulter. *
* x = position géographique sur la ligne concernée. *
* addr = position en mémoire à analyser. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* *
* Description : Retrouve l'emplacement correspondant à une position donnée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_binary_symbol_compute_addr(const GBinSymbol *symbol, gint x, vmpa2t *addr, size_t index, size_t repeat)
{
const mrange_t *range; /* Emplacement à manipuler */
range = g_binary_symbol_get_range(symbol);
copy_vmpa(addr, get_mrange_addr(range));
}
/******************************************************************************
* *
* Paramètres : symbol = générateur à consulter. *
* addr = position en mémoire à analyser. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* *
* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
* *
* Retour : Bilan de la détermination, utilisable en comparaisons. *
* *
* Remarques : - *
* *
******************************************************************************/
static int g_binary_symbol_contains_addr(const GBinSymbol *symbol, const vmpa2t *addr, size_t index, size_t repeat)
{
int result; /* Conclusion à retourner */
const mrange_t *range; /* Emplacement à manipuler */
range = g_binary_symbol_get_range(symbol);
result = cmp_mrange_with_vmpa(range, addr);
return result;
}
/******************************************************************************
* *
* Paramètres : symbol = générateur à consulter. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* *
* Description : Renseigne sur les propriétés liées à un générateur. *
* *
* Retour : Propriétés particulières associées. *
* *
* Remarques : - *
* *
******************************************************************************/
static BufferLineFlags g_binary_symbol_get_flags(const GBinSymbol *symbol, size_t index, size_t repeat)
{
return BLF_IS_LABEL;
}
/******************************************************************************
* *
* Paramètres : symbol = générateur à utiliser pour l'impression. *
* line = ligne de rendu à compléter. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* *
* Description : Imprime dans une ligne de rendu le contenu représenté. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_binary_symbol_print(GBinSymbol *symbol, GBufferLine *line, size_t index, size_t repeat)
{
const mrange_t *range; /* Emplacement à manipuler */
const char *label; /* Etiquette à insérer */
range = g_binary_symbol_get_range(symbol);
g_buffer_line_fill_vmpa(line, get_mrange_addr(range), MDS_32_BITS_UNSIGNED, MDS_32_BITS_UNSIGNED);
label = g_binary_symbol_get_label(symbol);
g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD);
g_buffer_line_append_text(line, BLC_ASSEMBLY_HEAD, SL(label), RTT_LABEL, NULL);
g_buffer_line_append_text(line, BLC_ASSEMBLY_HEAD, ":", 1, RTT_PUNCT, NULL);
}