/* Chrysalide - Outil d'analyse de fichiers binaires * abi.c - décodage des noms d'éléments selon 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 "abi.h" #include #include #include #include #include #include #include /* Liste des opérateurs reconnus */ #define IDT_NL(s) s, sizeof(s) - 1 const itanium_operator_info itanium_demangle_operators[] = { { "aN", IDT_NL("&="), 2 }, { "aS", IDT_NL("="), 2 }, { "aa", IDT_NL("&&"), 2 }, { "ad", IDT_NL("&"), 1 }, { "an", IDT_NL("&"), 2 }, { "at", IDT_NL("alignof "), 1 }, { "az", IDT_NL("alignof "), 1 }, { "cc", IDT_NL("const_cast"), 2 }, { "cl", IDT_NL("()"), 2 }, { "cm", IDT_NL(","), 2 }, { "co", IDT_NL("~"), 1 }, { "dV", IDT_NL("/="), 2 }, { "da", IDT_NL("delete[] "), 1 }, { "dc", IDT_NL("dynamic_cast"), 2 }, { "de", IDT_NL("*"), 1 }, { "dl", IDT_NL("delete "), 1 }, { "ds", IDT_NL(".*"), 2 }, { "dt", IDT_NL("."), 2 }, { "dv", IDT_NL("/"), 2 }, { "eO", IDT_NL("^="), 2 }, { "eo", IDT_NL("^"), 2 }, { "eq", IDT_NL("=="), 2 }, { "ge", IDT_NL(">="), 2 }, { "gs", IDT_NL("::"), 1 }, { "gt", IDT_NL(">"), 2 }, { "ix", IDT_NL("[]"), 2 }, { "lS", IDT_NL("<<="), 2 }, { "le", IDT_NL("<="), 2 }, { "li", IDT_NL("operator\"\" "), 1 }, { "ls", IDT_NL("<<"), 2 }, { "lt", IDT_NL("<"), 2 }, { "mI", IDT_NL("-="), 2 }, { "mL", IDT_NL("*="), 2 }, { "mi", IDT_NL("-"), 2 }, { "ml", IDT_NL("*"), 2 }, { "mm", IDT_NL("--"), 1 }, { "na", IDT_NL("new[]"), 3 }, { "ne", IDT_NL("!="), 2 }, { "ng", IDT_NL("-"), 1 }, { "nt", IDT_NL("!"), 1 }, { "nw", IDT_NL("new"), 3 }, { "oR", IDT_NL("|="), 2 }, { "oo", IDT_NL("||"), 2 }, { "or", IDT_NL("|"), 2 }, { "pL", IDT_NL("+="), 2 }, { "pl", IDT_NL("+"), 2 }, { "pm", IDT_NL("->*"), 2 }, { "pp", IDT_NL("++"), 1 }, { "ps", IDT_NL("+"), 1 }, { "pt", IDT_NL("->"), 2 }, { "qu", IDT_NL("?"), 3 }, { "rM", IDT_NL("%="), 2 }, { "rS", IDT_NL(">>="), 2 }, { "rc", IDT_NL("reinterpret_cast"), 2 }, { "rm", IDT_NL("%"), 2 }, { "rs", IDT_NL(">>"), 2 }, { "sc", IDT_NL("static_cast"), 2 }, { "st", IDT_NL("sizeof "), 1 }, { "sz", IDT_NL("sizeof "), 1 } }; /* Substitutions standards */ typedef struct _itanium_std_subst_info { char code; /* Identifiant associé */ const char *class; /* Classe visée dans l'espace */ } itanium_std_subst_info; const itanium_std_subst_info itanium_standard_substitutions[] = { { 't', NULL }, { 'a', "allocator" }, { 'b', "basic_string" }, { 's', "string" }, { 'i', "istream" }, { 'o', "ostream" }, { 'd', "iostream" } }; /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_encoding(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_name(GItaniumDemangling *); /* Détermine si le composant suivant correspond à un type donné. */ static bool is_itd_unscoped_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_unscoped_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_unscoped_template_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_nested_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_prefix(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_prefix_rec(GItaniumDemangling *, itanium_component *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_template_prefix(GItaniumDemangling *); /* Détermine si le composant suivant correspond à un type donné. */ static bool is_itd_unqualified_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_unqualified_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_source_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static bool itd_number(GItaniumDemangling *, ssize_t *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_identifier(GItaniumDemangling *, size_t); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_operator_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_special_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_call_offset(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_nv_offset(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_v_offset(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_ctor_dtor_name(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_type(GItaniumDemangling *); /* Extrait une propriété de composant pour un contexte Itanium. */ static TypeQualifier itd_cv_qualifiers(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_builtin_type(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_function_type(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_bare_function_type(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_class_enum_type(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_array_type(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_pointer_to_member_type(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_template_param(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_template_template_param(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_template_args(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_template_arg(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_expression(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_value_to_string(GItaniumDemangling *, bool); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_expr_primary(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static bool itd_seq_id(GItaniumDemangling *, char, size_t *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_substitution(GItaniumDemangling *); #define itd_local_name(ctx) NULL /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Extrait un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ itanium_component *itd_mangled_name(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ /** * La règle traitée ici est la suivante : * * ::= _Z * */ ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; if (!check_input_buffer_char(ibuf, '_')) return NULL; if (!check_input_buffer_char(ibuf, 'Z')) return NULL; result = itd_encoding(context); return result; } /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Extrait un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static itanium_component *itd_encoding(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ char peek; /* Prochain caractère lu */ itanium_component *types; /* Composant 'bare-function...'*/ /** * La règle traitée ici est la suivante : * * ::= * ::= * ::= * */ ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; peek = peek_input_buffer_char(ibuf); if (peek == 'T' || peek == 'G') result = itd_special_name(context); else { result = itd_name(context); if (result != NULL) { types = itd_bare_function_type(context); if (types != NULL) result = itd_make_binary(ICT_FUNCTION_ENCODING, result, types); /** * Si le chargement des types échoue, il peut y avoir deux explications : * - on ne chargeait qu'un simple nom. * - il y a eu une erreur de décodage pour les types. * * Le tampon aura été vidé dans le premier cas uniquement, * donc on laisse le contexte détecter une éventuelle erreur. */ } } return result; } /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Extrait un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static itanium_component *itd_name(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ itd_state saved; /* Position d'analyse courante */ itanium_component *tname; /* Composant '...template-name'*/ itanium_component *targs; /* Composant 'template-args' */ /** * La règle traitée ici est la suivante : * * ::= * ::= * ::= * ::= * */ g_itanium_demangling_push_state(context, &saved); result = itd_nested_name(context); if (result == NULL) { g_itanium_demangling_pop_state(context, &saved); tname = itd_unscoped_template_name(context); if (tname != NULL) { targs = itd_template_args(context); if (targs != NULL) result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, tname, targs); else itd_unref_comp(tname); } } /** * La règle doit être traitée après , * car ces deux dernières ont une base commune et la seconde peut avoir besoin * d'aller plus loin avec la règle . * * On termine donc par moins gourmand si la règle la plus complexe n'a pas abouti. */ if (result == NULL) { g_itanium_demangling_pop_state(context, &saved); result = itd_unscoped_name(context); } if (result == NULL) { g_itanium_demangling_pop_state(context, &saved); result = itd_local_name(context); } return result; } /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Détermine si le composant suivant correspond à un type donné.* * * * Retour : true si le décodage va à priori réussir, false sinon. * * * * Remarques : - * * * ******************************************************************************/ static bool is_itd_unscoped_name(GItaniumDemangling *context) { bool result; /* Bilan à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ char peek; /* Prochain caractère lu */ char next_peek; /* Caractère après le prochain */ /** * La règle anticipée ici est la suivante : * * ::= * ::= St # ::std:: * */ result = is_itd_unqualified_name(context); if (!result) { ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; peek = peek_input_buffer_char(ibuf); if (peek == 'S') { next_peek = peek_input_buffer_next_char(ibuf); result = (next_peek == 't'); } } return result; } /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Extrait un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static itanium_component *itd_unscoped_name(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ char peek; /* Prochain caractère lu */ char next_peek; /* Caractère après le prochain */ /** * La règle traitée ici est la suivante : * * ::= * ::= St # ::std:: * */ if (is_itd_unqualified_name(context)) result = itd_unqualified_name(context); else { ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; peek = peek_input_buffer_char(ibuf); if (peek == 'S') { next_peek = peek_input_buffer_next_char(ibuf); if (next_peek == 't') { advance_input_buffer(ibuf, 2); result = itd_unqualified_name(context); if (result != NULL) result = itd_make_unary(ICT_STD_UNSCOPED_NAME, result); } else result = NULL; } else result = NULL; } return result; } /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Extrait un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static itanium_component *itd_unscoped_template_name(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ char peek; /* Prochain caractère lu */ /** * La règle traitée ici est la suivante : * * ::= * ::= * */ if (is_itd_unscoped_name(context)) { result = itd_unscoped_name(context); if (result != NULL) g_itanium_demangling_add_substitution(context, result); } else { ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; peek = peek_input_buffer_char(ibuf); if (peek == 'S') result = itd_substitution(context); else result = NULL; } return result; } /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Extrait un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static itanium_component *itd_nested_name(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ TypeQualifier qualifier; /* Propriétés supplémentaires */ itd_state saved; /* Position d'analyse courante */ itanium_component *left; /* Première partie */ itanium_component *right; /* Seconde partie */ /** * La règle traitée ici est la suivante : * * ::= N [] E * ::= N [] E * */ ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; if (!check_input_buffer_char(ibuf, 'N')) return NULL; qualifier = itd_cv_qualifiers(context); result = NULL; g_itanium_demangling_push_state(context, &saved); /** * Comme peut aussi être , * on commence par traiter la seconde règle. */ left = itd_template_prefix(context); if (left != NULL) { right = itd_template_args(context); if (right != NULL) { if (check_input_buffer_char(ibuf, 'E')) result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, left, right); else { itd_unref_comp(left); itd_unref_comp(right); } } else itd_unref_comp(left); } if (result == NULL) { g_itanium_demangling_pop_state(context, &saved); left = itd_prefix(context); /** * Quand son traitement est un succès, doit toujours * se terminer par . */ assert(left == NULL || (left != NULL && is_itd_unqualified_name(context))); /** * La règle peut être vide, donc on se doit de tenter un * dans tous les cas. */ right = itd_unqualified_name(context); if (right != NULL) { if (check_input_buffer_char(ibuf, 'E')) result = itd_make_binary(ICT_NESTED_NAME, left, right); else { if (left != NULL) itd_unref_comp(left); itd_unref_comp(right); } } else if (left != NULL) itd_unref_comp(left); } if (result != NULL) itd_make_qualified_type(result, qualifier); return result; } /****************************************************************************** * * * Paramètres : context = contexte de décodage à utiliser. * * * * Description : Extrait un composant dans un contexte Itanium. * * * * Retour : Composant extrait ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static itanium_component *itd_prefix(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ char peek; /* Prochain caractère lu */ itanium_component *targs; /* Composant 'template-args' */ itd_state saved; /* Position d'analyse courante */ itanium_component *further; /* Tentative de progression */ /** * La règle traitée ici est la suivante : * * ::= * ::= * ::= * ::= # empty * ::= * * On note déjà la jolie petite boucle interne. * * Or on a également la règle voisine suivante : * * ::=