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)
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 | 36 ++++++++++++++++-------------------- 2 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index 58ecd1327a5..aee9980cd2d 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 */ {"??$?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 acfe96fe436..be736631626 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -1362,7 +1362,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) @@ -1385,18 +1384,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; @@ -1531,26 +1531,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)) @@ -1585,9 +1581,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 | 1 + dlls/msvcrt/undname.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index aee9980cd2d..14d4cfac84a 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1297,6 +1297,7 @@ static void test_demangle(void) /* 135 */ {"?x@@3PAY02HA", "int (* x)[3]"}, /* 136 */ {"??$?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"}, +/* 137 */ {"??Bcastop@@QAEHXZ", "public: __thiscall castop::operator int(void)"}, }; int i, num_test = ARRAY_SIZE(test); char* name; diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index be736631626..c30b7ebb95b 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -1331,7 +1331,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) 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; }
@@ -1406,7 +1406,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;
From: Eric Pouech eric.pouech@gmail.com
in preparation of semantics modification to this helper (and calling it str_printf might confuse devs as new semantics will diverge from printf's)
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 122 +++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 61 deletions(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index c30b7ebb95b..0aa22b485ac 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -226,11 +226,11 @@ static char* str_array_get_ref(struct array* cref, unsigned idx) }
/****************************************************************** - * str_printf + * str_build * Helper for printf type of command (only %s and %c are implemented) * while dynamically allocating the buffer */ -static char* WINAPIV str_printf(struct parsed_symbol* sym, const char* format, ...) +static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, ...) { va_list args; unsigned int len = 1, i, sz; @@ -365,7 +365,7 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t return NULL; /* 'void' terminates an argument list in a function */ if (z_term && !strcmp(ct.left, "void")) break; - if (!str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1, + if (!str_array_push(sym, str_build(sym, "%s%s", ct.left, ct.right), -1, &arg_collect)) return NULL; if (!strcmp(ct.left, "...")) break; @@ -377,20 +377,20 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t
if (arg_collect.num == 0 || (arg_collect.num == 1 && !strcmp(arg_collect.elts[0], "void"))) - return str_printf(sym, "%cvoid%c", open_char, close_char); + return str_build(sym, "%cvoid%c", open_char, close_char); for (i = 1; i < arg_collect.num; i++) { - args_str = str_printf(sym, "%s,%s", args_str, arg_collect.elts[i]); + args_str = str_build(sym, "%s,%s", args_str, arg_collect.elts[i]); }
last = args_str ? args_str : arg_collect.elts[0]; if (close_char == '>' && last[strlen(last) - 1] == '>') - args_str = str_printf(sym, "%c%s%s %c", - open_char, arg_collect.elts[0], args_str, close_char); + args_str = str_build(sym, "%c%s%s %c", + open_char, arg_collect.elts[0], args_str, close_char); else - args_str = str_printf(sym, "%c%s%s%c", - open_char, arg_collect.elts[0], args_str, close_char); - + args_str = str_build(sym, "%c%s%s%c", + open_char, arg_collect.elts[0], args_str, close_char); + return args_str; }
@@ -400,7 +400,7 @@ static void append_extended_modifier(struct parsed_symbol *sym, const char **whe { if (sym->flags & UNDNAME_NO_LEADING_UNDERSCORES) str += 2; - *where = *where ? str_printf(sym, "%s %s", *where, str) : str; + *where = *where ? str_build(sym, "%s %s", *where, str) : str; } }
@@ -438,7 +438,7 @@ static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt) default: return FALSE; } if (xdt->left && mod) - xdt->left = str_printf(sym, "%s %s", xdt->left, mod); + xdt->left = str_build(sym, "%s %s", xdt->left, mod); else if (mod) xdt->left = mod; return TRUE; @@ -466,11 +466,11 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, 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_build(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); else ct->left = NULL; ct->right = NULL; @@ -493,27 +493,27 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, if (ct->left && ct->left[0] == ' ' && !xdt.left) ct->left++;
- ct->left = str_printf(sym, " (%s%s", xdt.left, ct->left); + ct->left = str_build(sym, " (%s%s", xdt.left, ct->left); ct->right = ")"; xdt.left = NULL;
while (num--) - ct->right = str_printf(sym, "%s[%s]", ct->right, get_number(sym)); + ct->right = str_build(sym, "%s[%s]", ct->right, get_number(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); + ct->left = str_build(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); + ct->left = str_build(sym, "%s%s", sub_ct.left, ct->left); } - if (sub_ct.right) ct->right = str_printf(sym, "%s%s", ct->right, sub_ct.right); + if (sub_ct.right) ct->right = str_build(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; } return TRUE; @@ -572,7 +572,7 @@ static char* get_template_name(struct parsed_symbol* sym) str_array_init(&array_pmt); args = get_args(sym, &array_pmt, FALSE, '<', '>'); if (args != NULL) - name = str_printf(sym, "%s%s", name, args); + name = str_build(sym, "%s%s", name, args); sym->names.num = num_mark; sym->names.start = start_mark; sym->stack.num = stack_mark; @@ -623,7 +623,7 @@ static BOOL get_class(struct parsed_symbol* sym) unsigned int num = sym->names.num;
str_array_init( &sym->stack ); - if (symbol_demangle( sym )) name = str_printf( sym, "`%s'", sym->result ); + if (symbol_demangle( sym )) name = str_build( sym, "`%s'", sym->result ); sym->names.start = start; sym->names.num = num; sym->stack = stack; @@ -631,7 +631,7 @@ static BOOL get_class(struct parsed_symbol* sym) break; default: if (!(name = get_number( sym ))) return FALSE; - name = str_printf( sym, "`%s'", name ); + name = str_build( sym, "`%s'", name ); break; } break; @@ -849,7 +849,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, case 'Y': type_name = "cointerface "; break; } } - ct->left = str_printf(sym, "%s%s", type_name, struct_name); + ct->left = str_build(sym, "%s%s", type_name, struct_name); } break; case '?': @@ -858,7 +858,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, { const char* ptr; if (!(ptr = get_number(sym))) goto done; - ct->left = str_printf(sym, "`template-parameter-%s'", ptr); + ct->left = str_build(sym, "`template-parameter-%s'", ptr); } else { @@ -898,9 +898,9 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, if (!get_modifier(sym, &xdt)) goto done; if (xdt.left) - xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); + xdt.left = str_build(sym, "%s %s", xdt.left, xdt.right); else if (xdt.right) - xdt.left = str_printf(sym, " %s", xdt.right); + xdt.left = str_build(sym, " %s", xdt.right); if (!get_calling_convention(*sym->current++, &call_conv, &exported, sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE)) @@ -912,9 +912,9 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, 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); + ct->left = str_build(sym, "%s%s (%s %s::*", + sub_ct.left, sub_ct.right, call_conv, class); + ct->right = str_build(sym, ")%s%s", args, xdt.left); } else if (*sym->current == '6') { @@ -936,9 +936,9 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, 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); + ct->left = str_build(sym, "%s%s (%s*", + sub_ct.left, sub_ct.right, call_conv); + ct->right = str_build(sym, ")%s", args); } else goto done; } @@ -954,7 +954,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, if (sym->flags & UNDNAME_NO_COMPLEX_TYPE) ct->left = enum_name; else - ct->left = str_printf(sym, "enum %s", enum_name); + ct->left = str_build(sym, "enum %s", enum_name); } else goto done; break; @@ -978,7 +978,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, { const char* ptr; if (!(ptr = get_number(sym))) goto done; - ct->left = str_printf(sym, "`template-parameter%s'", ptr); + ct->left = str_build(sym, "`template-parameter%s'", ptr); } break; case 'F': @@ -987,7 +987,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, const char* p2; if (!(p1 = get_number(sym))) goto done; if (!(p2 = get_number(sym))) goto done; - ct->left = str_printf(sym, "{%s,%s}", p1, p2); + ct->left = str_build(sym, "{%s,%s}", p1, p2); } break; case 'G': @@ -998,14 +998,14 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, if (!(p1 = get_number(sym))) goto done; if (!(p2 = get_number(sym))) goto done; if (!(p3 = get_number(sym))) goto done; - ct->left = str_printf(sym, "{%s,%s,%s}", p1, p2, p3); + ct->left = str_build(sym, "{%s,%s,%s}", p1, p2, p3); } break; case 'Q': { const char* ptr; if (!(ptr = get_number(sym))) goto done; - ct->left = str_printf(sym, "`non-type-template-parameter%s'", ptr); + ct->left = str_build(sym, "`non-type-template-parameter%s'", ptr); } break; case '$': @@ -1027,13 +1027,13 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, num = atoi(n1);
while (num--) - arr = str_printf(sym, "%s[%s]", arr, get_number(sym)); + arr = str_build(sym, "%s[%s]", arr, get_number(sym)); }
if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) goto done;
if (arr) - ct->left = str_printf(sym, "%s %s", sub_ct.left, arr); + ct->left = str_build(sym, "%s %s", sub_ct.left, arr); else ct->left = sub_ct.left; ct->right = sub_ct.right; @@ -1046,7 +1046,7 @@ 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; - ct->left = str_printf(sym, "%s %s", ct->left, xdt.left); + ct->left = str_build(sym, "%s %s", ct->left, xdt.left); } else if (*sym->current == 'Q') { @@ -1127,7 +1127,7 @@ static BOOL handle_data(struct parsed_symbol* sym)
if (!demangle_datatype(sym, &ct, &pmt, FALSE)) 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); + if (xdt.left && xdt.right) xdt.left = str_build(sym, "%s %s", xdt.left, xdt.right); else if (!xdt.left) xdt.left = xdt.right; sym->stack.num = mark; } @@ -1142,7 +1142,7 @@ static BOOL handle_data(struct parsed_symbol* sym)
if (!(cls = get_class_name(sym))) goto done; - ct.right = str_printf(sym, "{for `%s'}", cls); + ct.right = str_build(sym, "{for `%s'}", cls); } break; case '8': @@ -1153,7 +1153,7 @@ static BOOL handle_data(struct parsed_symbol* sym) } if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = xdt.left = NULL;
- sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s", access, + sym->result = str_build(sym, "%s%s%s%s%s%s%s%s", access, member_type, ct.left, xdt.left && ct.left ? " " : NULL, xdt.left, xdt.left || ct.left ? " " : NULL, name, ct.right); @@ -1241,7 +1241,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) case 2: access = "public: "; break; } if (accmem == '$' || (accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7) - access = str_printf(sym, "[thunk]:%s", access ? access : " "); + access = str_build(sym, "[thunk]:%s", access ? access : " ");
if (accmem == '$' && *sym->current != 'B') member_type = "virtual "; @@ -1269,7 +1269,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) n = get_number(sym);
if(!n || *sym->current++ != 'A') goto done; - name = str_printf(sym, "%s{%s,{flat}}' }'", name, n); + name = str_build(sym, "%s{%s,{flat}}' }'", name, n); has_args = FALSE; has_ret = FALSE; } @@ -1284,7 +1284,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) n4 = get_number(sym);
if(!n1 || !n2 || !n3 || !n4) goto done; - name = str_printf(sym, "%s`vtordispex{%s,%s,%s,%s}' ", name, n1, n2, n3, n4); + name = str_build(sym, "%s`vtordispex{%s,%s,%s,%s}' ", name, n1, n2, n3, n4); } else if (accmem == '$') /* vtordisp thunk */ { @@ -1295,10 +1295,10 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) n2 = get_number(sym);
if (!n1 || !n2) goto done; - name = str_printf(sym, "%s`vtordisp{%s,%s}' ", name, n1, n2); + name = str_build(sym, "%s`vtordisp{%s,%s}' ", name, n1, n2); } else if ((accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7) /* a thunk */ - name = str_printf(sym, "%s`adjustor{%s}' ", name, get_number(sym)); + name = str_build(sym, "%s`adjustor{%s}' ", name, get_number(sym));
if (has_args && (accmem == '$' || (accmem <= 'X' && (accmem - 'A') % 8 != 2 && (accmem - 'A') % 8 != 3))) @@ -1306,7 +1306,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 (xdt.left || xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); + if (xdt.left || xdt.right) xdt.left = str_build(sym, "%s %s", xdt.left, xdt.right); }
if (!get_calling_convention(*sym->current++, &call_conv, &exported, @@ -1331,7 +1331,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) 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_build(sym, "%s %s%s", name, ct_ret.left, ct_ret.right); ct_ret.left = ct_ret.right = NULL; }
@@ -1344,7 +1344,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) /* Note: '()' after 'Z' means 'throws', but we don't care here * Yet!!! FIXME */ - sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s%s%s%s", + sym->result = str_build(sym, "%s%s%s%s%s%s%s%s%s%s%s", access, member_type, ct_ret.left, (ct_ret.left && !ct_ret.right) ? " " : NULL, call_conv, call_conv ? " " : NULL, exported, @@ -1370,7 +1370,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym)
if (demangle_datatype(sym, &ct, NULL, FALSE)) { - sym->result = str_printf(sym, "%s%s", ct.left, ct.right); + sym->result = str_build(sym, "%s%s", ct.left, ct.right); ret = TRUE; } goto done; @@ -1470,7 +1470,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) sym->current++; if (!demangle_datatype(sym, &ct, NULL, FALSE)) goto done; - function_name = str_printf(sym, "%s%s `RTTI Type Descriptor'", + function_name = str_build(sym, "%s%s `RTTI Type Descriptor'", ct.left, ct.right); sym->current--; } @@ -1484,7 +1484,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) n3 = get_number(sym); n4 = get_number(sym); sym->current--; - function_name = str_printf(sym, "`RTTI Base Class Descriptor at (%s,%s,%s,%s)'", + function_name = str_build(sym, "`RTTI Base Class Descriptor at (%s,%s,%s,%s)'", n1, n2, n3, n4); } break; @@ -1507,7 +1507,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym) { case 'K': sym->current++; - function_name = str_printf(sym, "operator "" %s", get_literal_string(sym)); + function_name = str_build(sym, "operator "" %s", get_literal_string(sym)); --sym->current; break; default: @@ -1538,7 +1538,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym)
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; + if (args) function_name = function_name ? str_build(sym, "%s%s", function_name, args) : args; sym->names.num = 0; } switch (do_after) @@ -1581,9 +1581,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] = str_printf(sym, "%s%s", sym->stack.elts[1], sym->stack.elts[0]); + sym->stack.elts[0] = str_build(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_build(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
this will append a string with potentially prepending ' ' as separator
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index 0aa22b485ac..f9f2535e13b 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -227,8 +227,12 @@ static char* str_array_get_ref(struct array* cref, unsigned idx)
/****************************************************************** * str_build - * Helper for printf type of command (only %s and %c are implemented) - * while dynamically allocating the buffer + * Helper for printf type of command while dynamically allocating the buffer + * Supported operators: + * + %s inserts the string (as printf does) ; argument can be NULL (inserts nothing) + * + %S same as %s, but insert before the string a ' ' as separator if in + * previous contiguous %s or %S something has been inserted and argument isn't NULL + * + %c inserts a char */ static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, ...) { @@ -237,6 +241,7 @@ static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, .. char* tmp; char* p; char* t; + BOOL s_printed = FALSE;
va_start(args, format); for (i = 0; format[i]; i++) @@ -245,6 +250,7 @@ static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, .. { switch (format[++i]) { + case 'S': len++; /* fall through */ case 's': t = va_arg(args, char*); if (t) len += strlen(t); break; case 'c': (void)va_arg(args, int); len++; break; default: i--; /* fall through */ @@ -258,27 +264,37 @@ static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, .. va_start(args, format); for (p = tmp, i = 0; format[i]; i++) { + if (format[i] == '%') { switch (format[++i]) { + case 'S': case 's': t = va_arg(args, char*); - if (t) + if (t && *t) { + if (format[i] == 'S' && s_printed) + *p++ = ' '; sz = strlen(t); memcpy(p, t, sz); p += sz; + s_printed = TRUE; } break; case 'c': *p++ = (char)va_arg(args, int); + s_printed = FALSE; break; default: i--; /* fall through */ - case '%': *p++ = '%'; break; + case '%': *p++ = '%'; s_printed = FALSE; break; } } - else *p++ = format[i]; + else + { + *p++ = format[i]; + s_printed = FALSE; + } } va_end(args); *p = '\0'; @@ -466,11 +482,7 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, default: return FALSE; } if (ref || str_modif || xdt.left || xdt.right) - ct->left = str_build(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_build(sym, " %s%S%S%S", xdt.left, ref, xdt.right, str_modif); else ct->left = NULL; ct->right = NULL; @@ -1153,10 +1165,7 @@ static BOOL handle_data(struct parsed_symbol* sym) } if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = xdt.left = NULL;
- sym->result = str_build(sym, "%s%s%s%s%s%s%s%s", access, - member_type, ct.left, - xdt.left && ct.left ? " " : NULL, xdt.left, - xdt.left || ct.left ? " " : NULL, name, ct.right); + sym->result = str_build(sym, "%s%s%s%S%S%s", access, member_type, ct.left, xdt.left, name, ct.right); ret = TRUE; done: return ret;
From: Eric Pouech eric.pouech@gmail.com
making better use of %S operator (especially don't force space at beginning of generated string but rather insert space as separator with %S operator)
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index f9f2535e13b..2f5adefc0d8 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -482,7 +482,7 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, default: return FALSE; } if (ref || str_modif || xdt.left || xdt.right) - ct->left = str_build(sym, " %s%S%S%S", xdt.left, ref, xdt.right, str_modif); + ct->left = str_build(sym, "%s%S%S%S", xdt.left, ref, xdt.right, str_modif); else ct->left = NULL; ct->right = NULL; @@ -502,10 +502,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_build(sym, " (%s%s", xdt.left, ct->left); + ct->left = str_build(sym, "(%s%S", xdt.left, ct->left); ct->right = ")"; xdt.left = NULL;
@@ -516,15 +513,15 @@ 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_build(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++; + /* don't insert a space between duplicate '*' */ + if (!in_args && + sub_ct.left && sub_ct.left[0] && sub_ct.left[strlen(sub_ct.left) - 1] == '*' && + !xdt.left && + ct->left && ct->left[0] == '*') ct->left = str_build(sym, "%s%s", sub_ct.left, ct->left); - } + else + ct->left = str_build(sym, "%s%S%S", sub_ct.left, xdt.left, ct->left); + if (sub_ct.right) ct->right = str_build(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; }
From: Eric Pouech eric.pouech@gmail.com
simplifying a bunch of invocations to str_build
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 84 ++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 33 deletions(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index 2f5adefc0d8..8c361643b0b 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -233,6 +233,12 @@ static char* str_array_get_ref(struct array* cref, unsigned idx) * + %S same as %s, but insert before the string a ' ' as separator if in * previous contiguous %s or %S something has been inserted and argument isn't NULL * + %c inserts a char + * + * Returns: + * + if format is only made of %s and %S, + * + returns NULL if all arguments are NULL + * + returns arg if only one argument (call it arg) is not NULL + + + allocates a new buffer in all the other cases */ static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, ...) { @@ -242,6 +248,8 @@ static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, .. char* p; char* t; BOOL s_printed = FALSE; + BOOL pure_concat = TRUE; + char* single = NULL;
va_start(args, format); for (i = 0; format[i]; i++) @@ -250,16 +258,41 @@ static char* WINAPIV str_build(struct parsed_symbol* sym, const char* format, .. { switch (format[++i]) { - case 'S': len++; /* fall through */ - case 's': t = va_arg(args, char*); if (t) len += strlen(t); break; - case 'c': (void)va_arg(args, int); len++; break; - default: i--; /* fall through */ - case '%': len++; break; + case 'S': + len++; + /* fall through */ + case 's': + t = va_arg(args, char*); + if (t) + { + len += strlen(t); + if (!single) single = t; + else pure_concat = FALSE; + } + break; + case 'c': + (void)va_arg(args, int); + len++; + pure_concat = FALSE; + break; + default: + i--; + /* fall through */ + case '%': + len++; + pure_concat = FALSE; + break; } } - else len++; + else + { + len++; + pure_concat = FALSE; + } } va_end(args); + if (pure_concat) return single; + if (!(tmp = und_alloc(sym, len))) return NULL; va_start(args, format); for (p = tmp, i = 0; format[i]; i++) @@ -416,7 +449,7 @@ static void append_extended_modifier(struct parsed_symbol *sym, const char **whe { if (sym->flags & UNDNAME_NO_LEADING_UNDERSCORES) str += 2; - *where = *where ? str_build(sym, "%s %s", *where, str) : str; + *where = str_build(sym, "%s%S", *where, str); } }
@@ -453,10 +486,7 @@ static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt) case 'D': mod = "const volatile"; break; default: return FALSE; } - if (xdt->left && mod) - xdt->left = str_build(sym, "%s %s", xdt->left, mod); - else if (mod) - xdt->left = mod; + xdt->left = str_build(sym, "%s%S", xdt->left, mod); return TRUE; }
@@ -481,10 +511,7 @@ 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_build(sym, "%s%S%S%S", xdt.left, ref, xdt.right, str_modif); - else - ct->left = NULL; + ct->left = str_build(sym, "%s%S%S%S", xdt.left, ref, xdt.right, str_modif); ct->right = NULL;
if (get_modifier(sym, &xdt)) @@ -522,7 +549,7 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, else ct->left = str_build(sym, "%s%S%S", sub_ct.left, xdt.left, ct->left);
- if (sub_ct.right) ct->right = str_build(sym, "%s%s", ct->right, sub_ct.right); + ct->right = str_build(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; } return TRUE; @@ -567,7 +594,7 @@ static char* get_literal_string(struct parsed_symbol* sym) */ static char* get_template_name(struct parsed_symbol* sym) { - char *name, *args; + char *name; unsigned num_mark = sym->names.num; unsigned start_mark = sym->names.start; unsigned stack_mark = sym->stack.num; @@ -579,9 +606,7 @@ static char* get_template_name(struct parsed_symbol* sym) return FALSE; } str_array_init(&array_pmt); - args = get_args(sym, &array_pmt, FALSE, '<', '>'); - if (args != NULL) - name = str_build(sym, "%s%s", name, args); + name = str_build(sym, "%s%s", name, get_args(sym, &array_pmt, FALSE, '<', '>')); sym->names.num = num_mark; sym->names.start = start_mark; sym->stack.num = stack_mark; @@ -906,10 +931,6 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, goto done; if (!get_modifier(sym, &xdt)) goto done; - if (xdt.left) - xdt.left = str_build(sym, "%s %s", xdt.left, xdt.right); - else if (xdt.right) - xdt.left = str_build(sym, " %s", xdt.right); if (!get_calling_convention(*sym->current++, &call_conv, &exported, sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE)) @@ -923,7 +944,8 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
ct->left = str_build(sym, "%s%s (%s %s::*", sub_ct.left, sub_ct.right, call_conv, class); - ct->right = str_build(sym, ")%s%s", args, xdt.left); + ct->right = str_build(sym, ")%s%s%s%s", + args, xdt.left, xdt.left || xdt.right ? " " : NULL, xdt.right); } else if (*sym->current == '6') { @@ -1041,10 +1063,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) goto done;
- if (arr) - ct->left = str_build(sym, "%s %s", sub_ct.left, arr); - else - ct->left = sub_ct.left; + ct->left = str_build(sym, "%s%S", sub_ct.left, arr); ct->right = sub_ct.right; sym->stack.num = mark; } @@ -1136,8 +1155,7 @@ static BOOL handle_data(struct parsed_symbol* sym)
if (!demangle_datatype(sym, &ct, &pmt, FALSE)) goto done; if (!get_modifier(sym, &xdt)) goto done; - if (xdt.left && xdt.right) xdt.left = str_build(sym, "%s %s", xdt.left, xdt.right); - else if (!xdt.left) xdt.left = xdt.right; + xdt.left = str_build(sym, "%s%S", xdt.left, xdt.right); sym->stack.num = mark; } break; @@ -1312,7 +1330,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 (xdt.left || xdt.right) xdt.left = str_build(sym, "%s %s", xdt.left, xdt.right); + xdt.left = str_build(sym, "%s%s%s", xdt.left, xdt.left || xdt.right ? " " : NULL, xdt.right); }
if (!get_calling_convention(*sym->current++, &call_conv, &exported, @@ -1544,7 +1562,7 @@ static BOOL symbol_demangle(struct parsed_symbol* sym)
str_array_init(&array_pmt); args = get_args(sym, &array_pmt, FALSE, '<', '>'); - if (args) function_name = function_name ? str_build(sym, "%s%s", function_name, args) : args; + function_name = str_build(sym, "%s%s", function_name, args); sym->names.num = 0; } switch (do_after)
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/tests/cpp.c | 6 +++++ dlls/msvcrt/undname.c | 56 ++++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 15 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index 14d4cfac84a..c96561c5a66 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1298,6 +1298,12 @@ static void test_demangle(void) /* 136 */ {"??$?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"}, /* 137 */ {"??Bcastop@@QAEHXZ", "public: __thiscall castop::operator int(void)"}, +/* 138 */ {"?pfield@@3PTAA@@DT1@", "char const volatile AA::* const volatile pfield"}, +/* 139 */ {"?ptititi1@@3PEQtititi@@IEQ1@", "unsigned int tititi::* __ptr64 __ptr64 ptititi1"}, +/* 140 */ {"?ptititi2@@3PERtititi@@IER1@", "unsigned int const tititi::* __ptr64 const __ptr64 ptititi2"}, +/* 141 */ {"?ptititi3@@3PEStititi@@IES1@", "unsigned int volatile tititi::* __ptr64 volatile __ptr64 ptititi3"}, +/* 142 */ {"?ptititi4@@3PETtititi@@IET1@", "unsigned int const volatile tititi::* __ptr64 const volatile __ptr64 ptititi4"}, +/* 143 */ {"?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 8c361643b0b..40ed7051e60 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -85,6 +85,7 @@ struct datatype_t };
static BOOL symbol_demangle(struct parsed_symbol* sym); +static char* get_class_name(struct parsed_symbol* sym);
/****************************************************************** * und_alloc @@ -473,31 +474,50 @@ 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) { const char* mod; + char ch;
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; } xdt->left = str_build(sym, "%s%S", 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, BOOL in_args) { - 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) { @@ -511,14 +531,17 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, case '$': ref = "&&"; str_modif = NULL; break; default: return FALSE; } - ct->left = str_build(sym, "%s%S%S%S", xdt.left, ref, xdt.right, str_modif); ct->right = NULL;
- if (get_modifier(sym, &xdt)) + if (get_modifier(sym, &xdt2, &class)) { unsigned mark = sym->stack.num; struct datatype_t sub_ct;
+ if (class) + ct->left = str_build(sym, "%s%S%s%s%S%s", xdt1.left, class, class ? "::" : NULL, ref, xdt1.right, str_modif); + else + ct->left = str_build(sym, "%s%S%S%S", xdt1.left, ref, xdt1.right, str_modif); /* multidimensional arrays */ if (*sym->current == 'Y') { @@ -529,9 +552,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_build(sym, "(%s%S", xdt.left, ct->left); + ct->left = str_build(sym, "(%s%S", xdt2.left, ct->left); ct->right = ")"; - xdt.left = NULL; + xdt2.left = NULL;
while (num--) ct->right = str_build(sym, "%s[%s]", ct->right, get_number(sym)); @@ -543,15 +566,17 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, /* don't insert a space between duplicate '*' */ if (!in_args && sub_ct.left && sub_ct.left[0] && sub_ct.left[strlen(sub_ct.left) - 1] == '*' && - !xdt.left && + !xdt2.left && ct->left && ct->left[0] == '*') ct->left = str_build(sym, "%s%s", sub_ct.left, ct->left); else - ct->left = str_build(sym, "%s%S%S", sub_ct.left, xdt.left, ct->left); + ct->left = str_build(sym, "%s%S%S", sub_ct.left, xdt2.left, ct->left);
ct->right = str_build(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; } + else + ct->left = str_build(sym, "%s%S%S%S", xdt1.left, ref, xdt1.right, str_modif); return TRUE; }
@@ -929,7 +954,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
if (!(class = get_class_name(sym))) goto done; - if (!get_modifier(sym, &xdt)) + if (!get_modifier(sym, &xdt, NULL)) goto done; if (!get_calling_convention(*sym->current++, &call_conv, &exported, @@ -1072,7 +1097,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, in_args)) goto done; ct->left = str_build(sym, "%s %s", ct->left, xdt.left); } @@ -1150,11 +1175,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, FALSE)) goto done; - if (!get_modifier(sym, &xdt)) goto done; + if (!get_modifier(sym, &xdt, &class)) goto done; xdt.left = str_build(sym, "%s%S", xdt.left, xdt.right); sym->stack.num = mark; } @@ -1162,7 +1188,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; @@ -1329,7 +1355,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; xdt.left = str_build(sym, "%s%s%s", xdt.left, xdt.left || xdt.right ? " " : NULL, xdt.right); }
From: Eric Pouech eric.pouech@gmail.com
introducing get_function_signature to factorize parsing of function signature
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/tests/cpp.c | 1 + dlls/msvcrt/undname.c | 86 +++++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 34 deletions(-)
diff --git a/dlls/msvcrt/tests/cpp.c b/dlls/msvcrt/tests/cpp.c index c96561c5a66..dc6de119214 100644 --- a/dlls/msvcrt/tests/cpp.c +++ b/dlls/msvcrt/tests/cpp.c @@ -1304,6 +1304,7 @@ static void test_demangle(void) /* 141 */ {"?ptititi3@@3PEStititi@@IES1@", "unsigned int volatile tititi::* __ptr64 volatile __ptr64 ptititi3"}, /* 142 */ {"?ptititi4@@3PETtititi@@IET1@", "unsigned int const volatile tititi::* __ptr64 const volatile __ptr64 ptititi4"}, /* 143 */ {"?ptititi4v@@3RETtititi@@IET1@", "unsigned int const volatile tititi::* __ptr64 const volatile __ptr64 ptititi4v"}, +/* 144 */ {"?foo@@YAX_NV?$B@$$A6A_N_N@Z@@@Z", "void __cdecl foo(bool,class B<bool __cdecl(bool)>)"}, }; int i, num_test = ARRAY_SIZE(test); char* name; diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index 40ed7051e60..c27d58f4b0b 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -858,6 +858,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 * @@ -942,13 +968,9 @@ 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++;
@@ -956,45 +978,26 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, goto done; if (!get_modifier(sym, &xdt, NULL)) goto done; - if (!get_calling_convention(*sym->current++, - &call_conv, &exported, - sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE)) + if (!get_function_signature(sym, pmt_ref, &fs)) goto done; - if (!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_build(sym, "%s%s (%s %s::*", - sub_ct.left, sub_ct.right, call_conv, class); + fs.return_ct.left, fs.return_ct.right, fs.call_conv, class); ct->right = str_build(sym, ")%s%s%s%s", - args, xdt.left, xdt.left || xdt.right ? " " : NULL, xdt.right); + fs.arguments, xdt.left, xdt.left || xdt.right ? " " : NULL, xdt.right); } 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, FALSE)) + if (!get_function_signature(sym, pmt_ref, &fs)) goto done;
- args = get_args(sym, pmt_ref, TRUE, '(', ')'); - if (!args) goto done; - sym->stack.num = mark; - ct->left = str_build(sym, "%s%s (%s*", - sub_ct.left, sub_ct.right, call_conv); - ct->right = str_build(sym, ")%s", args); + fs.return_ct.left, fs.return_ct.right, fs.call_conv); + ct->right = str_build(sym, ")%s", fs.arguments); } else goto done; } @@ -1065,7 +1068,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_build(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;
Piotr Caban (@piotr) commented about dlls/msvcrt/undname.c:
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;
The patch also affects do_after==3 (cast op) and do_after==4 (string literal) cases (maybe commit message can be improved). The do_after==3 case is kind of covered by next patch. It would be good to also cover do_after==4 case in tests. According to a quick test "_C" demangling is currently broken but a todo_wine test can still document it.
While it's not really related to the patch it would be good to define some kind of enum that can be used instead of 1..4 constants.
These are some general thoughts (I don't think that this patch should be blocked by anything above).
Piotr Caban (@piotr) commented about dlls/msvcrt/tests/cpp.c:
/* 135 */ {"?x@@3PAY02HA", "int (* x)[3]"}, /* 136 */ {"??$?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"}, +/* 137 */ {"??Bcastop@@QAEHXZ", "public: __thiscall castop::operator int(void)"},
The test you have added works both with and without your commit. I guess it's a templates related fix so something like "??$?BDM@castop@@QAEHXZ" will make more sense.
On Thu Jul 21 13:55:09 2022 +0000, Piotr Caban wrote:
The patch also affects do_after==3 (cast op) and do_after==4 (string literal) cases (maybe commit message can be improved). The do_after==3 case is kind of covered by next patch. It would be good to also cover do_after==4 case in tests. According to a quick test "_C" demangling is currently broken but a todo_wine test can still document it. While it's not really related to the patch it would be good to define some kind of enum that can be used instead of 1..4 constants. These are some general thoughts (I don't think that this patch should be blocked by anything above).
Hi Piotr,
I'll resend with updated commit message; should be something like 'template support is orthogonal to methods special name handling (ctor/dtor/cast operator...). In all cases, if we need to support templates in do_after 3/4 cases (I haven't tested if this is even a valid C++ construct), current code is broken (as template part will not be generated) => to be tested in other patches
agreed for having an enum for do_after (but I'm starting by removing the unneeded values first ;-) (I'd like to get rid of do_after=4, but need to be sure it doesn't require templates support)
Piotr Caban (@piotr) commented about dlls/msvcrt/undname.c:
{ switch (format[++i]) {
case 'S': len++; /* fall through */ case 's': t = va_arg(args, char*); if (t) len += strlen(t); break; case 'c': (void)va_arg(args, int); len++; break; default: i--; /* fall through */
I still need to think about this helper some more. Here are some initial thoughts: how about removing handling anything except %[Ssc] from the function? The switch may look like as follows: ``` switch (format[++i]) { case 'S': len++; /* fall through */ case 's': t = va_arg(args, char*); if (t) len += strlen(t); break; case 'c': (void)va_arg(args, int); len++; break; default: ERR("invalid format: '%c'\n", format[0]); return NULL; } ``` It's an internal function and there's no point in supporting unused switches there.
Piotr Caban (@piotr) commented about dlls/msvcrt/undname.c:
va_start(args, format); for (p = tmp, i = 0; format[i]; i++) {
Looks like a new line was accidentally added.
Piotr Caban (@piotr) commented about dlls/msvcrt/undname.c:
char* tmp; char* p; char* t;
- BOOL s_printed = FALSE;
How about changing the variable name to e.g. add_delim?
Piotr Caban (@piotr) commented about dlls/msvcrt/undname.c:
char* p; char* t; BOOL s_printed = FALSE;
- BOOL pure_concat = TRUE;
Could you please rename the variable to something like `needs_alloc`?
On Thu Jul 21 13:55:30 2022 +0000, Piotr Caban wrote:
The test you have added works both with and without your commit. I guess it's a templates related fix so something like "??$?BDM@castop@@QAEHXZ" will make more sense.
You got me...
actually I had another test in first version of the patch /* xxx */ {"??Bcastop@@QAE?BHXZ", "public: __thiscall castop::operator int const (void)"}, but this failed because of erroneous space character in the output (a space is inserted after the const, while none is inserted if there's no qualifier as in the test added to this patch). I removed the test and the rest of the changes to support it as I couldn't get it right in a decent way (ie
for the record I'm also running undecoration code against: A) a list of C++ symbols gotten from various pdb files B) a list of tests imported from llvm test suite... (in a bunch of cases llvm's output differs from native msvcrt as well) and comparing it against native msvcrt output
apart from a lot of undecoration errors in A) & B), I've got also a bunch of white space only discrepancies (and to link to test case above, there's some other cases where we're missing a white space after a non empty qualifier to a type); but I currently gave up to understanding where this comes from
I'm uncertain how to tackle this kind of issue: - fixing space for space the output looks not easy at all... and doing it at the right place even more (I don't like some of the ugly tests - for example: search for /* don't insert a space between duplicate '*' */) - mark the test as todo_wine; but shall we consider generating "operator int const(void)" instead of "operator int const (void)" as an error? both are valid C++ constructs, and both correspond to the mangled symbol - add a new mark for wine white space only changes (actully around some delimiters - likely "<>()*,"
On Thu Jul 21 15:31:48 2022 +0000, eric pouech wrote:
You got me... actually I had another test in first version of the patch /* xxx */ {"??Bcastop@@QAE?BHXZ", "public: __thiscall castop::operator int const (void)"}, but this failed because of erroneous space character in the output (a space is inserted after the const, while none is inserted if there's no qualifier as in the test added to this patch). I removed the test and the rest of the changes to support it as I couldn't get it right in a decent way (ie for the record I'm also running undecoration code against: A) a list of C++ symbols gotten from various pdb files B) a list of tests imported from llvm test suite... (in a bunch of cases llvm's output differs from native msvcrt as well) and comparing it against native msvcrt output apart from a lot of undecoration errors in A) & B), I've got also a bunch of white space only discrepancies (and to link to test case above, there's some other cases where we're missing a white space after a non empty qualifier to a type); but I currently gave up to understanding where this comes from I'm uncertain how to tackle this kind of issue:
- fixing space for space the output looks not easy at all... and doing
it at the right place even more (I don't like some of the ugly tests - for example: search for /* don't insert a space between duplicate '*' */)
- mark the test as todo_wine; but shall we consider generating "operator
int const(void)" instead of "operator int const (void)" as an error? both are valid C++ constructs, and both correspond to the mangled symbol
- add a new mark for wine white space only changes (actully around some
delimiters - likely "<>()*,"
If you're looking for some hints I'm afraid I don't have any. You're much more familiar with this code than I am. I would probably try to do it this way: - check if ucrtbase produces the output in the same way (usually it's better to follow ucrtbase output if there's difference) - try to implement it so the output is identical as in native - if it's hard or not possible output something that is valid C++ (but in this case there should be a test that fails)
I'm not sure if we need any special support for it in tests. Probably adding the tests and marking it as todo_wine is good enough. Another option is to introduce something like strcmp_ignore_ws function (that compares all the characters except ' ') and use it for tests marked as white space failures. If anything like strcmp_ignore_ws is introduced, I think it should be used in following way: ``` todo_wine_if(test[i].flags & TODO_WINE_WS) ok(!strcmp(test[i].out, name), ...); if (test[i].flags & TODO_WINE_WS) ok(!strcmp_ignore_ws(test[i].out, name), ...); ```
I will take a look on ** case to see if I can find an elegant solution for it. I'll let you know if I find anything.
On Thu Jul 21 17:24:34 2022 +0000, Piotr Caban wrote:
If you're looking for some hints I'm afraid I don't have any. You're much more familiar with this code than I am. I would probably try to do it this way:
- check if ucrtbase produces the output in the same way (usually it's
better to follow ucrtbase output if there's difference)
- try to implement it so the output is identical as in native
- if it's hard or not possible output something that is valid C++ (but
in this case there should be a test that fails) I'm not sure if we need any special support for it in tests. Probably adding the tests and marking it as todo_wine is good enough. Another option is to introduce something like strcmp_ignore_ws function (that compares all the characters except ' ') and use it for tests marked as white space failures. If anything like strcmp_ignore_ws is introduced, I think it should be used in following way:
todo_wine_if(test[i].flags & TODO_WINE_WS) ok(!strcmp(test[i].out, name), ...); if (test[i].flags & TODO_WINE_WS) ok(!strcmp_ignore_ws(test[i].out, name), ...);
I will take a look on ** case to see if I can find an elegant solution for it. I'll let you know if I find anything.
my point was "what do we do when no simple not-ugly solution for ws only discrepancies is at sight?"
so at least, I'll update the "operator cast" tests with the test I removed, and try to come up with a proposal to ws only changes (and we should also report when the flag is set and we get a correct match (ie without ws changes))
On Thu Jul 21 17:49:16 2022 +0000, eric pouech wrote:
my point was "what do we do when no simple not-ugly solution for ws only discrepancies is at sight?" so at least, I'll update the "operator cast" tests with the test I removed, and try to come up with a proposal to ws only changes (and we should also report when the flag is set and we get a correct match (ie without ws changes))
I think the pseudo-code I have pasted does that. In case of TODO_WINE_WS flag and exact match the strcmp test will succeed inside todo block.
When adding white space related test "?Qux@Bar@@0PAPAP6AHPAV1@AAH1PAH@ZA" may be interesting - it's a test that shows that "don't insert space" hack is broken.