tests: Make sure only one thread prints traces at a time.
[wine.git] / dlls / msvcrt / undname.c
blobeb95da98435a4b15393f71bb73ace8a600df20a5
1 /*
2 * Demangle VC++ symbols into C function prototypes
4 * Copyright 2000 Jon Griffiths
5 * 2004 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include "msvcrt.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
31 /* TODO:
32 * - document a bit (grammar + functions)
33 * - back-port this new code into tools/winedump/msmangle.c
36 /* How data types modifiers are stored:
37 * M (in the following definitions) is defined for
38 * 'A', 'B', 'C' and 'D' as follows
39 * {<A>}: ""
40 * {<B>}: "const "
41 * {<C>}: "volatile "
42 * {<D>}: "const volatile "
44 * in arguments:
45 * P<M>x {<M>}x*
46 * Q<M>x {<M>}x* const
47 * A<M>x {<M>}x&
48 * in data fields:
49 * same as for arguments and also the following
50 * ?<M>x {<M>}x
54 struct array
56 unsigned start; /* first valid reference in array */
57 unsigned num; /* total number of used elts */
58 unsigned max;
59 unsigned alloc;
60 char** elts;
63 /* Structure holding a parsed symbol */
64 struct parsed_symbol
66 unsigned flags; /* the UNDNAME_ flags used for demangling */
67 malloc_func_t mem_alloc_ptr; /* internal allocator */
68 free_func_t mem_free_ptr; /* internal deallocator */
70 const char* current; /* pointer in input (mangled) string */
71 char* result; /* demangled string */
73 struct array names; /* array of names for back reference */
74 struct array stack; /* stack of parsed strings */
76 void* alloc_list; /* linked list of allocated blocks */
77 unsigned avail_in_first; /* number of available bytes in head block */
80 enum datatype_e
82 DT_NO_LEADING_WS = 0x01,
85 /* Type for parsing mangled types */
86 struct datatype_t
88 const char* left;
89 const char* right;
90 enum datatype_e flags;
93 static BOOL symbol_demangle(struct parsed_symbol* sym);
94 static char* get_class_name(struct parsed_symbol* sym);
96 /******************************************************************
97 * und_alloc
99 * Internal allocator. Uses a simple linked list of large blocks
100 * where we use a poor-man allocator. It's fast, and since all
101 * allocation is pool, memory management is easy (esp. freeing).
103 static void* und_alloc(struct parsed_symbol* sym, unsigned int len)
105 void* ptr;
107 #define BLOCK_SIZE 1024
108 #define AVAIL_SIZE (1024 - sizeof(void*))
110 if (len > AVAIL_SIZE)
112 /* allocate a specific block */
113 ptr = sym->mem_alloc_ptr(sizeof(void*) + len);
114 if (!ptr) return NULL;
115 *(void**)ptr = sym->alloc_list;
116 sym->alloc_list = ptr;
117 sym->avail_in_first = 0;
118 ptr = (char*)sym->alloc_list + sizeof(void*);
120 else
122 if (len > sym->avail_in_first)
124 /* add a new block */
125 ptr = sym->mem_alloc_ptr(BLOCK_SIZE);
126 if (!ptr) return NULL;
127 *(void**)ptr = sym->alloc_list;
128 sym->alloc_list = ptr;
129 sym->avail_in_first = AVAIL_SIZE;
131 /* grab memory from head block */
132 ptr = (char*)sym->alloc_list + BLOCK_SIZE - sym->avail_in_first;
133 sym->avail_in_first -= len;
135 return ptr;
136 #undef BLOCK_SIZE
137 #undef AVAIL_SIZE
140 /******************************************************************
141 * und_free
142 * Frees all the blocks in the list of large blocks allocated by
143 * und_alloc.
145 static void und_free_all(struct parsed_symbol* sym)
147 void* next;
149 while (sym->alloc_list)
151 next = *(void**)sym->alloc_list;
152 if(sym->mem_free_ptr) sym->mem_free_ptr(sym->alloc_list);
153 sym->alloc_list = next;
155 sym->avail_in_first = 0;
158 /******************************************************************
159 * str_array_init
160 * Initialises an array of strings
162 static void str_array_init(struct array* a)
164 a->start = a->num = a->max = a->alloc = 0;
165 a->elts = NULL;
168 /******************************************************************
169 * str_array_push
170 * Adding a new string to an array
172 static BOOL str_array_push(struct parsed_symbol* sym, const char* ptr, int len,
173 struct array* a)
175 char** new;
177 assert(ptr);
178 assert(a);
180 if (!a->alloc)
182 new = und_alloc(sym, (a->alloc = 32) * sizeof(a->elts[0]));
183 if (!new) return FALSE;
184 a->elts = new;
186 else if (a->max >= a->alloc)
188 new = und_alloc(sym, (a->alloc * 2) * sizeof(a->elts[0]));
189 if (!new) return FALSE;
190 memcpy(new, a->elts, a->alloc * sizeof(a->elts[0]));
191 a->alloc *= 2;
192 a->elts = new;
194 if (len == -1) len = strlen(ptr);
195 a->elts[a->num] = und_alloc(sym, len + 1);
196 assert(a->elts[a->num]);
197 memcpy(a->elts[a->num], ptr, len);
198 a->elts[a->num][len] = '\0';
199 if (++a->num >= a->max) a->max = a->num;
201 int i;
202 char c;
204 for (i = a->max - 1; i >= 0; i--)
206 c = '>';
207 if (i < a->start) c = '-';
208 else if (i >= a->num) c = '}';
209 TRACE("%p\t%d%c %s\n", a, i, c, debugstr_a(a->elts[i]));
213 return TRUE;
216 /******************************************************************
217 * str_array_get_ref
218 * Extracts a reference from an existing array (doing proper type
219 * checking)
221 static char* str_array_get_ref(struct array* cref, unsigned idx)
223 assert(cref);
224 if (cref->start + idx >= cref->max)
226 WARN("Out of bounds: %p %d + %d >= %d\n",
227 cref, cref->start, idx, cref->max);
228 return NULL;
230 TRACE("Returning %p[%d] => %s\n",
231 cref, idx, debugstr_a(cref->elts[cref->start + idx]));
232 return cref->elts[cref->start + idx];
235 /******************************************************************
236 * str_printf
237 * Helper for printf type of command (only %s and %c are implemented)
238 * while dynamically allocating the buffer
240 static char* WINAPIV str_printf(struct parsed_symbol* sym, const char* format, ...)
242 va_list args;
243 unsigned int len = 1, i, sz;
244 char* tmp;
245 char* p;
246 char* t;
248 va_start(args, format);
249 for (i = 0; format[i]; i++)
251 if (format[i] == '%')
253 switch (format[++i])
255 case 's': t = va_arg(args, char*); if (t) len += strlen(t); break;
256 case 'c': (void)va_arg(args, int); len++; break;
257 default: i--; /* fall through */
258 case '%': len++; break;
261 else len++;
263 va_end(args);
264 if (!(tmp = und_alloc(sym, len))) return NULL;
265 va_start(args, format);
266 for (p = tmp, i = 0; format[i]; i++)
268 if (format[i] == '%')
270 switch (format[++i])
272 case 's':
273 t = va_arg(args, char*);
274 if (t)
276 sz = strlen(t);
277 memcpy(p, t, sz);
278 p += sz;
280 break;
281 case 'c':
282 *p++ = (char)va_arg(args, int);
283 break;
284 default: i--; /* fall through */
285 case '%': *p++ = '%'; break;
288 else *p++ = format[i];
290 va_end(args);
291 *p = '\0';
292 return tmp;
295 enum datatype_flags
297 IN_ARGS = 0x01,
298 WS_AFTER_QUAL_IF = 0x02,
301 /* forward declaration */
302 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
303 struct array* pmt, enum datatype_flags flags);
305 static const char* get_number(struct parsed_symbol* sym)
307 char* ptr;
308 BOOL sgn = FALSE;
310 if (*sym->current == '?')
312 sgn = TRUE;
313 sym->current++;
315 if (*sym->current >= '0' && *sym->current <= '8')
317 ptr = und_alloc(sym, 3);
318 if (sgn) ptr[0] = '-';
319 ptr[sgn ? 1 : 0] = *sym->current + 1;
320 ptr[sgn ? 2 : 1] = '\0';
321 sym->current++;
323 else if (*sym->current == '9')
325 ptr = und_alloc(sym, 4);
326 if (sgn) ptr[0] = '-';
327 ptr[sgn ? 1 : 0] = '1';
328 ptr[sgn ? 2 : 1] = '0';
329 ptr[sgn ? 3 : 2] = '\0';
330 sym->current++;
332 else if (*sym->current >= 'A' && *sym->current <= 'P')
334 int ret = 0;
336 while (*sym->current >= 'A' && *sym->current <= 'P')
338 ret *= 16;
339 ret += *sym->current++ - 'A';
341 if (*sym->current != '@') return NULL;
343 ptr = und_alloc(sym, 17);
344 sprintf(ptr, "%s%u", sgn ? "-" : "", ret);
345 sym->current++;
347 else return NULL;
348 return ptr;
351 /******************************************************************
352 * get_args
353 * Parses a list of function/method arguments, creates a string corresponding
354 * to the arguments' list.
356 static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_term,
357 char open_char, char close_char)
360 struct datatype_t ct;
361 struct array arg_collect;
362 char* args_str = NULL;
363 char* last;
364 unsigned int i;
366 str_array_init(&arg_collect);
368 /* Now come the function arguments */
369 while (*sym->current)
371 /* Decode each data type and append it to the argument list */
372 if (*sym->current == '@')
374 sym->current++;
375 break;
377 if (!demangle_datatype(sym, &ct, pmt_ref, IN_ARGS))
378 return NULL;
379 /* 'void' terminates an argument list in a function */
380 if (z_term && !strcmp(ct.left, "void")) break;
381 if (!str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1,
382 &arg_collect))
383 return NULL;
384 if (!strcmp(ct.left, "...")) break;
386 /* Functions are always terminated by 'Z'. If we made it this far and
387 * don't find it, we have incorrectly identified a data type.
389 if (z_term && *sym->current++ != 'Z') return NULL;
391 if (arg_collect.num == 0 ||
392 (arg_collect.num == 1 && !strcmp(arg_collect.elts[0], "void")))
393 return str_printf(sym, "%cvoid%c", open_char, close_char);
394 for (i = 1; i < arg_collect.num; i++)
396 args_str = str_printf(sym, "%s,%s", args_str, arg_collect.elts[i]);
399 last = args_str ? args_str : arg_collect.elts[0];
400 if (close_char == '>' && last[strlen(last) - 1] == '>')
401 args_str = str_printf(sym, "%c%s%s %c",
402 open_char, arg_collect.elts[0], args_str, close_char);
403 else
404 args_str = str_printf(sym, "%c%s%s%c",
405 open_char, arg_collect.elts[0], args_str, close_char);
407 return args_str;
410 static void append_extended_modifier(struct parsed_symbol *sym, const char **where, const char *str)
412 if (!(sym->flags & UNDNAME_NO_MS_KEYWORDS))
414 if (sym->flags & UNDNAME_NO_LEADING_UNDERSCORES)
415 str += 2;
416 *where = *where ? str_printf(sym, "%s %s", *where, str) : str;
420 static void get_extended_modifier(struct parsed_symbol *sym, struct datatype_t *xdt)
422 xdt->left = xdt->right = NULL;
423 xdt->flags = 0;
424 for (;;)
426 switch (*sym->current)
428 case 'E': append_extended_modifier(sym, &xdt->right, "__ptr64"); break;
429 case 'F': append_extended_modifier(sym, &xdt->left, "__unaligned"); break;
430 case 'I': append_extended_modifier(sym, &xdt->right, "__restrict"); break;
431 default: return;
433 sym->current++;
437 /******************************************************************
438 * get_modifier
439 * Parses the type modifier. Always returns static strings.
441 static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt, const char** pclass)
443 char ch;
444 const char* mod;
446 get_extended_modifier(sym, xdt);
447 switch (ch = *sym->current++)
449 case 'A': mod = NULL; break;
450 case 'B': mod = "const"; break;
451 case 'C': mod = "volatile"; break;
452 case 'D': mod = "const volatile"; break;
453 case 'Q': mod = NULL; break;
454 case 'R': mod = "const"; break;
455 case 'S': mod = "volatile"; break;
456 case 'T': mod = "const volatile"; break;
457 default: return FALSE;
459 if (mod)
460 xdt->left = xdt->left ? str_printf(sym, "%s %s", mod, xdt->left) : mod;
461 if (ch >= 'Q' && ch <= 'T') /* pointer to member, fetch class */
463 const char* class = get_class_name(sym);
464 if (!class) return FALSE;
465 if (!pclass)
467 FIXME("Got pointer to class %s member without storage\n", class);
468 return FALSE;
470 *pclass = class;
472 else if (pclass) *pclass = NULL;
473 return TRUE;
476 static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym,
477 struct array *pmt_ref, char modif, enum datatype_flags flags)
479 struct datatype_t xdt1;
480 struct datatype_t xdt2;
481 const char* ref;
482 const char* str_modif;
483 const char* class;
485 get_extended_modifier(sym, &xdt1);
487 switch (modif)
489 case 'A': ref = " &"; str_modif = NULL; break;
490 case 'B': ref = " &"; str_modif = " volatile"; break;
491 case 'P': ref = " *"; str_modif = NULL; break;
492 case 'Q': ref = " *"; str_modif = " const"; break;
493 case 'R': ref = " *"; str_modif = " volatile"; break;
494 case 'S': ref = " *"; str_modif = " const volatile"; break;
495 case '?': ref = NULL; str_modif = NULL; break;
496 case '$': ref = " &&"; str_modif = NULL; break;
497 default: return FALSE;
499 ct->right = NULL;
500 ct->flags = 0;
502 if (get_modifier(sym, &xdt2, &class))
504 unsigned mark = sym->stack.num;
505 struct datatype_t sub_ct;
507 if (ref || str_modif || xdt1.left || xdt1.right)
509 if (class)
510 ct->left = str_printf(sym, "%s%s%s%s::%s%s%s",
511 xdt1.left ? " " : NULL, xdt1.left,
512 class ? " " : NULL, class, ref ? ref + 1 : NULL,
513 xdt1.right ? " " : NULL, xdt1.right, str_modif);
514 else
515 ct->left = str_printf(sym, "%s%s%s%s%s%s",
516 xdt1.left ? " " : NULL, xdt1.left, ref,
517 xdt1.right ? " " : NULL, xdt1.right, str_modif);
519 else
520 ct->left = NULL;
521 /* multidimensional arrays */
522 if (*sym->current == 'Y')
524 const char* n1;
525 int num;
527 sym->current++;
528 if (!(n1 = get_number(sym))) return FALSE;
529 num = atoi(n1);
531 ct->left = str_printf(sym, " (%s%s", xdt2.left, ct->left && !xdt2.left ? ct->left + 1 : ct->left);
532 ct->right = ")";
533 xdt2.left = NULL;
535 while (num--)
536 ct->right = str_printf(sym, "%s[%s]", ct->right, get_number(sym));
539 /* Recurse to get the referred-to type */
540 if (!demangle_datatype(sym, &sub_ct, pmt_ref, 0))
541 return FALSE;
542 if (sub_ct.flags & DT_NO_LEADING_WS)
543 ct->left++;
544 ct->left = str_printf(sym, "%s%s%s%s%s", sub_ct.left, xdt2.left ? " " : NULL,
545 xdt2.left, ct->left,
546 ((xdt2.left || str_modif) && (flags & WS_AFTER_QUAL_IF)) ? " " : NULL);
547 if (sub_ct.right) ct->right = str_printf(sym, "%s%s", ct->right, sub_ct.right);
548 sym->stack.num = mark;
550 else if (ref || str_modif || xdt1.left || xdt1.right)
551 ct->left = str_printf(sym, "%s%s%s%s%s%s",
552 xdt1.left ? " " : NULL, xdt1.left, ref,
553 xdt1.right ? " " : NULL, xdt1.right, str_modif);
554 else
555 ct->left = NULL;
556 return TRUE;
559 /******************************************************************
560 * get_literal_string
561 * Gets the literal name from the current position in the mangled
562 * symbol to the first '@' character. It pushes the parsed name to
563 * the symbol names stack and returns a pointer to it or NULL in
564 * case of an error.
566 static char* get_literal_string(struct parsed_symbol* sym)
568 const char *ptr = sym->current;
570 do {
571 if (!((*sym->current >= 'A' && *sym->current <= 'Z') ||
572 (*sym->current >= 'a' && *sym->current <= 'z') ||
573 (*sym->current >= '0' && *sym->current <= '9') ||
574 *sym->current == '_' || *sym->current == '$')) {
575 TRACE("Failed at '%c' in %s\n", *sym->current, debugstr_a(ptr));
576 return NULL;
578 } while (*++sym->current != '@');
579 sym->current++;
580 if (!str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->names))
581 return NULL;
583 return str_array_get_ref(&sym->names, sym->names.num - sym->names.start - 1);
586 /******************************************************************
587 * get_template_name
588 * Parses a name with a template argument list and returns it as
589 * a string.
590 * In a template argument list the back reference to the names
591 * table is separately created. '0' points to the class component
592 * name with the template arguments. We use the same stack array
593 * to hold the names but save/restore the stack state before/after
594 * parsing the template argument list.
596 static char* get_template_name(struct parsed_symbol* sym)
598 char *name, *args;
599 unsigned num_mark = sym->names.num;
600 unsigned start_mark = sym->names.start;
601 unsigned stack_mark = sym->stack.num;
602 struct array array_pmt;
604 sym->names.start = sym->names.num;
605 if (!(name = get_literal_string(sym))) {
606 sym->names.start = start_mark;
607 return FALSE;
609 str_array_init(&array_pmt);
610 args = get_args(sym, &array_pmt, FALSE, '<', '>');
611 if (args != NULL)
612 name = str_printf(sym, "%s%s", name, args);
613 sym->names.num = num_mark;
614 sym->names.start = start_mark;
615 sym->stack.num = stack_mark;
616 return name;
619 /******************************************************************
620 * get_class
621 * Parses class as a list of parent-classes, terminated by '@' and stores the
622 * result in 'a' array. Each parent-classes, as well as the inner element
623 * (either field/method name or class name), are represented in the mangled
624 * name by a literal name ([a-zA-Z0-9_]+ terminated by '@') or a back reference
625 * ([0-9]) or a name with template arguments ('?$' literal name followed by the
626 * template argument list). The class name components appear in the reverse
627 * order in the mangled name, e.g aaa@bbb@ccc@@ will be demangled to
628 * ccc::bbb::aaa
629 * For each of these class name components a string will be allocated in the
630 * array.
632 static BOOL get_class(struct parsed_symbol* sym)
634 const char* name = NULL;
636 while (*sym->current != '@')
638 switch (*sym->current)
640 case '\0': return FALSE;
642 case '0': case '1': case '2': case '3':
643 case '4': case '5': case '6': case '7':
644 case '8': case '9':
645 name = str_array_get_ref(&sym->names, *sym->current++ - '0');
646 break;
647 case '?':
648 switch (*++sym->current)
650 case '$':
651 sym->current++;
652 if ((name = get_template_name(sym)) &&
653 !str_array_push(sym, name, -1, &sym->names))
654 return FALSE;
655 break;
656 case '?':
658 struct array stack = sym->stack;
659 unsigned int start = sym->names.start;
660 unsigned int num = sym->names.num;
662 str_array_init( &sym->stack );
663 if (symbol_demangle( sym )) name = str_printf( sym, "`%s'", sym->result );
664 sym->names.start = start;
665 sym->names.num = num;
666 sym->stack = stack;
668 break;
669 default:
670 if (!(name = get_number( sym ))) return FALSE;
671 name = str_printf( sym, "`%s'", name );
672 break;
674 break;
675 default:
676 name = get_literal_string(sym);
677 break;
679 if (!name || !str_array_push(sym, name, -1, &sym->stack))
680 return FALSE;
682 sym->current++;
683 return TRUE;
686 /******************************************************************
687 * get_class_string
688 * From an array collected by get_class in sym->stack, constructs the
689 * corresponding (allocated) string
691 static char* get_class_string(struct parsed_symbol* sym, int start)
693 int i;
694 unsigned int len, sz;
695 char* ret;
696 struct array *a = &sym->stack;
698 for (len = 0, i = start; i < a->num; i++)
700 assert(a->elts[i]);
701 len += 2 + strlen(a->elts[i]);
703 if (!(ret = und_alloc(sym, len - 1))) return NULL;
704 for (len = 0, i = a->num - 1; i >= start; i--)
706 sz = strlen(a->elts[i]);
707 memcpy(ret + len, a->elts[i], sz);
708 len += sz;
709 if (i > start)
711 ret[len++] = ':';
712 ret[len++] = ':';
715 ret[len] = '\0';
716 return ret;
719 /******************************************************************
720 * get_class_name
721 * Wrapper around get_class and get_class_string.
723 static char* get_class_name(struct parsed_symbol* sym)
725 unsigned mark = sym->stack.num;
726 char* s = NULL;
728 if (get_class(sym))
729 s = get_class_string(sym, mark);
730 sym->stack.num = mark;
731 return s;
734 /******************************************************************
735 * get_calling_convention
736 * Returns a static string corresponding to the calling convention described
737 * by char 'ch'. Sets export to TRUE iff the calling convention is exported.
739 static BOOL get_calling_convention(char ch, const char** call_conv,
740 const char** exported, unsigned flags)
742 *call_conv = *exported = NULL;
744 if (!(flags & (UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ALLOCATION_LANGUAGE)))
746 if (flags & UNDNAME_NO_LEADING_UNDERSCORES)
748 if (((ch - 'A') % 2) == 1) *exported = "dll_export ";
749 switch (ch)
751 case 'A': case 'B': *call_conv = "cdecl"; break;
752 case 'C': case 'D': *call_conv = "pascal"; break;
753 case 'E': case 'F': *call_conv = "thiscall"; break;
754 case 'G': case 'H': *call_conv = "stdcall"; break;
755 case 'I': case 'J': *call_conv = "fastcall"; break;
756 case 'K': case 'L': break;
757 case 'M': *call_conv = "clrcall"; break;
758 default: ERR("Unknown calling convention %c\n", ch); return FALSE;
761 else
763 if (((ch - 'A') % 2) == 1) *exported = "__dll_export ";
764 switch (ch)
766 case 'A': case 'B': *call_conv = "__cdecl"; break;
767 case 'C': case 'D': *call_conv = "__pascal"; break;
768 case 'E': case 'F': *call_conv = "__thiscall"; break;
769 case 'G': case 'H': *call_conv = "__stdcall"; break;
770 case 'I': case 'J': *call_conv = "__fastcall"; break;
771 case 'K': case 'L': break;
772 case 'M': *call_conv = "__clrcall"; break;
773 default: ERR("Unknown calling convention %c\n", ch); return FALSE;
777 return TRUE;
780 /*******************************************************************
781 * get_simple_type
782 * Return a string containing an allocated string for a simple data type
784 static const char* get_simple_type(char c)
786 const char* type_string;
788 switch (c)
790 case 'C': type_string = "signed char"; break;
791 case 'D': type_string = "char"; break;
792 case 'E': type_string = "unsigned char"; break;
793 case 'F': type_string = "short"; break;
794 case 'G': type_string = "unsigned short"; break;
795 case 'H': type_string = "int"; break;
796 case 'I': type_string = "unsigned int"; break;
797 case 'J': type_string = "long"; break;
798 case 'K': type_string = "unsigned long"; break;
799 case 'M': type_string = "float"; break;
800 case 'N': type_string = "double"; break;
801 case 'O': type_string = "long double"; break;
802 case 'X': type_string = "void"; break;
803 case 'Z': type_string = "..."; break;
804 default: type_string = NULL; break;
806 return type_string;
809 /*******************************************************************
810 * get_extended_type
811 * Return a string containing an allocated string for a simple data type
813 static const char* get_extended_type(char c)
815 const char* type_string;
817 switch (c)
819 case 'D': type_string = "__int8"; break;
820 case 'E': type_string = "unsigned __int8"; break;
821 case 'F': type_string = "__int16"; break;
822 case 'G': type_string = "unsigned __int16"; break;
823 case 'H': type_string = "__int32"; break;
824 case 'I': type_string = "unsigned __int32"; break;
825 case 'J': type_string = "__int64"; break;
826 case 'K': type_string = "unsigned __int64"; break;
827 case 'L': type_string = "__int128"; break;
828 case 'M': type_string = "unsigned __int128"; break;
829 case 'N': type_string = "bool"; break;
830 case 'Q': type_string = "char8_t"; break;
831 case 'S': type_string = "char16_t"; break;
832 case 'U': type_string = "char32_t"; break;
833 case 'W': type_string = "wchar_t"; break;
834 default: type_string = NULL; break;
836 return type_string;
839 struct function_signature
841 const char* call_conv;
842 const char* exported;
843 struct datatype_t return_ct;
844 const char* arguments;
847 static BOOL get_function_signature(struct parsed_symbol* sym, struct array* pmt_ref,
848 struct function_signature* fs)
850 unsigned mark = sym->stack.num;
852 if (!get_calling_convention(*sym->current++,
853 &fs->call_conv, &fs->exported,
854 sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
855 !demangle_datatype(sym, &fs->return_ct, pmt_ref, FALSE))
856 return FALSE;
858 if (!(fs->arguments = get_args(sym, pmt_ref, TRUE, '(', ')')))
859 return FALSE;
860 sym->stack.num = mark;
862 return TRUE;
865 /*******************************************************************
866 * demangle_datatype
868 * Attempt to demangle a C++ data type, which may be datatype.
869 * a datatype type is made up of a number of simple types. e.g:
870 * char** = (pointer to (pointer to (char)))
872 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
873 struct array* pmt_ref, enum datatype_flags flags)
875 char dt;
876 BOOL add_pmt = TRUE;
878 assert(ct);
879 ct->left = ct->right = NULL;
880 ct->flags = 0;
882 switch (dt = *sym->current++)
884 case '_':
885 /* MS type: __int8,__int16 etc */
886 ct->left = get_extended_type(*sym->current++);
887 break;
888 case 'C': case 'D': case 'E': case 'F': case 'G':
889 case 'H': case 'I': case 'J': case 'K': case 'M':
890 case 'N': case 'O': case 'X': case 'Z':
891 /* Simple data types */
892 ct->left = get_simple_type(dt);
893 add_pmt = FALSE;
894 break;
895 case 'T': /* union */
896 case 'U': /* struct */
897 case 'V': /* class */
898 case 'Y': /* cointerface */
899 /* Class/struct/union/cointerface */
901 const char* struct_name = NULL;
902 const char* type_name = NULL;
904 if (!(struct_name = get_class_name(sym)))
905 goto done;
906 if (!(sym->flags & UNDNAME_NO_COMPLEX_TYPE))
908 switch (dt)
910 case 'T': type_name = "union "; break;
911 case 'U': type_name = "struct "; break;
912 case 'V': type_name = "class "; break;
913 case 'Y': type_name = "cointerface "; break;
916 ct->left = str_printf(sym, "%s%s", type_name, struct_name);
918 break;
919 case '?':
920 /* not all the time is seems */
921 if (flags & IN_ARGS)
923 const char* ptr;
924 if (!(ptr = get_number(sym))) goto done;
925 ct->left = str_printf(sym, "`template-parameter-%s'", ptr);
927 else
929 if (!get_modified_type(ct, sym, pmt_ref, '?', flags)) goto done;
931 break;
932 case 'A': /* reference */
933 case 'B': /* volatile reference */
934 if (!get_modified_type(ct, sym, pmt_ref, dt, flags)) goto done;
935 break;
936 case 'Q': /* const pointer */
937 case 'R': /* volatile pointer */
938 case 'S': /* const volatile pointer */
939 if (!get_modified_type(ct, sym, pmt_ref, (flags & IN_ARGS) ? dt : 'P', flags)) goto done;
940 break;
941 case 'P': /* Pointer */
942 if (isdigit(*sym->current))
944 /* FIXME:
945 * P6 = Function pointer
946 * P8 = Member function pointer
947 * others who knows.. */
948 if (*sym->current == '8')
950 struct function_signature fs;
951 const char* class;
952 struct datatype_t xdt;
954 sym->current++;
956 if (!(class = get_class_name(sym)))
957 goto done;
958 if (!get_modifier(sym, &xdt, NULL))
959 goto done;
960 if (!get_function_signature(sym, pmt_ref, &fs))
961 goto done;
962 if (xdt.left)
963 xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right);
964 else if (xdt.right)
965 xdt.left = str_printf(sym, " %s", xdt.right);
967 ct->left = str_printf(sym, "%s%s (%s %s::*",
968 fs.return_ct.left, fs.return_ct.right, fs.call_conv, class);
969 ct->right = str_printf(sym, ")%s%s", fs.arguments, xdt.left);
971 else if (*sym->current == '6')
973 struct function_signature fs;
975 sym->current++;
977 if (!get_function_signature(sym, pmt_ref, &fs))
978 goto done;
980 ct->left = str_printf(sym, "%s%s (%s*",
981 fs.return_ct.left, fs.return_ct.right, fs.call_conv);
982 ct->flags = DT_NO_LEADING_WS;
983 ct->right = str_printf(sym, ")%s", fs.arguments);
985 else goto done;
987 else if (!get_modified_type(ct, sym, pmt_ref, 'P', flags)) goto done;
988 break;
989 case 'W':
990 if (*sym->current == '4')
992 char* enum_name;
993 sym->current++;
994 if (!(enum_name = get_class_name(sym)))
995 goto done;
996 if (sym->flags & UNDNAME_NO_COMPLEX_TYPE)
997 ct->left = enum_name;
998 else
999 ct->left = str_printf(sym, "enum %s", enum_name);
1001 else goto done;
1002 break;
1003 case '0': case '1': case '2': case '3': case '4':
1004 case '5': case '6': case '7': case '8': case '9':
1005 /* Referring back to previously parsed type */
1006 /* left and right are pushed as two separate strings */
1007 if (!pmt_ref) goto done;
1008 ct->left = str_array_get_ref(pmt_ref, (dt - '0') * 2);
1009 ct->right = str_array_get_ref(pmt_ref, (dt - '0') * 2 + 1);
1010 if (!ct->left) goto done;
1011 add_pmt = FALSE;
1012 break;
1013 case '$':
1014 switch (*sym->current++)
1016 case '0':
1017 if (!(ct->left = get_number(sym))) goto done;
1018 break;
1019 case 'D':
1021 const char* ptr;
1022 if (!(ptr = get_number(sym))) goto done;
1023 ct->left = str_printf(sym, "`template-parameter%s'", ptr);
1025 break;
1026 case 'F':
1028 const char* p1;
1029 const char* p2;
1030 if (!(p1 = get_number(sym))) goto done;
1031 if (!(p2 = get_number(sym))) goto done;
1032 ct->left = str_printf(sym, "{%s,%s}", p1, p2);
1034 break;
1035 case 'G':
1037 const char* p1;
1038 const char* p2;
1039 const char* p3;
1040 if (!(p1 = get_number(sym))) goto done;
1041 if (!(p2 = get_number(sym))) goto done;
1042 if (!(p3 = get_number(sym))) goto done;
1043 ct->left = str_printf(sym, "{%s,%s,%s}", p1, p2, p3);
1045 break;
1046 case 'Q':
1048 const char* ptr;
1049 if (!(ptr = get_number(sym))) goto done;
1050 ct->left = str_printf(sym, "`non-type-template-parameter%s'", ptr);
1052 break;
1053 case '$':
1054 if (*sym->current == 'A')
1056 sym->current++;
1057 if (*sym->current == '6')
1059 struct function_signature fs;
1061 sym->current++;
1063 if (!get_function_signature(sym, pmt_ref, &fs))
1064 goto done;
1065 ct->left = str_printf(sym, "%s%s %s%s",
1066 fs.return_ct.left, fs.return_ct.right, fs.call_conv, fs.arguments);
1069 else if (*sym->current == 'B')
1071 unsigned mark = sym->stack.num;
1072 struct datatype_t sub_ct;
1073 const char* arr = NULL;
1074 sym->current++;
1076 /* multidimensional arrays */
1077 if (*sym->current == 'Y')
1079 const char* n1;
1080 int num;
1082 sym->current++;
1083 if (!(n1 = get_number(sym))) goto done;
1084 num = atoi(n1);
1086 while (num--)
1087 arr = str_printf(sym, "%s[%s]", arr, get_number(sym));
1090 if (!demangle_datatype(sym, &sub_ct, pmt_ref, 0)) goto done;
1092 if (arr)
1093 ct->left = str_printf(sym, "%s %s", sub_ct.left, arr);
1094 else
1095 ct->left = sub_ct.left;
1096 ct->right = sub_ct.right;
1097 sym->stack.num = mark;
1099 else if (*sym->current == 'C')
1101 struct datatype_t xdt;
1103 sym->current++;
1104 if (!get_modifier(sym, &xdt, NULL)) goto done;
1105 if (!demangle_datatype(sym, ct, pmt_ref, flags)) goto done;
1106 ct->left = str_printf(sym, "%s %s", ct->left, xdt.left);
1108 else if (*sym->current == 'Q')
1110 sym->current++;
1111 if (!get_modified_type(ct, sym, pmt_ref, '$', flags)) goto done;
1113 break;
1115 break;
1116 default :
1117 ERR("Unknown type %c\n", dt);
1118 break;
1120 if (add_pmt && pmt_ref && (flags & IN_ARGS))
1122 /* left and right are pushed as two separate strings */
1123 if (!str_array_push(sym, ct->left ? ct->left : "", -1, pmt_ref) ||
1124 !str_array_push(sym, ct->right ? ct->right : "", -1, pmt_ref))
1125 return FALSE;
1127 done:
1129 return ct->left != NULL;
1132 /******************************************************************
1133 * handle_data
1134 * Does the final parsing and handling for a variable or a field in
1135 * a class.
1137 static BOOL handle_data(struct parsed_symbol* sym)
1139 const char* access = NULL;
1140 const char* member_type = NULL;
1141 struct datatype_t xdt = {NULL};
1142 struct datatype_t ct;
1143 char* name = NULL;
1144 BOOL ret = FALSE;
1146 /* 0 private static
1147 * 1 protected static
1148 * 2 public static
1149 * 3 private non-static
1150 * 4 protected non-static
1151 * 5 public non-static
1152 * 6 ?? static
1153 * 7 ?? static
1156 if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
1158 /* we only print the access for static members */
1159 switch (*sym->current)
1161 case '0': access = "private: "; break;
1162 case '1': access = "protected: "; break;
1163 case '2': access = "public: "; break;
1167 if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
1169 if (*sym->current >= '0' && *sym->current <= '2')
1170 member_type = "static ";
1173 name = get_class_string(sym, 0);
1175 switch (*sym->current++)
1177 case '0': case '1': case '2':
1178 case '3': case '4': case '5':
1180 unsigned mark = sym->stack.num;
1181 struct array pmt;
1182 const char* class;
1184 str_array_init(&pmt);
1186 if (!demangle_datatype(sym, &ct, &pmt, 0)) goto done;
1187 if (!get_modifier(sym, &xdt, &class)) goto done; /* class doesn't seem to be displayed */
1188 if (xdt.left && xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right);
1189 else if (!xdt.left) xdt.left = xdt.right;
1190 sym->stack.num = mark;
1192 break;
1193 case '6' : /* compiler generated static */
1194 case '7' : /* compiler generated static */
1195 ct.left = ct.right = NULL;
1196 if (!get_modifier(sym, &xdt, NULL)) goto done;
1197 if (*sym->current != '@')
1199 char* cls = NULL;
1201 if (!(cls = get_class_name(sym)))
1202 goto done;
1203 ct.right = str_printf(sym, "{for `%s'}", cls);
1205 break;
1206 case '8':
1207 case '9':
1208 xdt.left = ct.left = ct.right = NULL;
1209 break;
1210 default: goto done;
1212 if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = xdt.left = NULL;
1214 sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s", access,
1215 member_type, ct.left,
1216 xdt.left && ct.left ? " " : NULL, xdt.left,
1217 xdt.left || ct.left ? " " : NULL, name, ct.right);
1218 ret = TRUE;
1219 done:
1220 return ret;
1223 /******************************************************************
1224 * handle_method
1225 * Does the final parsing and handling for a function or a method in
1226 * a class.
1228 static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op)
1230 char accmem;
1231 const char* access = NULL;
1232 int access_id = -1;
1233 const char* member_type = NULL;
1234 struct datatype_t ct_ret;
1235 const char* call_conv;
1236 struct datatype_t xdt = {NULL};
1237 const char* exported;
1238 const char* args_str = NULL;
1239 const char* name = NULL;
1240 BOOL ret = FALSE, has_args = TRUE, has_ret = TRUE;
1241 unsigned mark;
1242 struct array array_pmt;
1244 /* FIXME: why 2 possible letters for each option?
1245 * 'A' private:
1246 * 'B' private:
1247 * 'C' private: static
1248 * 'D' private: static
1249 * 'E' private: virtual
1250 * 'F' private: virtual
1251 * 'G' private: thunk
1252 * 'H' private: thunk
1253 * 'I' protected:
1254 * 'J' protected:
1255 * 'K' protected: static
1256 * 'L' protected: static
1257 * 'M' protected: virtual
1258 * 'N' protected: virtual
1259 * 'O' protected: thunk
1260 * 'P' protected: thunk
1261 * 'Q' public:
1262 * 'R' public:
1263 * 'S' public: static
1264 * 'T' public: static
1265 * 'U' public: virtual
1266 * 'V' public: virtual
1267 * 'W' public: thunk
1268 * 'X' public: thunk
1269 * 'Y'
1270 * 'Z'
1271 * "$0" private: thunk vtordisp
1272 * "$1" private: thunk vtordisp
1273 * "$2" protected: thunk vtordisp
1274 * "$3" protected: thunk vtordisp
1275 * "$4" public: thunk vtordisp
1276 * "$5" public: thunk vtordisp
1277 * "$B" vcall thunk
1278 * "$R" thunk vtordispex
1280 accmem = *sym->current++;
1281 if (accmem == '$')
1283 if (*sym->current >= '0' && *sym->current <= '5')
1284 access_id = (*sym->current - '0') / 2;
1285 else if (*sym->current == 'R')
1286 access_id = (sym->current[1] - '0') / 2;
1287 else if (*sym->current != 'B')
1288 goto done;
1290 else if (accmem >= 'A' && accmem <= 'Z')
1291 access_id = (accmem - 'A') / 8;
1292 else
1293 goto done;
1295 switch (access_id)
1297 case 0: access = "private: "; break;
1298 case 1: access = "protected: "; break;
1299 case 2: access = "public: "; break;
1301 if (accmem == '$' || (accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7)
1302 access = str_printf(sym, "[thunk]:%s", access ? access : " ");
1304 if (accmem == '$' && *sym->current != 'B')
1305 member_type = "virtual ";
1306 else if (accmem <= 'X')
1308 switch ((accmem - 'A') % 8)
1310 case 2: case 3: member_type = "static "; break;
1311 case 4: case 5: case 6: case 7: member_type = "virtual "; break;
1315 if (sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS)
1316 access = NULL;
1317 if (sym->flags & UNDNAME_NO_MEMBER_TYPE)
1318 member_type = NULL;
1320 name = get_class_string(sym, 0);
1322 if (accmem == '$' && *sym->current == 'B') /* vcall thunk */
1324 const char *n;
1326 sym->current++;
1327 n = get_number(sym);
1329 if(!n || *sym->current++ != 'A') goto done;
1330 name = str_printf(sym, "%s{%s,{flat}}' }'", name, n);
1331 has_args = FALSE;
1332 has_ret = FALSE;
1334 else if (accmem == '$' && *sym->current == 'R') /* vtordispex thunk */
1336 const char *n1, *n2, *n3, *n4;
1338 sym->current += 2;
1339 n1 = get_number(sym);
1340 n2 = get_number(sym);
1341 n3 = get_number(sym);
1342 n4 = get_number(sym);
1344 if(!n1 || !n2 || !n3 || !n4) goto done;
1345 name = str_printf(sym, "%s`vtordispex{%s,%s,%s,%s}' ", name, n1, n2, n3, n4);
1347 else if (accmem == '$') /* vtordisp thunk */
1349 const char *n1, *n2;
1351 sym->current++;
1352 n1 = get_number(sym);
1353 n2 = get_number(sym);
1355 if (!n1 || !n2) goto done;
1356 name = str_printf(sym, "%s`vtordisp{%s,%s}' ", name, n1, n2);
1358 else if ((accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7) /* a thunk */
1359 name = str_printf(sym, "%s`adjustor{%s}' ", name, get_number(sym));
1361 if (has_args && (accmem == '$' ||
1362 (accmem <= 'X' && (accmem - 'A') % 8 != 2 && (accmem - 'A') % 8 != 3)))
1364 /* Implicit 'this' pointer */
1365 /* If there is an implicit this pointer, const modifier follows */
1366 if (!get_modifier(sym, &xdt, NULL)) goto done;
1367 if (xdt.left || xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right);
1370 if (!get_calling_convention(*sym->current++, &call_conv, &exported,
1371 sym->flags))
1372 goto done;
1374 str_array_init(&array_pmt);
1376 /* Return type, or @ if 'void' */
1377 if (has_ret && *sym->current == '@')
1379 ct_ret.left = "void";
1380 ct_ret.right = NULL;
1381 sym->current++;
1383 else if (has_ret)
1385 if (!demangle_datatype(sym, &ct_ret, &array_pmt, cast_op ? WS_AFTER_QUAL_IF : 0))
1386 goto done;
1388 if (!has_ret || sym->flags & UNDNAME_NO_FUNCTION_RETURNS)
1389 ct_ret.left = ct_ret.right = NULL;
1390 if (cast_op)
1392 name = str_printf(sym, "%s %s%s", name, ct_ret.left, ct_ret.right);
1393 ct_ret.left = ct_ret.right = NULL;
1396 mark = sym->stack.num;
1397 if (has_args && !(args_str = get_args(sym, &array_pmt, TRUE, '(', ')'))) goto done;
1398 if (sym->flags & UNDNAME_NAME_ONLY) args_str = xdt.left = NULL;
1399 if (sym->flags & UNDNAME_NO_THISTYPE) xdt.left = NULL;
1400 sym->stack.num = mark;
1402 /* Note: '()' after 'Z' means 'throws', but we don't care here
1403 * Yet!!! FIXME
1405 sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s%s%s%s",
1406 access, member_type, ct_ret.left,
1407 (ct_ret.left && !ct_ret.right) ? " " : NULL,
1408 call_conv, call_conv ? " " : NULL, exported,
1409 name, args_str, xdt.left, ct_ret.right);
1410 ret = TRUE;
1411 done:
1412 return ret;
1415 /*******************************************************************
1416 * symbol_demangle
1417 * Demangle a C++ linker symbol
1419 static BOOL symbol_demangle(struct parsed_symbol* sym)
1421 BOOL ret = FALSE;
1422 enum {
1423 PP_NONE,
1424 PP_CONSTRUCTOR,
1425 PP_DESTRUCTOR,
1426 PP_CAST_OPERATOR,
1427 } post_process = PP_NONE;
1429 /* FIXME seems wrong as name, as it demangles a simple data type */
1430 if (sym->flags & UNDNAME_NO_ARGUMENTS)
1432 struct datatype_t ct;
1434 if (demangle_datatype(sym, &ct, NULL, 0))
1436 sym->result = str_printf(sym, "%s%s", ct.left, ct.right);
1437 ret = TRUE;
1439 goto done;
1442 /* MS mangled names always begin with '?' */
1443 if (*sym->current != '?') return FALSE;
1444 sym->current++;
1446 /* Then function name or operator code */
1447 if (*sym->current == '?')
1449 const char* function_name = NULL;
1450 BOOL in_template = FALSE;
1452 if (sym->current[1] == '$' && sym->current[2] == '?')
1454 in_template = TRUE;
1455 sym->current += 2;
1458 /* C++ operator code (one character, or two if the first is '_') */
1459 switch (*++sym->current)
1461 case '0': function_name = ""; post_process = PP_CONSTRUCTOR; break;
1462 case '1': function_name = ""; post_process = PP_DESTRUCTOR; break;
1463 case '2': function_name = "operator new"; break;
1464 case '3': function_name = "operator delete"; break;
1465 case '4': function_name = "operator="; break;
1466 case '5': function_name = "operator>>"; break;
1467 case '6': function_name = "operator<<"; break;
1468 case '7': function_name = "operator!"; break;
1469 case '8': function_name = "operator=="; break;
1470 case '9': function_name = "operator!="; break;
1471 case 'A': function_name = "operator[]"; break;
1472 case 'B': function_name = "operator"; post_process = PP_CAST_OPERATOR; break;
1473 case 'C': function_name = "operator->"; break;
1474 case 'D': function_name = "operator*"; break;
1475 case 'E': function_name = "operator++"; break;
1476 case 'F': function_name = "operator--"; break;
1477 case 'G': function_name = "operator-"; break;
1478 case 'H': function_name = "operator+"; break;
1479 case 'I': function_name = "operator&"; break;
1480 case 'J': function_name = "operator->*"; break;
1481 case 'K': function_name = "operator/"; break;
1482 case 'L': function_name = "operator%"; break;
1483 case 'M': function_name = "operator<"; break;
1484 case 'N': function_name = "operator<="; break;
1485 case 'O': function_name = "operator>"; break;
1486 case 'P': function_name = "operator>="; break;
1487 case 'Q': function_name = "operator,"; break;
1488 case 'R': function_name = "operator()"; break;
1489 case 'S': function_name = "operator~"; break;
1490 case 'T': function_name = "operator^"; break;
1491 case 'U': function_name = "operator|"; break;
1492 case 'V': function_name = "operator&&"; break;
1493 case 'W': function_name = "operator||"; break;
1494 case 'X': function_name = "operator*="; break;
1495 case 'Y': function_name = "operator+="; break;
1496 case 'Z': function_name = "operator-="; break;
1497 case '_':
1498 switch (*++sym->current)
1500 case '0': function_name = "operator/="; break;
1501 case '1': function_name = "operator%="; break;
1502 case '2': function_name = "operator>>="; break;
1503 case '3': function_name = "operator<<="; break;
1504 case '4': function_name = "operator&="; break;
1505 case '5': function_name = "operator|="; break;
1506 case '6': function_name = "operator^="; break;
1507 case '7': function_name = "`vftable'"; break;
1508 case '8': function_name = "`vbtable'"; break;
1509 case '9': function_name = "`vcall'"; break;
1510 case 'A': function_name = "`typeof'"; break;
1511 case 'B': function_name = "`local static guard'"; break;
1512 case 'C': sym->result = (char*)"`string'"; /* string literal: followed by string encoding (native never undecode it) */
1513 /* FIXME: should unmangle the whole string for error reporting */
1514 if (*sym->current && sym->current[strlen(sym->current) - 1] == '@') ret = TRUE;
1515 goto done;
1516 case 'D': function_name = "`vbase destructor'"; break;
1517 case 'E': function_name = "`vector deleting destructor'"; break;
1518 case 'F': function_name = "`default constructor closure'"; break;
1519 case 'G': function_name = "`scalar deleting destructor'"; break;
1520 case 'H': function_name = "`vector constructor iterator'"; break;
1521 case 'I': function_name = "`vector destructor iterator'"; break;
1522 case 'J': function_name = "`vector vbase constructor iterator'"; break;
1523 case 'K': function_name = "`virtual displacement map'"; break;
1524 case 'L': function_name = "`eh vector constructor iterator'"; break;
1525 case 'M': function_name = "`eh vector destructor iterator'"; break;
1526 case 'N': function_name = "`eh vector vbase constructor iterator'"; break;
1527 case 'O': function_name = "`copy constructor closure'"; break;
1528 case 'R':
1529 sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;
1530 switch (*++sym->current)
1532 case '0':
1534 struct datatype_t ct;
1536 sym->current++;
1537 if (!demangle_datatype(sym, &ct, NULL, 0))
1538 goto done;
1539 function_name = str_printf(sym, "%s%s `RTTI Type Descriptor'",
1540 ct.left, ct.right);
1541 sym->current--;
1543 break;
1544 case '1':
1546 const char* n1, *n2, *n3, *n4;
1547 sym->current++;
1548 n1 = get_number(sym);
1549 n2 = get_number(sym);
1550 n3 = get_number(sym);
1551 n4 = get_number(sym);
1552 sym->current--;
1553 function_name = str_printf(sym, "`RTTI Base Class Descriptor at (%s,%s,%s,%s)'",
1554 n1, n2, n3, n4);
1556 break;
1557 case '2': function_name = "`RTTI Base Class Array'"; break;
1558 case '3': function_name = "`RTTI Class Hierarchy Descriptor'"; break;
1559 case '4': function_name = "`RTTI Complete Object Locator'"; break;
1560 default:
1561 ERR("Unknown RTTI operator: _R%c\n", *sym->current);
1562 break;
1564 break;
1565 case 'S': function_name = "`local vftable'"; break;
1566 case 'T': function_name = "`local vftable constructor closure'"; break;
1567 case 'U': function_name = "operator new[]"; break;
1568 case 'V': function_name = "operator delete[]"; break;
1569 case 'X': function_name = "`placement delete closure'"; break;
1570 case 'Y': function_name = "`placement delete[] closure'"; break;
1571 case '_':
1572 switch (*++sym->current)
1574 case 'K':
1575 sym->current++;
1576 function_name = str_printf(sym, "operator \"\" %s", get_literal_string(sym));
1577 --sym->current;
1578 break;
1579 default:
1580 FIXME("Unknown operator: __%c\n", *sym->current);
1581 return FALSE;
1583 break;
1584 default:
1585 ERR("Unknown operator: _%c\n", *sym->current);
1586 return FALSE;
1588 break;
1589 case '$':
1590 sym->current++;
1591 if (!(function_name = get_template_name(sym))) goto done;
1592 --sym->current;
1593 break;
1594 default:
1595 /* FIXME: Other operators */
1596 ERR("Unknown operator: %c\n", *sym->current);
1597 return FALSE;
1599 sym->current++;
1600 if (in_template)
1602 const char *args;
1603 struct array array_pmt;
1605 str_array_init(&array_pmt);
1606 args = get_args(sym, &array_pmt, FALSE, '<', '>');
1607 if (args) function_name = function_name ? str_printf(sym, "%s%s", function_name, args) : args;
1608 sym->names.num = 0;
1610 if (!str_array_push(sym, function_name, -1, &sym->stack))
1611 return FALSE;
1613 else if (*sym->current == '$')
1615 /* Strange construct, it's a name with a template argument list
1616 and that's all. */
1617 sym->current++;
1618 ret = (sym->result = get_template_name(sym)) != NULL;
1619 goto done;
1622 /* Either a class name, or '@' if the symbol is not a class member */
1623 switch (*sym->current)
1625 case '@': sym->current++; break;
1626 case '$': break;
1627 default:
1628 /* Class the function is associated with, terminated by '@@' */
1629 if (!get_class(sym)) goto done;
1630 break;
1633 switch (post_process)
1635 case PP_NONE: default: break;
1636 case PP_CONSTRUCTOR: case PP_DESTRUCTOR:
1637 /* it's time to set the member name for ctor & dtor */
1638 if (sym->stack.num <= 1) goto done;
1639 sym->stack.elts[0] = str_printf(sym, "%s%s%s", post_process == PP_DESTRUCTOR ? "~" : NULL,
1640 sym->stack.elts[1], sym->stack.elts[0]);
1641 /* ctors and dtors don't have return type */
1642 sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;
1643 break;
1644 case PP_CAST_OPERATOR:
1645 sym->flags &= ~UNDNAME_NO_FUNCTION_RETURNS;
1646 break;
1649 /* Function/Data type and access level */
1650 if (*sym->current >= '0' && *sym->current <= '9')
1651 ret = handle_data(sym);
1652 else if ((*sym->current >= 'A' && *sym->current <= 'Z') || *sym->current == '$')
1653 ret = handle_method(sym, post_process == PP_CAST_OPERATOR);
1654 else ret = FALSE;
1655 done:
1656 if (ret) assert(sym->result);
1657 else WARN("Failed at %s\n", debugstr_a(sym->current));
1659 return ret;
1662 /*********************************************************************
1663 * __unDNameEx (MSVCRT.@)
1665 * Demangle a C++ identifier.
1667 * PARAMS
1668 * buffer [O] If not NULL, the place to put the demangled string
1669 * mangled [I] Mangled name of the function
1670 * buflen [I] Length of buffer
1671 * memget [I] Function to allocate memory with
1672 * memfree [I] Function to free memory with
1673 * unknown [?] Unknown, possibly a call back
1674 * flags [I] Flags determining demangled format
1676 * RETURNS
1677 * Success: A string pointing to the unmangled name, allocated with memget.
1678 * Failure: NULL.
1680 char* CDECL __unDNameEx(char* buffer, const char* mangled, int buflen,
1681 malloc_func_t memget, free_func_t memfree,
1682 void* unknown, unsigned short int flags)
1684 struct parsed_symbol sym;
1685 const char* result;
1687 TRACE("(%p,%s,%d,%p,%p,%p,%x)\n",
1688 buffer, debugstr_a(mangled), buflen, memget, memfree, unknown, flags);
1690 /* The flags details is not documented by MS. However, it looks exactly
1691 * like the UNDNAME_ manifest constants from imagehlp.h and dbghelp.h
1692 * So, we copied those (on top of the file)
1694 memset(&sym, 0, sizeof(struct parsed_symbol));
1695 if (flags & UNDNAME_NAME_ONLY)
1696 flags |= UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_ACCESS_SPECIFIERS |
1697 UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_ALLOCATION_LANGUAGE |
1698 UNDNAME_NO_COMPLEX_TYPE;
1700 sym.flags = flags;
1701 sym.mem_alloc_ptr = memget;
1702 sym.mem_free_ptr = memfree;
1703 sym.current = mangled;
1704 str_array_init( &sym.names );
1705 str_array_init( &sym.stack );
1707 result = symbol_demangle(&sym) ? sym.result : mangled;
1708 if (buffer && buflen)
1710 lstrcpynA( buffer, result, buflen);
1712 else
1714 buffer = memget(strlen(result) + 1);
1715 if (buffer) strcpy(buffer, result);
1718 und_free_all(&sym);
1720 return buffer;
1724 /*********************************************************************
1725 * __unDName (MSVCRT.@)
1727 char* CDECL __unDName(char* buffer, const char* mangled, int buflen,
1728 malloc_func_t memget, free_func_t memfree,
1729 unsigned short int flags)
1731 return __unDNameEx(buffer, mangled, buflen, memget, memfree, NULL, flags);