From d0314437fcad499f45a4bdb93d085100cee2c70b Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 4 Mar 2020 00:32:42 +0100
Subject: Handled destructors properly when demangling C++ Itanium names.

---
 plugins/itanium/abi.c       |  2 +-
 plugins/itanium/component.c | 86 +++++++++++++++++++++++++++------------------
 plugins/itanium/component.h |  4 +--
 plugins/itanium/context.c   |  2 +-
 src/analysis/routine.c      | 33 ++++++++++++-----
 src/analysis/type.c         | 23 ++++++++++++
 src/analysis/type.h         |  3 ++
 tests/mangling/itanium.py   |  9 +++++
 8 files changed, 115 insertions(+), 47 deletions(-)

diff --git a/plugins/itanium/abi.c b/plugins/itanium/abi.c
index c2e56e1..7094aa4 100644
--- a/plugins/itanium/abi.c
+++ b/plugins/itanium/abi.c
@@ -1772,7 +1772,7 @@ static itanium_component *itd_ctor_dtor_name(GItaniumDemangling *context)
     if (next == 'C')
         type = ICT_CONSTRUCTOR;
     else if (next == 'D')
-        type = ICT_DESSTRUCTOR;
+        type = ICT_DESTRUCTOR;
     else
         return NULL;
 
diff --git a/plugins/itanium/component.c b/plugins/itanium/component.c
index 1b2c33c..3474639 100644
--- a/plugins/itanium/component.c
+++ b/plugins/itanium/component.c
@@ -43,7 +43,6 @@
 
 
 
-
 /* Procédure à appliquer sur un composant visité */
 typedef void (* visit_comp_fc) (itanium_component *);
 
@@ -187,7 +186,7 @@ static void visit_comp(itanium_component *comp, visit_comp_fc visitor)
             break;
 
         case ICT_CONSTRUCTOR:
-        case ICT_DESSTRUCTOR:
+        case ICT_DESTRUCTOR:
             break;
 
         case ICT_TYPE:
@@ -1019,7 +1018,7 @@ char *itd_translate_component(const itanium_component *comp, char *base)
             result = stradd(base, "<ctor>");
             break;
 
-        case ICT_DESSTRUCTOR:
+        case ICT_DESTRUCTOR:
             result = stradd(base, "<dtor>");
             break;
 
@@ -1339,7 +1338,8 @@ static void itd_prepend_namespace_to_type(GDataType *type, GDataType *ns)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : comp = composant Itanium à traduire en type.                 *
+*  Paramètres  : comp  = composant Itanium à traduire en type.                *
+*                rtype = type de l'éventuelle routine en construction.        *
 *                                                                             *
 *  Description : Traduit les composants de contexte Itanium en type.          *
 *                                                                             *
@@ -1349,7 +1349,7 @@ static void itd_prepend_namespace_to_type(GDataType *type, GDataType *ns)
 *                                                                             *
 ******************************************************************************/
 
