From 46cf7042cf511215001bb28c072821998a83d011 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 15 Mar 2020 20:28:02 +0100
Subject: Added support for packed template arguments in Itanium demangling.

---
 plugins/itanium/abi.c       | 57 +++++++++++++++++++++++++++++++++++++++++++--
 plugins/itanium/component.c | 52 ++++++++++++++++++++++++++++++++++++++++-
 plugins/itanium/component.h |  9 +++++++
 tests/mangling/itanium.py   |  3 +++
 4 files changed, 118 insertions(+), 3 deletions(-)

diff --git a/plugins/itanium/abi.c b/plugins/itanium/abi.c
index 300bf59..0304938 100644
--- a/plugins/itanium/abi.c
+++ b/plugins/itanium/abi.c
@@ -1818,6 +1818,7 @@ static itanium_component *itd_type(GItaniumDemangling *context)
      *        ::= C <type>   # complex pair (C 2000)
      *        ::= G <type>   # imaginary (C 2000)
      *        ::= U <source-name> <type> # vendor extended type qualifier
+     *        ::= Dp <type>  # pack expansion (C++0x)
      *
      */
 
@@ -1946,6 +1947,17 @@ static itanium_component *itd_type(GItaniumDemangling *context)
             handled = true;
             break;
 
+        case 'D':
+            if (peek_input_buffer_next_char(ibuf) == 'p')
+            {
+                advance_input_buffer(ibuf, 2);
+
+                result = itd_type(context);
+                handled = true;
+
+            }
+            break;
+
         case 'T':
 
             /**
@@ -2832,7 +2844,7 @@ static itanium_component *itd_template_args(GItaniumDemangling *context)
     arg = itd_template_arg(context);
     if (arg == NULL) return NULL;
 
-    result = itd_append_right_to_binary(ICT_TYPES_LIST, NULL, arg);
+    result = itd_merge_list_right_to_binary(ICT_TYPES_LIST, NULL, arg);
 
     while (1)
     {
@@ -2845,7 +2857,7 @@ static itanium_component *itd_template_args(GItaniumDemangling *context)
             break;
         }
 
-        result = itd_append_right_to_binary(ICT_TYPES_LIST, result, arg);
+        result = itd_merge_list_right_to_binary(ICT_TYPES_LIST, result, arg);
 
     }
 
@@ -2881,6 +2893,7 @@ static itanium_component *itd_template_arg(GItaniumDemangling *context)
     itanium_component *result;              /* Construction à retourner    */
     input_buffer *ibuf;                     /* Tampon de texte manipulé    */
     char peek;                              /* Prochain caractère lu       */
+    itanium_component *packed;              /* Argument compressé          */
 
     /**
      * La règle traitée ici est la suivante :
@@ -2888,6 +2901,7 @@ static itanium_component *itd_template_arg(GItaniumDemangling *context)
      * <template-arg> ::= <type>                     # type or template
      *                ::= X <expression> E           # expression
      *                ::= <expr-primary>             # simple expressions
+     *                ::= J <template-arg>* E        # argument pack
      *
      */
 
@@ -2912,9 +2926,48 @@ static itanium_component *itd_template_arg(GItaniumDemangling *context)
     else if (peek == 'L')
         result = itd_expr_primary(context);
 
+    else if (peek == 'J')
+    {
+        advance_input_buffer(ibuf, 1);
+
+        result = NULL;
+
+        while (peek_input_buffer_char(ibuf) != 'E')
+        {
+            packed = itd_template_arg(context);
+
+            if (packed == NULL)
+            {
+                if (result != NULL)
+                {
+                    itd_unref_comp(result);
+                    result = NULL;
+                }
+
+                goto packed_failed;
+
+            }
+
+            result = itd_merge_list_right_to_binary(ICT_TYPES_LIST, result, packed);
+
+        }
+
+        if (result == NULL)
+            result = itd_make_with_type(ICT_PACKED_EMPTY);
+
+        if (!check_input_buffer_char(ibuf, 'E'))
+        {
+            itd_unref_comp(result);
+            result = NULL;
+        }
+
+    }
+
     else
         result = itd_type(context);
 
+ packed_failed:
+
     return result;
 
 }
diff --git a/plugins/itanium/component.c b/plugins/itanium/component.c
index f5aad1d..f035e36 100644
--- a/plugins/itanium/component.c
+++ b/plugins/itanium/component.c
@@ -254,6 +254,9 @@ static void visit_comp(itanium_component *comp, visit_comp_fc visitor)
 
             break;
 
+        case ICT_PACKED_EMPTY:
+            break;
+
         case ICT_EXPR_LIST:
 
             visit_comp(comp->binary.left, visitor);
