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