summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2020-03-08 22:12:42 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2020-03-08 22:12:42 (GMT)
commite1bda768f573b84e340bfcdc59fe353eb665f8e6 (patch)
treed96e146ef8282d9fba7c3741e5ff29c7b5c38f5f
parent1f3917fe0254198a4dbadb9a195ba076ae12736d (diff)
Fixed some mistakes in the Itanium prefixes demangling.
-rw-r--r--plugins/itanium/abi.c447
-rw-r--r--tests/mangling/itanium.py21
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)')