/* Chrysalide - Outil d'analyse de fichiers binaires
* component.c - représentation des composants extraits de l'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 "component.h"
#include
#include
#include "component-int.h"
#include "../../../common/extstr.h"
#include "../../../common/fnv1a.h"
/* Procédure à appliquer sur un composant visité */
typedef void (* visit_comp_fc) (itanium_component *);
#define reset_comp_hash(c) c->hash = 0
/* Visite les composants en présence. */
static void visit_comp(itanium_component *, visit_comp_fc);
/******************************************************************************
* *
* Paramètres : comp = composant à traiter. *
* visitor = fonction à appliquer sur les composants présents. *
* *
* Description : Visite les composants en présence. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void visit_comp(itanium_component *comp, visit_comp_fc visitor)
{
itanium_component *sub; /* Sous-partie de composant */
switch (comp->type)
{
case ICT_NESTED_NAME:
case ICT_TEMPLATE_NAME_ARGS:
visit_comp(comp->binary.left, visitor);
visit_comp(comp->binary.right, visitor);
break;
case ICT_PREFIX_UNARY:
case ICT_TPREFIX_UNARY:
visit_comp(comp->unary, visitor);
break;
case ICT_PREFIX_BINARY:
case ICT_TPREFIX_BINARY:
visit_comp(comp->binary.left, visitor);
visit_comp(comp->binary.right, visitor);
break;
case ICT_FUNCTION_THUNK:
visit_comp(comp->binary.left, visitor);
visit_comp(comp->binary.right, visitor);
break;
case ICT_FUNCTION_COVARIANT_THUNK:
visit_comp(comp->ternary.first, visitor);
visit_comp(comp->ternary.second, visitor);
visit_comp(comp->ternary.third, visitor);
break;
case ICT_POINTER_TO:
visit_comp(comp->unary, visitor);
break;
case ICT_REFERENCE_TO:
visit_comp(comp->unary, visitor);
break;
case ICT_RVALUE_REFERENCE_TO:
visit_comp(comp->unary, visitor);
break;
case ICT_COMPLEX_PAIR:
visit_comp(comp->unary, visitor);
break;
case ICT_IMAGINARY:
visit_comp(comp->unary, visitor);
break;
case ICT_FUNCTION_ENCODING:
/* Retour ? */
sub = NULL;//IT_BINARY_COMP(IT_BINARY_COMP(comp).right).left;
if (sub != NULL)
visit_comp(sub, visitor);
/* Nom de la fonction */
visit_comp(comp->binary.left, visitor);
visit_comp(comp->binary.right, visitor);
break;
case ICT_TEMPLATE_ARGS:
visit_comp(comp->unary, visitor);
break;
case ICT_TYPES_LIST:
visit_comp(comp->binary.left, visitor);
if (comp->binary.right != NULL)
visit_comp(comp->binary.right, visitor);
break;
default:
break;
}
visitor(comp);
}
/******************************************************************************
* *
* Paramètres : comp = composant à mettre à jour. *
* *
* Description : Incrémente le nombre d'utilisation du composant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void itd_ref_comp(itanium_component *comp)
{
void visit_for_ref(itanium_component *comp)
{
comp->refcount++;
}
visit_comp(comp, visit_for_ref);
}
/******************************************************************************
* *
* Paramètres : comp = composant à mettre à jour. *
* *
* Description : Décrémente le nombre d'utilisation du composant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void itd_unref_comp(itanium_component *comp)
{
return;
void visit_for_unref(itanium_component *comp)
{
if (--comp->refcount == 0)
{
if (comp->type == ICT_TYPE)
g_object_unref(G_OBJECT(comp->dtype));
g_itanium_dcontext_mark_component_as_free(comp->context, comp);
}
}
visit_comp(comp, visit_for_unref);
}
/******************************************************************************
* *
* Paramètres : comp = composant à manipuler. *
* *
* Description : Détermine ou fournit l'empreinte d'un composant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
fnv64_t itd_hash_comp(itanium_component *comp)
{
char *desc; /* Description du composant */
if (comp->hash == 0)
{
desc = itd_translate_component(comp->context, comp, NULL);
comp->hash = fnv_64a_hash(desc);
free(desc);
}
return comp->hash;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_make_empty(GItaniumDContext *context)
{
itanium_component *result; /* Composant à renvoyer */
result = g_itanium_dcontext_get_empty_component(context);
result->type = ICT_EMPTY;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* str = chaîne de caractères à conserver. *
* len = taille de l'identifiant à retrouver. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_make_name(GItaniumDContext *context, const char *str, size_t len)
{
itanium_component *result; /* Composant à renvoyer */
result = g_itanium_dcontext_get_empty_component(context);
result->type = ICT_NAME;
result->s_name.str = str;
result->s_name.len = len;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* info = information de base sur l'opérateur manipulé. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_make_operator(GItaniumDContext *context, const itanium_operator_info *info)
{
itanium_component *result; /* Composant à renvoyer */
result = g_itanium_dcontext_get_empty_component(context);
result->type = ICT_OPERATOR_NAME;
result->operator.otype = IOT_SIMPLE;
result->operator.info = *info;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* type = type exacte de décallage. *
* offset = décallage extrait de l'encodage. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_make_offset(GItaniumDContext *context, ItaniumComponentType type, ssize_t offset)
{
itanium_component *result; /* Composant à renvoyer */
result = g_itanium_dcontext_get_empty_component(context);
result->type = type;
result->offset = offset;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* dtype = instance de type en place à conserver. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_make_type(GItaniumDContext *context, GDataType *dtype)
{
itanium_component *result; /* Composant à renvoyer */
result = g_itanium_dcontext_get_empty_component(context);
result->type = ICT_TYPE;
result->dtype = dtype;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* type = type du composant à mettre en place. *
* left = premier composant à associer. *
* right = second composant à associer. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_make_binary(GItaniumDContext *context, ItaniumComponentType type, itanium_component *left, itanium_component *right)
{
itanium_component *result; /* Composant à renvoyer */
result = g_itanium_dcontext_get_empty_component(context);
result->type = type;
result->binary.left = left;
result->binary.right = right;
return result;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* type = type du composant à mettre en place. *
* left = second composant à associer. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_append_right_to_binary(GItaniumDContext *context, ItaniumComponentType type, itanium_component *parent, itanium_component *left)
{
itanium_component *result; /* Composant à renvoyer */
itanium_component *iter; /* Boucle de parcours */
result = g_itanium_dcontext_get_empty_component(context);
result->type = type;
result->binary.left = left;
if (parent != NULL)
{
for (iter = parent; iter->binary.right != NULL; iter = iter->binary.right)
reset_comp_hash(iter);
iter->binary.right = result;
}
return (parent != NULL ? parent : result);
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* type = type du composant à mettre en place. *
* unary = sous-composant à associer. *
* *
* Description : Construit un composant dans un contexte Itanium. *
* *
* Retour : Composant extrait ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
itanium_component *itd_make_unary(GItaniumDContext *context, ItaniumComponentType type, itanium_component *unary)
{
itanium_component *result; /* Composant à renvoyer */
result = g_itanium_dcontext_get_empty_component(context);
result->type = type;
result->unary = unary;
return result;
}
/******************************************************************************
* *
* Paramètres : comp = composant à mettre à jour. *
* type = type à redéfinir pour le composant. *
* *
* Description : Modifie légèrement le type d'un composant donné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void itd_set_type(itanium_component *comp, ItaniumComponentType type)
{
comp->type = type;
reset_comp_hash(comp);
}
/******************************************************************************
* *
* Paramètres : comp = composant à consulter. *
* *
* Description : Fournit le type d'un composant issu d'un contexte Itanium. *
* *
* Retour : Type enregistré. *
* *
* Remarques : - *
* *
******************************************************************************/
ItaniumComponentType itd_get_component_type(const itanium_component *comp)
{
return comp->type;
}
/******************************************************************************
* *
* Paramètres : context = contexte de décodage à utiliser. *
* comp = second composant à associer. *
* base = éventuelle base à compléter ou NULL si aucune. *
* *
* Description : Traduit les composants de contexte Itanium. *
* *
* Retour : Traduction en format humainement lisible effectuée. *
* *
* Remarques : - *
* *
******************************************************************************/
char *itd_translate_component(GItaniumDContext *context, const itanium_component *comp, char *base)
{
char *result; /* Chaîne à retourner */
char *name; /* Désignation à copier */
const itanium_component *sub; /* Sous-partie de composant */
//if (base != NULL)
//printf(".... %s\n", base);
switch (comp->type)
{
case ICT_EMPTY:
result = base;
break;
case ICT_NAME:
case ICT_STD_SUBST:
result = strnadd(base, comp->s_name.str, comp->s_name.len);
break;
case ICT_NESTED_NAME:
result = itd_translate_component(context, comp->binary.left, base);
if (comp->binary.right->type != ICT_TEMPLATE_ARGS)
result = stradd(result, "::");
result = itd_translate_component(context, comp->binary.right, result);
break;
case ICT_TEMPLATE_NAME_ARGS:
result = itd_translate_component(context, comp->binary.left, base);
result = itd_translate_component(context, comp->binary.right, result);
break;
case ICT_PREFIX_UNARY:
case ICT_TPREFIX_UNARY:
result = stradd(base, "::");
result = itd_translate_component(context, comp->unary, result);
break;
case ICT_PREFIX_BINARY:
case ICT_TPREFIX_BINARY:
result = itd_translate_component(context, comp->binary.left, base);
result = stradd(result, "::");
result = itd_translate_component(context, comp->binary.right, result);
break;
case ICT_OPERATOR_NAME:
switch (comp->operator.otype)
{
case IOT_SIMPLE:
result = stradd(base, comp->operator.info.name);
break;
case IOT_CAST:
result = stradd(base, "TODO_CAST");
break;
case IOT_VENDOR:
result = stradd(base, "TODO_VENDOR");
break;
default:
result = NULL;
break;
}
break;
case ICT_FUNCTION_THUNK:
result = itd_translate_component(context, comp->binary.right, base);
break;
case ICT_FUNCTION_COVARIANT_THUNK:
result = itd_translate_component(context, comp->ternary.third, base);
break;
case ICT_CONSTRUCTOR:
result = stradd(base, "");
break;
case ICT_DESSTRUCTOR:
result = stradd(base, "");
break;
case ICT_TYPE:
name = g_data_type_to_string(comp->dtype);
result = stradd(base, name);
free(name);
break;
case ICT_POINTER_TO:
result = itd_translate_component(context, comp->unary, base);
result = stradd(result, " *");
break;
case ICT_REFERENCE_TO:
result = itd_translate_component(context, comp->unary, base);
result = stradd(result, " &");
break;
case ICT_RVALUE_REFERENCE_TO:
result = itd_translate_component(context, comp->unary, base);
result = stradd(result, " &");
break;
case ICT_COMPLEX_PAIR:
result = stradd(base, ">");
result = itd_translate_component(context, comp->unary, result);
break;
case ICT_IMAGINARY:
result = stradd(base, ">");
result = itd_translate_component(context, comp->unary, result);
break;
case ICT_FUNCTION_ENCODING:
result = base;
/* Retour ? */
sub = NULL;//IT_BINARY_COMP(IT_BINARY_COMP(comp).right).left;
if (sub != NULL)
result = itd_translate_component(context, sub, result);
else
result = stradd(result, "???");
result = stradd(result, " ");
/* Nom de la fonction */
result = itd_translate_component(context, comp->binary.left, result);
result = stradd(result, "(");
result = itd_translate_component(context, comp->binary.right, result);
result = stradd(result, ")");
break;
case ICT_TEMPLATE_ARGS:
result = stradd(base, "<");
result = itd_translate_component(context, comp->unary, result);
result = stradd(result, ">");
break;
case ICT_TYPES_LIST:
result = itd_translate_component(context, comp->binary.left, base);
if (comp->binary.right != NULL)
{
result = stradd(result, ", ");
result = itd_translate_component(context, comp->binary.right, result);
}
//sub = IT_BINARY_COMP(IT_BINARY_COMP(comp).right).right;
break;
default: /* ICT_* */
result = base;
break;
}
return result;
}