/* Chrysalide - Outil d'analyse de fichiers binaires * component.c - représentation des composants extraits de l'ABI C++ Itanium * * Copyright (C) 2013-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 "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; }