msvcrt: support more symbol types in undname

Andrey Zhezherun zhezherun at yandex.ru
Thu Oct 31 18:48:30 CDT 2013


This patch extends undname to support

* Type modifiers for class members
* Anonymous namespaces
* Pointers to member functions
* Non-pointer function types
* Template constructors
* Dynamic initializers and dynamic atexit destructors
* Also suppresses some warnings

Regards,
Andrey
-------------- next part --------------
--- wine-1.7.5.orig/dlls/msvcrt/undname.c	2013-10-25 18:45:30.000000000 +0100
+++ wine-1.7.5/dlls/msvcrt/undname.c	2013-10-30 11:09:56.000000000 +0000
@@ -397,6 +397,8 @@
     return args_str;
 }
 
+static char* get_class_name(struct parsed_symbol* sym);
+
 /******************************************************************
  *		get_modifier
  * Parses the type modifier. Always returns static strings.
@@ -420,6 +422,10 @@
     case 'B': *ret = "const"; break;
     case 'C': *ret = "volatile"; break;
     case 'D': *ret = "const volatile"; break;
+    case 'Q': *ret = str_printf(sym, "%s::", get_class_name(sym)); break;
+    case 'R': *ret = str_printf(sym, "const %s::", get_class_name(sym)); break;
+    case 'S': *ret = str_printf(sym, "volatile %s::", get_class_name(sym)); break;
+    case 'T': *ret = str_printf(sym, "const volatile %s::", get_class_name(sym)); break;
     default: return FALSE;
     }
     return TRUE;
@@ -615,6 +621,11 @@
                 }
                 break;
             default:
+                if (*sym->current == 'A') {
+                    get_literal_string(sym);
+                    name = str_printf(sym, "`anonymous namespace'");
+                    break;
+                }
                 if (!(name = get_number( sym ))) return FALSE;
                 name = str_printf( sym, "`%s'", name );
                 break;
@@ -860,7 +871,7 @@
         if (isdigit(*sym->current))
 	{
             /* FIXME: P6 = Function pointer, others who knows.. */