@@ -810,6 +813,46 @@ itanium_component *itd_append_right_to_binary(ItaniumComponentType type, itanium
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : type = type du composant à mettre en place.                  *
+*                left = second composant à associer.                          *
+*                                                                             *
+*  Description : Construit un composant dans un contexte Itanium.             *
+*                                                                             *
+*  Retour      : Composant extrait ou NULL en cas d'échec.                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+itanium_component *itd_merge_list_right_to_binary(ItaniumComponentType type, itanium_component *parent, itanium_component *left)
+{
+    itanium_component *result;              /* Composant à renvoyer        */
+    itanium_component *iter;                /* Boucle de parcours          */
+
+    if (left->type != ICT_TYPES_LIST)
+        result = itd_append_right_to_binary(type, parent, left);
+
+    else
+    {
+        if (parent == NULL)
+            result = left;
+
+        else
+        {
+            for (iter = parent; iter->binary.right != NULL; iter = iter->binary.right)
+                ;
+            iter->binary.right = left;
+        }
+
+    }
+
+    return (parent != NULL ? parent : result);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type du composant à mettre en place.                  *
 *                c0   = premier composant à associer.                         *
 *                c1   = second composant à associer.                          *
 *                c2   = troisième composant à associer.                       *
@@ -1146,6 +1189,9 @@ char *itd_translate_component(const itanium_component *comp, char *base)
 
             break;
 
+        case ICT_PACKED_EMPTY:
+            break;
+
         case ICT_EXPR_LIST:
 
             /**
@@ -1751,12 +1797,15 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp, Routin
 
         case ICT_TEMPLATE_ARGS:
 
-            assert(comp->unary->type == ICT_TYPES_LIST);
+            assert(comp->unary->type == ICT_TYPES_LIST || comp->unary->type == ICT_PACKED_EMPTY);
 
             result = g_template_type_new();
 
             for (iter = comp->unary; iter != NULL && result != NULL; iter = iter->binary.right)
             {
+                if (iter->type == ICT_PACKED_EMPTY)
+                    continue;
+
                 assert(iter->type == ICT_TYPES_LIST);
 
                 param = itd_translate_component_to_type(iter->binary.left, rtype);
@@ -1774,6 +1823,7 @@ GDataType *itd_translate_component_to_type(const itanium_component *comp, Routin
             break;
 
         case ICT_TYPES_LIST:
+        case ICT_PACKED_EMPTY:
 
             /**
              * Les listes doient être rassemblées par l'appelant !
diff --git a/plugins/itanium/component.h b/plugins/itanium/component.h
index 36852d9..c4b5eb3 100644
--- a/plugins/itanium/component.h
+++ b/plugins/itanium/component.h
@@ -178,6 +178,12 @@ typedef enum _ItaniumComponentType
     ICT_TYPES_LIST,
 
     /**
+     * Paramètres compressés de patron non définis.
+     * (cf. règle <template-arg> ::= J <template-arg>* E )
+     */
+    ICT_PACKED_EMPTY,
+
+    /**
      * Liste d'expressions, sous forme binaire comme pour ICT_TYPES_LIST :
      *  -> left = élément de la liste de types.
      *  -> right = reste de la liste de types.
@@ -283,6 +289,9 @@ itanium_component *itd_make_binary(ItaniumComponentType, itanium_component *, it
 itanium_component *itd_append_right_to_binary(ItaniumComponentType, itanium_component *, itanium_component *);
 
 /* Construit un composant dans un contexte Itanium. */
+itanium_component *itd_merge_list_right_to_binary(ItaniumComponentType, itanium_component *, itanium_component *);
+
+/* Construit un composant dans un contexte Itanium. */
 itanium_component *itd_make_ternary(ItaniumComponentType, itanium_component *, itanium_component *, itanium_component *);
 
 /* Modifie légèrement le type d'un composant donné. */
diff --git a/tests/mangling/itanium.py b/tests/mangling/itanium.py
index a1cc517..1b24c3d 100644
--- a/tests/mangling/itanium.py
+++ b/tests/mangling/itanium.py
@@ -214,3 +214,6 @@ class TestItaniumMangling(ChrysalideTestCase):
 
         demangled = demangler.decode_routine('_ZNSt3__111__tree_nextIPNS_16__tree_node_baseIPvEEEET_S5_')
         self.check_demangling(demangled, 'std::__1::__tree_node_base<void *> *std::__1::__tree_next<std::__1::__tree_node_base<void *> *>(std::__1::__tree_node_base<void *> *)')
+
+        demangled = demangler.decode_routine('_ZNSt3__110shared_ptrIN7android14CameraMetadataEE11make_sharedIJRKS2_EEES3_DpOT_')
+        self.check_demangling(demangled, 'std::__1::shared_ptr<android::CameraMetadata> std::__1::shared_ptr<android::CameraMetadata>::make_shared<const android::CameraMetadata &>(const android::CameraMetadata &&&)')
-- 
cgit v0.11.2-87-g4458