-GDataType *itd_translate_component_to_type(const itanium_component *comp)
+GDataType *itd_translate_component_to_type(const itanium_component *comp, RoutineType *rtype)
 {
     GDataType *result;                      /* Type à retourner            */
     char *name;                             /* Attribution finale          */
@@ -1373,7 +1373,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             break;
 
         case ICT_STD_UNSCOPED_NAME:
-            result = itd_translate_component_to_type(comp->unary);
+            result = itd_translate_component_to_type(comp->unary, rtype);
             if (result != NULL)
             {
                 ns = g_class_enum_type_new(CET_NAMESPACE, strdup("std"));
@@ -1396,7 +1396,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             {
                 if (comp->binary.left != NULL)
                 {
-                    ns = itd_translate_component_to_type(comp->binary.left);
+                    ns = itd_translate_component_to_type(comp->binary.left, rtype);
                     if (ns == NULL)
                     {
                         result = NULL;
@@ -1406,7 +1406,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
                 else
                     ns = NULL;
 
-                result = itd_translate_component_to_type(comp->binary.right);
+                result = itd_translate_component_to_type(comp->binary.right, rtype);
 
                 if (result != NULL)
                 {
@@ -1416,8 +1416,12 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
                 else
                 {
-                    if (ns != NULL)
+                    if (*rtype != RTT_CLASSIC)
+                        result = ns;
+
+                    else if (ns != NULL)
                         g_object_unref(G_OBJECT(ns));
+
                 }
 
             }
@@ -1426,11 +1430,11 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
         case ICT_TEMPLATE_NAME_ARGS:
 
-            result = itd_translate_component_to_type(comp->binary.right);
+            result = itd_translate_component_to_type(comp->binary.right, rtype);
 
             if (result != NULL)
             {
-                sub = itd_translate_component_to_type(comp->binary.left);
+                sub = itd_translate_component_to_type(comp->binary.left, rtype);
 
                 if (sub == NULL)
                 {
@@ -1471,14 +1475,14 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
             else
             {
-                ns = itd_translate_component_to_type(comp->binary.left);
+                ns = itd_translate_component_to_type(comp->binary.left, rtype);
                 if (ns == NULL)
                 {
                     result = NULL;
                     break;
                 }
 
-                result = itd_translate_component_to_type(comp->binary.right);
+                result = itd_translate_component_to_type(comp->binary.right, rtype);
 
                 if (result != NULL)
                     itd_prepend_namespace_to_type(result, ns);
@@ -1502,7 +1506,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             {
                 if (comp->binary.left != NULL)
                 {
-                    ns = itd_translate_component_to_type(comp->binary.left);
+                    ns = itd_translate_component_to_type(comp->binary.left, rtype);
                     if (ns == NULL)
                     {
                         result = NULL;
@@ -1513,7 +1517,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
                 else
                     ns = NULL;
 
-                result = itd_translate_component_to_type(comp->binary.right);
+                result = itd_translate_component_to_type(comp->binary.right, rtype);
 
                 if (result != NULL)
                 {
@@ -1536,7 +1540,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
         case ICT_SPECIAL_NAME_VTABLE:
 
-            ns = itd_translate_component_to_type(comp->unary);
+            ns = itd_translate_component_to_type(comp->unary, rtype);
 
             if (ns == NULL)
                 result = NULL;
@@ -1551,7 +1555,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
         case ICT_SPECIAL_NAME_VSTRUCT:
 
-            ns = itd_translate_component_to_type(comp->unary);
+            ns = itd_translate_component_to_type(comp->unary, rtype);
 
             if (ns == NULL)
                 result = NULL;
@@ -1578,7 +1582,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
                 break;
             }
 
-            result = itd_translate_component_to_type(comp->binary.left);
+            result = itd_translate_component_to_type(comp->binary.left, rtype);
 
             if (result != NULL)
                 result = g_override_type_new(result, &off0);
@@ -1599,7 +1603,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
                 break;
             }
 
-            result = itd_translate_component_to_type(comp->ternary.first);
+            result = itd_translate_component_to_type(comp->ternary.first, rtype);
 
             if (result != NULL)
                 result = g_override_type_new_with_covariant(result, &off0, &off1);
@@ -1607,7 +1611,14 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             break;
 
         case ICT_CONSTRUCTOR:
-        case ICT_DESSTRUCTOR:
+            if (rtype != NULL)
+                *rtype = RTT_CONSTRUCTOR;
+            result = NULL;
+            break;
+
+        case ICT_DESTRUCTOR:
+            if (rtype != NULL)
+                *rtype = RTT_DESTRUCTOR;
             result = NULL;
             break;
 
@@ -1617,37 +1628,37 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             break;
 
         case ICT_QUALIFIED_TYPE:
-            result = itd_translate_component_to_type(comp->qualified.sub);
+            result = itd_translate_component_to_type(comp->qualified.sub, rtype);
             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);
+            result = itd_translate_component_to_type(comp->unary, rtype);
             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);
+            result = itd_translate_component_to_type(comp->unary, rtype);
             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);
+            result = itd_translate_component_to_type(comp->unary, rtype);
             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);
+            result = itd_translate_component_to_type(comp->unary, rtype);
             if (result != NULL)
                 result = g_encapsulated_type_new(ECT_COMPLEX, result);
             break;
 
         case ICT_IMAGINARY:
-            result = itd_translate_component_to_type(comp->unary);
+            result = itd_translate_component_to_type(comp->unary, rtype);
             if (result != NULL)
                 result = g_encapsulated_type_new(ECT_IMAGINARY, result);
             break;
@@ -1662,7 +1673,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             {
                 assert(iter->type == ICT_TYPES_LIST);
 
-                arg = itd_translate_component_to_type(iter->binary.left);
+                arg = itd_translate_component_to_type(iter->binary.left, rtype);
 
                 if (arg == NULL)
                 {
@@ -1689,7 +1700,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
         case ICT_ARRAY:
 
-            members = itd_translate_component_to_type(comp->array.atype);
+            members = itd_translate_component_to_type(comp->array.atype, rtype);
 
             if (members == NULL)
                 result = NULL;
@@ -1714,14 +1725,14 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 
         case ICT_POINTER_TO_MEMBER:
 
-            ns = itd_translate_component_to_type(comp->pmember.class);
+            ns = itd_translate_component_to_type(comp->pmember.class, rtype);
 
             if (ns == NULL)
                 result = NULL;
 
             else
             {
-                result = itd_translate_component_to_type(comp->pmember.member);
+                result = itd_translate_component_to_type(comp->pmember.member, rtype);
 
                 if (result == NULL)
                     g_object_unref(G_OBJECT(ns));
@@ -1734,7 +1745,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             break;
 
         case ICT_TEMPLATE_PARAM:
-            result = itd_translate_component_to_type(comp->unary);
+            result = itd_translate_component_to_type(comp->unary, rtype);
             break;
 
         case ICT_TEMPLATE_ARGS:
@@ -1747,7 +1758,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
             {
                 assert(iter->type == ICT_TYPES_LIST);
 
-                param = itd_translate_component_to_type(iter->binary.left);
+                param = itd_translate_component_to_type(iter->binary.left, rtype);
 
                 if (param == NULL)
                 {
@@ -1816,8 +1827,9 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp)
 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   */
+    RoutineType rtype;                      /* Type déclaré de routine     */
+    bool has_ret;                           /* Type de retour présent ?    */
     char *desc;                             /* Description humaine         */
     GDataType *ns;                          /* Espace de noms de la routine*/
     itanium_component *args;                /* Liste de ses arguments      */
@@ -1834,6 +1846,8 @@ GBinRoutine *itd_translate_component_to_routine(const itanium_component *comp)
 
     name = comp->binary.left;
 
+    rtype = RTT_CLASSIC;
+
     /**
      * A la fin de § 5.1.3 ("Operator Encodings") est précisé :
      *
@@ -1857,7 +1871,7 @@ GBinRoutine *itd_translate_component_to_routine(const itanium_component *comp)
         case ICT_STD_UNSCOPED_NAME:
         case ICT_NAME:
 
-            type = itd_translate_component_to_type(name);
+            type = itd_translate_component_to_type(name, &rtype);
             if (type == NULL) goto unsupported_encoding;
 
             ns = g_data_type_get_namespace(type);
@@ -1892,6 +1906,8 @@ GBinRoutine *itd_translate_component_to_routine(const itanium_component *comp)
 
     }
 
+    g_binary_routine_set_type(result, rtype);
+
     /* Liste d'arguments */
 
     args = comp->binary.right;
@@ -1901,7 +1917,7 @@ GBinRoutine *itd_translate_component_to_routine(const itanium_component *comp)
 
     for (iter = args; iter != NULL; iter = iter->binary.right)
     {
-        type = itd_translate_component_to_type(iter->binary.left);
+        type = itd_translate_component_to_type(iter->binary.left, NULL);
 
         if (type == NULL)
             goto unsupported_encoding;
diff --git a/plugins/itanium/component.h b/plugins/itanium/component.h
index a2dc607..36852d9 100644
--- a/plugins/itanium/component.h
+++ b/plugins/itanium/component.h
@@ -104,7 +104,7 @@ typedef enum _ItaniumComponentType
      * Constructeur ou destructeur, sans plus de détail.
      */
     ICT_CONSTRUCTOR,
-    ICT_DESSTRUCTOR,
+    ICT_DESTRUCTOR,
 
     /**
      * Type instanciable dans le programme.
@@ -295,7 +295,7 @@ ItaniumComponentType itd_get_component_type(const itanium_component *);
 char *itd_translate_component(const itanium_component *, char *);
 
 /* Traduit les composants de contexte Itanium en type. */
-GDataType *itd_translate_component_to_type(const itanium_component *);
+GDataType *itd_translate_component_to_type(const itanium_component *, RoutineType *);
 
 /* Traduit les composants de contexte Itanium en routine. */
 GBinRoutine *itd_translate_component_to_routine(const itanium_component *);
diff --git a/plugins/itanium/context.c b/plugins/itanium/context.c
index 315131e..6a79a40 100644
--- a/plugins/itanium/context.c
+++ b/plugins/itanium/context.c
@@ -289,7 +289,7 @@ static GDataType *g_itanium_demangling_decode_type(GItaniumDemangling *context)
 
     else
     {
-        result = itd_translate_component_to_type(comp);
+        result = itd_translate_component_to_type(comp, NULL);
 
         itd_unref_comp(comp);
 
diff --git a/src/analysis/routine.c b/src/analysis/routine.c
index 8c38ff1..240004f 100644
--- a/src/analysis/routine.c
+++ b/src/analysis/routine.c
@@ -826,12 +826,11 @@ char *g_binary_routine_to_string(const GBinRoutine *routine, bool include)
     {
         case RTT_CONSTRUCTOR:
             result = g_binary_routine_get_label(routine);
-            result = stradd(result, "." /* FIXME */);
+            result = stradd(result, " *");
             break;
 
         case RTT_DESTRUCTOR:
-            result = g_binary_routine_get_label(routine);
-            result = stradd(result, "::~");
+            result = strdup("void ");
             break;
 
         default: /* Pour gcc */
@@ -863,17 +862,35 @@ char *g_binary_routine_to_string(const GBinRoutine *routine, bool include)
     }
 
     if (routine->full_name != NULL)
-    {
         name = g_data_type_to_string(routine->full_name, true);
 
-        result = stradd(result, name);
+    else if (routine->name != NULL)
+        name = routine->name;
 
-        free(name);
+    switch (routine->type)
+    {
+        case RTT_CONSTRUCTOR:
+            result = stradd(result, name);
+            result = stradd(result, routine->ns_sep);
+            result = stradd(result, name);
+            break;
+
+        case RTT_DESTRUCTOR:
+            result = stradd(result, name);
+            result = stradd(result, routine->ns_sep);
+            result = stradd(result, "~");
+            result = stradd(result, name);
+            break;
+
+        default: /* Pour gcc */
+        case RTT_CLASSIC:
+            result = stradd(result, name);
+            break;
 
     }
 
-    else if (routine->name != NULL)
-        result = stradd(result, routine->name);
+    if (routine->full_name != NULL)
+        free(name);
 
     /* Liste des arguments */
 
diff --git a/src/analysis/type.c b/src/analysis/type.c
index ddc068f..5bcb0e2 100644
--- a/src/analysis/type.c
+++ b/src/analysis/type.c
@@ -281,6 +281,29 @@ GDataType *g_data_type_get_namespace(const GDataType *type)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : type = type à consulter.                                     *
+*                                                                             *
+*  Description : Fournit la chaîne de séparation entre deux entités.          *
+*                                                                             *
+*  Retour      : Eventuelle chaîne de séparation ou NULL.                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const char *g_data_type_get_namespace_separator(const GDataType *type)
+{
+    char *result;                           /* Séparateur à retourner      */
+
+    result = type->ns_sep;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : type       = instance à mettre à jour.                       *
 *                qualifiers = nouveaux qualificatifs pour la variable.        *
 *                                                                             *
diff --git a/src/analysis/type.h b/src/analysis/type.h
index 96c8835..431c080 100644
--- a/src/analysis/type.h
+++ b/src/analysis/type.h
@@ -75,6 +75,9 @@ void g_data_type_set_namespace(GDataType *, GDataType *, char *);
 /* Fournit le groupe d'appartenance d'un type donné. */
 GDataType *g_data_type_get_namespace(const GDataType *);
 
+/* Fournit la chaîne de séparation entre deux entités. */
+const char *g_data_type_get_namespace_separator(const GDataType *);
+
 /* Définit l'ensemble des qualificatifs d'une instance de type. */
 void g_data_type_set_qualifiers(GDataType *, TypeQualifier);
 
diff --git a/tests/mangling/itanium.py b/tests/mangling/itanium.py
index a04c590..2d13d77 100644
--- a/tests/mangling/itanium.py
+++ b/tests/mangling/itanium.py
@@ -175,3 +175,12 @@ class TestItaniumMangling(ChrysalideTestCase):
 
         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<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 testAndroidSystem(self):
+        """Check Itanium routine demangling from Android system cases."""
+
+        demangler = ItaniumDemangler()
+
+        demangled = demangler.decode_routine('_ZN7android7String8D1Ev')
+        self.check_demangling(demangled, 'void android::String8::~String8(void)')
-- 
cgit v0.11.2-87-g4458