This series implements a couple of enhancements to symbol undecoration in msvcrt: - more C++ constructs are correctly supported (pointer to member, constructors/destructors from template class, non-type function pointer template parameter...) - some internal cleanups & simplification (most of them based on revamped helper to build up the undecorated C++ symbols)
-- v3: dlls/msvcrt: Fix order of extended qualifiers and qualifiers dlls/msvcrt: Use enum to clarify post-processing actions. dlls/msvcrt: Undecorate function signature as template argument. dlls/msvcrt: Fix white space output for typecast operator. dlls/msvcrt: Improve support for template in methods. dlls/msvcrt: Correctly support space generation in pointers.
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/tests/cpp.c | 2 ++ dlls/msvcrt/undname.c | 53 ++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 27 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index 58ecd1327a5..90f3d6a9d6a 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1295,6 +1295,8 @@ static void test_demangle(void) /* 132 */ {"??$meth@FD@DD@CC@@QAE_NK@Z", "public: bool __thiscall CC::DD::meth<short,char>(unsigned long)"}, /* 133 */ {"?func@@YAXPIFAH@Z", "void __cdecl func(int __unaligned * __restrict)"}, /* 135 */ {"?x@@3PAY02HA", "int (* x)[3]"}, +/* 136 */ {"?Qux@Bar@@0PAPAP6AHPAV1@AAH1PAH@ZA", + "private: static int (__cdecl** * Bar::Qux)(class Bar *,int &,int &,int *)"}, /* variation of 105: note white space handling! */ }; int i, num_test = ARRAY_SIZE(test); char* name; diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index acfe96fe436..3da3bd67a8a 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -77,11 +77,17 @@ struct parsed_symbol unsigned avail_in_first; /* number of available bytes in head block */ };
+enum datatype_e +{ + DT_NO_LEADING_WS = 0x01, +}; + /* Type for parsing mangled types */ struct datatype_t { const char* left; const char* right; + enum datatype_e flags; };
static BOOL symbol_demangle(struct parsed_symbol* sym); @@ -407,6 +413,7 @@ static void append_extended_modifier(struct parsed_symbol *sym, const char **whe static void get_extended_modifier(struct parsed_symbol *sym, struct datatype_t *xdt) { xdt->left = xdt->right = NULL; + xdt->flags = 0; for (;;) { switch (*sym->current) @@ -455,25 +462,24 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym,
switch (modif) { - case 'A': ref = "&"; str_modif = NULL; break; - case 'B': ref = "&"; str_modif = "volatile"; break; - case 'P': ref = "*"; str_modif = NULL; break; - case 'Q': ref = "*"; str_modif = "const"; break; - case 'R': ref = "*"; str_modif = "volatile"; break; - case 'S': ref = "*"; str_modif = "const volatile"; break; - case '?': ref = NULL; str_modif = NULL; break; - case '$': ref = "&&"; str_modif = NULL; break; + case 'A': ref = " &"; str_modif = NULL; break; + case 'B': ref = " &"; str_modif = " volatile"; break; + case 'P': ref = " *"; str_modif = NULL; break; + case 'Q': ref = " *"; str_modif = " const"; break; + case 'R': ref = " *"; str_modif = " volatile"; break; + case 'S': ref = " *"; str_modif = " const volatile"; break; + case '?': ref = NULL; str_modif = NULL; break; + case '$': ref = " &&"; str_modif = NULL; break; default: return FALSE; } if (ref || str_modif || xdt.left || xdt.right) - ct->left = str_printf(sym, " %s%s%s%s%s%s%s", - xdt.left, - xdt.left && ref ? " " : NULL, ref, - (xdt.left || ref) && xdt.right ? " " : NULL, xdt.right, - (xdt.left || ref || xdt.right) && str_modif ? " " : NULL, str_modif); + ct->left = str_printf(sym, "%s%s%s%s%s%s", + xdt.left ? " " : NULL, xdt.left, ref, + xdt.right ? " " : NULL, xdt.right, str_modif); else ct->left = NULL; ct->right = NULL; + ct->flags = 0;
if (get_modifier(sym, &xdt)) { @@ -490,10 +496,7 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, if (!(n1 = get_number(sym))) return FALSE; num = atoi(n1);
- if (ct->left && ct->left[0] == ' ' && !xdt.left) - ct->left++; - - ct->left = str_printf(sym, " (%s%s", xdt.left, ct->left); + ct->left = str_printf(sym, " (%s%s", xdt.left, ct->left + (ct->left && xdt.left ? 0 : 1)); ct->right = ")"; xdt.left = NULL;
@@ -504,15 +507,9 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, /* Recurse to get the referred-to type */ if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) return FALSE; - if (xdt.left) - ct->left = str_printf(sym, "%s %s%s", sub_ct.left, xdt.left, ct->left); - else - { - /* don't insert a space between duplicate '*' */ - if (!in_args && ct->left && ct->left[0] && ct->left[1] == '*' && sub_ct.left[strlen(sub_ct.left)-1] == '*') - ct->left++; - ct->left = str_printf(sym, "%s%s", sub_ct.left, ct->left); - } + if (sub_ct.flags & DT_NO_LEADING_WS) + ct->left++; + ct->left = str_printf(sym, "%s%s%s%s", sub_ct.left, xdt.left ? " " : NULL, xdt.left, ct->left); if (sub_ct.right) ct->right = str_printf(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; } @@ -814,7 +811,8 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
assert(ct); ct->left = ct->right = NULL; - + ct->flags = 0; + switch (dt = *sym->current++) { case '_': @@ -938,6 +936,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
ct->left = str_printf(sym, "%s%s (%s*", sub_ct.left, sub_ct.right, call_conv); + ct->flags = DT_NO_LEADING_WS; ct->right = str_printf(sym, ")%s", args); } else goto done;
From: Eric Pouech eric.pouech@gmail.com
Adding function template support for methods that need specific post processing in demangling (constructor, destructor, cast operator)
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/tests/cpp.c | 4 ++++ dlls/msvcrt/undname.c | 48 +++++++++++++++++++---------------------- 2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index 90f3d6a9d6a..04573aa3d65 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1297,6 +1297,10 @@ static void test_demangle(void) /* 135 */ {"?x@@3PAY02HA", "int (* x)[3]"}, /* 136 */ {"?Qux@Bar@@0PAPAP6AHPAV1@AAH1PAH@ZA", "private: static int (__cdecl** * Bar::Qux)(class Bar *,int &,int &,int *)"}, /* variation of 105: note white space handling! */ +/* 137 */ {"?x@@3PAW4myenum@@A", "enum myenum * x"}, +/* 138 */ {"?pfunc@@3PAY0E@P6AXF@ZA", "void (__cdecl*(* pfunc)[4])(short)"}, +/* 139 */ {"??$?0AEAVzzz@BB4@AA@@AEAV012@$0A@@?$pair@Vzzz@BB4@AA@@V123@@std@@QEAA@AEAVzzz@BB4@AA@@0@Z", + "public: __cdecl std::pair<class AA::BB4::zzz,class AA::BB4::zzz>::pair<class AA::BB4::zzz,class AA::BB4::zzz><class AA::BB4::zzz & __ptr64,class AA::BB4::zzz & __ptr64,0>(class AA::BB4::zzz & __ptr64,class AA::BB4::zzz & __ptr64) __ptr64"}, }; int i, num_test = ARRAY_SIZE(test); char* name; diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index 3da3bd67a8a..16293e87820 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -452,7 +452,7 @@ static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt) }
static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, - struct array *pmt_ref, char modif, BOOL in_args) + struct array *pmt_ref, char modif) { struct datatype_t xdt; const char* ref; @@ -860,17 +860,17 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, } else { - if (!get_modified_type(ct, sym, pmt_ref, '?', in_args)) goto done; + if (!get_modified_type(ct, sym, pmt_ref, '?')) goto done; } break; case 'A': /* reference */ case 'B': /* volatile reference */ - if (!get_modified_type(ct, sym, pmt_ref, dt, in_args)) goto done; + if (!get_modified_type(ct, sym, pmt_ref, dt)) goto done; break; case 'Q': /* const pointer */ case 'R': /* volatile pointer */ case 'S': /* const volatile pointer */ - if (!get_modified_type(ct, sym, pmt_ref, in_args ? dt : 'P', in_args)) goto done; + if (!get_modified_type(ct, sym, pmt_ref, in_args ? dt : 'P')) goto done; break; case 'P': /* Pointer */ if (isdigit(*sym->current)) @@ -941,7 +941,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, } else goto done; } - else if (!get_modified_type(ct, sym, pmt_ref, 'P', in_args)) goto done; + else if (!get_modified_type(ct, sym, pmt_ref, 'P')) goto done; break; case 'W': if (*sym->current == '4') @@ -1050,7 +1050,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, else if (*sym->current == 'Q') { sym->current++; - if (!get_modified_type(ct, sym, pmt_ref, '$', in_args)) goto done; + if (!get_modified_type(ct, sym, pmt_ref, '$')) goto done; } break; } @@ -1361,7 +1361,6 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) { BOOL ret = FALSE; unsigned do_after = 0; - static CHAR dashed_null[] = "--null--";
/* FIXME seems wrong as name, as it demangles a simple data type */ if (sym->flags & UNDNAME_NO_ARGUMENTS) @@ -1384,18 +1383,19 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) if (*sym->current == '?') { const char* function_name = NULL; + BOOL in_template = FALSE;
if (sym->current[1] == '$' && sym->current[2] == '?') { - do_after = 5; + in_template = TRUE; sym->current += 2; }
/* C++ operator code (one character, or two if the first is '_') */ switch (*++sym->current) { - case '0': do_after = 1; break; - case '1': do_after = 2; break; + case '0': function_name = ""; do_after = 1; break; + case '1': function_name = ""; do_after = 2; break; case '2': function_name = "operator new"; break; case '3': function_name = "operator delete"; break; case '4': function_name = "operator="; break; @@ -1530,26 +1530,22 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) return FALSE; } sym->current++; + if (in_template) + { + const char *args; + struct array array_pmt; + + str_array_init(&array_pmt); + args = get_args(sym, &array_pmt, FALSE, '<', '>'); + if (args) function_name = function_name ? str_printf(sym, "%s%s", function_name, args) : args; + sym->names.num = 0; + } switch (do_after) { - case 1: case 2: - if (!str_array_push(sym, dashed_null, -1, &sym->stack)) - return FALSE; - break; case 4: sym->result = (char*)function_name; ret = TRUE; goto done; - case 5: - { - char *args; - struct array array_pmt; - - str_array_init(&array_pmt); - args = get_args(sym, &array_pmt, FALSE, '<', '>'); - if (args != NULL) function_name = str_printf(sym, "%s%s", function_name, args); - sym->names.num = 0; - } /* fall through */ default: if (!str_array_push(sym, function_name, -1, &sym->stack)) @@ -1584,9 +1580,9 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) /* it's time to set the member name for ctor & dtor */ if (sym->stack.num <= 1) goto done; if (do_after == 1) - sym->stack.elts[0] = sym->stack.elts[1]; + sym->stack.elts[0] = str_printf(sym, "%s%s", sym->stack.elts[1], sym->stack.elts[0]); else - sym->stack.elts[0] = str_printf(sym, "~%s", sym->stack.elts[1]); + sym->stack.elts[0] = str_printf(sym, "~%s%s", sym->stack.elts[1], sym->stack.elts[0]); /* ctors and dtors don't have return type */ sym->flags |= UNDNAME_NO_FUNCTION_RETURNS; break;
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/tests/cpp.c | 3 +++ dlls/msvcrt/undname.c | 54 +++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 23 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index 04573aa3d65..98733300a90 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1301,6 +1301,9 @@ static void test_demangle(void) /* 138 */ {"?pfunc@@3PAY0E@P6AXF@ZA", "void (__cdecl*(* pfunc)[4])(short)"}, /* 139 */ {"??$?0AEAVzzz@BB4@AA@@AEAV012@$0A@@?$pair@Vzzz@BB4@AA@@V123@@std@@QEAA@AEAVzzz@BB4@AA@@0@Z", "public: __cdecl std::pair<class AA::BB4::zzz,class AA::BB4::zzz>::pair<class AA::BB4::zzz,class AA::BB4::zzz><class AA::BB4::zzz & __ptr64,class AA::BB4::zzz & __ptr64,0>(class AA::BB4::zzz & __ptr64,class AA::BB4::zzz & __ptr64) __ptr64"}, +/* 140 */ {"??$?BH@?$foo@N@@QEAAHXZ", "public: __cdecl foo<double>::operator<int> int(void) __ptr64"}, +/* 141 */ {"??Bcastop@@QAEHXZ", "public: __thiscall castop::operator int(void)"}, +/* 142 */ {"??Bcastop@@QAE?BHXZ", "public: __thiscall castop::operator int const (void)"}, }; int i, num_test = ARRAY_SIZE(test); char* name; diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index 16293e87820..f7dc330a4e2 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -291,9 +291,15 @@ static char* WINAPIV str_printf(struct parsed_symbol* sym, const char* format, . return tmp; }
+enum datatype_flags +{ + IN_ARGS = 0x01, + WS_AFTER_QUAL_IF = 0x02, +}; + /* forward declaration */ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, - struct array* pmt, BOOL in_args); + struct array* pmt, enum datatype_flags flags);
static const char* get_number(struct parsed_symbol* sym) { @@ -367,7 +373,7 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t sym->current++; break; } - if (!demangle_datatype(sym, &ct, pmt_ref, TRUE)) + if (!demangle_datatype(sym, &ct, pmt_ref, IN_ARGS)) return NULL; /* 'void' terminates an argument list in a function */ if (z_term && !strcmp(ct.left, "void")) break; @@ -452,7 +458,7 @@ static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt) }
static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, - struct array *pmt_ref, char modif) + struct array *pmt_ref, char modif, enum datatype_flags flags) { struct datatype_t xdt; const char* ref; @@ -505,11 +511,13 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, }
/* Recurse to get the referred-to type */ - if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) + if (!demangle_datatype(sym, &sub_ct, pmt_ref, 0)) return FALSE; if (sub_ct.flags & DT_NO_LEADING_WS) ct->left++; - ct->left = str_printf(sym, "%s%s%s%s", sub_ct.left, xdt.left ? " " : NULL, xdt.left, ct->left); + ct->left = str_printf(sym, "%s%s%s%s%s", sub_ct.left, xdt.left ? " " : NULL, + xdt.left, ct->left, + ((xdt.left || str_modif) && (flags & WS_AFTER_QUAL_IF)) ? " " : NULL); if (sub_ct.right) ct->right = str_printf(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; } @@ -804,7 +812,7 @@ static const char* get_extended_type(char c) * char** = (pointer to (pointer to (char))) */ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, - struct array* pmt_ref, BOOL in_args) + struct array* pmt_ref, enum datatype_flags flags) { char dt; BOOL add_pmt = TRUE; @@ -852,7 +860,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, break; case '?': /* not all the time is seems */ - if (in_args) + if (flags & IN_ARGS) { const char* ptr; if (!(ptr = get_number(sym))) goto done; @@ -860,17 +868,17 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, } else { - if (!get_modified_type(ct, sym, pmt_ref, '?')) goto done; + if (!get_modified_type(ct, sym, pmt_ref, '?', flags)) goto done; } break; case 'A': /* reference */ case 'B': /* volatile reference */ - if (!get_modified_type(ct, sym, pmt_ref, dt)) goto done; + if (!get_modified_type(ct, sym, pmt_ref, dt, flags)) goto done; break; case 'Q': /* const pointer */ case 'R': /* volatile pointer */ case 'S': /* const volatile pointer */ - if (!get_modified_type(ct, sym, pmt_ref, in_args ? dt : 'P')) goto done; + if (!get_modified_type(ct, sym, pmt_ref, (flags & IN_ARGS) ? dt : 'P', flags)) goto done; break; case 'P': /* Pointer */ if (isdigit(*sym->current)) @@ -903,7 +911,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, &call_conv, &exported, sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE)) goto done; - if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) + if (!demangle_datatype(sym, &sub_ct, pmt_ref, 0)) goto done;
args = get_args(sym, pmt_ref, TRUE, '(', ')'); @@ -927,7 +935,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, if (!get_calling_convention(*sym->current++, &call_conv, &exported, sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) || - !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) + !demangle_datatype(sym, &sub_ct, pmt_ref, 0)) goto done;
args = get_args(sym, pmt_ref, TRUE, '(', ')'); @@ -941,7 +949,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, } else goto done; } - else if (!get_modified_type(ct, sym, pmt_ref, 'P')) goto done; + else if (!get_modified_type(ct, sym, pmt_ref, 'P', flags)) goto done; break; case 'W': if (*sym->current == '4') @@ -1029,7 +1037,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, arr = str_printf(sym, "%s[%s]", arr, get_number(sym)); }
- if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) goto done; + if (!demangle_datatype(sym, &sub_ct, pmt_ref, 0)) goto done;
if (arr) ct->left = str_printf(sym, "%s %s", sub_ct.left, arr); @@ -1044,13 +1052,13 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
sym->current++; if (!get_modifier(sym, &xdt)) goto done; - if (!demangle_datatype(sym, ct, pmt_ref, in_args)) goto done; + if (!demangle_datatype(sym, ct, pmt_ref, flags)) goto done; ct->left = str_printf(sym, "%s %s", ct->left, xdt.left); } else if (*sym->current == 'Q') { sym->current++; - if (!get_modified_type(ct, sym, pmt_ref, '$')) goto done; + if (!get_modified_type(ct, sym, pmt_ref, '$', flags)) goto done; } break; } @@ -1059,7 +1067,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, ERR("Unknown type %c\n", dt); break; } - if (add_pmt && pmt_ref && in_args) + if (add_pmt && pmt_ref && (flags & IN_ARGS)) { /* left and right are pushed as two separate strings */ if (!str_array_push(sym, ct->left ? ct->left : "", -1, pmt_ref) || @@ -1124,7 +1132,7 @@ static BOOL handle_data(struct parsed_symbol* sym)
str_array_init(&pmt);
- if (!demangle_datatype(sym, &ct, &pmt, FALSE)) goto done; + if (!demangle_datatype(sym, &ct, &pmt, 0)) goto done; if (!get_modifier(sym, &xdt)) goto done; if (xdt.left && xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); else if (!xdt.left) xdt.left = xdt.right; @@ -1323,14 +1331,14 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) } else if (has_ret) { - if (!demangle_datatype(sym, &ct_ret, &array_pmt, FALSE)) + if (!demangle_datatype(sym, &ct_ret, &array_pmt, cast_op ? WS_AFTER_QUAL_IF : 0)) goto done; } if (!has_ret || sym->flags & UNDNAME_NO_FUNCTION_RETURNS) ct_ret.left = ct_ret.right = NULL; if (cast_op) { - name = str_printf(sym, "%s%s%s", name, ct_ret.left, ct_ret.right); + name = str_printf(sym, "%s %s%s", name, ct_ret.left, ct_ret.right); ct_ret.left = ct_ret.right = NULL; }
@@ -1367,7 +1375,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) { struct datatype_t ct;
- if (demangle_datatype(sym, &ct, NULL, FALSE)) + if (demangle_datatype(sym, &ct, NULL, 0)) { sym->result = str_printf(sym, "%s%s", ct.left, ct.right); ret = TRUE; @@ -1405,7 +1413,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) case '8': function_name = "operator=="; break; case '9': function_name = "operator!="; break; case 'A': function_name = "operator[]"; break; - case 'B': function_name = "operator "; do_after = 3; break; + case 'B': function_name = "operator"; do_after = 3; break; case 'C': function_name = "operator->"; break; case 'D': function_name = "operator*"; break; case 'E': function_name = "operator++"; break; @@ -1467,7 +1475,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) struct datatype_t ct;
sym->current++; - if (!demangle_datatype(sym, &ct, NULL, FALSE)) + if (!demangle_datatype(sym, &ct, NULL, 0)) goto done; function_name = str_printf(sym, "%s%s `RTTI Type Descriptor'", ct.left, ct.right);
From: Eric Pouech eric.pouech@gmail.com
Introducing get_function_signaturei() to factorize parsing of function signature.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/tests/cpp.c | 6 ++ dlls/msvcrt/undname.c | 169 ++++++++++++++++++++++++++-------------- 2 files changed, 117 insertions(+), 58 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index 98733300a90..7735da4ea89 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1304,6 +1304,12 @@ static void test_demangle(void) /* 140 */ {"??$?BH@?$foo@N@@QEAAHXZ", "public: __cdecl foo<double>::operator<int> int(void) __ptr64"}, /* 141 */ {"??Bcastop@@QAEHXZ", "public: __thiscall castop::operator int(void)"}, /* 142 */ {"??Bcastop@@QAE?BHXZ", "public: __thiscall castop::operator int const (void)"}, +/* 143 */ {"?pfield@@3PTAA@@DT1@", "char const volatile AA::* const volatile pfield"}, +/* 144 */ {"?ptititi1@@3PEQtititi@@IEQ1@", "unsigned int tititi::* __ptr64 __ptr64 ptititi1"}, +/* 145 */ {"?ptititi2@@3PERtititi@@IER1@", "unsigned int const tititi::* __ptr64 const __ptr64 ptititi2"}, +/* 146 */ {"?ptititi3@@3PEStititi@@IES1@", "unsigned int volatile tititi::* __ptr64 volatile __ptr64 ptititi3"}, +/* 147 */ {"?ptititi4@@3PETtititi@@IET1@", "unsigned int const volatile tititi::* __ptr64 const volatile __ptr64 ptititi4"}, +/* 148 */ {"?ptititi4v@@3RETtititi@@IET1@", "unsigned int const volatile tititi::* __ptr64 const volatile __ptr64 ptititi4v"}, }; int i, num_test = ARRAY_SIZE(test); char* name; diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index f7dc330a4e2..c716533ad16 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -91,6 +91,7 @@ struct datatype_t };
static BOOL symbol_demangle(struct parsed_symbol* sym); +static char* get_class_name(struct parsed_symbol* sym);
/****************************************************************** * und_alloc @@ -437,34 +438,53 @@ static void get_extended_modifier(struct parsed_symbol *sym, struct datatype_t * * get_modifier * Parses the type modifier. Always returns static strings. */ -static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt) +static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt, const char** pclass) { + char ch; const char* mod;
get_extended_modifier(sym, xdt); - switch (*sym->current++) + switch (ch = *sym->current++) { case 'A': mod = NULL; break; case 'B': mod = "const"; break; case 'C': mod = "volatile"; break; case 'D': mod = "const volatile"; break; + case 'Q': mod = NULL; break; + case 'R': mod = "const"; break; + case 'S': mod = "volatile"; break; + case 'T': mod = "const volatile"; break; default: return FALSE; } if (xdt->left && mod) xdt->left = str_printf(sym, "%s %s", xdt->left, mod); else if (mod) xdt->left = mod; + if (ch >= 'Q' && ch <= 'T') /* pointer to member, fetch class */ + { + const char* class = get_class_name(sym); + if (!class) return FALSE; + if (!pclass) + { + FIXME("Got pointer to class %s member without storage\n", class); + return FALSE; + } + *pclass = class; + } + else if (pclass) *pclass = NULL; return TRUE; }
static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, struct array *pmt_ref, char modif, enum datatype_flags flags) { - struct datatype_t xdt; + struct datatype_t xdt1; + struct datatype_t xdt2; const char* ref; const char* str_modif; + const char* class;
- get_extended_modifier(sym, &xdt); + get_extended_modifier(sym, &xdt1);
switch (modif) { @@ -478,20 +498,28 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, case '$': ref = " &&"; str_modif = NULL; break; default: return FALSE; } - if (ref || str_modif || xdt.left || xdt.right) - ct->left = str_printf(sym, "%s%s%s%s%s%s", - xdt.left ? " " : NULL, xdt.left, ref, - xdt.right ? " " : NULL, xdt.right, str_modif); - else - ct->left = NULL; ct->right = NULL; ct->flags = 0;
- if (get_modifier(sym, &xdt)) + if (get_modifier(sym, &xdt2, &class)) { unsigned mark = sym->stack.num; struct datatype_t sub_ct;
+ if (ref || str_modif || xdt1.left || xdt1.right) + { + if (class) + ct->left = str_printf(sym, "%s%s%s%s::%s%s%s", + xdt1.left ? " " : NULL, xdt1.left, + class ? " " : NULL, class, ref ? ref + 1 : NULL, + xdt1.right ? " " : NULL, xdt1.right, str_modif); + else + ct->left = str_printf(sym, "%s%s%s%s%s%s", + xdt1.left ? " " : NULL, xdt1.left, ref, + xdt1.right ? " " : NULL, xdt1.right, str_modif); + } + else + ct->left = NULL; /* multidimensional arrays */ if (*sym->current == 'Y') { @@ -502,9 +530,9 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, if (!(n1 = get_number(sym))) return FALSE; num = atoi(n1);
- ct->left = str_printf(sym, " (%s%s", xdt.left, ct->left + (ct->left && xdt.left ? 0 : 1)); + ct->left = str_printf(sym, " (%s%s", xdt2.left, ct->left + (ct->left && xdt2.left ? 0 : 1)); ct->right = ")"; - xdt.left = NULL; + xdt2.left = NULL;
while (num--) ct->right = str_printf(sym, "%s[%s]", ct->right, get_number(sym)); @@ -515,12 +543,18 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, return FALSE; if (sub_ct.flags & DT_NO_LEADING_WS) ct->left++; - ct->left = str_printf(sym, "%s%s%s%s%s", sub_ct.left, xdt.left ? " " : NULL, - xdt.left, ct->left, - ((xdt.left || str_modif) && (flags & WS_AFTER_QUAL_IF)) ? " " : NULL); + ct->left = str_printf(sym, "%s%s%s%s%s", sub_ct.left, xdt2.left ? " " : NULL, + xdt2.left, ct->left, + ((xdt2.left || str_modif) && (flags & WS_AFTER_QUAL_IF)) ? " " : NULL); if (sub_ct.right) ct->right = str_printf(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; } + else if (ref || str_modif || xdt1.left || xdt1.right) + ct->left = str_printf(sym, "%s%s%s%s%s%s", + xdt1.left ? " " : NULL, xdt1.left, ref, + xdt1.right ? " " : NULL, xdt1.right, str_modif); + else + ct->left = NULL; return TRUE; }
@@ -804,6 +838,32 @@ static const char* get_extended_type(char c) return type_string; }
+struct function_signature +{ + const char* call_conv; + const char* exported; + struct datatype_t return_ct; + const char* arguments; +}; + +static BOOL get_function_signature(struct parsed_symbol* sym, struct array* pmt_ref, + struct function_signature* fs) +{ + unsigned mark = sym->stack.num; + + if (!get_calling_convention(*sym->current++, + &fs->call_conv, &fs->exported, + sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) || + !demangle_datatype(sym, &fs->return_ct, pmt_ref, FALSE)) + return FALSE; + + if (!(fs->arguments = get_args(sym, pmt_ref, TRUE, '(', ')'))) + return FALSE; + sym->stack.num = mark; + + return TRUE; +} + /******************************************************************* * demangle_datatype * @@ -889,63 +949,40 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, * others who knows.. */ if (*sym->current == '8') { - char* args = NULL; - const char* call_conv; - const char* exported; - struct datatype_t sub_ct; - unsigned mark = sym->stack.num; - const char* class; - struct datatype_t xdt; + struct function_signature fs; + const char* class; + struct datatype_t xdt;
sym->current++;
if (!(class = get_class_name(sym))) goto done; - if (!get_modifier(sym, &xdt)) + if (!get_modifier(sym, &xdt, NULL)) goto done; + if (!get_function_signature(sym, pmt_ref, &fs)) + goto done; if (xdt.left) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); else if (xdt.right) xdt.left = str_printf(sym, " %s", xdt.right); - if (!get_calling_convention(*sym->current++, - &call_conv, &exported, - sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE)) - goto done; - if (!demangle_datatype(sym, &sub_ct, pmt_ref, 0)) - 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); - ct->right = str_printf(sym, ")%s%s", args, xdt.left); + fs.return_ct.left, fs.return_ct.right, fs.call_conv, class); + ct->right = str_printf(sym, ")%s%s", fs.arguments, xdt.left); } else if (*sym->current == '6') { - char* args = NULL; - const char* call_conv; - const char* exported; - struct datatype_t sub_ct; - unsigned mark = sym->stack.num; + struct function_signature fs;
sym->current++;
- if (!get_calling_convention(*sym->current++, - &call_conv, &exported, - sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) || - !demangle_datatype(sym, &sub_ct, pmt_ref, 0)) - goto done; - - args = get_args(sym, pmt_ref, TRUE, '(', ')'); - if (!args) goto done; - sym->stack.num = mark; + if (!get_function_signature(sym, pmt_ref, &fs)) + goto done;
- ct->left = str_printf(sym, "%s%s (%s*", - sub_ct.left, sub_ct.right, call_conv); + ct->left = str_printf(sym, "%s%s (%s*", + fs.return_ct.left, fs.return_ct.right, fs.call_conv); ct->flags = DT_NO_LEADING_WS; - ct->right = str_printf(sym, ")%s", args); + ct->right = str_printf(sym, ")%s", fs.arguments); } else goto done; } @@ -1016,7 +1053,22 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, } break; case '$': - if (*sym->current == 'B') + if (*sym->current == 'A') + { + sym->current++; + if (*sym->current == '6') + { + struct function_signature fs; + + sym->current++; + + if (!get_function_signature(sym, pmt_ref, &fs)) + goto done; + ct->left = str_printf(sym, "%s%s %s%s", + fs.return_ct.left, fs.return_ct.right, fs.call_conv, fs.arguments); + } + } + else if (*sym->current == 'B') { unsigned mark = sym->stack.num; struct datatype_t sub_ct; @@ -1051,7 +1103,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, struct datatype_t xdt;
sym->current++; - if (!get_modifier(sym, &xdt)) goto done; + if (!get_modifier(sym, &xdt, NULL)) goto done; if (!demangle_datatype(sym, ct, pmt_ref, flags)) goto done; ct->left = str_printf(sym, "%s %s", ct->left, xdt.left); } @@ -1129,11 +1181,12 @@ static BOOL handle_data(struct parsed_symbol* sym) { unsigned mark = sym->stack.num; struct array pmt; + const char* class;
str_array_init(&pmt);
if (!demangle_datatype(sym, &ct, &pmt, 0)) goto done; - if (!get_modifier(sym, &xdt)) goto done; + if (!get_modifier(sym, &xdt, &class)) goto done; /* class doesn't seem to be displayed */ if (xdt.left && xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); else if (!xdt.left) xdt.left = xdt.right; sym->stack.num = mark; @@ -1142,7 +1195,7 @@ static BOOL handle_data(struct parsed_symbol* sym) case '6' : /* compiler generated static */ case '7' : /* compiler generated static */ ct.left = ct.right = NULL; - if (!get_modifier(sym, &xdt)) goto done; + if (!get_modifier(sym, &xdt, NULL)) goto done; if (*sym->current != '@') { char* cls = NULL; @@ -1312,7 +1365,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) { /* Implicit 'this' pointer */ /* If there is an implicit this pointer, const modifier follows */ - if (!get_modifier(sym, &xdt)) goto done; + if (!get_modifier(sym, &xdt, NULL)) goto done; if (xdt.left || xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); }
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 48 ++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 26 deletions(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index c716533ad16..0f74bd12187 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -1421,7 +1421,12 @@ done: static BOOL symbol_demangle(struct parsed_symbol* sym) { BOOL ret = FALSE; - unsigned do_after = 0; + enum { + PP_NONE, + PP_CONSTRUCTOR, + PP_DESTRUCTOR, + PP_CAST_OPERATOR, + } post_process = PP_NONE;
/* FIXME seems wrong as name, as it demangles a simple data type */ if (sym->flags & UNDNAME_NO_ARGUMENTS) @@ -1455,8 +1460,8 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) /* C++ operator code (one character, or two if the first is '_') */ switch (*++sym->current) { - case '0': function_name = ""; do_after = 1; break; - case '1': function_name = ""; do_after = 2; break; + case '0': function_name = ""; post_process = PP_CONSTRUCTOR; break; + case '1': function_name = ""; post_process = PP_DESTRUCTOR; break; case '2': function_name = "operator new"; break; case '3': function_name = "operator delete"; break; case '4': function_name = "operator="; break; @@ -1466,7 +1471,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) case '8': function_name = "operator=="; break; case '9': function_name = "operator!="; break; case 'A': function_name = "operator[]"; break; - case 'B': function_name = "operator"; do_after = 3; break; + case 'B': function_name = "operator"; post_process = PP_CAST_OPERATOR; break; case 'C': function_name = "operator->"; break; case 'D': function_name = "operator*"; break; case 'E': function_name = "operator++"; break; @@ -1506,7 +1511,10 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) case '9': function_name = "`vcall'"; break; case 'A': function_name = "`typeof'"; break; case 'B': function_name = "`local static guard'"; break; - case 'C': function_name = "`string'"; do_after = 4; break; + case 'C': sym->result = (char*)"`string'"; /* string literal: followed by string encoding (native nevers undecode it) */ + /* FIXME: should unmangle the whole string for error reporting */ + if (*sym->current && sym->current[strlen(sym->current) - 1] == '@') ret = TRUE; + goto done; case 'D': function_name = "`vbase destructor'"; break; case 'E': function_name = "`vector deleting destructor'"; break; case 'F': function_name = "`default constructor closure'"; break; @@ -1601,18 +1609,8 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) if (args) function_name = function_name ? str_printf(sym, "%s%s", function_name, args) : args; sym->names.num = 0; } - switch (do_after) - { - case 4: - sym->result = (char*)function_name; - ret = TRUE; - goto done; - /* fall through */ - default: - if (!str_array_push(sym, function_name, -1, &sym->stack)) - return FALSE; - break; - } + if (!str_array_push(sym, function_name, -1, &sym->stack)) + return FALSE; } else if (*sym->current == '$') { @@ -1634,20 +1632,18 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) break; }
- switch (do_after) + switch (post_process) { - case 0: default: break; - case 1: case 2: + case PP_NONE: default: break; + case PP_CONSTRUCTOR: case PP_DESTRUCTOR: /* it's time to set the member name for ctor & dtor */ if (sym->stack.num <= 1) goto done; - if (do_after == 1) - sym->stack.elts[0] = str_printf(sym, "%s%s", sym->stack.elts[1], sym->stack.elts[0]); - else - sym->stack.elts[0] = str_printf(sym, "~%s%s", sym->stack.elts[1], sym->stack.elts[0]); + sym->stack.elts[0] = str_printf(sym, "%s%s%s", post_process == PP_DESTRUCTOR ? "~" : NULL, + sym->stack.elts[1], sym->stack.elts[0]); /* ctors and dtors don't have return type */ sym->flags |= UNDNAME_NO_FUNCTION_RETURNS; break; - case 3: + case PP_CAST_OPERATOR: sym->flags &= ~UNDNAME_NO_FUNCTION_RETURNS; break; } @@ -1656,7 +1652,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) if (*sym->current >= '0' && *sym->current <= '9') ret = handle_data(sym); else if ((*sym->current >= 'A' && *sym->current <= 'Z') || *sym->current == '$') - ret = handle_method(sym, do_after == 3); + ret = handle_method(sym, post_process == PP_CAST_OPERATOR); else ret = FALSE; done: if (ret) assert(sym->result);
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index 0f74bd12187..5ff778eacf9 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -457,7 +457,7 @@ static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt, cons default: return FALSE; } if (xdt->left && mod) - xdt->left = str_printf(sym, "%s %s", xdt->left, mod); + xdt->left = str_printf(sym, "%s %s", mod, xdt->left/*, mod*/); else if (mod) xdt->left = mod; if (ch >= 'Q' && ch <= 'T') /* pointer to member, fetch class */
V3: - same functional target as previous series - added control flags (in datatype_t and type demanling) for finer space output control - added enum for post processing (cleanup of do_after machinery)
Hi Piotr, any comments on latest version of the series?
Piotr Caban (@piotr) commented about dlls/msvcrt/undname.c:
if (!(n1 = get_number(sym))) return FALSE; num = atoi(n1);
if (ct->left && ct->left[0] == ' ' && !xdt.left)
ct->left++;
ct->left = str_printf(sym, " (%s%s", xdt.left, ct->left);
ct->left = str_printf(sym, " (%s%s", xdt.left, ct->left + (ct->left && xdt.left ? 0 : 1));
This looks broken in ct->left == NULL case.
Piotr Caban (@piotr) commented about dlls/msvcrt/undname.c:
default: return FALSE; } if (xdt->left && mod)
xdt->left = str_printf(sym, "%s %s", xdt->left, mod);
xdt->left = str_printf(sym, "%s %s", mod, xdt->left/*, mod*/);
Please add a test for that change. Also please remove the /*, mod*/ comment.
On Tue Aug 30 14:22:35 2022 +0000, eric pouech wrote:
Hi Piotr, any comments on latest version of the series?
Sorry, I have missed the v3 push.