ReactOS 0.4.15-dev-7788-g1ad9096
undname.c
Go to the documentation of this file.
1/*
2 * Demangle VC++ symbols into C function prototypes
3 *
4 * Copyright 2000 Jon Griffiths
5 * 2004 Eric Pouech
6 *
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.
11 *
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.
16 *
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
20 */
21
22#include "config.h"
23#include "wine/port.h"
24
25#include <assert.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include "msvcrt.h"
29
30#include "wine/debug.h"
31
33
34/* TODO:
35 * - document a bit (grammar + functions)
36 * - back-port this new code into tools/winedump/msmangle.c
37 */
38
39/* How data types modifiers are stored:
40 * M (in the following definitions) is defined for
41 * 'A', 'B', 'C' and 'D' as follows
42 * {<A>}: ""
43 * {<B>}: "const "
44 * {<C>}: "volatile "
45 * {<D>}: "const volatile "
46 *
47 * in arguments:
48 * P<M>x {<M>}x*
49 * Q<M>x {<M>}x* const
50 * A<M>x {<M>}x&
51 * in data fields:
52 * same as for arguments and also the following
53 * ?<M>x {<M>}x
54 *
55 */
56
57struct array
58{
59 unsigned start; /* first valid reference in array */
60 unsigned num; /* total number of used elts */
61 unsigned max;
62 unsigned alloc;
63 char** elts;
64};
65
66/* Structure holding a parsed symbol */
68{
69 unsigned flags; /* the UNDNAME_ flags used for demangling */
70 malloc_func_t mem_alloc_ptr; /* internal allocator */
71 free_func_t mem_free_ptr; /* internal deallocator */
72
73 const char* current; /* pointer in input (mangled) string */
74 char* result; /* demangled string */
75
76 struct array names; /* array of names for back reference */
77 struct array stack; /* stack of parsed strings */
78
79 void* alloc_list; /* linked list of allocated blocks */
80 unsigned avail_in_first; /* number of available bytes in head block */
81};
82
83/* Type for parsing mangled types */
85{
86 const char* left;
87 const char* right;
88};
89
90static BOOL symbol_demangle(struct parsed_symbol* sym);
91
92/******************************************************************
93 * und_alloc
94 *
95 * Internal allocator. Uses a simple linked list of large blocks
96 * where we use a poor-man allocator. It's fast, and since all
97 * allocation is pool, memory management is easy (esp. freeing).
98 */
99static void* und_alloc(struct parsed_symbol* sym, unsigned int len)
100{
101 void* ptr;
102
103#define BLOCK_SIZE 1024
104#define AVAIL_SIZE (1024 - sizeof(void*))
105
106 if (len > AVAIL_SIZE)
107 {
108 /* allocate a specific block */
109 ptr = sym->mem_alloc_ptr(sizeof(void*) + len);
110 if (!ptr) return NULL;
111 *(void**)ptr = sym->alloc_list;
112 sym->alloc_list = ptr;
113 sym->avail_in_first = 0;
114 ptr = (char*)sym->alloc_list + sizeof(void*);
115 }
116 else
117 {
118 if (len > sym->avail_in_first)
119 {
120 /* add a new block */
122 if (!ptr) return NULL;
123 *(void**)ptr = sym->alloc_list;
124 sym->alloc_list = ptr;
126 }
127 /* grab memory from head block */
128 ptr = (char*)sym->alloc_list + BLOCK_SIZE - sym->avail_in_first;
129 sym->avail_in_first -= len;
130 }
131 return ptr;
132#undef BLOCK_SIZE
133#undef AVAIL_SIZE
134}
135
136/******************************************************************
137 * und_free
138 * Frees all the blocks in the list of large blocks allocated by
139 * und_alloc.
140 */
141static void und_free_all(struct parsed_symbol* sym)
142{
143 void* next;
144
145 while (sym->alloc_list)
146 {
147 next = *(void**)sym->alloc_list;
148 if(sym->mem_free_ptr) sym->mem_free_ptr(sym->alloc_list);
149 sym->alloc_list = next;
150 }
151 sym->avail_in_first = 0;
152}
153
154/******************************************************************
155 * str_array_init
156 * Initialises an array of strings
157 */
158static void str_array_init(struct array* a)
159{
160 a->start = a->num = a->max = a->alloc = 0;
161 a->elts = NULL;
162}
163
164/******************************************************************
165 * str_array_push
166 * Adding a new string to an array
167 */
168static BOOL str_array_push(struct parsed_symbol* sym, const char* ptr, int len,
169 struct array* a)
170{
171 char** new;
172
173 assert(ptr);
174 assert(a);
175
176 if (!a->alloc)
177 {
178 new = und_alloc(sym, (a->alloc = 32) * sizeof(a->elts[0]));
179 if (!new) return FALSE;
180 a->elts = new;
181 }
182 else if (a->max >= a->alloc)
183 {
184 new = und_alloc(sym, (a->alloc * 2) * sizeof(a->elts[0]));
185 if (!new) return FALSE;
186 memcpy(new, a->elts, a->alloc * sizeof(a->elts[0]));
187 a->alloc *= 2;
188 a->elts = new;
189 }
190 if (len == -1) len = strlen(ptr);
191 a->elts[a->num] = und_alloc(sym, len + 1);
192 assert(a->elts[a->num]);
193 memcpy(a->elts[a->num], ptr, len);
194 a->elts[a->num][len] = '\0';
195 if (++a->num >= a->max) a->max = a->num;
196 {
197 int i;
198 char c;
199
200 for (i = a->max - 1; i >= 0; i--)
201 {
202 c = '>';
203 if (i < a->start) c = '-';
204 else if (i >= a->num) c = '}';
205 TRACE("%p\t%d%c %s\n", a, i, c, debugstr_a(a->elts[i]));
206 }
207 }
208
209 return TRUE;
210}
211
212/******************************************************************
213 * str_array_get_ref
214 * Extracts a reference from an existing array (doing proper type
215 * checking)
216 */
217static char* str_array_get_ref(struct array* cref, unsigned idx)
218{
219 assert(cref);
220 if (cref->start + idx >= cref->max)
221 {
222 WARN("Out of bounds: %p %d + %d >= %d\n",
223 cref, cref->start, idx, cref->max);
224 return NULL;
225 }
226 TRACE("Returning %p[%d] => %s\n",
227 cref, idx, debugstr_a(cref->elts[cref->start + idx]));
228 return cref->elts[cref->start + idx];
229}
230
231/******************************************************************
232 * str_printf
233 * Helper for printf type of command (only %s and %c are implemented)
234 * while dynamically allocating the buffer
235 */
236static char* str_printf(struct parsed_symbol* sym, const char* format, ...)
237{
239 unsigned int len = 1, i, sz;
240 char* tmp;
241 char* p;
242 char* t;
243
245 for (i = 0; format[i]; i++)
246 {
247 if (format[i] == '%')
248 {
249 switch (format[++i])
250 {
251 case 's': t = va_arg(args, char*); if (t) len += strlen(t); break;
252 case 'c': (void)va_arg(args, int); len++; break;
253 default: i--; /* fall through */
254 case '%': len++; break;
255 }
256 }
257 else len++;
258 }
259 va_end(args);
260 if (!(tmp = und_alloc(sym, len))) return NULL;
262 for (p = tmp, i = 0; format[i]; i++)
263 {
264 if (format[i] == '%')
265 {
266 switch (format[++i])
267 {
268 case 's':
269 t = va_arg(args, char*);
270 if (t)
271 {
272 sz = strlen(t);
273 memcpy(p, t, sz);
274 p += sz;
275 }
276 break;
277 case 'c':
278 *p++ = (char)va_arg(args, int);
279 break;
280 default: i--; /* fall through */
281 case '%': *p++ = '%'; break;
282 }
283 }
284 else *p++ = format[i];
285 }
286 va_end(args);
287 *p = '\0';
288 return tmp;
289}
290
291/* forward declaration */
292static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
293 struct array* pmt, BOOL in_args);
294
295static const char* get_number(struct parsed_symbol* sym)
296{
297 char* ptr;
298 BOOL sgn = FALSE;
299
300 if (*sym->current == '?')
301 {
302 sgn = TRUE;
303 sym->current++;
304 }
305 if (*sym->current >= '0' && *sym->current <= '8')
306 {
307 ptr = und_alloc(sym, 3);
308 if (sgn) ptr[0] = '-';
309 ptr[sgn ? 1 : 0] = *sym->current + 1;
310 ptr[sgn ? 2 : 1] = '\0';
311 sym->current++;
312 }
313 else if (*sym->current == '9')
314 {
315 ptr = und_alloc(sym, 4);
316 if (sgn) ptr[0] = '-';
317 ptr[sgn ? 1 : 0] = '1';
318 ptr[sgn ? 2 : 1] = '0';
319 ptr[sgn ? 3 : 2] = '\0';
320 sym->current++;
321 }
322 else if (*sym->current >= 'A' && *sym->current <= 'P')
323 {
324 int ret = 0;
325
326 while (*sym->current >= 'A' && *sym->current <= 'P')
327 {
328 ret *= 16;
329 ret += *sym->current++ - 'A';
330 }
331 if (*sym->current != '@') return NULL;
332
333 ptr = und_alloc(sym, 17);
334 sprintf(ptr, "%s%u", sgn ? "-" : "", ret);
335 sym->current++;
336 }
337 else return NULL;
338 return ptr;
339}
340
341/******************************************************************
342 * get_args
343 * Parses a list of function/method arguments, creates a string corresponding
344 * to the arguments' list.
345 */
346static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_term,
347 char open_char, char close_char)
348
349{
350 struct datatype_t ct;
351 struct array arg_collect;
352 char* args_str = NULL;
353 char* last;
354 unsigned int i;
355
356 str_array_init(&arg_collect);
357
358 /* Now come the function arguments */
359 while (*sym->current)
360 {
361 /* Decode each data type and append it to the argument list */
362 if (*sym->current == '@')
363 {
364 sym->current++;
365 break;
366 }
367 if (!demangle_datatype(sym, &ct, pmt_ref, TRUE))
368 return NULL;
369 /* 'void' terminates an argument list in a function */
370 if (z_term && !strcmp(ct.left, "void")) break;
371 if (!str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1,
372 &arg_collect))
373 return NULL;
374 if (!strcmp(ct.left, "...")) break;
375 }
376 /* Functions are always terminated by 'Z'. If we made it this far and
377 * don't find it, we have incorrectly identified a data type.
378 */
379 if (z_term && *sym->current++ != 'Z') return NULL;
380
381 if (arg_collect.num == 0 ||
382 (arg_collect.num == 1 && !strcmp(arg_collect.elts[0], "void")))
383 return str_printf(sym, "%cvoid%c", open_char, close_char);
384 for (i = 1; i < arg_collect.num; i++)
385 {
386 args_str = str_printf(sym, "%s,%s", args_str, arg_collect.elts[i]);
387 }
388
389 last = args_str ? args_str : arg_collect.elts[0];
390 if (close_char == '>' && last[strlen(last) - 1] == '>')
391 args_str = str_printf(sym, "%c%s%s %c",
392 open_char, arg_collect.elts[0], args_str, close_char);
393 else
394 args_str = str_printf(sym, "%c%s%s%c",
395 open_char, arg_collect.elts[0], args_str, close_char);
396
397 return args_str;
398}
399
400/******************************************************************
401 * get_modifier
402 * Parses the type modifier. Always returns static strings.
403 */
404static BOOL get_modifier(struct parsed_symbol *sym, const char **ret, const char **ptr_modif)
405{
406 *ptr_modif = NULL;
407 if (*sym->current == 'E')
408 {
409 if (!(sym->flags & UNDNAME_NO_MS_KEYWORDS))
410 {
411 *ptr_modif = "__ptr64";
413 *ptr_modif = *ptr_modif + 2;
414 }
415 sym->current++;
416 }
417 switch (*sym->current++)
418 {
419 case 'A': *ret = NULL; break;
420 case 'B': *ret = "const"; break;
421 case 'C': *ret = "volatile"; break;
422 case 'D': *ret = "const volatile"; break;
423 default: return FALSE;
424 }
425 return TRUE;
426}
427
428static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym,
429 struct array *pmt_ref, char modif, BOOL in_args)
430{
431 const char* modifier;
432 const char* str_modif;
433 const char *ptr_modif = "";
434
435 if (*sym->current == 'E')
436 {
437 if (!(sym->flags & UNDNAME_NO_MS_KEYWORDS))
438 {
440 ptr_modif = " ptr64";
441 else
442 ptr_modif = " __ptr64";
443 }
444 sym->current++;
445 }
446
447 switch (modif)
448 {
449 case 'A': str_modif = str_printf(sym, " &%s", ptr_modif); break;
450 case 'B': str_modif = str_printf(sym, " &%s volatile", ptr_modif); break;
451 case 'P': str_modif = str_printf(sym, " *%s", ptr_modif); break;
452 case 'Q': str_modif = str_printf(sym, " *%s const", ptr_modif); break;
453 case 'R': str_modif = str_printf(sym, " *%s volatile", ptr_modif); break;
454 case 'S': str_modif = str_printf(sym, " *%s const volatile", ptr_modif); break;
455 case '?': str_modif = ""; break;
456 default: return FALSE;
457 }
458
459 if (get_modifier(sym, &modifier, &ptr_modif))
460 {
461 unsigned mark = sym->stack.num;
462 struct datatype_t sub_ct;
463
464 /* multidimensional arrays */
465 if (*sym->current == 'Y')
466 {
467 const char* n1;
468 int num;
469
470 sym->current++;
471 if (!(n1 = get_number(sym))) return FALSE;
472 num = atoi(n1);
473
474 if (str_modif[0] == ' ' && !modifier)
475 str_modif++;
476
477 if (modifier)
478 {
479 str_modif = str_printf(sym, " (%s%s)", modifier, str_modif);
480 modifier = NULL;
481 }
482 else
483 str_modif = str_printf(sym, " (%s)", str_modif);
484
485 while (num--)
486 str_modif = str_printf(sym, "%s[%s]", str_modif, get_number(sym));
487 }
488
489 /* Recurse to get the referred-to type */
490 if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
491 return FALSE;
492 if (modifier)
493 ct->left = str_printf(sym, "%s %s%s", sub_ct.left, modifier, str_modif );
494 else
495 {
496 /* don't insert a space between duplicate '*' */
497 if (!in_args && str_modif[0] && str_modif[1] == '*' && sub_ct.left[strlen(sub_ct.left)-1] == '*')
498 str_modif++;
499 ct->left = str_printf(sym, "%s%s", sub_ct.left, str_modif );
500 }
501 ct->right = sub_ct.right;
502 sym->stack.num = mark;
503 }
504 return TRUE;
505}
506
507/******************************************************************
508 * get_literal_string
509 * Gets the literal name from the current position in the mangled
510 * symbol to the first '@' character. It pushes the parsed name to
511 * the symbol names stack and returns a pointer to it or NULL in
512 * case of an error.
513 */
514static char* get_literal_string(struct parsed_symbol* sym)
515{
516 const char *ptr = sym->current;
517
518 do {
519 if (!((*sym->current >= 'A' && *sym->current <= 'Z') ||
520 (*sym->current >= 'a' && *sym->current <= 'z') ||
521 (*sym->current >= '0' && *sym->current <= '9') ||
522 *sym->current == '_' || *sym->current == '$')) {
523 TRACE("Failed at '%c' in %s\n", *sym->current, debugstr_a(ptr));
524 return NULL;
525 }
526 } while (*++sym->current != '@');
527 sym->current++;
528 if (!str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->names))
529 return NULL;
530
531 return str_array_get_ref(&sym->names, sym->names.num - sym->names.start - 1);
532}
533
534/******************************************************************
535 * get_template_name
536 * Parses a name with a template argument list and returns it as
537 * a string.
538 * In a template argument list the back reference to the names
539 * table is separately created. '0' points to the class component
540 * name with the template arguments. We use the same stack array
541 * to hold the names but save/restore the stack state before/after
542 * parsing the template argument list.
543 */
544static char* get_template_name(struct parsed_symbol* sym)
545{
546 char *name, *args;
547 unsigned num_mark = sym->names.num;
548 unsigned start_mark = sym->names.start;
549 unsigned stack_mark = sym->stack.num;
550 struct array array_pmt;
551
552 sym->names.start = sym->names.num;
553 if (!(name = get_literal_string(sym))) {
554 sym->names.start = start_mark;
555 return FALSE;
556 }
557 str_array_init(&array_pmt);
558 args = get_args(sym, &array_pmt, FALSE, '<', '>');
559 if (args != NULL)
560 name = str_printf(sym, "%s%s", name, args);
561 sym->names.num = num_mark;
562 sym->names.start = start_mark;
563 sym->stack.num = stack_mark;
564 return name;
565}
566
567/******************************************************************
568 * get_class
569 * Parses class as a list of parent-classes, terminated by '@' and stores the
570 * result in 'a' array. Each parent-classes, as well as the inner element
571 * (either field/method name or class name), are represented in the mangled
572 * name by a literal name ([a-zA-Z0-9_]+ terminated by '@') or a back reference
573 * ([0-9]) or a name with template arguments ('?$' literal name followed by the
574 * template argument list). The class name components appear in the reverse
575 * order in the mangled name, e.g aaa@bbb@ccc@@ will be demangled to
576 * ccc::bbb::aaa
577 * For each of these class name components a string will be allocated in the
578 * array.
579 */
580static BOOL get_class(struct parsed_symbol* sym)
581{
582 const char* name = NULL;
583
584 while (*sym->current != '@')
585 {
586 switch (*sym->current)
587 {
588 case '\0': return FALSE;
589
590 case '0': case '1': case '2': case '3':
591 case '4': case '5': case '6': case '7':
592 case '8': case '9':
593 name = str_array_get_ref(&sym->names, *sym->current++ - '0');
594 break;
595 case '?':
596 switch (*++sym->current)
597 {
598 case '$':
599 sym->current++;
600 if ((name = get_template_name(sym)) &&
601 !str_array_push(sym, name, -1, &sym->names))
602 return FALSE;
603 break;
604 case '?':
605 {
606 struct array stack = sym->stack;
607 unsigned int start = sym->names.start;
608 unsigned int num = sym->names.num;
609
610 str_array_init( &sym->stack );
611 if (symbol_demangle( sym )) name = str_printf( sym, "`%s'", sym->result );
612 sym->names.start = start;
613 sym->names.num = num;
614 sym->stack = stack;
615 }
616 break;
617 default:
618 if (!(name = get_number( sym ))) return FALSE;
619 name = str_printf( sym, "`%s'", name );
620 break;
621 }
622 break;
623 default:
625 break;
626 }
627 if (!name || !str_array_push(sym, name, -1, &sym->stack))
628 return FALSE;
629 }
630 sym->current++;
631 return TRUE;
632}
633
634/******************************************************************
635 * get_class_string
636 * From an array collected by get_class in sym->stack, constructs the
637 * corresponding (allocated) string
638 */
639static char* get_class_string(struct parsed_symbol* sym, int start)
640{
641 int i;
642 unsigned int len, sz;
643 char* ret;
644 struct array *a = &sym->stack;
645
646 for (len = 0, i = start; i < a->num; i++)
647 {
648 assert(a->elts[i]);
649 len += 2 + strlen(a->elts[i]);
650 }
651 if (!(ret = und_alloc(sym, len - 1))) return NULL;
652 for (len = 0, i = a->num - 1; i >= start; i--)
653 {
654 sz = strlen(a->elts[i]);
655 memcpy(ret + len, a->elts[i], sz);
656 len += sz;
657 if (i > start)
658 {
659 ret[len++] = ':';
660 ret[len++] = ':';
661 }
662 }
663 ret[len] = '\0';
664 return ret;
665}
666
667/******************************************************************
668 * get_class_name
669 * Wrapper around get_class and get_class_string.
670 */
671static char* get_class_name(struct parsed_symbol* sym)
672{
673 unsigned mark = sym->stack.num;
674 char* s = NULL;
675
676 if (get_class(sym))
677 s = get_class_string(sym, mark);
678 sym->stack.num = mark;
679 return s;
680}
681
682/******************************************************************
683 * get_calling_convention
684 * Returns a static string corresponding to the calling convention described
685 * by char 'ch'. Sets export to TRUE iff the calling convention is exported.
686 */
687static BOOL get_calling_convention(char ch, const char** call_conv,
688 const char** exported, unsigned flags)
689{
690 *call_conv = *exported = NULL;
691
693 {
695 {
696 if (((ch - 'A') % 2) == 1) *exported = "dll_export ";
697 switch (ch)
698 {
699 case 'A': case 'B': *call_conv = "cdecl"; break;
700 case 'C': case 'D': *call_conv = "pascal"; break;
701 case 'E': case 'F': *call_conv = "thiscall"; break;
702 case 'G': case 'H': *call_conv = "stdcall"; break;
703 case 'I': case 'J': *call_conv = "fastcall"; break;
704 case 'K': case 'L': break;
705 case 'M': *call_conv = "clrcall"; break;
706 default: ERR("Unknown calling convention %c\n", ch); return FALSE;
707 }
708 }
709 else
710 {
711 if (((ch - 'A') % 2) == 1) *exported = "__dll_export ";
712 switch (ch)
713 {
714 case 'A': case 'B': *call_conv = "__cdecl"; break;
715 case 'C': case 'D': *call_conv = "__pascal"; break;
716 case 'E': case 'F': *call_conv = "__thiscall"; break;
717 case 'G': case 'H': *call_conv = "__stdcall"; break;
718 case 'I': case 'J': *call_conv = "__fastcall"; break;
719 case 'K': case 'L': break;
720 case 'M': *call_conv = "__clrcall"; break;
721 default: ERR("Unknown calling convention %c\n", ch); return FALSE;
722 }
723 }
724 }
725 return TRUE;
726}
727
728/*******************************************************************
729 * get_simple_type
730 * Return a string containing an allocated string for a simple data type
731 */
732static const char* get_simple_type(char c)
733{
734 const char* type_string;
735
736 switch (c)
737 {
738 case 'C': type_string = "signed char"; break;
739 case 'D': type_string = "char"; break;
740 case 'E': type_string = "unsigned char"; break;
741 case 'F': type_string = "short"; break;
742 case 'G': type_string = "unsigned short"; break;
743 case 'H': type_string = "int"; break;
744 case 'I': type_string = "unsigned int"; break;
745 case 'J': type_string = "long"; break;
746 case 'K': type_string = "unsigned long"; break;
747 case 'M': type_string = "float"; break;
748 case 'N': type_string = "double"; break;
749 case 'O': type_string = "long double"; break;
750 case 'X': type_string = "void"; break;
751 case 'Z': type_string = "..."; break;
752 default: type_string = NULL; break;
753 }
754 return type_string;
755}
756
757/*******************************************************************
758 * get_extended_type
759 * Return a string containing an allocated string for a simple data type
760 */
761static const char* get_extended_type(char c)
762{
763 const char* type_string;
764
765 switch (c)
766 {
767 case 'D': type_string = "__int8"; break;
768 case 'E': type_string = "unsigned __int8"; break;
769 case 'F': type_string = "__int16"; break;
770 case 'G': type_string = "unsigned __int16"; break;
771 case 'H': type_string = "__int32"; break;
772 case 'I': type_string = "unsigned __int32"; break;
773 case 'J': type_string = "__int64"; break;
774 case 'K': type_string = "unsigned __int64"; break;
775 case 'L': type_string = "__int128"; break;
776 case 'M': type_string = "unsigned __int128"; break;
777 case 'N': type_string = "bool"; break;
778 case 'W': type_string = "wchar_t"; break;
779 default: type_string = NULL; break;
780 }
781 return type_string;
782}
783
784/*******************************************************************
785 * demangle_datatype
786 *
787 * Attempt to demangle a C++ data type, which may be datatype.
788 * a datatype type is made up of a number of simple types. e.g:
789 * char** = (pointer to (pointer to (char)))
790 */
791static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
792 struct array* pmt_ref, BOOL in_args)
793{
794 char dt;
795 BOOL add_pmt = TRUE;
796
797 assert(ct);
798 ct->left = ct->right = NULL;
799
800 switch (dt = *sym->current++)
801 {
802 case '_':
803 /* MS type: __int8,__int16 etc */
804 ct->left = get_extended_type(*sym->current++);
805 break;
806 case 'C': case 'D': case 'E': case 'F': case 'G':
807 case 'H': case 'I': case 'J': case 'K': case 'M':
808 case 'N': case 'O': case 'X': case 'Z':
809 /* Simple data types */
810 ct->left = get_simple_type(dt);
811 add_pmt = FALSE;
812 break;
813 case 'T': /* union */
814 case 'U': /* struct */
815 case 'V': /* class */
816 case 'Y': /* cointerface */
817 /* Class/struct/union/cointerface */
818 {
819 const char* struct_name = NULL;
820 const char* type_name = NULL;
821
822 if (!(struct_name = get_class_name(sym)))
823 goto done;
824 if (!(sym->flags & UNDNAME_NO_COMPLEX_TYPE))
825 {
826 switch (dt)
827 {
828 case 'T': type_name = "union "; break;
829 case 'U': type_name = "struct "; break;
830 case 'V': type_name = "class "; break;
831 case 'Y': type_name = "cointerface "; break;
832 }
833 }
834 ct->left = str_printf(sym, "%s%s", type_name, struct_name);
835 }
836 break;
837 case '?':
838 /* not all the time is seems */
839 if (in_args)
840 {
841 const char* ptr;
842 if (!(ptr = get_number(sym))) goto done;
843 ct->left = str_printf(sym, "`template-parameter-%s'", ptr);
844 }
845 else
846 {
847 if (!get_modified_type(ct, sym, pmt_ref, '?', in_args)) goto done;
848 }
849 break;
850 case 'A': /* reference */
851 case 'B': /* volatile reference */
852 if (!get_modified_type(ct, sym, pmt_ref, dt, in_args)) goto done;
853 break;
854 case 'Q': /* const pointer */
855 case 'R': /* volatile pointer */
856 case 'S': /* const volatile pointer */
857 if (!get_modified_type(ct, sym, pmt_ref, in_args ? dt : 'P', in_args)) goto done;
858 break;
859 case 'P': /* Pointer */
860 if (isdigit(*sym->current))
861 {
862 /* FIXME:
863 * P6 = Function pointer
864 * P8 = Member function pointer
865 * others who knows.. */
866 if (*sym->current == '8')
867 {
868 char* args = NULL;
869 const char* call_conv;
870 const char* exported;
871 struct datatype_t sub_ct;
872 unsigned mark = sym->stack.num;
873 const char* class;
874 const char* modifier;
875 const char* ptr_modif;
876
877 sym->current++;
878
879 if (!(class = get_class_name(sym)))
880 goto done;
881 if (!get_modifier(sym, &modifier, &ptr_modif))
882 goto done;
883 if (modifier)
884 modifier = str_printf(sym, "%s %s", modifier, ptr_modif);
885 else if(ptr_modif[0])
886 modifier = str_printf(sym, " %s", ptr_modif);
887 if (!get_calling_convention(*sym->current++,
888 &call_conv, &exported,
890 goto done;
891 if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
892 goto done;
893
894 args = get_args(sym, pmt_ref, TRUE, '(', ')');
895 if (!args) goto done;
896 sym->stack.num = mark;
897
898 ct->left = str_printf(sym, "%s%s (%s %s::*",
899 sub_ct.left, sub_ct.right, call_conv, class);
900 ct->right = str_printf(sym, ")%s%s", args, modifier);
901 }
902 else if (*sym->current == '6')
903 {
904 char* args = NULL;
905 const char* call_conv;
906 const char* exported;
907 struct datatype_t sub_ct;
908 unsigned mark = sym->stack.num;
909
910 sym->current++;
911
912 if (!get_calling_convention(*sym->current++,
913 &call_conv, &exported,
915 !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
916 goto done;
917
918 args = get_args(sym, pmt_ref, TRUE, '(', ')');
919 if (!args) goto done;
920 sym->stack.num = mark;
921
922 ct->left = str_printf(sym, "%s%s (%s*",
923 sub_ct.left, sub_ct.right, call_conv);
924 ct->right = str_printf(sym, ")%s", args);
925 }
926 else goto done;
927 }
928 else if (!get_modified_type(ct, sym, pmt_ref, 'P', in_args)) goto done;
929 break;
930 case 'W':
931 if (*sym->current == '4')
932 {
933 char* enum_name;
934 sym->current++;
935 if (!(enum_name = get_class_name(sym)))
936 goto done;
938 ct->left = enum_name;
939 else
940 ct->left = str_printf(sym, "enum %s", enum_name);
941 }
942 else goto done;
943 break;
944 case '0': case '1': case '2': case '3': case '4':
945 case '5': case '6': case '7': case '8': case '9':
946 /* Referring back to previously parsed type */
947 /* left and right are pushed as two separate strings */
948 if (!pmt_ref) goto done;
949 ct->left = str_array_get_ref(pmt_ref, (dt - '0') * 2);
950 ct->right = str_array_get_ref(pmt_ref, (dt - '0') * 2 + 1);
951 if (!ct->left) goto done;
952 add_pmt = FALSE;
953 break;
954 case '$':
955 switch (*sym->current++)
956 {
957 case '0':
958 if (!(ct->left = get_number(sym))) goto done;
959 break;
960 case 'D':
961 {
962 const char* ptr;
963 if (!(ptr = get_number(sym))) goto done;
964 ct->left = str_printf(sym, "`template-parameter%s'", ptr);
965 }
966 break;
967 case 'F':
968 {
969 const char* p1;
970 const char* p2;
971 if (!(p1 = get_number(sym))) goto done;
972 if (!(p2 = get_number(sym))) goto done;
973 ct->left = str_printf(sym, "{%s,%s}", p1, p2);
974 }
975 break;
976 case 'G':
977 {
978 const char* p1;
979 const char* p2;
980 const char* p3;
981 if (!(p1 = get_number(sym))) goto done;
982 if (!(p2 = get_number(sym))) goto done;
983 if (!(p3 = get_number(sym))) goto done;
984 ct->left = str_printf(sym, "{%s,%s,%s}", p1, p2, p3);
985 }
986 break;
987 case 'Q':
988 {
989 const char* ptr;
990 if (!(ptr = get_number(sym))) goto done;
991 ct->left = str_printf(sym, "`non-type-template-parameter%s'", ptr);
992 }
993 break;
994 case '$':
995 if (*sym->current == 'B')
996 {
997 unsigned mark = sym->stack.num;
998 struct datatype_t sub_ct;
999 const char* arr = NULL;
1000 sym->current++;
1001
1002 /* multidimensional arrays */
1003 if (*sym->current == 'Y')
1004 {
1005 const char* n1;
1006 int num;
1007
1008 sym->current++;
1009 if (!(n1 = get_number(sym))) goto done;
1010 num = atoi(n1);
1011
1012 while (num--)
1013 arr = str_printf(sym, "%s[%s]", arr, get_number(sym));
1014 }
1015
1016 if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE)) goto done;
1017
1018 if (arr)
1019 ct->left = str_printf(sym, "%s %s", sub_ct.left, arr);
1020 else
1021 ct->left = sub_ct.left;
1022 ct->right = sub_ct.right;
1023 sym->stack.num = mark;
1024 }
1025 else if (*sym->current == 'C')
1026 {
1027 const char *ptr, *ptr_modif;
1028
1029 sym->current++;
1030 if (!get_modifier(sym, &ptr, &ptr_modif)) goto done;
1031 if (!demangle_datatype(sym, ct, pmt_ref, in_args)) goto done;
1032 ct->left = str_printf(sym, "%s %s", ct->left, ptr);
1033 }
1034 break;
1035 }
1036 break;
1037 default :
1038 ERR("Unknown type %c\n", dt);
1039 break;
1040 }
1041 if (add_pmt && pmt_ref && in_args)
1042 {
1043 /* left and right are pushed as two separate strings */
1044 if (!str_array_push(sym, ct->left ? ct->left : "", -1, pmt_ref) ||
1045 !str_array_push(sym, ct->right ? ct->right : "", -1, pmt_ref))
1046 return FALSE;
1047 }
1048done:
1049
1050 return ct->left != NULL;
1051}
1052
1053/******************************************************************
1054 * handle_data
1055 * Does the final parsing and handling for a variable or a field in
1056 * a class.
1057 */
1058static BOOL handle_data(struct parsed_symbol* sym)
1059{
1060 const char* access = NULL;
1061 const char* member_type = NULL;
1062 const char* modifier = NULL;
1063 const char* ptr_modif;
1064 struct datatype_t ct;
1065 char* name = NULL;
1066 BOOL ret = FALSE;
1067
1068 /* 0 private static
1069 * 1 protected static
1070 * 2 public static
1071 * 3 private non-static
1072 * 4 protected non-static
1073 * 5 public non-static
1074 * 6 ?? static
1075 * 7 ?? static
1076 */
1077
1078 if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
1079 {
1080 /* we only print the access for static members */
1081 switch (*sym->current)
1082 {
1083 case '0': access = "private: "; break;
1084 case '1': access = "protected: "; break;
1085 case '2': access = "public: "; break;
1086 }
1087 }
1088
1089 if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
1090 {
1091 if (*sym->current >= '0' && *sym->current <= '2')
1092 member_type = "static ";
1093 }
1094
1095 name = get_class_string(sym, 0);
1096
1097 switch (*sym->current++)
1098 {
1099 case '0': case '1': case '2':
1100 case '3': case '4': case '5':
1101 {
1102 unsigned mark = sym->stack.num;
1103 struct array pmt;
1104
1105 str_array_init(&pmt);
1106
1107 if (!demangle_datatype(sym, &ct, &pmt, FALSE)) goto done;
1108 if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;
1109 if (modifier && ptr_modif) modifier = str_printf(sym, "%s %s", modifier, ptr_modif);
1110 else if (!modifier) modifier = ptr_modif;
1111 sym->stack.num = mark;
1112 }
1113 break;
1114 case '6' : /* compiler generated static */
1115 case '7' : /* compiler generated static */
1116 ct.left = ct.right = NULL;
1117 if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;
1118 if (*sym->current != '@')
1119 {
1120 char* cls = NULL;
1121
1122 if (!(cls = get_class_name(sym)))
1123 goto done;
1124 ct.right = str_printf(sym, "{for `%s'}", cls);
1125 }
1126 break;
1127 case '8':
1128 case '9':
1129 modifier = ct.left = ct.right = NULL;
1130 break;
1131 default: goto done;
1132 }
1133 if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = modifier = NULL;
1134
1135 sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s", access,
1136 member_type, ct.left,
1137 modifier && ct.left ? " " : NULL, modifier,
1138 modifier || ct.left ? " " : NULL, name, ct.right);
1139 ret = TRUE;
1140done:
1141 return ret;
1142}
1143
1144/******************************************************************
1145 * handle_method
1146 * Does the final parsing and handling for a function or a method in
1147 * a class.
1148 */
1149static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op)
1150{
1151 char accmem;
1152 const char* access = NULL;
1153 int access_id = -1;
1154 const char* member_type = NULL;
1155 struct datatype_t ct_ret;
1156 const char* call_conv;
1157 const char* modifier = NULL;
1158 const char* exported;
1159 const char* args_str = NULL;
1160 const char* name = NULL;
1161 BOOL ret = FALSE, has_args = TRUE, has_ret = TRUE;
1162 unsigned mark;
1163 struct array array_pmt;
1164
1165 /* FIXME: why 2 possible letters for each option?
1166 * 'A' private:
1167 * 'B' private:
1168 * 'C' private: static
1169 * 'D' private: static
1170 * 'E' private: virtual
1171 * 'F' private: virtual
1172 * 'G' private: thunk
1173 * 'H' private: thunk
1174 * 'I' protected:
1175 * 'J' protected:
1176 * 'K' protected: static
1177 * 'L' protected: static
1178 * 'M' protected: virtual
1179 * 'N' protected: virtual
1180 * 'O' protected: thunk
1181 * 'P' protected: thunk
1182 * 'Q' public:
1183 * 'R' public:
1184 * 'S' public: static
1185 * 'T' public: static
1186 * 'U' public: virtual
1187 * 'V' public: virtual
1188 * 'W' public: thunk
1189 * 'X' public: thunk
1190 * 'Y'
1191 * 'Z'
1192 * "$0" private: thunk vtordisp
1193 * "$1" private: thunk vtordisp
1194 * "$2" protected: thunk vtordisp
1195 * "$3" protected: thunk vtordisp
1196 * "$4" public: thunk vtordisp
1197 * "$5" public: thunk vtordisp
1198 * "$B" vcall thunk
1199 * "$R" thunk vtordispex
1200 */
1201 accmem = *sym->current++;
1202 if (accmem == '$')
1203 {
1204 if (*sym->current >= '0' && *sym->current <= '5')
1205 access_id = (*sym->current - '0') / 2;
1206 else if (*sym->current == 'R')
1207 access_id = (sym->current[1] - '0') / 2;
1208 else if (*sym->current != 'B')
1209 goto done;
1210 }
1211 else if (accmem >= 'A' && accmem <= 'Z')
1212 access_id = (accmem - 'A') / 8;
1213 else
1214 goto done;
1215
1216 switch (access_id)
1217 {
1218 case 0: access = "private: "; break;
1219 case 1: access = "protected: "; break;
1220 case 2: access = "public: "; break;
1221 }
1222 if (accmem == '$' || (accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7)
1223 access = str_printf(sym, "[thunk]:%s", access ? access : " ");
1224
1225 if (accmem == '$' && *sym->current != 'B')
1226 member_type = "virtual ";
1227 else if (accmem <= 'X')
1228 {
1229 switch ((accmem - 'A') % 8)
1230 {
1231 case 2: case 3: member_type = "static "; break;
1232 case 4: case 5: case 6: case 7: member_type = "virtual "; break;
1233 }
1234 }
1235
1237 access = NULL;
1238 if (sym->flags & UNDNAME_NO_MEMBER_TYPE)
1239 member_type = NULL;
1240
1241 name = get_class_string(sym, 0);
1242
1243 if (accmem == '$' && *sym->current == 'B') /* vcall thunk */
1244 {
1245 const char *n;
1246
1247 sym->current++;
1248 n = get_number(sym);
1249
1250 if(!n || *sym->current++ != 'A') goto done;
1251 name = str_printf(sym, "%s{%s,{flat}}' }'", name, n);
1252 has_args = FALSE;
1253 has_ret = FALSE;
1254 }
1255 else if (accmem == '$' && *sym->current == 'R') /* vtordispex thunk */
1256 {
1257 const char *n1, *n2, *n3, *n4;
1258
1259 sym->current += 2;
1260 n1 = get_number(sym);
1261 n2 = get_number(sym);
1262 n3 = get_number(sym);
1263 n4 = get_number(sym);
1264
1265 if(!n1 || !n2 || !n3 || !n4) goto done;
1266 name = str_printf(sym, "%s`vtordispex{%s,%s,%s,%s}' ", name, n1, n2, n3, n4);
1267 }
1268 else if (accmem == '$') /* vtordisp thunk */
1269 {
1270 const char *n1, *n2;
1271
1272 sym->current++;
1273 n1 = get_number(sym);
1274 n2 = get_number(sym);
1275
1276 if (!n1 || !n2) goto done;
1277 name = str_printf(sym, "%s`vtordisp{%s,%s}' ", name, n1, n2);
1278 }
1279 else if ((accmem - 'A') % 8 == 6 || (accmem - 'A') % 8 == 7) /* a thunk */
1280 name = str_printf(sym, "%s`adjustor{%s}' ", name, get_number(sym));
1281
1282 if (has_args && (accmem == '$' ||
1283 (accmem <= 'X' && (accmem - 'A') % 8 != 2 && (accmem - 'A') % 8 != 3)))
1284 {
1285 const char *ptr_modif;
1286 /* Implicit 'this' pointer */
1287 /* If there is an implicit this pointer, const modifier follows */
1288 if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;
1289 if (modifier || ptr_modif) modifier = str_printf(sym, "%s %s", modifier, ptr_modif);
1290 }
1291
1292 if (!get_calling_convention(*sym->current++, &call_conv, &exported,
1293 sym->flags))
1294 goto done;
1295
1296 str_array_init(&array_pmt);
1297
1298 /* Return type, or @ if 'void' */
1299 if (has_ret && *sym->current == '@')
1300 {
1301 ct_ret.left = "void";
1302 ct_ret.right = NULL;
1303 sym->current++;
1304 }
1305 else if (has_ret)
1306 {
1307 if (!demangle_datatype(sym, &ct_ret, &array_pmt, FALSE))
1308 goto done;
1309 }
1310 if (!has_ret || sym->flags & UNDNAME_NO_FUNCTION_RETURNS)
1311 ct_ret.left = ct_ret.right = NULL;
1312 if (cast_op)
1313 {
1314 name = str_printf(sym, "%s%s%s", name, ct_ret.left, ct_ret.right);
1315 ct_ret.left = ct_ret.right = NULL;
1316 }
1317
1318 mark = sym->stack.num;
1319 if (has_args && !(args_str = get_args(sym, &array_pmt, TRUE, '(', ')'))) goto done;
1320 if (sym->flags & UNDNAME_NAME_ONLY) args_str = modifier = NULL;
1321 if (sym->flags & UNDNAME_NO_THISTYPE) modifier = NULL;
1322 sym->stack.num = mark;
1323
1324 /* Note: '()' after 'Z' means 'throws', but we don't care here
1325 * Yet!!! FIXME
1326 */
1327 sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s%s%s%s",
1328 access, member_type, ct_ret.left,
1329 (ct_ret.left && !ct_ret.right) ? " " : NULL,
1330 call_conv, call_conv ? " " : NULL, exported,
1331 name, args_str, modifier, ct_ret.right);
1332 ret = TRUE;
1333done:
1334 return ret;
1335}
1336
1337/*******************************************************************
1338 * symbol_demangle
1339 * Demangle a C++ linker symbol
1340 */
1342{
1343 BOOL ret = FALSE;
1344 unsigned do_after = 0;
1345 static CHAR dashed_null[] = "--null--";
1346
1347 /* FIXME seems wrong as name, as it demangles a simple data type */
1348 if (sym->flags & UNDNAME_NO_ARGUMENTS)
1349 {
1350 struct datatype_t ct;
1351
1352 if (demangle_datatype(sym, &ct, NULL, FALSE))
1353 {
1354 sym->result = str_printf(sym, "%s%s", ct.left, ct.right);
1355 ret = TRUE;
1356 }
1357 goto done;
1358 }
1359
1360 /* MS mangled names always begin with '?' */
1361 if (*sym->current != '?') return FALSE;
1362 sym->current++;
1363
1364 /* Then function name or operator code */
1365 if (*sym->current == '?' && (sym->current[1] != '$' || sym->current[2] == '?'))
1366 {
1367 const char* function_name = NULL;
1368
1369 if (sym->current[1] == '$')
1370 {
1371 do_after = 6;
1372 sym->current += 2;
1373 }
1374
1375 /* C++ operator code (one character, or two if the first is '_') */
1376 switch (*++sym->current)
1377 {
1378 case '0': do_after = 1; break;
1379 case '1': do_after = 2; break;
1380 case '2': function_name = "operator new"; break;
1381 case '3': function_name = "operator delete"; break;
1382 case '4': function_name = "operator="; break;
1383 case '5': function_name = "operator>>"; break;
1384 case '6': function_name = "operator<<"; break;
1385 case '7': function_name = "operator!"; break;
1386 case '8': function_name = "operator=="; break;
1387 case '9': function_name = "operator!="; break;
1388 case 'A': function_name = "operator[]"; break;
1389 case 'B': function_name = "operator "; do_after = 3; break;
1390 case 'C': function_name = "operator->"; break;
1391 case 'D': function_name = "operator*"; break;
1392 case 'E': function_name = "operator++"; break;
1393 case 'F': function_name = "operator--"; break;
1394 case 'G': function_name = "operator-"; break;
1395 case 'H': function_name = "operator+"; break;
1396 case 'I': function_name = "operator&"; break;
1397 case 'J': function_name = "operator->*"; break;
1398 case 'K': function_name = "operator/"; break;
1399 case 'L': function_name = "operator%"; break;
1400 case 'M': function_name = "operator<"; break;
1401 case 'N': function_name = "operator<="; break;
1402 case 'O': function_name = "operator>"; break;
1403 case 'P': function_name = "operator>="; break;
1404 case 'Q': function_name = "operator,"; break;
1405 case 'R': function_name = "operator()"; break;
1406 case 'S': function_name = "operator~"; break;
1407 case 'T': function_name = "operator^"; break;
1408 case 'U': function_name = "operator|"; break;
1409 case 'V': function_name = "operator&&"; break;
1410 case 'W': function_name = "operator||"; break;
1411 case 'X': function_name = "operator*="; break;
1412 case 'Y': function_name = "operator+="; break;
1413 case 'Z': function_name = "operator-="; break;
1414 case '_':
1415 switch (*++sym->current)
1416 {
1417 case '0': function_name = "operator/="; break;
1418 case '1': function_name = "operator%="; break;
1419 case '2': function_name = "operator>>="; break;
1420 case '3': function_name = "operator<<="; break;
1421 case '4': function_name = "operator&="; break;
1422 case '5': function_name = "operator|="; break;
1423 case '6': function_name = "operator^="; break;
1424 case '7': function_name = "`vftable'"; break;
1425 case '8': function_name = "`vbtable'"; break;
1426 case '9': function_name = "`vcall'"; break;
1427 case 'A': function_name = "`typeof'"; break;
1428 case 'B': function_name = "`local static guard'"; break;
1429 case 'C': function_name = "`string'"; do_after = 4; break;
1430 case 'D': function_name = "`vbase destructor'"; break;
1431 case 'E': function_name = "`vector deleting destructor'"; break;
1432 case 'F': function_name = "`default constructor closure'"; break;
1433 case 'G': function_name = "`scalar deleting destructor'"; break;
1434 case 'H': function_name = "`vector constructor iterator'"; break;
1435 case 'I': function_name = "`vector destructor iterator'"; break;
1436 case 'J': function_name = "`vector vbase constructor iterator'"; break;
1437 case 'K': function_name = "`virtual displacement map'"; break;
1438 case 'L': function_name = "`eh vector constructor iterator'"; break;
1439 case 'M': function_name = "`eh vector destructor iterator'"; break;
1440 case 'N': function_name = "`eh vector vbase constructor iterator'"; break;
1441 case 'O': function_name = "`copy constructor closure'"; break;
1442 case 'R':
1444 switch (*++sym->current)
1445 {
1446 case '0':
1447 {
1448 struct datatype_t ct;
1449 struct array pmt;
1450
1451 sym->current++;
1452 str_array_init(&pmt);
1453 demangle_datatype(sym, &ct, &pmt, FALSE);
1454 if (!demangle_datatype(sym, &ct, NULL, FALSE))
1455 goto done;
1456 function_name = str_printf(sym, "%s%s `RTTI Type Descriptor'",
1457 ct.left, ct.right);
1458 sym->current--;
1459 }
1460 break;
1461 case '1':
1462 {
1463 const char* n1, *n2, *n3, *n4;
1464 sym->current++;
1465 n1 = get_number(sym);
1466 n2 = get_number(sym);
1467 n3 = get_number(sym);
1468 n4 = get_number(sym);
1469 sym->current--;
1470 function_name = str_printf(sym, "`RTTI Base Class Descriptor at (%s,%s,%s,%s)'",
1471 n1, n2, n3, n4);
1472 }
1473 break;
1474 case '2': function_name = "`RTTI Base Class Array'"; break;
1475 case '3': function_name = "`RTTI Class Hierarchy Descriptor'"; break;
1476 case '4': function_name = "`RTTI Complete Object Locator'"; break;
1477 default:
1478 ERR("Unknown RTTI operator: _R%c\n", *sym->current);
1479 break;
1480 }
1481 break;
1482 case 'S': function_name = "`local vftable'"; break;
1483 case 'T': function_name = "`local vftable constructor closure'"; break;
1484 case 'U': function_name = "operator new[]"; break;
1485 case 'V': function_name = "operator delete[]"; break;
1486 case 'X': function_name = "`placement delete closure'"; break;
1487 case 'Y': function_name = "`placement delete[] closure'"; break;
1488 default:
1489 ERR("Unknown operator: _%c\n", *sym->current);
1490 return FALSE;
1491 }
1492 break;
1493 default:
1494 /* FIXME: Other operators */
1495 ERR("Unknown operator: %c\n", *sym->current);
1496 return FALSE;
1497 }
1498 sym->current++;
1499 switch (do_after)
1500 {
1501 case 1: case 2:
1502 if (!str_array_push(sym, dashed_null, -1, &sym->stack))
1503 return FALSE;
1504 break;
1505 case 4:
1506 sym->result = (char*)function_name;
1507 ret = TRUE;
1508 goto done;
1509 case 6:
1510 {
1511 char *args;
1512 struct array array_pmt;
1513
1514 str_array_init(&array_pmt);
1515 args = get_args(sym, &array_pmt, FALSE, '<', '>');
1516 if (args != NULL) function_name = str_printf(sym, "%s%s", function_name, args);
1517 sym->names.num = 0;
1518 }
1519 /* fall through */
1520 default:
1521 if (!str_array_push(sym, function_name, -1, &sym->stack))
1522 return FALSE;
1523 break;
1524 }
1525 }
1526 else if (*sym->current == '$')
1527 {
1528 /* Strange construct, it's a name with a template argument list
1529 and that's all. */
1530 sym->current++;
1531 ret = (sym->result = get_template_name(sym)) != NULL;
1532 goto done;
1533 }
1534 else if (*sym->current == '?' && sym->current[1] == '$')
1535 do_after = 5;
1536
1537 /* Either a class name, or '@' if the symbol is not a class member */
1538 switch (*sym->current)
1539 {
1540 case '@': sym->current++; break;
1541 case '$': break;
1542 default:
1543 /* Class the function is associated with, terminated by '@@' */
1544 if (!get_class(sym)) goto done;
1545 break;
1546 }
1547
1548 switch (do_after)
1549 {
1550 case 0: default: break;
1551 case 1: case 2:
1552 /* it's time to set the member name for ctor & dtor */
1553 if (sym->stack.num <= 1) goto done;
1554 if (do_after == 1)
1555 sym->stack.elts[0] = sym->stack.elts[1];
1556 else
1557 sym->stack.elts[0] = str_printf(sym, "~%s", sym->stack.elts[1]);
1558 /* ctors and dtors don't have return type */
1560 break;
1561 case 3:
1562 sym->flags &= ~UNDNAME_NO_FUNCTION_RETURNS;
1563 break;
1564 case 5:
1565 sym->names.start++;
1566 break;
1567 }
1568
1569 /* Function/Data type and access level */
1570 if (*sym->current >= '0' && *sym->current <= '9')
1571 ret = handle_data(sym);
1572 else if ((*sym->current >= 'A' && *sym->current <= 'Z') || *sym->current == '$')
1573 ret = handle_method(sym, do_after == 3);
1574 else ret = FALSE;
1575done:
1576 if (ret) assert(sym->result);
1577 else WARN("Failed at %s\n", debugstr_a(sym->current));
1578
1579 return ret;
1580}
1581
1582/*********************************************************************
1583 * __unDNameEx (MSVCRT.@)
1584 *
1585 * Demangle a C++ identifier.
1586 *
1587 * PARAMS
1588 * buffer [O] If not NULL, the place to put the demangled string
1589 * mangled [I] Mangled name of the function
1590 * buflen [I] Length of buffer
1591 * memget [I] Function to allocate memory with
1592 * memfree [I] Function to free memory with
1593 * unknown [?] Unknown, possibly a call back
1594 * flags [I] Flags determining demangled format
1595 *
1596 * RETURNS
1597 * Success: A string pointing to the unmangled name, allocated with memget.
1598 * Failure: NULL.
1599 */
1600char* CDECL __unDNameEx(char* buffer, const char* mangled, int buflen,
1601 malloc_func_t memget, free_func_t memfree,
1602 void* unknown, unsigned short int flags)
1603{
1604 struct parsed_symbol sym;
1605 const char* result;
1606
1607 TRACE("(%p,%s,%d,%p,%p,%p,%x)\n",
1608 buffer, debugstr_a(mangled), buflen, memget, memfree, unknown, flags);
1609
1610 /* The flags details is not documented by MS. However, it looks exactly
1611 * like the UNDNAME_ manifest constants from imagehlp.h and dbghelp.h
1612 * So, we copied those (on top of the file)
1613 */
1614 memset(&sym, 0, sizeof(struct parsed_symbol));
1619
1620 sym.flags = flags;
1621 sym.mem_alloc_ptr = memget;
1622 sym.mem_free_ptr = memfree;
1623 sym.current = mangled;
1624 str_array_init( &sym.names );
1625 str_array_init( &sym.stack );
1626
1627 result = symbol_demangle(&sym) ? sym.result : mangled;
1628 if (buffer && buflen)
1629 {
1630 lstrcpynA( buffer, result, buflen);
1631 }
1632 else
1633 {
1634 buffer = memget(strlen(result) + 1);
1635 if (buffer) strcpy(buffer, result);
1636 }
1637
1638 und_free_all(&sym);
1639
1640 return buffer;
1641}
1642
1643
1644/*********************************************************************
1645 * __unDName (MSVCRT.@)
1646 */
1647char* CDECL __unDName(char* buffer, const char* mangled, int buflen,
1648 malloc_func_t memget, free_func_t memfree,
1649 unsigned short int flags)
1650{
1651 return __unDNameEx(buffer, mangled, buflen, memget, memfree, NULL, flags);
1652}
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define isdigit(c)
Definition: acclib.h:68
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define va_arg(ap, T)
Definition: acmsvcex.h:89
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
Definition: _stack.h:55
#define UNDNAME_NO_MS_KEYWORDS
Definition: dbghelp.h:1253
#define UNDNAME_NO_THISTYPE
Definition: dbghelp.h:1259
#define UNDNAME_NO_LEADING_UNDERSCORES
Definition: dbghelp.h:1252
#define UNDNAME_NO_ALLOCATION_LANGUAGE
Definition: dbghelp.h:1256
#define UNDNAME_NO_ARGUMENTS
Definition: dbghelp.h:1266
#define UNDNAME_NO_FUNCTION_RETURNS
Definition: dbghelp.h:1254
#define UNDNAME_NO_ACCESS_SPECIFIERS
Definition: dbghelp.h:1260
#define UNDNAME_NO_MEMBER_TYPE
Definition: dbghelp.h:1262
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int idx
Definition: utils.c:41
static WCHAR unknown[MAX_STRING_RESOURCE_LEN]
Definition: object.c:1605
#define CDECL
Definition: compat.h:29
#define lstrcpynA
Definition: compat.h:751
#define UNDNAME_NAME_ONLY
Definition: compat.h:1017
unsigned char
Definition: typeof.h:29
#define assert(x)
Definition: debug.h:53
unsigned int BOOL
Definition: ntddk_ex.h:94
GLuint start
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLdouble GLdouble t
Definition: gl.h:2047
GLdouble n
Definition: glext.h:7729
GLuint GLuint * names
Definition: glext.h:11545
GLuint buffer
Definition: glext.h:5915
const GLubyte * c
Definition: glext.h:8905
GLbitfield flags
Definition: glext.h:7161
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLuint64EXT * result
Definition: glext.h:11304
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static char close_char
Definition: i386-dis.c:2054
static char open_char
Definition: i386-dis.c:2053
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define c
Definition: ke_i.h:80
#define debugstr_a
Definition: kernel32.h:31
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static PVOID ptr
Definition: dispmode.c:27
#define sprintf(buf, format,...)
Definition: sprintf.c:55
static UINT UINT last
Definition: font.c:45
void *(__cdecl * malloc_func_t)(MSVCRT_size_t)
Definition: msvcrt.h:227
void(__cdecl * free_func_t)(void *)
Definition: msvcrt.h:228
static unsigned __int64 next
Definition: rand_nt.c:6
int n4
Definition: dwarfget.c:147
int n2
Definition: dwarfget.c:147
int n1
Definition: dwarfget.c:147
int n3
Definition: dwarfget.c:147
#define UNDNAME_NO_COMPLEX_TYPE
Definition: msvcrt.h:140
#define memset(x, y, z)
Definition: compat.h:39
#define args
Definition: format.c:66
#define TRACE(s)
Definition: solgame.cpp:4
Definition: match.c:390
unsigned num
Definition: undname.c:60
unsigned alloc
Definition: undname.c:62
char ** elts
Definition: undname.c:63
unsigned start
Definition: undname.c:59
unsigned max
Definition: undname.c:61
const char * right
Definition: undname.c:87
const char * left
Definition: undname.c:86
Definition: name.c:39
void * alloc_list
Definition: undname.c:79
malloc_func_t mem_alloc_ptr
Definition: undname.c:70
unsigned flags
Definition: undname.c:69
struct array stack
Definition: undname.c:77
const char * current
Definition: undname.c:73
char * result
Definition: undname.c:74
unsigned avail_in_first
Definition: undname.c:80
free_func_t mem_free_ptr
Definition: undname.c:71
struct array names
Definition: undname.c:76
static void und_free_all(struct parsed_symbol *sym)
Definition: undname.c:141
static BOOL demangle_datatype(struct parsed_symbol *sym, struct datatype_t *ct, struct array *pmt, BOOL in_args)
Definition: undname.c:791
static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol *sym, struct array *pmt_ref, char modif, BOOL in_args)
Definition: undname.c:428
static const char * get_number(struct parsed_symbol *sym)
Definition: undname.c:295
static char * str_printf(struct parsed_symbol *sym, const char *format,...)
Definition: undname.c:236
static BOOL get_modifier(struct parsed_symbol *sym, const char **ret, const char **ptr_modif)
Definition: undname.c:404
static BOOL symbol_demangle(struct parsed_symbol *sym)
Definition: undname.c:1341
static char * get_args(struct parsed_symbol *sym, struct array *pmt_ref, BOOL z_term, char open_char, char close_char)
Definition: undname.c:346
static BOOL get_calling_convention(char ch, const char **call_conv, const char **exported, unsigned flags)
Definition: undname.c:687
static void str_array_init(struct array *a)
Definition: undname.c:158
static char * get_literal_string(struct parsed_symbol *sym)
Definition: undname.c:514
#define AVAIL_SIZE
static BOOL str_array_push(struct parsed_symbol *sym, const char *ptr, int len, struct array *a)
Definition: undname.c:168
static BOOL get_class(struct parsed_symbol *sym)
Definition: undname.c:580
static const char * get_extended_type(char c)
Definition: undname.c:761
char *CDECL __unDNameEx(char *buffer, const char *mangled, int buflen, malloc_func_t memget, free_func_t memfree, void *unknown, unsigned short int flags)
Definition: undname.c:1600
static char * get_class_string(struct parsed_symbol *sym, int start)
Definition: undname.c:639
static BOOL handle_method(struct parsed_symbol *sym, BOOL cast_op)
Definition: undname.c:1149
static char * get_template_name(struct parsed_symbol *sym)
Definition: undname.c:544
static void * und_alloc(struct parsed_symbol *sym, unsigned int len)
Definition: undname.c:99
static char * str_array_get_ref(struct array *cref, unsigned idx)
Definition: undname.c:217
static const char * get_simple_type(char c)
Definition: undname.c:732
#define BLOCK_SIZE
static char * get_class_name(struct parsed_symbol *sym)
Definition: undname.c:671
char *CDECL __unDName(char *buffer, const char *mangled, int buflen, malloc_func_t memget, free_func_t memfree, unsigned short int flags)
Definition: undname.c:1647
static BOOL handle_data(struct parsed_symbol *sym)
Definition: undname.c:1058
long sgn(REAL x)
Definition: varray.cc:48
int ret
char CHAR
Definition: xmlstorage.h:175