-            if (*sym->current++ == '6')
+            if (*sym->current == '6')
             {
                 char*                   args = NULL;
                 const char*             call_conv;
@@ -868,6 +879,8 @@
                 struct datatype_t       sub_ct;
                 unsigned                mark = sym->stack.num;
 
+                ++sym->current;
+
                 if (!get_calling_convention(*sym->current++,
                                             &call_conv, &exported, 
                                             sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
@@ -882,7 +895,43 @@
                                        sub_ct.left, sub_ct.right, call_conv);
                 ct->right = str_printf(sym, ")%s", args);
             }
-            else goto done;
+            else if (*sym->current == '8')
+            {
+                /* P8 = Member function pointer */
+                char*                   args = NULL;
+                const char*             call_conv;
+                const char*             exported;
+                struct datatype_t       sub_ct;
+                unsigned                mark = sym->stack.num;
+                const char*             class_name;
+                const char*             ptr;
+                const char*             ptr_modif;
+
+                ++sym->current;
+                class_name = get_class_name( sym );
+
+                if (!get_modifier(sym, &ptr, &ptr_modif)) goto done;
+                if (ptr == NULL) ptr = "";
+
+                if (!get_calling_convention(*sym->current++,
+                                            &call_conv, &exported, 
+                                            sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
+                    !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
+                    goto done;
+
+                args = get_args(sym, pmt_ref, TRUE, '(', ')');
+                if (!args) goto done;
+                sym->stack.num = mark;
+
+                ct->left  = str_printf(sym, "%s%s (%s %s::*", 
+                                       sub_ct.left, sub_ct.right, call_conv, class_name);
+                ct->right = str_printf(sym, ")%s %s", args, ptr);
+            }
+            else
+            {
+                ++sym->current;
+                goto done;
+            }
 	}
 	else if (!get_modified_type(ct, sym, pmt_ref, 'P', in_args)) goto done;
         break;
@@ -959,11 +1008,41 @@
                 if (!demangle_datatype(sym, ct, pmt_ref, in_args)) goto done;
                 ct->left = str_printf(sym, "%s %s", ct->left, ptr);
             }
+            else if (*sym->current == 'A' && sym->current[1] == '6')
+            {
+                /* $$A6 = Function type (non-pointer) */
+
+                char*                   args = NULL;
+                const char*             call_conv;
+                const char*             exported;
+                struct datatype_t       sub_ct;
+                unsigned                mark = sym->stack.num;
+
+                sym->current += 2;
+
+                if (!get_calling_convention(*sym->current++,
+                                            &call_conv, &exported, 
+                                            sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
+                    !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
+                    goto done;
+
+                args = get_args(sym, pmt_ref, TRUE, '(', ')');
+                if (!args) goto done;
+                sym->stack.num = mark;
+
+                ct->left  = str_printf(sym, "%s%s %s", 
+                                       sub_ct.left, sub_ct.right, call_conv);
+                ct->right = str_printf(sym, "%s", args);
+            }
             break;
         }
         break;
     default :
-        ERR("Unknown type %c\n", dt);
+        /* MSVC can intentionally generate symbols that look like
+           <prefix>@<hex digits>, which the native undname cannot
+           demangle either. Don't report an error in this case. */
+        if (dt < 'a' || dt > 'f')
+            ERR("Unknown type %c\n", dt);
         break;
     }
     if (add_pmt && pmt_ref && in_args)
@@ -1271,6 +1350,7 @@
     BOOL                ret = FALSE;
     unsigned            do_after = 0;
     static CHAR         dashed_null[] = "--null--";
+    const char*         template_args = NULL;
 
     /* FIXME seems wrong as name, as it demangles a simple data type */
     if (sym->flags & UNDNAME_NO_ARGUMENTS)
@@ -1293,10 +1373,12 @@
     if (*sym->current == '?' && (sym->current[1] != '$' || sym->current[2] == '?'))
     {
         const char* function_name = NULL;
+        BOOL is_template = FALSE;
 
         if (sym->current[1] == '$')
         {
             do_after = 6;
+            is_template = TRUE;
             sym->current += 2;
         }
 
@@ -1411,6 +1493,84 @@
             case 'V': function_name = "operator delete[]"; break;
             case 'X': function_name = "`placement delete closure'"; break;
             case 'Y': function_name = "`placement delete[] closure'"; break;
+            case '_':
+                switch (*++sym->current)
+                {
+                case 'E':
+                    {
+                        const char* result = NULL;
+
+                        if (*++sym->current == '?')
+                        {
+                            struct array stack = sym->stack;
+                            unsigned int start = sym->names.start;
+                            unsigned int num = sym->names.num;
+
+                            str_array_init( &sym->stack );
+                            if (symbol_demangle( sym )) result = sym->result;
+                            if (*sym->current != '@') result = NULL;
+
+                            sym->names.start = start;
+                            sym->names.num = num;
+                            sym->stack = stack;
+                        }
+                        else
+                        {
+                            result = get_literal_string(sym);
+                            --sym->current;
+                        }
+
+                        if (result)
+                        {
+                            function_name = str_printf(sym, "`dynamic initializer for '%s''", result);
+                        }
+                        else
+                        {
+                            ERR("Invalid operator: __E\n");
+                            return FALSE;
+                        }
+                    }
+                    break;
+                case 'F':
+                    {
+                        const char* result = NULL;
+
+                        if (*++sym->current == '?')
+                        {
+                            struct array stack = sym->stack;
+                            unsigned int start = sym->names.start;
+                            unsigned int num = sym->names.num;
+
+                            str_array_init( &sym->stack );
+                            if (symbol_demangle( sym )) result = sym->result;
+                            if (*sym->current != '@') result = NULL;
+
+                            sym->names.start = start;
+                            sym->names.num = num;
+                            sym->stack = stack;
+                        }
+                        else
+                        {
+                            result = get_literal_string(sym);
+                            --sym->current;
+                        }
+
+                        if (result)
+                        {
+                            function_name = str_printf(sym, "`dynamic atexit destructor for '%s''", result);
+                        }
+                        else
+                        {
+                            ERR("Invalid operator: __F\n");
+                            return FALSE;
+                        }
+                    }
+                    break;
+                default:
+                    ERR("Unknown operator: __%c\n", *sym->current);
+                    return FALSE;
+                }
+                break;
             default:
                 ERR("Unknown operator: _%c\n", *sym->current);
                 return FALSE;
@@ -1427,6 +1587,15 @@
         case 1: case 2:
             if (!str_array_push(sym, dashed_null, -1, &sym->stack))
                 return FALSE;
+            if (is_template)
+            {
+                char *args;
+                struct array array_pmt;
+
+                str_array_init(&array_pmt);
+                template_args = get_args(sym, &array_pmt, FALSE, '<', '>');
+                sym->names.num = 0;
+            }
             break;
         case 4:
             sym->result = (char*)function_name;
@@ -1481,6 +1650,8 @@
             sym->stack.elts[0] = sym->stack.elts[1];
         else
             sym->stack.elts[0] = str_printf(sym, "~%s", sym->stack.elts[1]);
+        if (template_args)
+            sym->stack.elts[0] = str_printf(sym, "%s%s", sym->stack.elts[0], template_args);
         /* ctors and dtors don't have return type */
         sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;
         break;


More information about the wine-patches mailing list