/* Chrysalide - Outil d'analyse de fichiers binaires
* context.c - contexte de décodage à la sauce ABI C++ Itanium
*
* Copyright (C) 2013 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 "context.h"
#include
#include
#include "abi.h"
#include "component-int.h"
#include "../context-int.h"
/* Taille des extensions d'allocation */
#define ITCOMP_ALLOC_BULK 200
/* Marqueur de fin pour les disponibilités */
#define ITCOMP_INVALID ((size_t)-1)
/* Contexte de décodage Itanium (instance) */
struct _GItaniumDContext
{
GDemanglingContext parent; /* A laisser en premier */
char *mangled; /* Caractères à traiter */
size_t len; /* Quantité de caractères */
size_t pos; /* Position d'analyse */
itanium_component *components; /* Tableaux des composants */
size_t *next_links; /* Chemins d'allocation */
size_t length; /* Taille allouée */
size_t last_used; /* Lien vers la disponibilité */
itanium_component **substitutions; /* Table de substitutions */
size_t subst_count; /* Quantité utilisée */
};
/* Contexte de décodage Itanium (classe) */
struct _GItaniumDContextClass
{
GDemanglingContextClass parent; /* A laisser en premier */
};
/* Indique le type défini pour un contexte de décodage. */
G_DEFINE_TYPE(GItaniumDContext, g_itanium_dcontext, G_TYPE_DEMANGLING_CONTEXT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des contextes de décodage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_itanium_dcontext_class_init(GItaniumDContextClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : context = instance à initialiser. *
* *
* Description : Initialise une instance de contexte pour décodage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_itanium_dcontext_init(GItaniumDContext *context)
{
context->last_used = ITCOMP_INVALID;
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Prépare de quoi effectuer un décodage Itanium. *
* *
* Retour : Instance du contexte mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GDemanglingContext *g_itanium_dcontext_new(void)
{
GDemanglingContext *result; /* Structure à retourner */
result = g_object_new(G_TYPE_ITANIUM_DCONTEXT, NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage sur lequel s'appuyer. *
* desc = chaîne de caractères à décoder. *
* *
* Description : Tente de décoder une chaîne de caractères donnée. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
void /*GBinRoutine **/g_itanium_dcontext_demangle_routine(GItaniumDContext *context, const char *desc)
{
itanium_component *comp;
char *str;
printf("<<== %s\n", desc);
context->mangled = strdup(desc);
context->len = strlen(desc);
context->pos = 0;
/**
* On part du principe qu'il n'y aura jamais plus de substitutions
* à enregistrer que de caractères dans la chaîne à traiter.
* Du coup, on peut tout allouer d'un coup !
*/
context->substitutions = (itanium_component **)calloc(context->len, sizeof(itanium_component *));
comp = itd_mangled_name(context);
printf("Got :: %p\n", comp);
str = itd_translate_component(context, comp, NULL);
printf("==>> %s\n", str);
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à manipuler. *
* state = état courant à sauvegarder. [OUT] *
* *
* Description : Fournit l'état courant à une fin de retour en arrière. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_itanium_dcontext_push_state(const GItaniumDContext *context, itd_state *state)
{
state->pos = context->pos;
state->subst_count = context->subst_count;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à manipuler. *
* state = état courant à restaurer. *
* *
* Description : Définit l'état courant suite à un retour en arrière. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_itanium_dcontext_pop_state(GItaniumDContext *context, const itd_state *state)
{
size_t i; /* Boucle de parcours */
/*
printf("--deleting subst-- from %zu to %zu\n",
state->subst_count, context->subst_count);
*/
for (i = state->subst_count; i < context->subst_count; i++)
itd_unref_comp(context->substitutions[i]);
context->pos = state->pos;
context->subst_count = state->subst_count;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* *
* Description : Fournit la valeur du caractère courant. *
* *
* Retour : Caractère courant. *
* *
* Remarques : - *
* *
******************************************************************************/
char g_itanium_dcontext_peek_char(const GItaniumDContext *context)
{
return *(context->mangled + context->pos);
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* quantity = quantié de caractères à marquer comme traités. *
* *
* Description : Avance la tête de lecture courante. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_itanium_dcontext_advance(GItaniumDContext *context, size_t quantity)
{
context->pos += quantity;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* *
* Description : Fournit et avance la tête de lecture courante. *
* *
* Retour : Caractère courant. *
* *
* Remarques : - *
* *
******************************************************************************/
char g_itanium_dcontext_next_char(GItaniumDContext *context)
{
return *(context->mangled + context->pos++);
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* c = caractère à retrouver. *
* *
* Description : Vérifie la nature du caractère courant. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_itanium_dcontext_check_char(GItaniumDContext *context, char c)
{
bool result; /* Validation à retourner */
if (g_itanium_dcontext_peek_char(context) == c)
{
result = true;
g_itanium_dcontext_advance(context, 1);
}
else
result = false;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* remaining = taille de la chaîne retournée. [OUT] *
* *
* Description : Fournit la chaîne de caractère restant à traiter. *
* *
* Retour : Pointeur vers les données courantes. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *g_itanium_dcontext_get_string(const GItaniumDContext *context, size_t *remaining)
{
const char *result; /* Données à renvoyer */
*remaining = context->len - context->pos;
result = &context->mangled[context->pos];
return result;
}
/*
################define d_peek_char(di) (*((di)->n))
#define d_peek_next_char(di) ((di)->n[1])
################define d_advance(di, i) ((di)->n += (i))
################define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
################define d_str(di) ((di)->n)
*/
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à manipuler. *
* *
* Description : Fournit un nouveau composant vierge. *
* *
* Retour : Composant prêt à être défini. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *g_itanium_dcontext_get_empty_component(GItaniumDContext *context)
{
itanium_component *result; /* Disponibilité à retourner */
size_t i; /* Boucle de parcours */
size_t next; /* Indice de disponibilité */
if (context->last_used == ITCOMP_INVALID
|| context->next_links[context->last_used] == ITCOMP_INVALID)
{
/* Création d'extensions */
context->components = (itanium_component *)
realloc(context->components,
(context->length + ITCOMP_ALLOC_BULK) * sizeof(itanium_component));
context->next_links = (size_t *)
realloc(context->next_links, (context->length + ITCOMP_ALLOC_BULK) * sizeof(size_t));
/* Inscription des liens d'allocation */
for (i = context->length; i < (context->length + ITCOMP_ALLOC_BULK - 1); i++)
context->next_links[i] = i + 1;
context->next_links[context->length + ITCOMP_ALLOC_BULK - 1] = ITCOMP_INVALID;
if (context->last_used != ITCOMP_INVALID)
context->next_links[context->last_used] = context->length;
/* Mise à jour globale */
context->length += ITCOMP_ALLOC_BULK;
}
/* Extraction d'un composant disponible */
if (context->last_used == ITCOMP_INVALID)
next = 0;
else
next = context->next_links[context->last_used];
result = &context->components[next];
context->last_used = next;
memset(result, 0, sizeof(itanium_component));
result->context = context;
g_object_ref(G_OBJECT(result->context));
result->refcount = 1;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à manipuler. *
* comp = composant à libérer. *
* *
* Description : Marque un composant comme étant disponible pour un usage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_itanium_dcontext_mark_component_as_free(GItaniumDContext *context, itanium_component *comp)
{
size_t index; /* Indice du composant concerné*/
/*BUG_ON(comp->refcount != 0);*/
g_object_unref(G_OBJECT(comp->context));
index = comp - context->components;
context->next_links[index] = context->next_links[context->last_used];
context->next_links[context->last_used] = index;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à manipuler. *
* comp = composant à conserver en mémoire. *
* *
* Description : Indexe un composant comme future substitution potentielle. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_itanium_dcontext_add_substitution(GItaniumDContext *context, itanium_component *comp)
{
fnv64_t hash; /* Empreinte du candidat */
size_t i; /* Boucle de parcours */
hash = itd_hash_comp(comp);
for (i = 0; i < context->subst_count; i++)
if (cmp_fnv_64a(itd_hash_comp(context->substitutions[i]), hash) == 0)
break;
if (i == context->subst_count)
{
printf("[ADDING SUBST] [%zu] '%s'\n",
context->subst_count,
itd_translate_component(context, comp, NULL));
context->substitutions[context->subst_count++] = comp;
itd_ref_comp(comp);
}
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à manipuler. *
* index = indice de la substitution visée. *
* *
* Description : Fournit un composant en place pour une substitution. *
* *
* Retour : Composant déjà extrait et conservé. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *g_itanium_dcontext_get_substitution(GItaniumDContext *context, size_t index)
{
itanium_component *result; /* Composant à retourner */
if (index < context->subst_count)
{
result = context->substitutions[index];
itd_ref_comp(result);
}
else
result = NULL;
return result;
}
void test_itanium(void)
{
#define TEST_DEMANG(v) \
do \
{ \
GDemanglingContext *ctx; \
/*char *str;*/ \
ctx = g_itanium_dcontext_new(); \
/*str = */g_itanium_dcontext_demangle_routine(G_ITANIUM_DCONTEXT(ctx), v); \
/*printf("==> %s\n", str);*/ \
} \
while (0)
TEST_DEMANG("_Z3fooILi2EEvRAplT_Li1E_i");
exit(0);
TEST_DEMANG("_Z1fv");
TEST_DEMANG("_Z3foo3bar");
}