From 1ade82e135d4e815db5b33c9ebd67632b74e5e1d Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 4 Jul 2018 12:24:39 +0200 Subject: Fixed various mistakes in Itanium C++ demangling. --- plugins/itanium/abi.c | 59 +++++++++++--------------- plugins/itanium/component-int.h | 5 +-- plugins/itanium/component.c | 63 +++++++++++---------------- plugins/itanium/component.h | 16 +++++-- plugins/itanium/context.c | 43 +++++++++++++++---- plugins/itanium/context.h | 2 +- plugins/pychrysalide/analysis/types/array.c | 19 +++++++-- src/analysis/types/array.c | 33 +++++++++++++-- src/analysis/types/array.h | 3 ++ tests/mangling/itanium.py | 66 +++++++++++++++++++++++++++++ 10 files changed, 212 insertions(+), 97 deletions(-) diff --git a/plugins/itanium/abi.c b/plugins/itanium/abi.c index 5f76342..3f6f713 100644 --- a/plugins/itanium/abi.c +++ b/plugins/itanium/abi.c @@ -1954,6 +1954,7 @@ static itanium_component *itd_type(GItaniumDemangling *context) { builtin = g_class_enum_type_new(CET_UNKNOWN, itd_translate_component(vendor, NULL)); result = itd_make_type(builtin); + itd_set_type(result, ICT_VENDOR_TYPE); itd_unref_comp(vendor); sub = itd_type(context); @@ -2483,10 +2484,10 @@ static itanium_component *itd_array_type(GItaniumDemangling *context) { itanium_component *result; /* Construction à retourner */ input_buffer *ibuf; /* Tampon de texte manipulé */ - char peek; /* Prochain caractère dispo. */ - itanium_component *dim_expr; /* Dimension via expression */ ssize_t dim_number; /* Dimension par un nombre */ itanium_component *type; /* Type du tableau */ + itd_state saved; /* Position d'analyse courante */ + itanium_component *dim_expr; /* Dimension via expression */ /** * La règle traitée ici est la suivante : @@ -2501,58 +2502,46 @@ static itanium_component *itd_array_type(GItaniumDemangling *context) if (!check_input_buffer_char(ibuf, 'A')) return NULL; - peek = peek_input_buffer_char(ibuf); - - if (peek == '[') + if (itd_number(context, &dim_number)) { - advance_input_buffer(ibuf, 1); - - dim_expr = itd_expression(context); - - if (dim_expr == NULL) - return NULL; - - if (!check_input_buffer_char(ibuf, ']')) - return NULL; - if (!check_input_buffer_char(ibuf, '_')) return NULL; type = itd_type(context); if (type == NULL) - { - itd_unref_comp(dim_expr); return NULL; - } - result = itd_make_array_with_dim_expr(dim_expr, type); - - if (result == NULL) - { - itd_unref_comp(dim_expr); - itd_unref_comp(type); - } + result = itd_make_array_with_dim_number(dim_number, type); } else { - if (!itd_number(context, &dim_number)) - return NULL; + g_itanium_demangling_push_state(context, &saved); + + dim_expr = itd_expression(context); + + if (dim_expr == NULL) + g_itanium_demangling_pop_state(context, &saved); if (!check_input_buffer_char(ibuf, '_')) + { + if (dim_expr != NULL) + itd_unref_comp(dim_expr); return NULL; + } type = itd_type(context); if (type == NULL) + { + if (dim_expr != NULL) + itd_unref_comp(dim_expr); return NULL; + } - result = itd_make_array_with_dim_number(dim_number, type); - - if (result == NULL) - itd_unref_comp(type); + result = itd_make_array_with_dim_expr(dim_expr, type); } @@ -2660,6 +2649,9 @@ static itanium_component *itd_template_param(GItaniumDemangling *context) result = g_itanium_demangling_get_template_arg(context, id); + if (result != NULL) + result = itd_make_unary(ICT_TEMPLATE_PARAM, result); + } } @@ -2761,6 +2753,8 @@ static itanium_component *itd_template_args(GItaniumDemangling *context) result = itd_make_unary(ICT_TEMPLATE_ARGS, result); + g_itanium_demangling_add_template_args(context, result); + return result; } @@ -2817,9 +2811,6 @@ static itanium_component *itd_template_arg(GItaniumDemangling *context) else result = itd_type(context); - if (result != NULL) - g_itanium_demangling_add_template_arg(context, result); - return result; } diff --git a/plugins/itanium/component-int.h b/plugins/itanium/component-int.h index fb8c423..20b2c8d 100644 --- a/plugins/itanium/component-int.h +++ b/plugins/itanium/component-int.h @@ -36,8 +36,6 @@ struct _itanium_component unsigned int refcount; /* Compteur de références */ - fnv64_t hash; /* Empreinte en cache */ - union { /* ICT_NAME */ @@ -66,8 +64,9 @@ struct _itanium_component /* ICT_VIRTUAL_OFFSET */ ssize_t offset; /* Décalage de fonction */ - /* ICT_STD_SUBST */ /* ICT_TYPE */ + /* ICT_VENDOR_TYPE */ + /* ICT_STD_SUBST */ GDataType *dtype; /* Type instancié */ /* ICT_QUALIFIED_TYPE */ diff --git a/plugins/itanium/component.c b/plugins/itanium/component.c index 6e580f6..d890a1b 100644 --- a/plugins/itanium/component.c +++ b/plugins/itanium/component.c @@ -48,9 +48,6 @@ typedef void (* visit_comp_fc) (itanium_component *); -#define reset_comp_hash(c) c->hash = 0 - - /* Crée un composant de contexte Itanium complètement vierge. */ static itanium_component *itd_alloc(void); @@ -191,6 +188,7 @@ static void visit_comp(itanium_component *comp, visit_comp_fc visitor) break; case ICT_TYPE: + case ICT_VENDOR_TYPE: break; case ICT_QUALIFIED_TYPE: @@ -227,7 +225,7 @@ static void visit_comp(itanium_component *comp, visit_comp_fc visitor) break; case ICT_ARRAY: - if (!comp->array.numbered_dim) + if (!comp->array.numbered_dim && comp->array.dim_expr != NULL) visit_comp(comp->array.dim_expr, visitor); visit_comp(comp->array.atype, visitor); break; @@ -237,6 +235,10 @@ static void visit_comp(itanium_component *comp, visit_comp_fc 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; @@ -320,7 +322,7 @@ void itd_unref_comp(itanium_component *comp) { if (--comp->refcount == 0) { - if (comp->type == ICT_TYPE || comp->type == ICT_STD_SUBST) + 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); @@ -336,34 +338,6 @@ void itd_unref_comp(itanium_component *comp) /****************************************************************************** * * -* Paramètres : comp = composant à manipuler. * -* * -* Description : Détermine ou fournit l'empreinte d'un composant. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -fnv64_t itd_hash_comp(itanium_component *comp) -{ - char *desc; /* Description du composant */ - - if (comp->hash == 0) - { - desc = itd_translate_component(comp, NULL); - comp->hash = fnv_64a_hash(desc); - free(desc); - } - - return comp->hash; - -} - - -/****************************************************************************** -* * * Paramètres : type = type à définir pour le composant. * * * * Description : Construit un composant dans un contexte Itanium. * @@ -797,7 +771,7 @@ itanium_component *itd_append_right_to_binary(ItaniumComponentType type, itanium if (parent != NULL) { for (iter = parent; iter->binary.right != NULL; iter = iter->binary.right) - reset_comp_hash(iter); + ; iter->binary.right = result; } @@ -854,8 +828,6 @@ void itd_set_type(itanium_component *comp, ItaniumComponentType type) { comp->type = type; - reset_comp_hash(comp); - } @@ -1025,6 +997,7 @@ char *itd_translate_component(const itanium_component *comp, char *base) break; case ICT_TYPE: + case ICT_VENDOR_TYPE: name = g_data_type_to_string(comp->dtype, true); result = stradd(base, name); free(name); @@ -1112,7 +1085,7 @@ char *itd_translate_component(const itanium_component *comp, char *base) free(tmp); } - else + else if (comp->array.dim_expr != NULL) result = itd_translate_component(comp->array.dim_expr, result); result = stradd(result, "]"); @@ -1125,6 +1098,10 @@ char *itd_translate_component(const itanium_component *comp, char *base) 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); @@ -1543,6 +1520,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp) break; case ICT_TYPE: + case ICT_VENDOR_TYPE: result = g_data_type_dup(comp->dtype); break; @@ -1631,9 +1609,12 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp) if (comp->array.numbered_dim) g_array_type_set_dimension_number(G_ARRAY_TYPE(result), comp->array.dim_number); - else + else if (comp->array.dim_expr != NULL) g_array_type_set_dimension_expression(G_ARRAY_TYPE(result), - itd_translate_component(comp, NULL)); + itd_translate_component(comp->array.dim_expr, NULL)); + + else + g_array_type_set_empty_dimension(G_ARRAY_TYPE(result)); } @@ -1660,6 +1641,10 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp) 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); diff --git a/plugins/itanium/component.h b/plugins/itanium/component.h index f921ff9..7012283 100644 --- a/plugins/itanium/component.h +++ b/plugins/itanium/component.h @@ -34,7 +34,6 @@ #include #include -#include @@ -113,6 +112,12 @@ typedef enum _ItaniumComponentType ICT_TYPE, /** + * Simple distinction de ICT_TYPE, pour la distinction lors des candidatures + * aux substitutions. + */ + ICT_VENDOR_TYPE, + + /** * Type qualifié ; les infos utilies sont explicitement * conservées dans le champ qualified. */ @@ -154,6 +159,12 @@ typedef enum _ItaniumComponentType ICT_POINTER_TO_MEMBER, /** + * Argument de template. Utile pour les candidatures aux substitutions. + * 'unary' renvoie vers le composant utile. + */ + ICT_TEMPLATE_PARAM, + + /** * Liste d'arguments pour templates, à encadrer par des chevrons. * 'unary' pointe vers la liste des éléments. */ @@ -223,9 +234,6 @@ void itd_ref_comp(itanium_component *); /* Décrémente le nombre d'utilisation du composant. */ void itd_unref_comp(itanium_component *); -/* Détermine ou fournit l'empreinte d'un composant. */ -fnv64_t itd_hash_comp(itanium_component *); - /* Construit un composant dans un contexte Itanium. */ itanium_component *itd_make_with_type(ItaniumComponentType); diff --git a/plugins/itanium/context.c b/plugins/itanium/context.c index 1d2c365..c89f823 100644 --- a/plugins/itanium/context.c +++ b/plugins/itanium/context.c @@ -411,10 +411,12 @@ void g_itanium_demangling_pop_state(GItaniumDemangling *context, const itd_state * * ******************************************************************************/ -void g_itanium_demangling_add_template_arg(GItaniumDemangling *context, itanium_component *comp) +void g_itanium_demangling_add_template_args(GItaniumDemangling *context, itanium_component *comp) { assert(comp != NULL); + assert(itd_get_component_type(comp) == ICT_TEMPLATE_ARGS); + context->template_args[context->targs_count++] = comp; itd_ref_comp(comp); @@ -437,14 +439,37 @@ void g_itanium_demangling_add_template_arg(GItaniumDemangling *context, itanium_ itanium_component *g_itanium_demangling_get_template_arg(GItaniumDemangling *context, size_t index) { itanium_component *result; /* Composant à retourner */ + itanium_component *targs; /* Racine des arguments */ + itanium_component *iter; /* Boucle de parcours #1 */ + + if (context->targs_count == 0) + result = NULL; - if (index < context->targs_count) + else { - result = context->template_args[index]; - itd_ref_comp(result); + targs = context->template_args[context->targs_count - 1]; + + for (iter = targs->unary; iter != NULL; iter = iter->binary.right) + { + assert(itd_get_component_type(iter) == ICT_TYPES_LIST); + + if (index == 0) + break; + + index--; + + } + + if (iter != NULL) + { + result = iter->binary.left; + itd_ref_comp(result); + } + + else + result = NULL; + } - else - result = NULL; return result; @@ -466,15 +491,15 @@ itanium_component *g_itanium_demangling_get_template_arg(GItaniumDemangling *con void g_itanium_demangling_add_substitution(GItaniumDemangling *context, itanium_component *comp) { - fnv64_t hash; /* Empreinte du candidat */ size_t i; /* Boucle de parcours */ assert(comp != NULL); - hash = itd_hash_comp(comp); + if (itd_get_component_type(comp) == ICT_STD_SUBST) + return; for (i = 0; i < context->subst_count; i++) - if (cmp_fnv_64a(itd_hash_comp(context->substitutions[i]), hash) == 0) + if (comp == context->substitutions[i]) break; if (i == context->subst_count) diff --git a/plugins/itanium/context.h b/plugins/itanium/context.h index 6ec65ae..d836afb 100644 --- a/plugins/itanium/context.h +++ b/plugins/itanium/context.h @@ -67,7 +67,7 @@ void g_itanium_demangling_push_state(const GItaniumDemangling *, itd_state *); void g_itanium_demangling_pop_state(GItaniumDemangling *, const itd_state *); /* Indexe un composant représentant un argument de modèle. */ -void g_itanium_demangling_add_template_arg(GItaniumDemangling *, itanium_component *); +void g_itanium_demangling_add_template_args(GItaniumDemangling *, itanium_component *); /* Fournit un composant représentant un argument de modèle. */ itanium_component *g_itanium_demangling_get_template_arg(GItaniumDemangling *, size_t); diff --git a/plugins/pychrysalide/analysis/types/array.c b/plugins/pychrysalide/analysis/types/array.c index d021e16..6f70b02 100644 --- a/plugins/pychrysalide/analysis/types/array.c +++ b/plugins/pychrysalide/analysis/types/array.c @@ -281,7 +281,14 @@ static PyObject *py_array_type_get_dimension_expression(PyObject *self, void *cl dim = g_array_type_get_dimension_expression(type); - result = PyUnicode_FromString(dim); + if (dim != NULL) + result = PyUnicode_FromString(dim); + + else + { + result = Py_None; + Py_INCREF(result); + } return result; @@ -306,15 +313,19 @@ static int py_array_type_set_dimension_expression(PyObject *self, PyObject *valu { GArrayType *type; /* Version GLib du type */ - if (!PyUnicode_Check(value)) + if (!PyUnicode_Check(value) && value != Py_None) { - PyErr_SetString(PyExc_TypeError, _("The attribute value must be a string.")); + PyErr_SetString(PyExc_TypeError, _("The attribute value must be a string or None.")); return -1; } type = G_ARRAY_TYPE(pygobject_get(self)); - g_array_type_set_dimension_expression(type, strdup(PyUnicode_DATA(value))); + if (value == Py_None) + g_array_type_set_empty_dimension(type); + + else + g_array_type_set_dimension_expression(type, strdup(PyUnicode_DATA(value))); return 0; diff --git a/src/analysis/types/array.c b/src/analysis/types/array.c index 714ab58..5aea07b 100644 --- a/src/analysis/types/array.c +++ b/src/analysis/types/array.c @@ -230,6 +230,9 @@ static GDataType *g_array_type_dup(const GArrayType *type) else if (type->dim_expr != NULL) g_array_type_set_dimension_expression(G_ARRAY_TYPE(result), strdup(type->dim_expr)); + else + g_array_type_set_empty_dimension(G_ARRAY_TYPE(result)); + return result; } @@ -268,7 +271,7 @@ static char *g_array_type_to_string(const GArrayType *type, bool include) } } - else + else if (type->dim_expr != NULL) result = stradd(result, type->dim_expr); result = stradd(result, "]"); @@ -356,7 +359,7 @@ ssize_t g_array_type_get_dimension_number(const GArrayType *type) /****************************************************************************** * * -* Paramètres : type = type à consulter. * +* Paramètres : type = type à traiter. * * dim = dimension positive ou nulle. * * * * Description : Définit la dimension associée au tableau. * @@ -406,7 +409,7 @@ const char *g_array_type_get_dimension_expression(const GArrayType *type) /****************************************************************************** * * -* Paramètres : type = type à consulter. * +* Paramètres : type = type à traiter. * * expr = expression de dimension. * * * * Description : Définit la dimension associée au tableau. * @@ -427,3 +430,27 @@ void g_array_type_set_dimension_expression(GArrayType *type, char *expr) type->dim_expr = expr; } + + +/****************************************************************************** +* * +* Paramètres : type = type à traiter. * +* * +* Description : Définit une dimension vide pour le tableau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_array_type_set_empty_dimension(GArrayType *type) +{ + if (!type->numbered && type->dim_expr != NULL) + free(type->dim_expr); + + type->numbered = false; + + type->dim_expr = NULL; + +} diff --git a/src/analysis/types/array.h b/src/analysis/types/array.h index d432c22..3bec2a0 100644 --- a/src/analysis/types/array.h +++ b/src/analysis/types/array.h @@ -71,6 +71,9 @@ const char *g_array_type_get_dimension_expression(const GArrayType *); /* Définit la dimension associée au tableau. */ void g_array_type_set_dimension_expression(GArrayType *, char *); +/* Définit une dimension vide pour le tableau. */ +void g_array_type_set_empty_dimension(GArrayType *); + #endif /* _ANALYSIS_TYPES_ARRAY_H */ diff --git a/tests/mangling/itanium.py b/tests/mangling/itanium.py index 6bb49d3..a04c590 100644 --- a/tests/mangling/itanium.py +++ b/tests/mangling/itanium.py @@ -109,3 +109,69 @@ class TestItaniumMangling(ChrysalideTestCase): demangled = demangler.decode_routine('_ZN1N1TIiiE2mfES0_IddE') self.check_demangling(demangled, '??? N::T::mf(N::T)') + + + def testItaniumRoutineManglingExtra(self): + """Check extra Itanium routine demangling cases.""" + + # http://refspecs.linuxbase.org/cxxabi-1.83.html#linkage + + demangler = ItaniumDemangler() + + # A la lecture, il s'agit d'une référence sur un tableau, et non + # d'un tableau de références. + demangled = demangler.decode_routine('_Z3fooILi2EEvRAplT_Li1E_i') + self.check_demangling(demangled, 'void foo<2>(int[2+1] &)') + + + def testAFL(self): + """Tests from AFL.""" + + demangler = ItaniumDemangler() + + demangled = demangler.decode_routine('_Z4makeI7FactoryiET_IT') + self.assertIsNone(demangled) + + demangled = demangler.decode_routine('_Z4makeN7FactoryiET_IT0_Ev') + self.assertIsNone(demangled) + + demangled = demangler.decode_routine('_Z4makeI7FactoryiET_I4makeIMGaptoryiET_T0_Ev') + self.assertIsNone(demangled) + + demangled = demangler.decode_routine('_Z4maktoryiaS_ILNd') + self.assertIsNone(demangled) + + # ?! + demangled = demangler.decode_routine('_Z4makeMVFactoryiES_') + self.assertIsNotNone(demangled) + + + def testOldRealWorldDemanglings(self): + """Check real world demangling cases from previous code.""" + + demangler = ItaniumDemangler() + + demangled = demangler.decode_routine('_ZNSt6vectorItSaItEE6insertEN9__gnu_cxx17__normal_iteratorIPtS1_EERKt') + self.check_demangling(demangled, '??? std::vector>::insert(__gnu_cxx::__normal_iterator>>, const unsigned short &)') + + demangled = demangler.decode_routine('_ZSt26__uninitialized_fill_n_auxIP15CProfStringListiS0_ET_S2_T0_RKT1_12__false_type') + self.check_demangling(demangled, 'CProfStringList *std::__uninitialized_fill_n_aux(CProfStringList *, int, const CProfStringList &, __false_type)') + + + demangled = demangler.decode_routine('_ZN21IUDFSettingsValidator15IdNotIllegalStdEN13UDFParameters12UDF_STANDARDES1_') + self.check_demangling(demangled, '??? IUDFSettingsValidator::IdNotIllegalStd(UDFParameters::UDF_STANDARD, UDFParameters::UDF_STANDARD)') + + demangled = demangler.decode_routine('_ZNSbI26NeroMediumFeatureSpecifierSt11char_traitsIS_ESaIS_EE4_Rep10_M_destroyERKS2_') + self.check_demangling(demangled, '??? std::basic_string, std::allocator>::_Rep::_M_destroy(const std::allocator &)') + + demangled = demangler.decode_routine('_ZNSt6vectorIlSaIlEE6insertEN9__gnu_cxx17__normal_iteratorIPlS1_EERKl') + self.check_demangling(demangled, '??? std::vector>::insert(__gnu_cxx::__normal_iterator>>, const long &)') + + demangled = demangler.decode_routine('_ZSt22__merge_without_bufferIN9__gnu_cxx17__normal_iteratorIP15CProfStringListSt6vectorIS2_SaIS2_EEEEiEvT_S8_S8_T0_S9_') + self.check_demangling(demangled, 'void std::__merge_without_buffer<__gnu_cxx::__normal_iterator>>, int>(__gnu_cxx::__normal_iterator>>, __gnu_cxx::__normal_iterator>>, __gnu_cxx::__normal_iterator>>, int, int)') + + demangled = demangler.decode_routine('_ZSt11__push_heapIN9__gnu_cxx17__normal_iteratorIP8DRIVE_IDSt6vectorIS2_SaIS2_EEEEiS2_EvT_T0_S9_T1_') + self.check_demangling(demangled, 'void std::__push_heap<__gnu_cxx::__normal_iterator>>, int, DRIVE_ID>(__gnu_cxx::__normal_iterator>>, int, int, DRIVE_ID)') + + demangled = demangler.decode_routine('_ZSt12partial_sortIN9__gnu_cxx17__normal_iteratorIP28CPR_MAI_ADPTY_SectorSequenceSt6vectorIS2_SaIS2_EEEEEvT_S8_S8_') + self.check_demangling(demangled, 'void std::partial_sort<__gnu_cxx::__normal_iterator>>>(__gnu_cxx::__normal_iterator>>, __gnu_cxx::__normal_iterator>>, __gnu_cxx::__normal_iterator>>)') -- cgit v0.11.2-87-g4458