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