/* 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 Chrysalide. If not, see . */ #include "component.h" #include #include #include #include #include #include #include #include #include #include #include #include "component-int.h" /* Procédure à appliquer sur un composant visité */ typedef void (* visit_comp_fc) (itanium_component *); /* Crée un composant de contexte Itanium complètement vierge. */ static itanium_component *itd_alloc(void); /* Efface de la mémoire un composant de context Itanium. */ static void itd_free(itanium_component *); /* Visite les composants en présence. */ static void visit_comp(itanium_component *, visit_comp_fc); /* Traduit les composants de contexte Itanium en décalage. */ static bool itd_translate_component_to_offset(const itanium_component *, call_offset_t *); /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un composant de contexte Itanium complètement vierge. * * * * Retour : Composant créé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static itanium_component *itd_alloc(void) { itanium_component *result; /* Composant à renvoyer */ result = calloc(1, sizeof(itanium_component)); result->refcount = 1; return result; } /****************************************************************************** * * * Paramètres : comp = composant à supprimer. * * * * Description : Efface de la mémoire un composant de context Itanium. * * * * Retour : Composant créé ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static void itd_free(itanium_component *comp) { free(comp); } /****************************************************************************** * * * 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) { switch (comp->type) { case ICT_NAME: break; case ICT_STD_UNSCOPED_NAME: visit_comp(comp->unary, visitor); break; case ICT_NESTED_NAME: if (comp->binary.left != NULL) visit_comp(comp->binary.left, visitor); visit_comp(comp->binary.right, visitor); break; case ICT_TEMPLATE_NAME_ARGS: visit_comp(comp->binary.left, visitor); visit_comp(comp->binary.right, visitor); break; case ICT_PREFIX_BINARY: visit_comp(comp->binary.left, visitor); visit_comp(comp->binary.right, visitor); break; case ICT_TPREFIX_BINARY: if (comp->binary.left != NULL) visit_comp(comp->binary.left, visitor); visit_comp(comp->binary.right, visitor); break; case ICT_OPERATOR_NAME: if (comp->operator.otype == IOT_CAST) visit_comp(comp->operator.trans, visitor); break; case ICT_SPECIAL_NAME_VTABLE: case ICT_SPECIAL_NAME_VSTRUCT: visit_comp(comp->unary, visitor); break; case ICT_NON_VIRTUAL_OFFSET: case ICT_VIRTUAL_OFFSET: break; case ICT_DOUBLE_OFFSET: 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_CONSTRUCTOR: case ICT_DESSTRUCTOR: break; case ICT_TYPE: case ICT_VENDOR_TYPE: break; case ICT_QUALIFIED_TYPE: visit_comp(comp->qualified.sub, 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_TYPE: visit_comp(comp->function.args, visitor); break; case ICT_FUNCTION_ENCODING: visit_comp(comp->binary.left, visitor); visit_comp(comp->binary.right, visitor); break; case ICT_ARRAY: if (!comp->array.numbered_dim && comp->array.dim_expr != NULL) visit_comp(comp->array.dim_expr, visitor); visit_comp(comp->array.atype, visitor); break; case ICT_POINTER_TO_MEMBER: visit_comp(comp->pmember.class, visitor); visit_comp(comp->pmember.member, visitor); break; case ICT_TEMPLATE_PARAM: visit_comp(comp->unary, 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; case ICT_EXPR_LIST: visit_comp(comp->binary.left, visitor); if (comp->binary.right != NULL) visit_comp(comp->binary.right, visitor); break; case ICT_OPERATED_EXPRESSION: visit_comp(comp->binary.left, visitor); visit_comp(comp->binary.right, visitor); break; case ICT_STD_SUBST: break; case ICT_COUNT: 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) { void visit_for_unref(itanium_component *comp) { if (--comp->refcount == 0) { if (comp->type == ICT_TYPE || comp->type == ICT_VENDOR_TYPE || comp->type == ICT_STD_SUBST) g_object_unref(G_OBJECT(comp->dtype)); itd_free(comp); } } visit_comp(comp, visit_for_unref); } /****************************************************************************** * * * Paramètres : type = type à définir pour le composant. * * * * Description : Construit un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_make_with_type(ItaniumComponentType type) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = type; return result; } /****************************************************************************** * * * Paramètres : 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(const char *str, size_t len) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_NAME; result->s_name.str = str; result->s_name.len = len; return result; } /****************************************************************************** * * * Paramètres : 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(const itanium_operator_info *info) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_OPERATOR_NAME; result->operator.otype = IOT_SIMPLE; result->operator.info = *info; return result; } /****************************************************************************** * * * Paramètres : 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_cast_operator(itanium_component *type) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_OPERATOR_NAME; result->operator.otype = IOT_CAST; result->operator.trans = type; return result; } /****************************************************************************** * * * Paramètres : comp = composant Itanium décodé à consulter. * * type = type d'opérateur représenté. * * * * Description : Donne des indications quant à un opérateur Itanium. * * * * Retour : Informations à interpréter selon le type transmis. * * * * Remarques : - * * * ******************************************************************************/ const void *itd_get_operator_info(const itanium_component *comp, ItaniumOperatorType *type) { const void *result; /* Données à retourner */ assert(comp->type == ICT_OPERATOR_NAME); *type = comp->operator.otype; switch (*type) { case IOT_SIMPLE: result = &comp->operator.info; break; case IOT_CAST: result = comp->operator.trans; break; default: assert(false); result = NULL; break; } return result; } /****************************************************************************** * * * Paramètres : type = type exacte de décalage. * * offset = décalage 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(ItaniumComponentType type, ssize_t offset) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = type; result->offset = offset; return result; } /****************************************************************************** * * * Paramètres : 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(GDataType *dtype) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_TYPE; result->dtype = dtype; return result; } /****************************************************************************** * * * Paramètres : sub = composant de type en place à référencer. * * qualifier = propriétés supplémentaires pour le type. * * * * Description : Construit un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_make_qualified_type(itanium_component *sub, TypeQualifier qualifier) { itanium_component *result; /* Composant à renvoyer */ if (qualifier == TQF_NONE) result = sub; else { result = itd_alloc(); result->type = ICT_QUALIFIED_TYPE; result->qualified.sub = sub; result->qualified.qualifier = qualifier; } return result; } /****************************************************************************** * * * Paramètres : sub = composant de type en place à référencer. * * qualifier = propriétés supplémentaires pour le type. * * * * Description : Construit un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_make_function_type(bool extern_c, itanium_component *args) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_FUNCTION_TYPE; result->function.extern_c = extern_c; result->function.args = args; return result; } /****************************************************************************** * * * Paramètres : number = dimension du tableau. * * type = type des membres du même tableau. * * * * Description : Construit un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_make_array_with_dim_number(ssize_t number, itanium_component *type) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_ARRAY; result->array.numbered_dim = true; result->array.dim_number = number; result->array.atype = type; return result; } /****************************************************************************** * * * Paramètres : expr = dimension du tableau. * * type = type des membres du même tableau. * * * * Description : Construit un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_make_array_with_dim_expr(itanium_component *expr, itanium_component *type) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_ARRAY; result->array.numbered_dim = false; result->array.dim_expr = expr; result->array.atype = type; return result; } /****************************************************************************** * * * Paramètres : class = classe d'appatenance. * * member = membre représenté. * * * * Description : Construit un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_make_pointer_to_memeber_type(itanium_component *class, itanium_component *member) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = ICT_POINTER_TO_MEMBER; result->pmember.class = class; result->pmember.member = member; return result; } /****************************************************************************** * * * Paramètres : 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(ItaniumComponentType type, itanium_component *unary) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = type; result->unary = unary; return result; } /****************************************************************************** * * * Paramètres : 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(ItaniumComponentType type, itanium_component *left, itanium_component *right) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = type; result->binary.left = left; result->binary.right = right; return result; } /****************************************************************************** * * * Paramètres : 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(ItaniumComponentType type, itanium_component *parent, itanium_component *left) { itanium_component *result; /* Composant à renvoyer */ itanium_component *iter; /* Boucle de parcours */ result = itd_alloc(); result->type = type; result->binary.left = left; result->binary.right = NULL; if (parent != NULL) { for (iter = parent; iter->binary.right != NULL; iter = iter->binary.right) ; iter->binary.right = result; } return (parent != NULL ? parent : result); } /****************************************************************************** * * * Paramètres : type = type du composant à mettre en place. * * c0 = premier composant à associer. * * c1 = second composant à associer. * * c2 = troisième composant à associer. * * * * Description : Construit un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_make_ternary(ItaniumComponentType type, itanium_component *c0, itanium_component *c1, itanium_component *c2) { itanium_component *result; /* Composant à renvoyer */ result = itd_alloc(); result->type = type; result->ternary.first = c0; result->ternary.second = c1; result->ternary.third = c2; 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; } /****************************************************************************** * * * 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 : 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(const itanium_component *comp, char *base) { char *result; /* Chaîne à retourner */ char *name; /* Désignation à copier */ const itanium_component *sub; /* Sous-partie de composant */ ItaniumOperatorType otype; /* Type d'opérateur */ const void *odata; /* Données associées */ const itanium_operator_info *simple; /* Données d'opérateur simple */ char *tmp; /* Transcription temporaire */ switch (comp->type) { case ICT_NAME: result = strnadd(base, comp->s_name.str, comp->s_name.len); break; case ICT_STD_UNSCOPED_NAME: result = stradd(base, "std::"); result = itd_translate_component(comp->unary, result); break; case ICT_NESTED_NAME: if (comp->binary.right->type == ICT_TEMPLATE_ARGS) { result = itd_translate_component(comp->binary.left, base); result = itd_translate_component(comp->binary.right, result); } else { if (comp->binary.left != NULL) { result = itd_translate_component(comp->binary.left, base); result = stradd(result, "::"); } else result = base; result = itd_translate_component(comp->binary.right, result); } break; case ICT_TEMPLATE_NAME_ARGS: result = itd_translate_component(comp->binary.left, base); result = itd_translate_component(comp->binary.right, result); break; case ICT_PREFIX_BINARY: result = itd_translate_component(comp->binary.left, base); if (comp->binary.right->type != ICT_TEMPLATE_ARGS) result = stradd(result, "::"); result = itd_translate_component(comp->binary.right, result); break; case ICT_TPREFIX_BINARY: if (comp->binary.left != NULL) { result = itd_translate_component(comp->binary.left, base); if (comp->binary.right->type != ICT_TEMPLATE_ARGS) result = stradd(result, "::"); } else result = base; result = itd_translate_component(comp->binary.right, result); break; case ICT_OPERATOR_NAME: switch (comp->operator.otype) { case IOT_SIMPLE: result = stradd(base, "operator"); result = stradd(result, comp->operator.info.name); break; case IOT_CAST: result = stradd(base, "("); sub = (const itanium_component *)odata; result = itd_translate_component(comp->operator.trans, result); result = stradd(result, ")"); break; default: result = NULL; break; } break; case ICT_SPECIAL_NAME_VTABLE: result = itd_translate_component(comp->unary, base); result = stradd(result, "::vtable"); break; case ICT_SPECIAL_NAME_VSTRUCT: result = itd_translate_component(comp->unary, base); result = stradd(result, "::vstruct"); break; case ICT_NON_VIRTUAL_OFFSET: case ICT_VIRTUAL_OFFSET: asprintf(&tmp, "%zd", comp->offset); result = stradd(base, tmp); free(tmp); break; case ICT_DOUBLE_OFFSET: result = itd_translate_component(comp->binary.left, base); result = stradd(result, "_"); result = itd_translate_component(comp->binary.right, result); break; case ICT_FUNCTION_THUNK: result = itd_translate_component(comp->binary.left, base); result = stradd(result, "_"); result = itd_translate_component(comp->binary.right, result); break; case ICT_FUNCTION_COVARIANT_THUNK: result = itd_translate_component(comp->ternary.first, base); result = stradd(result, "_"); result = itd_translate_component(comp->ternary.second, result); result = stradd(result, "_"); result = itd_translate_component(comp->ternary.third, result); break; case ICT_CONSTRUCTOR: result = stradd(base, ""); break; case ICT_DESSTRUCTOR: result = stradd(base, ""); break; case ICT_TYPE: case ICT_VENDOR_TYPE: name = g_data_type_to_string(comp->dtype, true); result = stradd(base, name); free(name); break; case ICT_QUALIFIED_TYPE: switch (comp->qualified.qualifier) { case TQF_RESTRICT: result = stradd(base, "restrict "); break; case TQF_VOLATILE: result = stradd(base, "volatile "); break; case TQF_CONST: result = stradd(base, "const "); break; default: assert(false); break; } result = itd_translate_component(comp->qualified.sub, result); break; case ICT_POINTER_TO: result = itd_translate_component(comp->unary, base); result = stradd(result, " *"); break; case ICT_REFERENCE_TO: result = itd_translate_component(comp->unary, base); result = stradd(result, " &"); break; case ICT_RVALUE_REFERENCE_TO: result = itd_translate_component(comp->unary, base); result = stradd(result, " &"); break; case ICT_COMPLEX_PAIR: result = stradd(base, ""); result = itd_translate_component(comp->unary, result); break; case ICT_IMAGINARY: result = stradd(base, ""); result = itd_translate_component(comp->unary, result); break; case ICT_FUNCTION_TYPE: result = stradd(base, "(*) ("); result = itd_translate_component(comp->function.args, result); result = stradd(result, ")"); break; case ICT_FUNCTION_ENCODING: result = stradd(base, "???"); result = stradd(result, " "); result = itd_translate_component(comp->binary.left, result); result = stradd(result, "("); result = itd_translate_component(comp->binary.right, result); result = stradd(result, ")"); break; case ICT_ARRAY: result = itd_translate_component(comp->array.atype, base); result = stradd(result, "["); if (comp->array.numbered_dim) { asprintf(&tmp, "%zd", comp->array.dim_number); result = stradd(result, tmp); free(tmp); } else if (comp->array.dim_expr != NULL) result = itd_translate_component(comp->array.dim_expr, result); result = stradd(result, "]"); break; case ICT_POINTER_TO_MEMBER: result = itd_translate_component(comp->pmember.class, base); result = stradd(result, "::"); result = itd_translate_component(comp->pmember.member, result); break; case ICT_TEMPLATE_PARAM: result = itd_translate_component(comp->unary, base); break; case ICT_TEMPLATE_ARGS: result = stradd(base, "<"); result = itd_translate_component(comp->unary, result); result = stradd(result, ">"); break; case ICT_TYPES_LIST: result = itd_translate_component(comp->binary.left, base); if (comp->binary.right != NULL) { result = stradd(result, ", "); result = itd_translate_component(comp->binary.right, result); } break; case ICT_EXPR_LIST: /** * A priori traité en amont. */ result = itd_translate_component(comp->binary.left, base); if (comp->binary.right != NULL) { result = stradd(result, ", "); result = itd_translate_component(comp->binary.right, result); } break; case ICT_OPERATED_EXPRESSION: odata = itd_get_operator_info(comp->binary.left, &otype); sub = comp->binary.right; assert(sub->type == ICT_EXPR_LIST); switch (otype) { case IOT_SIMPLE: simple = (const itanium_operator_info *)odata; switch (simple->args) { case 1: result = stradd(base, simple->name); result = itd_translate_component(sub->binary.left, result); assert(sub->binary.right == NULL); break; case 2: result = itd_translate_component(sub->binary.left, base); result = stradd(result, simple->name); sub = sub->binary.right; assert(sub->type == ICT_EXPR_LIST); result = itd_translate_component(sub->binary.left, result); assert(sub->binary.right == NULL); break; case 3: result = itd_translate_component(sub->binary.left, base); result = stradd(result, simple->name); sub = sub->binary.right; assert(sub->type == ICT_EXPR_LIST); result = itd_translate_component(sub->binary.left, result); result = stradd(result, ":"); sub = sub->binary.right; assert(sub->type == ICT_EXPR_LIST); result = itd_translate_component(sub->binary.left, result); assert(sub->binary.right == NULL); break; } break; case IOT_CAST: result = stradd(base, "("); sub = (const itanium_component *)odata; result = itd_translate_component(sub, result); result = stradd(result, ")"); break; default: result = NULL; break; } break; case ICT_STD_SUBST: name = g_data_type_to_string(comp->dtype, true); result = stradd(base, name); free(name); break; case ICT_COUNT: result = base; break; } return result; } /****************************************************************************** * * * Paramètres : comp = composant Itanium à traduire en décalage. * * off = réceptacle pour les informations traduites. * * * * Description : Traduit les composants de contexte Itanium en décalage. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool itd_translate_component_to_offset(const itanium_component *comp, call_offset_t *off) { bool result; /* Bilan à retourner */ if (comp->type == ICT_DOUBLE_OFFSET) { result = comp->binary.left->type == ICT_NON_VIRTUAL_OFFSET && comp->binary.right->type == ICT_VIRTUAL_OFFSET; assert(result); if (result) { off->values[0] = comp->binary.left->offset; off->values[1] = comp->binary.right->offset; off->virtual = true; } } else if (comp->type == ICT_NON_VIRTUAL_OFFSET) { result = true; off->values[0] = comp->offset; off->virtual = false; } else result = false; return result; } /****************************************************************************** * * * Paramètres : comp = composant Itanium à traduire en type. * * * * Description : Traduit les composants de contexte Itanium en type. * * * * Retour : Traduction en type décodé. * * * * Remarques : - * * * ******************************************************************************/ GDataType *itd_translate_component_to_type(const itanium_component *comp) { GDataType *result; /* Type à retourner */ char *name; /* Attribution finale */ GDataType *ns; /* Espace de noms d'un type */ call_offset_t off0; /* Décalage #0 */ call_offset_t off1; /* Décalage #1 */ itanium_component *iter; /* Boucle de parcours */ GDataType *arg; /* Argument de prototype */ GDataType *members; /* Type de membres de tableau */ GDataType *param; /* Paramètre de gabarit */ /* Pour GCC !? */ result = NULL; switch (comp->type) { case ICT_NAME: name = itd_translate_component(comp, NULL); result = g_class_enum_type_new(CET_STRUCT, name); break; case ICT_STD_UNSCOPED_NAME: result = itd_translate_component_to_type(comp->unary); if (result != NULL) { ns = g_class_enum_type_new(CET_NAMESPACE, strdup("std")); g_data_type_set_namespace(result, ns, "::"); } break; case ICT_NESTED_NAME: if (comp->binary.right->type == ICT_TEMPLATE_ARGS) { name = itd_translate_component(comp->binary.left, NULL); name = itd_translate_component(comp->binary.right, name); result = g_class_enum_type_new(CET_CLASS, name); } else { if (comp->binary.left != NULL) { ns = itd_translate_component_to_type(comp->binary.left); if (ns == NULL) { result = NULL; break; } } else ns = NULL; result = itd_translate_component_to_type(comp->binary.right); if (result != NULL && ns != NULL) g_data_type_set_namespace(result, ns, "::"); } break; case ICT_TEMPLATE_NAME_ARGS: result = itd_translate_component_to_type(comp->binary.right); if (result != NULL) { name = itd_translate_component(comp->binary.left, NULL); g_template_type_set_name(G_TEMPLATE_TYPE(result), name); } break; case ICT_PREFIX_BINARY: if (comp->binary.right->type == ICT_TEMPLATE_ARGS) { name = itd_translate_component(comp->binary.left, NULL); name = itd_translate_component(comp->binary.right, name); result = g_class_enum_type_new(CET_CLASS, name); } else { ns = itd_translate_component_to_type(comp->binary.left); if (ns == NULL) { result = NULL; break; } result = itd_translate_component_to_type(comp->binary.right); if (result != NULL) g_data_type_set_namespace(result, ns, "::"); } break; case ICT_TPREFIX_BINARY: if (comp->binary.right->type == ICT_TEMPLATE_ARGS) { name = itd_translate_component(comp->binary.left, NULL); name = itd_translate_component(comp->binary.right, name); result = g_class_enum_type_new(CET_CLASS, name); } else { if (comp->binary.left != NULL) { ns = itd_translate_component_to_type(comp->binary.left); if (ns == NULL) { result = NULL; break; } } else ns = NULL; result = itd_translate_component_to_type(comp->binary.right); if (result != NULL) { if (ns != NULL) g_data_type_set_namespace(result, ns, "::"); } else { if (ns != NULL) g_object_unref(G_OBJECT(ns)); } } break; case ICT_OPERATOR_NAME: result = NULL; break; case ICT_SPECIAL_NAME_VTABLE: ns = itd_translate_component_to_type(comp->unary); if (ns == NULL) result = NULL; else { result = g_class_enum_type_new(CET_VIRTUAL_TABLE, NULL); g_data_type_set_namespace(result, ns, "::"); } break; case ICT_SPECIAL_NAME_VSTRUCT: ns = itd_translate_component_to_type(comp->unary); if (ns == NULL) result = NULL; else { result = g_class_enum_type_new(CET_VIRTUAL_STRUCT, NULL); g_data_type_set_namespace(result, ns, "::"); } break; case ICT_NON_VIRTUAL_OFFSET: case ICT_VIRTUAL_OFFSET: case ICT_DOUBLE_OFFSET: result = NULL; break; case ICT_FUNCTION_THUNK: if (!itd_translate_component_to_offset(comp->binary.right, &off0)) { result = NULL; break; } result = itd_translate_component_to_type(comp->binary.left); if (result != NULL) result = g_override_type_new(result, &off0); break; case ICT_FUNCTION_COVARIANT_THUNK: if (!itd_translate_component_to_offset(comp->ternary.second, &off0)) { result = NULL; break; } if (!itd_translate_component_to_offset(comp->ternary.third, &off1)) { result = NULL; break; } result = itd_translate_component_to_type(comp->ternary.first); if (result != NULL) result = g_override_type_new_with_covariant(result, &off0, &off1); break; case ICT_CONSTRUCTOR: case ICT_DESSTRUCTOR: result = NULL; break; case ICT_TYPE: case ICT_VENDOR_TYPE: result = g_data_type_dup(comp->dtype); break; case ICT_QUALIFIED_TYPE: result = itd_translate_component_to_type(comp->qualified.sub); if (result != NULL) g_data_type_add_qualifier(result, comp->qualified.qualifier); break; case ICT_POINTER_TO: result = itd_translate_component_to_type(comp->unary); if (result != NULL && !G_IS_PROTO_TYPE(result)) result = g_encapsulated_type_new(ECT_POINTER, result); break; case ICT_REFERENCE_TO: result = itd_translate_component_to_type(comp->unary); if (result != NULL) result = g_encapsulated_type_new(ECT_REFERENCE, result); break; case ICT_RVALUE_REFERENCE_TO: result = itd_translate_component_to_type(comp->unary); if (result != NULL) result = g_encapsulated_type_new(ECT_RVALUE_REF, result); break; case ICT_COMPLEX_PAIR: result = itd_translate_component_to_type(comp->unary); if (result != NULL) result = g_encapsulated_type_new(ECT_COMPLEX, result); break; case ICT_IMAGINARY: result = itd_translate_component_to_type(comp->unary); if (result != NULL) result = g_encapsulated_type_new(ECT_IMAGINARY, result); break; case ICT_FUNCTION_TYPE: result = g_proto_type_new(); assert(comp->function.args->type == ICT_TYPES_LIST); for (iter = comp->function.args; iter != NULL && result != NULL; iter = iter->binary.right) { assert(iter->type == ICT_TYPES_LIST); arg = itd_translate_component_to_type(iter->binary.left); if (arg == NULL) { g_object_unref(G_OBJECT(result)); result = NULL; } else { if (iter == comp->function.args) g_proto_type_set_return_type(G_PROTO_TYPE(result), arg); else g_proto_type_add_arg(G_PROTO_TYPE(result), arg); } } break; case ICT_FUNCTION_ENCODING: result = NULL; break; case ICT_ARRAY: members = itd_translate_component_to_type(comp->array.atype); if (members == NULL) result = NULL; else { result = g_array_type_new(members); if (comp->array.numbered_dim) g_array_type_set_dimension_number(G_ARRAY_TYPE(result), comp->array.dim_number); else if (comp->array.dim_expr != NULL) g_array_type_set_dimension_expression(G_ARRAY_TYPE(result), itd_translate_component(comp->array.dim_expr, NULL)); else g_array_type_set_empty_dimension(G_ARRAY_TYPE(result)); } break; case ICT_POINTER_TO_MEMBER: ns = itd_translate_component_to_type(comp->pmember.class); if (ns == NULL) result = NULL; else { result = itd_translate_component_to_type(comp->pmember.member); if (result == NULL) g_object_unref(G_OBJECT(ns)); else g_data_type_set_namespace(result, ns, "::"); } break; case ICT_TEMPLATE_PARAM: result = itd_translate_component_to_type(comp->unary); break; case ICT_TEMPLATE_ARGS: assert(comp->unary->type == ICT_TYPES_LIST); result = g_template_type_new(); for (iter = comp->unary; iter != NULL && result != NULL; iter = iter->binary.right) { assert(iter->type == ICT_TYPES_LIST); param = itd_translate_component_to_type(iter->binary.left); if (param == NULL) { g_object_unref(G_OBJECT(result)); result = NULL; } else g_template_type_add_param(G_TEMPLATE_TYPE(result), param); } break; case ICT_TYPES_LIST: /** * Les listes doient être rassemblées par l'appelant ! */ assert(false); result = NULL; break; case ICT_EXPR_LIST: /** * Les listes doient être rassemblées par l'appelant ! */ assert(false); result = NULL; break; case ICT_OPERATED_EXPRESSION: result = g_expr_type_new(itd_translate_component(comp, NULL)); break; case ICT_STD_SUBST: result = g_data_type_dup(comp->dtype); break; case ICT_COUNT: assert(false); result = NULL; break; } return result; } /****************************************************************************** * * * Paramètres : comp = composant Itanium à traduire en routine. * * * * Description : Traduit les composants de contexte Itanium en routine. * * * * Retour : Traduction en routine décodée. * * * * Remarques : - * * * ******************************************************************************/ GBinRoutine *itd_translate_component_to_routine(const itanium_component *comp) { GBinRoutine *result; /* Routine à retourner */ bool has_ret; /* Type de retour présent ? */ itanium_component *name; /* Désignation de la routine */ char *desc; /* Description humaine */ GDataType *ns; /* Espace de noms de la routine*/ itanium_component *args; /* Liste de ses arguments */ itanium_component *iter; /* Boucle de parcours */ GDataType *type; /* Type d'un argument */ GBinVariable *arg; /* Argument à ajouter */ if (comp->type != ICT_FUNCTION_ENCODING) goto bad_encoding; result = g_binary_routine_new(); /* Nom de la routine */ name = comp->binary.left; /** * A la fin de § 5.1.3 ("Operator Encodings") est précisé : * * If the conversion operator is a member template, the result type will * appear before the template parameters. * * On note donc cette particularité. */ has_ret = (name->type == ICT_TEMPLATE_NAME_ARGS); switch (name->type) { /** * Seules les productions de itd_name() sont valides ici. * On écarte volontairement les noms qualifiés ICT_QUALIFIED_TYPE. */ case ICT_NESTED_NAME: case ICT_TEMPLATE_NAME_ARGS: case ICT_STD_UNSCOPED_NAME: case ICT_NAME: type = itd_translate_component_to_type(name); if (type == NULL) goto unsupported_encoding; ns = g_data_type_get_namespace(type); g_data_type_set_namespace(type, NULL, NULL); if (G_IS_TEMPLATE_TYPE(type)) g_binary_routine_set_name_from_type(result, type); else { desc = g_data_type_to_string(type, true); g_object_unref(G_OBJECT(type)); g_binary_routine_set_name(result, desc); } g_binary_routine_set_namespace(result, ns, "::"); break; case ICT_OPERATOR_NAME: g_binary_routine_set_name(result, itd_translate_component(name, NULL)); break; default: goto unsupported_encoding; break; } /* Liste d'arguments */ args = comp->binary.right; if (args->type != ICT_TYPES_LIST) goto unsupported_encoding; for (iter = args; iter != NULL; iter = iter->binary.right) { type = itd_translate_component_to_type(iter->binary.left); if (type == NULL) goto unsupported_encoding; if (iter == args && has_ret) g_binary_routine_set_return_type(result, type); else { arg = g_binary_variable_new(type); g_binary_routine_add_arg(result, arg); } } return result; unsupported_encoding: g_object_unref(G_OBJECT(result)); bad_encoding: return NULL; }