diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2020-03-08 22:12:42 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2020-03-08 22:12:42 (GMT) |
commit | e1bda768f573b84e340bfcdc59fe353eb665f8e6 (patch) | |
tree | d96e146ef8282d9fba7c3741e5ff29c7b5c38f5f | |
parent | 1f3917fe0254198a4dbadb9a195ba076ae12736d (diff) |
Fixed some mistakes in the Itanium prefixes demangling.
-rw-r--r-- | plugins/itanium/abi.c | 447 | ||||
-rw-r--r-- | tests/mangling/itanium.py | 21 |
2 files changed, 273 insertions, 195 deletions
diff --git a/plugins/itanium/abi.c b/plugins/itanium/abi.c index 7094aa4..0e7ce27 100644 --- a/plugins/itanium/abi.c +++ b/plugins/itanium/abi.c @@ -147,9 +147,6 @@ static itanium_component *itd_nested_name(GItaniumDemangling *); 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é. */ @@ -215,6 +212,9 @@ static itanium_component *itd_template_param(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_template_template_param(GItaniumDemangling *); +/* Détermine si le composant suivant correspond à un type donné. */ +static bool is_itd_template_args(GItaniumDemangling *); + /* Extrait un composant dans un contexte Itanium. */ static itanium_component *itd_template_args(GItaniumDemangling *); @@ -231,6 +231,9 @@ static itanium_component *itd_value_to_string(GItaniumDemangling *, bool); static itanium_component *itd_expr_primary(GItaniumDemangling *); /* Extrait un composant dans un contexte Itanium. */ +static itanium_component *itd_data_member_prefix(GItaniumDemangling *); + +/* Extrait un composant dans un contexte Itanium. */ static bool itd_seq_id(GItaniumDemangling *, char, size_t *); /* Extrait un composant dans un contexte Itanium. */ @@ -643,6 +646,13 @@ static itanium_component *itd_nested_name(GItaniumDemangling *context) if (left != NULL) { + /** + * Quand son traitement est un succès, <template-prefix> doit toujours + * se terminer par <template-args>. + */ + + assert(is_itd_template_args(context)); + right = itd_template_args(context); if (right != NULL) @@ -728,86 +738,98 @@ static itanium_component *itd_prefix(GItaniumDemangling *context) input_buffer *ibuf; /* Tampon de texte manipulé */ char peek; /* Prochain caractère lu */ itanium_component *targs; /* Composant 'template-args' */ + bool backup; /* Solution de repli existante */ + bool merge_targs; /* Fusion nécessaire ? */ itd_state saved; /* Position d'analyse courante */ itanium_component *further; /* Tentative de progression */ /** * La règle traitée ici est la suivante : * - * <prefix> ::= <prefix> <unqualified-name> + * <prefix> ::= <unqualified-name> + * ::= <prefix> <unqualified-name> * ::= <template-prefix> <template-args> * ::= <template-param> - * ::= # empty + * ::= <decltype> + * ::= <prefix> <data-member-prefix> * ::= <substitution> * - * On note déjà la jolie petite boucle interne. + * Réorganisée, cette règle <prefix> a pour définition : + * + * <prefix> ::= <unqualified-name> + * ::= <template-param> + * ::= <decltype> + * ::= <substitution> + * ::= <template-prefix> <template-args> * - * Or on a également la règle voisine suivante : + * ::= <prefix> <unqualified-name> + * ::= <prefix> <data-member-prefix> + * + * Il existe cependant une boucle infinie avec une règle de <prefix> : * * <template-prefix> ::= <prefix> <template unqualified-name> - * ::= <template-param> - * ::= <substitution> * - * Pour éviter une récursivité qui ferait exploser la pile, on les fusionne - * en une nouvelle règle <prefix> étendue : + * On déplie donc les règles afin de casser la boucle, quitte à gérer ici + * une partie de la règle <template-prefix> : * - * <prefix> ::= <prefix> <unqualified-name> - * ::= <prefix> <unqualified-name> <template-args> + * <prefix> ::= <unqualified-name> * ::= <template-param> - * ::= <template-param> <template-args> + * ::= <decltype> * ::= <substitution> + * + * ::= <unqualified-name> <template-args> + * ::= <template-param> <template-args> * ::= <substitution> <template-args> - * ::= # empty * + * ::= <prefix> <unqualified-name> + * ::= <prefix> <unqualified-name> <template-args> + * ::= <prefix> <data-member-prefix> */ - ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; - - if (is_itd_unqualified_name(context)) - result = itd_unqualified_name(context); - - else - { - peek = peek_input_buffer_char(ibuf); - - if (peek == 'T') - result = itd_template_param(context); + result = NULL; - else if (peek == 'S') - result = itd_substitution(context); + ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; - else - result = NULL; + peek = peek_input_buffer_char(ibuf); - } + if (peek == 'S') + result = itd_substitution(context); - if (result == NULL) - goto prefix_exit; + else if (peek == 'T') + result = itd_template_param(context); - g_itanium_demangling_add_substitution(context, result); + else if (is_itd_unqualified_name(context)) + result = itd_unqualified_name(context); /** - * Détection et traitement de <template-args>. + * Si le traitement débouche sur une règle <template-args>, c'est qu'il + * était en fait potentiellement dans une voie <template-prefix>. + * + * Cette voie est vérifiée après coup en analysant la suite. */ - peek = peek_input_buffer_char(ibuf); - - if (peek == 'I') + if (is_itd_template_args(context)) { - /** - * Si la détection est avérée, on vient donc de traiter un cas <template-prefix>. - * On corrige donc le type au passage. - */ - if (itd_get_component_type(result) == ICT_PREFIX_BINARY) - itd_set_type(result, ICT_TPREFIX_BINARY); + g_itanium_demangling_push_state(context, &saved); targs = itd_template_args(context); if (targs != NULL) { - result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs); + if (!is_itd_unqualified_name(context)) + { + g_itanium_demangling_pop_state(context, &saved); + itd_unref_comp(targs); + } - g_itanium_demangling_add_substitution(context, result); + else + { + /* Ajout de la substitution tirée de <template-prefix> */ + g_itanium_demangling_add_substitution(context, result); + + result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs); + + } } @@ -815,175 +837,118 @@ static itanium_component *itd_prefix(GItaniumDemangling *context) { itd_unref_comp(result); result = NULL; + goto done; } } if (result == NULL) - goto prefix_exit; + goto done; - /** - * Toutes les règles <prefix> sont suivie par un <[template] unqualified-name>. - * - * On vérifie donc que c'est le cas. - */ - - if (!is_itd_unqualified_name(context)) - { - itd_unref_comp(result); - result = NULL; - goto prefix_exit; - - } - - /** - * Cette vérification passée, on peut se trouver dans l'un des cas suivants : - * - * <prefix> ::= <prefix> <unqualified-name> - * ::= <prefix> <template unqualified-name> <template-args> - * - * On tente donc une itération supplémentaire. - */ - - g_itanium_demangling_push_state(context, &saved); + g_itanium_demangling_add_substitution(context, result); - further = itd_prefix_rec(context, result); + /* Tentative de rebouclage sur la règle <prefix> */ - if (further != NULL) - result = further; + while (count_input_buffer_remaining(ibuf) > 0) + { + backup = is_itd_unqualified_name(context); - else - g_itanium_demangling_pop_state(context, &saved); + if (backup) + g_itanium_demangling_push_state(context, &saved); - prefix_exit: + merge_targs = false; + targs = NULL; - return result; + /** + * Comme <data-member-prefix> commence par une régle <source-name> et + * complète ensuite sa définition et comme <unqualified-name> contient + * également cette même règle <source-name> sans l'étendre, on commence + * par traiter la règle <data-member-prefix>. + */ -} + further = itd_data_member_prefix(context); + if (further == NULL) + { + further = itd_unqualified_name(context); -/****************************************************************************** -* * -* Paramètres : context = contexte de décodage à utiliser. * -* loop = consigne pour la poursuite de la boucle. [OUT] * -* * -* Description : Extrait un composant dans un contexte Itanium. * -* * -* Retour : Composant extrait ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ + if (further != NULL && is_itd_template_args(context)) + { + merge_targs = true; + targs = itd_template_args(context); -static itanium_component *itd_prefix_rec(GItaniumDemangling *context, itanium_component *leaf) -{ - 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 */ + /* Si l'ensemble ne se termine pas par la règle finale attendue, on rétro-pédale */ + if (targs != NULL && !is_itd_unqualified_name(context)) + { + itd_unref_comp(targs); - /** - * La règle locale traitée ici est la suivante : - * - * <prefix> ::= <prefix> <unqualified-name> - * ::= <prefix> <unqualified-name> <template-args> - * - * Le premier <prefix> des règles est contenu dans l'arguement leaf. - */ + merge_targs = false; + targs = NULL; - ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; + g_itanium_demangling_pop_state(context, &saved); - /** - * La présence du <unqualified-name> intial doit être assurée - * par l'appelant. - * - * Mais comme le test ne vaut pas la création, on valide quand même derrière. - */ + break; - assert(is_itd_unqualified_name(context)); + } - result = itd_unqualified_name(context); + } - if (result == NULL) - goto prefix_rec_exit; + } - result = itd_make_binary(ICT_PREFIX_BINARY, leaf, result); + if (further == NULL) + break; - g_itanium_demangling_add_substitution(context, result); + if (!is_itd_unqualified_name(context)) + { + if (backup) + g_itanium_demangling_pop_state(context, &saved); - /** - * Détection et traitement de <template-args>. - */ + itd_unref_comp(further); - peek = peek_input_buffer_char(ibuf); + break; - if (peek == 'I') - { - /** - * Si la détection est avérée, on vient donc de traiter un cas <template-prefix>. - * On corrige donc le type au passage. - */ - if (itd_get_component_type(result) == ICT_PREFIX_BINARY) - itd_set_type(result, ICT_TPREFIX_BINARY); + } - targs = itd_template_args(context); + result = itd_make_binary(ICT_PREFIX_BINARY, result, further); - if (targs != NULL) + if (merge_targs) { - result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs); + if (targs != NULL) + { + g_itanium_demangling_add_substitution(context, result); - g_itanium_demangling_add_substitution(context, result); + result = itd_make_binary(ICT_TEMPLATE_NAME_ARGS, result, targs); - } + } + else + { + itd_unref_comp(result); + result = NULL; + goto done; + } - else - { - itd_ref_comp(leaf); - itd_unref_comp(result); - result = NULL; } + g_itanium_demangling_add_substitution(context, result); + } - if (result == NULL) - goto prefix_rec_exit; + done: /** - * Toutes les règles <prefix> sont suivie par un <[template] unqualified-name>. - * - * On vérifie donc que c'est le cas. + * Quand son traitement est un succès, <prefix> doit toujours + * se terminer par <unqualified-name>. */ - if (!is_itd_unqualified_name(context)) + if (result != NULL) { - itd_ref_comp(leaf); - itd_unref_comp(result); - result = NULL; - goto prefix_rec_exit; - } - - /** - * Cette vérification passée, on peut se trouver dans l'un des cas suivants : - * - * <prefix> ::= <prefix> <unqualified-name> - * ::= <prefix> <template unqualified-name> <template-args> - * - * On tente donc une itération supplémentaire. - */ - - g_itanium_demangling_push_state(context, &saved); - - further = itd_prefix_rec(context, result); - - if (further != NULL) - result = further; - - else - g_itanium_demangling_pop_state(context, &saved); + if (!is_itd_unqualified_name(context)) + { + itd_unref_comp(result); + result = NULL; + } - prefix_rec_exit: + } return result; @@ -1005,71 +970,112 @@ static itanium_component *itd_prefix_rec(GItaniumDemangling *context, itanium_co static itanium_component *itd_template_prefix(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ + bool new_subst; /* Ajoute d'une substitution ? */ input_buffer *ibuf; /* Tampon de texte manipulé */ char peek; /* Prochain caractère lu */ - itanium_component *prefix; /* Premier d'un couple de comp.*/ + itd_state saved; /* Position d'analyse courante */ itanium_component *name; /* Second d'un couple de comp. */ /** * La règle traitée ici est la suivante : * - * <template-prefix> ::= <prefix> <template unqualified-name> + * <template-prefix> ::= <template unqualified-name> + * ::= <prefix> <template unqualified-name> * ::= <template-param> * ::= <substitution> * + * Il existe cependant une boucle infinie avec une règle de <prefix> : + * + * <prefix> ::= <template-prefix> <template-args> + * + * On traite donc cette règle de <prefix> en dernier, quand les autres + * options ont été épuisées. */ + result = NULL; + + new_subst = true; + ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; peek = peek_input_buffer_char(ibuf); + g_itanium_demangling_push_state(context, &saved); + if (peek == 'S') + { result = itd_substitution(context); + new_subst = false; + } else if (peek == 'T') - { result = itd_template_param(context); - if (result != NULL) - g_itanium_demangling_add_substitution(context, result); + if (is_itd_unqualified_name(context)) + result = itd_unqualified_name(context); - } + /* Vérification : a-t-on empiété sur une règle <prefix> ? */ - else + if (result != NULL) { - prefix = itd_prefix(context); + if (is_itd_template_args(context)) + goto done; + + else + { + new_subst = true; + itd_unref_comp(result); + result = NULL; + + g_itanium_demangling_pop_state(context, &saved); + + } + + } + + /* Tentative avec <prefix> <template unqualified-name> en dernier recours */ + + result = itd_prefix(context); + + if (result != NULL) + { /** * Quand son traitement est un succès, <prefix> doit toujours * se terminer par <unqualified-name>. + * + * De même, toutes les règles <template-prefix> se poursuivent avec une + * règle <template-args> ; la procédure n'est donc un succès que dans ce cas. */ - assert(prefix == NULL || (prefix != NULL && is_itd_unqualified_name(context))); - - /** - * Par ailleurs, la règle <prefix> peut être vide, donc on se doit - * de tenter un <unqualified-name> dans tous les cas. - */ + assert(is_itd_unqualified_name(context)); name = itd_unqualified_name(context); if (name != NULL) - { - result = itd_make_binary(ICT_TPREFIX_BINARY, prefix, name); - - g_itanium_demangling_add_substitution(context, result); - - } + result = itd_make_binary(ICT_TPREFIX_BINARY, result, name); else { + itd_unref_comp(result); result = NULL; + } - if (prefix != NULL) - itd_unref_comp(prefix); + } + done: + + if (result != NULL) + { + if (!is_itd_template_args(context)) + { + itd_unref_comp(result); + result = NULL; } + else if (new_subst) + g_itanium_demangling_add_substitution(context, result); + } return result; @@ -2699,6 +2705,40 @@ static itanium_component *itd_template_template_param(GItaniumDemangling *contex 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_template_args(GItaniumDemangling *context) +{ + bool result; /* Bilan à retourner */ + input_buffer *ibuf; /* Tampon de texte manipulé */ + char peek; /* Prochain caractère lu */ + + /** + * La règle anticipée ici est la suivante : + * + * <template-args> ::= I <template-arg>+ E + * + */ + + ibuf = &G_DEMANGLING_CONTEXT(context)->buffer; + + peek = peek_input_buffer_char(ibuf); + + result = (peek == 'I'); + + return result; + +} /****************************************************************************** @@ -3183,10 +3223,27 @@ static itanium_component *itd_expr_primary(GItaniumDemangling *context) } +/****************************************************************************** +* * +* 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_data_member_prefix(GItaniumDemangling *context) +{ + itanium_component *result; /* Construction à retourner */ + result = NULL; + return result; +} /****************************************************************************** diff --git a/tests/mangling/itanium.py b/tests/mangling/itanium.py index 6808a99..57a1129 100644 --- a/tests/mangling/itanium.py +++ b/tests/mangling/itanium.py @@ -177,6 +177,24 @@ class TestItaniumMangling(ChrysalideTestCase): self.check_demangling(demangled, 'void std::partial_sort<__gnu_cxx::__normal_iterator<CPR_MAI_ADPTY_SectorSequence *, std::vector<CPR_MAI_ADPTY_SectorSequence, std::allocator<CPR_MAI_ADPTY_SectorSequence>>>>(__gnu_cxx::__normal_iterator<CPR_MAI_ADPTY_SectorSequence *, std::vector<CPR_MAI_ADPTY_SectorSequence, std::allocator<CPR_MAI_ADPTY_SectorSequence>>>, __gnu_cxx::__normal_iterator<CPR_MAI_ADPTY_SectorSequence *, std::vector<CPR_MAI_ADPTY_SectorSequence, std::allocator<CPR_MAI_ADPTY_SectorSequence>>>, __gnu_cxx::__normal_iterator<CPR_MAI_ADPTY_SectorSequence *, std::vector<CPR_MAI_ADPTY_SectorSequence, std::allocator<CPR_MAI_ADPTY_SectorSequence>>>)') + def testPrefixLoop(self): + """Handle the loop between prefixes defined in the specifications.""" + + demangler = ItaniumDemangler() + + demangled = demangler.decode_routine('_ZN2aaIN4ccccIfEEE5dddddEj') + self.check_demangling(demangled, '??? aa<cccc<float>>::ddddd(unsigned int)') + + demangled = demangler.decode_routine('_ZN2aaIN4cccc4xxxxIfEEE5dddddEj') + self.check_demangling(demangled, '??? aa<cccc::xxxx<float>>::ddddd(unsigned int)') + + demangled = demangler.decode_routine('_ZN3zzz2aaIN4cccc4xxxxIfEEE5dddddEj') + self.check_demangling(demangled, '??? zzz::aa<cccc::xxxx<float>>::ddddd(unsigned int)') + + demangled = demangler.decode_routine('_ZN3aaa3bbbINS_3cccIfEEE3dddEj') + self.check_demangling(demangled, '??? aaa::bbb<ccc<float>>::ddd(unsigned int)') + + def testAndroidSystem(self): """Check Itanium routine demangling from Android system cases.""" @@ -187,3 +205,6 @@ class TestItaniumMangling(ChrysalideTestCase): demangled = demangler.decode_routine('_ZN6icu_556LocaleaSERKS0_') self.check_demangling(demangled, '??? icu_55::Locale::operator=(const icu_55::Locale &)') + + demangled = demangler.decode_routine('_ZNSt3__16vectorIfNS_9allocatorIfEEE8__appendEj') + self.check_demangling(demangled, '??? std::__1::vector<float, allocator<float>>::__append(unsigned int)') |