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