msvcrt: Misc cleanups in undname.c.
[wine/hacks.git] / dlls / msvcrt / undname.c
blobd2e7668359dac7c45ee4a76507d9c0c06972d8f7
1 /*
2 * Demangle VC++ symbols into C function prototypes
4 * Copyright 2000 Jon Griffiths
5 * 2004 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <assert.h>
26 #include <stdio.h>
27 #include "msvcrt.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
33 /* TODO:
34 * - document a bit (grammar + functions)
35 * - back-port this new code into tools/winedump/msmangle.c
38 #define UNDNAME_COMPLETE (0x0000)
39 #define UNDNAME_NO_LEADING_UNDERSCORES (0x0001) /* Don't show __ in calling convention */
40 #define UNDNAME_NO_MS_KEYWORDS (0x0002) /* Don't show calling convention at all */
41 #define UNDNAME_NO_FUNCTION_RETURNS (0x0004) /* Don't show function/method return value */
42 #define UNDNAME_NO_ALLOCATION_MODEL (0x0008)
43 #define UNDNAME_NO_ALLOCATION_LANGUAGE (0x0010)
44 #define UNDNAME_NO_MS_THISTYPE (0x0020)
45 #define UNDNAME_NO_CV_THISTYPE (0x0040)
46 #define UNDNAME_NO_THISTYPE (0x0060)
47 #define UNDNAME_NO_ACCESS_SPECIFIERS (0x0080) /* Don't show access specifier (public/protected/private) */
48 #define UNDNAME_NO_THROW_SIGNATURES (0x0100)
49 #define UNDNAME_NO_MEMBER_TYPE (0x0200) /* Don't show static/virtual specifier */
50 #define UNDNAME_NO_RETURN_UDT_MODEL (0x0400)
51 #define UNDNAME_32_BIT_DECODE (0x0800)
52 #define UNDNAME_NAME_ONLY (0x1000) /* Only report the variable/method name */
53 #define UNDNAME_NO_ARGUMENTS (0x2000) /* Don't show method arguments */
54 #define UNDNAME_NO_SPECIAL_SYMS (0x4000)
55 #define UNDNAME_NO_COMPLEX_TYPE (0x8000)
57 /* How data types modifiers are stored:
58 * M (in the following definitions) is defined for
59 * 'A', 'B', 'C' and 'D' as follows
60 * {<A>}: ""
61 * {<B>}: "const "
62 * {<C>}: "volatile "
63 * {<D>}: "const volatile "
65 * in arguments:
66 * P<M>x {<M>}x*
67 * Q<M>x {<M>}x* const
68 * A<M>x {<M>}x&
69 * in data fields:
70 * same as for arguments and also the following
71 * ?<M>x {<M>}x
75 #define MAX_ARRAY_ELTS 32
76 struct array
78 unsigned start; /* first valid reference in array */
79 unsigned num; /* total number of used elts */
80 unsigned max;
81 char* elts[MAX_ARRAY_ELTS];
84 /* Structure holding a parsed symbol */
85 struct parsed_symbol
87 unsigned flags; /* the UNDNAME_ flags used for demangling */
88 malloc_func_t mem_alloc_ptr; /* internal allocator */
89 free_func_t mem_free_ptr; /* internal deallocator */
91 const char* current; /* pointer in input (mangled) string */
92 char* result; /* demangled string */
94 struct array names; /* array of names for back reference */
95 struct array stack; /* stack of parsed strings */
97 void* alloc_list; /* linked list of allocated blocks */
98 unsigned avail_in_first; /* number of available bytes in head block */
101 /* Type for parsing mangled types */
102 struct datatype_t
104 const char* left;
105 const char* right;
108 /******************************************************************
109 * und_alloc
111 * Internal allocator. Uses a simple linked list of large blocks
112 * where we use a poor-man allocator. It's fast, and since all
113 * allocation is pool, memory management is easy (esp. freeing).
115 static void* und_alloc(struct parsed_symbol* sym, size_t len)
117 void* ptr;
119 #define BLOCK_SIZE 1024
120 #define AVAIL_SIZE (1024 - sizeof(void*))
122 if (len > AVAIL_SIZE)
124 /* allocate a specific block */
125 ptr = sym->mem_alloc_ptr(sizeof(void*) + len);
126 if (!ptr) return NULL;
127 *(void**)ptr = sym->alloc_list;
128 sym->alloc_list = ptr;
129 sym->avail_in_first = 0;
130 ptr = (char*)sym->alloc_list + sizeof(void*);
132 else
134 if (len > sym->avail_in_first)
136 /* add a new block */
137 ptr = sym->mem_alloc_ptr(BLOCK_SIZE);
138 if (!ptr) return NULL;
139 *(void**)ptr = sym->alloc_list;
140 sym->alloc_list = ptr;
141 sym->avail_in_first = AVAIL_SIZE;
143 /* grab memory from head block */
144 ptr = (char*)sym->alloc_list + BLOCK_SIZE - sym->avail_in_first;
145 sym->avail_in_first -= len;
147 return ptr;
148 #undef BLOCK_SIZE
149 #undef AVAIL_SIZE
152 /******************************************************************
153 * und_free
154 * Frees all the blocks in the list of large blocks allocated by
155 * und_alloc.
157 static void und_free_all(struct parsed_symbol* sym)
159 void* next;
161 while (sym->alloc_list)
163 next = *(void**)sym->alloc_list;
164 sym->mem_free_ptr(sym->alloc_list);
165 sym->alloc_list = next;
167 sym->avail_in_first = 0;
170 /******************************************************************
171 * str_array_init
172 * Initialises an array of strings
174 static void str_array_init(struct array* a)
176 a->start = a->num = a->max = 0;
179 /******************************************************************
180 * str_array_push
181 * Adding a new string to an array
183 static void str_array_push(struct parsed_symbol* sym, const char* ptr, size_t len,
184 struct array* a)
186 assert(ptr);
187 assert(a);
188 assert(a->num < MAX_ARRAY_ELTS);
189 if (len == -1) len = strlen(ptr);
190 a->elts[a->num] = und_alloc(sym, len + 1);
191 assert(a->elts[a->num]);
192 memcpy(a->elts[a->num], ptr, len);
193 a->elts[a->num][len] = '\0';
194 if (++a->num >= a->max) a->max = a->num;
196 int i;
197 char c;
199 for (i = a->max - 1; i >= 0; i--)
201 c = '>';
202 if (i < a->start) c = '-';
203 else if (i >= a->num) c = '}';
204 TRACE("%p\t%d%c %s\n", a, i, c, a->elts[i]);
209 /******************************************************************
210 * str_array_get_ref
211 * Extracts a reference from an existing array (doing proper type
212 * checking)
214 static char* str_array_get_ref(struct array* cref, unsigned idx)
216 assert(cref);
217 if (cref->start + idx >= cref->max)
219 WARN("Out of bounds: %p %d + %d >= %d\n",
220 cref, cref->start, idx, cref->max);
221 return NULL;
223 TRACE("Returning %p[%d] => %s\n",
224 cref, idx, cref->elts[cref->start + idx]);
225 return cref->elts[cref->start + idx];
228 /******************************************************************
229 * str_printf
230 * Helper for printf type of command (only %s and %c are implemented)
231 * while dynamically allocating the buffer
233 static char* str_printf(struct parsed_symbol* sym, const char* format, ...)
235 va_list args;
236 size_t len = 1, i, sz;
237 char* tmp;
238 char* p;
239 char* t;
241 va_start(args, format);
242 for (i = 0; format[i]; i++)
244 if (format[i] == '%')
246 switch (format[++i])
248 case 's': t = va_arg(args, char*); if (t) len += strlen(t); break;
249 case 'c': (void)va_arg(args, int); len++; break;
250 default: i--; /* fall thru */
251 case '%': len++; break;
254 else len++;
256 va_end(args);
257 if (!(tmp = (char*)und_alloc(sym, len))) return NULL;
258 va_start(args, format);
259 for (p = tmp, i = 0; format[i]; i++)
261 if (format[i] == '%')
263 switch (format[++i])
265 case 's':
266 t = va_arg(args, char*);
267 if (t)
269 sz = strlen(t);
270 memcpy(p, t, sz);
271 p += sz;
273 break;
274 case 'c':
275 *p++ = (char)va_arg(args, int);
276 break;
277 default: i--; /* fall thru */
278 case '%': *p++ = '%'; break;
281 else *p++ = format[i];
283 va_end(args);
284 *p = '\0';
285 return tmp;
288 /* forward declaration */
289 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
290 struct array* pmt, BOOL in_args);
292 /******************************************************************
293 * get_args
294 * Parses a list of function/method arguments, creates a string corresponding
295 * to the arguments' list.
297 static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_term,
298 char open_char, char close_char)
301 struct datatype_t ct;
302 struct array arg_collect;
303 char* args_str = NULL;
304 int i;
306 str_array_init(&arg_collect);
308 /* Now come the function arguments */
309 while (*sym->current)
311 /* Decode each data type and append it to the argument list */
312 if (*sym->current == '@')
314 sym->current++;
315 break;
317 if (!demangle_datatype(sym, &ct, pmt_ref, TRUE))
318 return NULL;
319 /* 'void' terminates an argument list */
320 if (!strcmp(ct.left, "void"))
322 if (!z_term && *sym->current == '@') sym->current++;
323 break;
325 str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1,
326 &arg_collect);
327 if (!strcmp(ct.left, "...")) break;
329 /* Functions are always terminated by 'Z'. If we made it this far and
330 * don't find it, we have incorrectly identified a data type.
332 if (z_term && *sym->current++ != 'Z') return NULL;
334 if (arg_collect.num == 0 ||
335 (arg_collect.num == 1 && !strcmp(arg_collect.elts[0], "void")))
336 return str_printf(sym, "%cvoid%c", open_char, close_char);
337 for (i = 1; i < arg_collect.num; i++)
339 args_str = str_printf(sym, "%s,%s", args_str, arg_collect.elts[i]);
342 if (close_char == '>' && args_str && args_str[strlen(args_str) - 1] == '>')
343 args_str = str_printf(sym, "%c%s%s %c",
344 open_char, arg_collect.elts[0], args_str, close_char);
345 else
346 args_str = str_printf(sym, "%c%s%s%c",
347 open_char, arg_collect.elts[0], args_str, close_char);
349 return args_str;
352 /******************************************************************
353 * get_modifier
354 * Parses the type modifier. Always returns a static string
356 static BOOL get_modifier(char ch, const char** ret)
358 switch (ch)
360 case 'A': *ret = NULL; break;
361 case 'B': *ret = "const"; break;
362 case 'C': *ret = "volatile"; break;
363 case 'D': *ret = "const volatile"; break;
364 default: return FALSE;
366 return TRUE;
369 static const char* get_modified_type(struct parsed_symbol* sym, char modif)
371 const char* modifier;
372 const char* ret = NULL;
373 const char* str_modif;
375 switch (modif)
377 case 'A': str_modif = " &"; break;
378 case 'B': str_modif = " & volatile"; break;
379 case 'P': str_modif = " *"; break;
380 case 'Q': str_modif = " * const"; break;
381 case 'R': str_modif = " * volatile"; break;
382 case 'S': str_modif = " * const volatile"; break;
383 case '?': str_modif = ""; break;
384 default: return NULL;
387 if (get_modifier(*sym->current++, &modifier))
389 unsigned mark = sym->stack.num;
390 struct datatype_t sub_ct;
392 /* Recurse to get the referred-to type */
393 if (!demangle_datatype(sym, &sub_ct, NULL, FALSE))
394 return NULL;
395 ret = str_printf(sym, "%s%s%s%s%s",
396 sub_ct.left, sub_ct.left && modifier ? " " : NULL,
397 modifier, sub_ct.right, str_modif);
398 sym->stack.num = mark;
400 return ret;
403 /******************************************************************
404 * get_literal_string
405 * Gets the literal name from the current position in the mangled
406 * symbol to the first '@' character. It pushes the parsed name to
407 * the symbol names stack and returns a pointer to it or NULL in
408 * case of an error.
410 static char* get_literal_string(struct parsed_symbol* sym)
412 const char *ptr = sym->current;
414 do {
415 if (!((*sym->current >= 'A' && *sym->current <= 'Z') ||
416 (*sym->current >= 'a' && *sym->current <= 'z') ||
417 (*sym->current >= '0' && *sym->current <= '9') ||
418 *sym->current == '_' || *sym->current == '$')) {
419 TRACE("Failed at '%c' in %s\n", *sym->current, ptr);
420 return NULL;
422 } while (*++sym->current != '@');
423 sym->current++;
424 str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->names);
426 return str_array_get_ref(&sym->names, sym->names.num - sym->names.start - 1);
429 /******************************************************************
430 * get_class
431 * Parses class as a list of parent-classes, terminated by '@' and stores the
432 * result in 'a' array. Each parent-classes, as well as the inner element
433 * (either field/method name or class name), are represented in the mangled
434 * name by a literal name ([a-zA-Z0-9_]+ terminated by '@') or a back reference
435 * ([0-9]) or a name with template arguments ('?$' literal name followed by the
436 * template argument list). The class name components appear in the reverse
437 * order in the mangled name, e.g aaa@bbb@ccc@@ will be demangled to
438 * ccc::bbb::aaa
439 * For each of this class name componets a string will be allocated in the
440 * array.
442 static BOOL get_class(struct parsed_symbol* sym)
444 const char* name = NULL;
446 while (*sym->current != '@')
448 switch (*sym->current)
450 case '\0': return FALSE;
452 case '0': case '1': case '2': case '3':
453 case '4': case '5': case '6': case '7':
454 case '8': case '9':
455 name = str_array_get_ref(&sym->names, *sym->current++ - '0');
456 break;
457 case '?':
458 if (*++sym->current == '$')
460 /* In a template argument list the back reference to names
461 table is separately created. '0' points to the class
462 component name with the template arguments. We use the same
463 stack array to hold the names but save/restore the stack
464 state before/after parsing the template argument list. */
465 char* args = NULL;
466 unsigned num_mark = sym->names.num;
467 unsigned start_mark = sym->names.start;
468 unsigned stack_mark = sym->stack.num;
470 sym->names.start = sym->names.num;
471 sym->current++;
472 if (!(name = get_literal_string(sym)))
473 return FALSE;
474 args = get_args(sym, NULL, FALSE, '<', '>');
475 if (args != NULL)
476 name = str_printf(sym, "%s%s", name, args);
477 sym->names.num = num_mark;
478 sym->names.start = start_mark;
479 sym->stack.num = stack_mark;
480 /* Now that we are back to the standard name scope push
481 the class component with all its template arguments
482 to the names array for back reference. */
483 str_array_push(sym, name, -1, &sym->names);
485 break;
486 default:
487 name = get_literal_string(sym);
488 break;
490 if (!name)
491 return FALSE;
492 str_array_push(sym, name, -1, &sym->stack);
494 sym->current++;
495 return TRUE;
498 /******************************************************************
499 * get_class_string
500 * From an array collected by get_class in sym->stack, constructs the
501 * corresponding (allocated) string
503 static char* get_class_string(struct parsed_symbol* sym, int start)
505 int i;
506 size_t len, sz;
507 char* ret;
508 struct array *a = &sym->stack;
510 for (len = 0, i = start; i < a->num; i++)
512 assert(a->elts[i]);
513 len += 2 + strlen(a->elts[i]);
515 if (!(ret = und_alloc(sym, len - 1))) return NULL;
516 for (len = 0, i = a->num - 1; i >= start; i--)
518 sz = strlen(a->elts[i]);
519 memcpy(ret + len, a->elts[i], sz);
520 len += sz;
521 if (i > start)
523 ret[len++] = ':';
524 ret[len++] = ':';
527 ret[len] = '\0';
528 return ret;
531 /******************************************************************
532 * get_class_name
533 * Wrapper around get_class and get_class_string.
535 static char* get_class_name(struct parsed_symbol* sym)
537 unsigned mark = sym->stack.num;
538 char* s = NULL;
540 if (get_class(sym))
541 s = get_class_string(sym, mark);
542 sym->stack.num = mark;
543 return s;
546 /******************************************************************
547 * get_calling_convention
548 * Returns a static string corresponding to the calling convention described
549 * by char 'ch'. Sets export to TRUE iff the calling convention is exported.
551 static BOOL get_calling_convention(char ch, const char** call_conv,
552 const char** exported, unsigned flags)
554 *call_conv = *exported = NULL;
556 if (!(flags & (UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ALLOCATION_LANGUAGE)))
558 if (flags & UNDNAME_NO_LEADING_UNDERSCORES)
560 if (((ch - 'A') % 2) == 1) *exported = "dll_export ";
561 switch (ch)
563 case 'A': case 'B': *call_conv = "cdecl"; break;
564 case 'C': case 'D': *call_conv = "pascal"; break;
565 case 'E': case 'F': *call_conv = "thiscall"; break;
566 case 'G': case 'H': *call_conv = "stdcall"; break;
567 case 'I': case 'J': *call_conv = "fastcall"; break;
568 case 'K': break;
569 default: ERR("Unknown calling convention %c\n", ch); return FALSE;
572 else
574 if (((ch - 'A') % 2) == 1) *exported = "__dll_export ";
575 switch (ch)
577 case 'A': case 'B': *call_conv = "__cdecl"; break;
578 case 'C': case 'D': *call_conv = "__pascal"; break;
579 case 'E': case 'F': *call_conv = "__thiscall"; break;
580 case 'G': case 'H': *call_conv = "__stdcall"; break;
581 case 'I': case 'J': *call_conv = "__fastcall"; break;
582 case 'K': break;
583 default: ERR("Unknown calling convention %c\n", ch); return FALSE;
587 return TRUE;
590 /*******************************************************************
591 * get_simple_type
592 * Return a string containing an allocated string for a simple data type
594 static const char* get_simple_type(char c)
596 const char* type_string;
598 switch (c)
600 case 'C': type_string = "signed char"; break;
601 case 'D': type_string = "char"; break;
602 case 'E': type_string = "unsigned char"; break;
603 case 'F': type_string = "short"; break;
604 case 'G': type_string = "unsigned short"; break;
605 case 'H': type_string = "int"; break;
606 case 'I': type_string = "unsigned int"; break;
607 case 'J': type_string = "long"; break;
608 case 'K': type_string = "unsigned long"; break;
609 case 'M': type_string = "float"; break;
610 case 'N': type_string = "double"; break;
611 case 'O': type_string = "long double"; break;
612 case 'X': type_string = "void"; break;
613 case 'Z': type_string = "..."; break;
614 default: type_string = NULL; break;
616 return type_string;
619 /*******************************************************************
620 * get_extented_type
621 * Return a string containing an allocated string for a simple data type
623 static const char* get_extended_type(char c)
625 const char* type_string;
627 switch (c)
629 case 'D': type_string = "__int8"; break;
630 case 'E': type_string = "unsigned __int8"; break;
631 case 'F': type_string = "__int16"; break;
632 case 'G': type_string = "unsigned __int16"; break;
633 case 'H': type_string = "__int32"; break;
634 case 'I': type_string = "unsigned __int32"; break;
635 case 'J': type_string = "__int64"; break;
636 case 'K': type_string = "unsigned __int64"; break;
637 case 'L': type_string = "__int128"; break;
638 case 'M': type_string = "unsigned __int128"; break;
639 case 'N': type_string = "bool"; break;
640 case 'W': type_string = "wchar_t"; break;
641 default: type_string = NULL; break;
643 return type_string;
646 /*******************************************************************
647 * demangle_datatype
649 * Attempt to demangle a C++ data type, which may be datatype.
650 * a datatype type is made up of a number of simple types. e.g:
651 * char** = (pointer to (pointer to (char)))
653 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
654 struct array* pmt_ref, BOOL in_args)
656 char dt;
657 BOOL add_pmt = TRUE;
658 int num_args=0;
660 assert(ct);
661 ct->left = ct->right = NULL;
663 switch (dt = *sym->current++)
665 case '_':
666 /* MS type: __int8,__int16 etc */
667 ct->left = get_extended_type(*sym->current++);
668 break;
669 case 'C': case 'D': case 'E': case 'F': case 'G':
670 case 'H': case 'I': case 'J': case 'K': case 'M':
671 case 'N': case 'O': case 'X': case 'Z':
672 /* Simple data types */
673 ct->left = get_simple_type(dt);
674 add_pmt = FALSE;
675 break;
676 case 'T': /* union */
677 case 'U': /* struct */
678 case 'V': /* class */
679 /* Class/struct/union */
681 const char* struct_name = NULL;
682 const char* type_name = NULL;
684 if (!(struct_name = get_class_name(sym)))
685 goto done;
686 if (!(sym->flags & UNDNAME_NO_COMPLEX_TYPE))
688 switch (dt)
690 case 'T': type_name = "union "; break;
691 case 'U': type_name = "struct "; break;
692 case 'V': type_name = "class "; break;
695 ct->left = str_printf(sym, "%s%s", type_name, struct_name);
697 break;
698 case '?':
699 /* not all the time is seems */
700 if (!(ct->left = get_modified_type(sym, '?'))) goto done;
701 break;
702 case 'A': /* reference */
703 case 'B': /* volatile reference */
704 if (!(ct->left = get_modified_type(sym, dt))) goto done;
705 break;
706 case 'Q': /* const pointer */
707 case 'R': /* volatile pointer */
708 case 'S': /* const volatile pointer */
709 if (!(ct->left = get_modified_type(sym, in_args ? dt : 'P'))) goto done;
710 break;
711 case 'P': /* Pointer */
712 if (isdigit(*sym->current))
714 /* FIXME: P6 = Function pointer, others who knows.. */
715 if (*sym->current++ == '6')
717 char* args = NULL;
718 const char* call_conv;
719 const char* exported;
720 struct datatype_t sub_ct;
721 unsigned mark = sym->stack.num;
723 if (!get_calling_convention(*sym->current++,
724 &call_conv, &exported,
725 sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
726 !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
727 goto done;
729 args = get_args(sym, pmt_ref, TRUE, '(', ')');
730 if (!args) goto done;
731 sym->stack.num = mark;
733 ct->left = str_printf(sym, "%s%s (%s*",
734 sub_ct.left, sub_ct.right, call_conv);
735 ct->right = str_printf(sym, ")%s", args);
737 else goto done;
739 else if (!(ct->left = get_modified_type(sym, 'P'))) goto done;
740 break;
741 case 'W':
742 if (*sym->current == '4')
744 char* enum_name;
745 sym->current++;
746 if (!(enum_name = get_class_name(sym)))
747 goto done;
748 if (sym->flags & UNDNAME_NO_COMPLEX_TYPE)
749 ct->left = enum_name;
750 else
751 ct->left = str_printf(sym, "enum %s", enum_name);
753 else goto done;
754 break;
755 case '0': case '1': case '2': case '3': case '4':
756 case '5': case '6': case '7': case '8': case '9':
757 /* Referring back to previously parsed type */
758 ct->left = str_array_get_ref(pmt_ref, dt - '0');
759 if (!ct->left) goto done;
760 add_pmt = FALSE;
761 break;
762 case '$':
763 if (sym->current[0] != '0') goto done;
764 if (sym->current[1] >= '0' && sym->current[1] <= '9')
766 char* ptr;
767 ptr = und_alloc(sym, 2);
768 ptr[0] = sym->current[1] + 1;
769 ptr[1] = 0;
770 ct->left = ptr;
771 sym->current += 2;
773 else if (sym->current[1] >= 'A' && sym->current[1] <= 'P')
775 while (sym->current[1] >= 'A' && sym->current[1] <= 'P')
777 num_args *= 16;
778 num_args += sym->current[1] - 'A';
779 sym->current += 1;
781 if(sym->current[1] == '@')
783 char *ptr;
784 ptr = und_alloc(sym, 17);
785 sprintf(ptr,"%d",num_args);
786 ct->left = ptr;
787 sym->current += 1;
790 else goto done;
791 break;
792 default :
793 ERR("Unknown type %c\n", dt);
794 break;
796 if (add_pmt && pmt_ref && in_args)
797 str_array_push(sym, str_printf(sym, "%s%s", ct->left, ct->right),
798 -1, pmt_ref);
799 done:
801 return ct->left != NULL;
804 /******************************************************************
805 * handle_data
806 * Does the final parsing and handling for a variable or a field in
807 * a class.
809 static BOOL handle_data(struct parsed_symbol* sym)
811 const char* access = NULL;
812 const char* member_type = NULL;
813 const char* modifier = NULL;
814 struct datatype_t ct;
815 char* name = NULL;
816 BOOL ret = FALSE;
817 char dt;
819 /* 0 private static
820 * 1 protected static
821 * 2 public static
822 * 3 private non-static
823 * 4 protected non-static
824 * 5 public non-static
825 * 6 ?? static
826 * 7 ?? static
829 if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
831 /* we only print the access for static members */
832 switch (*sym->current)
834 case '0': access = "private: "; break;
835 case '1': access = "protected: "; break;
836 case '2': access = "public: "; break;
840 if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
842 if (*sym->current >= '0' && *sym->current <= '2')
843 member_type = "static ";
846 name = get_class_string(sym, 0);
848 switch (dt = *sym->current++)
850 case '0': case '1': case '2':
851 case '3': case '4': case '5':
853 unsigned mark = sym->stack.num;
854 if (!demangle_datatype(sym, &ct, NULL, FALSE)) goto done;
855 if (!get_modifier(*sym->current++, &modifier)) goto done;
856 sym->stack.num = mark;
858 break;
859 case '6' : /* compiler generated static */
860 case '7' : /* compiler generated static */
861 ct.left = ct.right = NULL;
862 if (!get_modifier(*sym->current++, &modifier)) goto done;
863 if (*sym->current != '@')
865 char* cls = NULL;
867 if (!(cls = get_class_name(sym)))
868 goto done;
869 ct.right = str_printf(sym, "{for `%s'}", cls);
871 break;
872 default: goto done;
874 if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = modifier = NULL;
875 sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s", access,
876 member_type, ct.left,
877 modifier && ct.left ? " " : NULL, modifier,
878 modifier || ct.left ? " " : NULL, name, ct.right);
879 ret = TRUE;
880 done:
881 return ret;
884 /******************************************************************
885 * handle_method
886 * Does the final parsing and handling for a function or a method in
887 * a class.
889 static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op)
891 const char* access = NULL;
892 const char* member_type = NULL;
893 struct datatype_t ct_ret;
894 const char* call_conv;
895 const char* modifier = NULL;
896 const char* exported;
897 const char* args_str = NULL;
898 const char* name = NULL;
899 BOOL ret = FALSE;
900 unsigned mark;
901 struct array array_pmt;
903 /* FIXME: why 2 possible letters for each option?
904 * 'A' private:
905 * 'B' private:
906 * 'C' private: static
907 * 'D' private: static
908 * 'E' private: virtual
909 * 'F' private: virtual
910 * 'G' private: thunk
911 * 'H' private: thunk
912 * 'I' protected:
913 * 'J' protected:
914 * 'K' protected: static
915 * 'L' protected: static
916 * 'M' protected: virtual
917 * 'N' protected: virtual
918 * 'O' protected: thunk
919 * 'P' protected: thunk
920 * 'Q' public:
921 * 'R' public:
922 * 'S' public: static
923 * 'T' public: static
924 * 'U' public: virtual
925 * 'V' public: virtual
926 * 'W' public: thunk
927 * 'X' public: thunk
928 * 'Y'
929 * 'Z'
932 if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
934 switch ((*sym->current - 'A') / 8)
936 case 0: access = "private: "; break;
937 case 1: access = "protected: "; break;
938 case 2: access = "public: "; break;
941 if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
943 if (*sym->current >= 'A' && *sym->current <= 'X')
945 switch ((*sym->current - 'A') % 8)
947 case 2: case 3: member_type = "static "; break;
948 case 4: case 5: member_type = "virtual "; break;
949 case 6: case 7: member_type = "thunk "; break;
954 if (*sym->current >= 'A' && *sym->current <= 'X')
956 if (!((*sym->current - 'A') & 2))
958 /* Implicit 'this' pointer */
959 /* If there is an implicit this pointer, const modifier follows */
960 if (!get_modifier(*++sym->current, &modifier)) goto done;
963 else if (*sym->current < 'A' || *sym->current > 'Z') goto done;
964 sym->current++;
966 name = get_class_string(sym, 0);
968 if (!get_calling_convention(*sym->current++, &call_conv, &exported,
969 sym->flags))
970 goto done;
972 str_array_init(&array_pmt);
974 /* Return type, or @ if 'void' */
975 if (*sym->current == '@')
977 ct_ret.left = "void";
978 ct_ret.right = NULL;
979 sym->current++;
981 else
983 if (!demangle_datatype(sym, &ct_ret, &array_pmt, FALSE))
984 goto done;
986 if (sym->flags & UNDNAME_NO_FUNCTION_RETURNS)
987 ct_ret.left = ct_ret.right = NULL;
988 if (cast_op)
990 name = str_printf(sym, "%s%s%s", name, ct_ret.left, ct_ret.right);
991 ct_ret.left = ct_ret.right = NULL;
994 mark = sym->stack.num;
995 if (!(args_str = get_args(sym, &array_pmt, TRUE, '(', ')'))) goto done;
996 if (sym->flags & UNDNAME_NAME_ONLY) args_str = modifier = NULL;
997 sym->stack.num = mark;
999 /* Note: '()' after 'Z' means 'throws', but we don't care here
1000 * Yet!!! FIXME
1002 sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s%s%s%s%s",
1003 access, member_type, ct_ret.left,
1004 (ct_ret.left && !ct_ret.right) ? " " : NULL,
1005 call_conv, call_conv ? " " : NULL, exported,
1006 name, args_str, modifier,
1007 modifier ? " " : NULL, ct_ret.right);
1008 ret = TRUE;
1009 done:
1010 return ret;
1013 /*******************************************************************
1014 * symbol_demangle
1015 * Demangle a C++ linker symbol
1017 static BOOL symbol_demangle(struct parsed_symbol* sym)
1019 BOOL ret = FALSE;
1020 unsigned do_after = 0;
1022 /* FIXME seems wrong as name, as it demangles a simple data type */
1023 if (sym->flags & UNDNAME_NO_ARGUMENTS)
1025 struct datatype_t ct;
1027 if (demangle_datatype(sym, &ct, NULL, FALSE))
1029 sym->result = str_printf(sym, "%s%s", ct.left, ct.right);
1030 ret = TRUE;
1032 goto done;
1035 /* MS mangled names always begin with '?' */
1036 if (*sym->current != '?') return FALSE;
1037 str_array_init(&sym->names);
1038 str_array_init(&sym->stack);
1039 sym->current++;
1041 /* Then function name or operator code */
1042 if (*sym->current == '?' && sym->current[1] != '$')
1044 const char* function_name = NULL;
1046 /* C++ operator code (one character, or two if the first is '_') */
1047 switch (*++sym->current)
1049 case '0': do_after = 1; break;
1050 case '1': do_after = 2; break;
1051 case '2': function_name = "operator new"; break;
1052 case '3': function_name = "operator delete"; break;
1053 case '4': function_name = "operator="; break;
1054 case '5': function_name = "operator>>"; break;
1055 case '6': function_name = "operator<<"; break;
1056 case '7': function_name = "operator!"; break;
1057 case '8': function_name = "operator=="; break;
1058 case '9': function_name = "operator!="; break;
1059 case 'A': function_name = "operator[]"; break;
1060 case 'B': function_name = "operator "; do_after = 3; break;
1061 case 'C': function_name = "operator->"; break;
1062 case 'D': function_name = "operator*"; break;
1063 case 'E': function_name = "operator++"; break;
1064 case 'F': function_name = "operator--"; break;
1065 case 'G': function_name = "operator-"; break;
1066 case 'H': function_name = "operator+"; break;
1067 case 'I': function_name = "operator&"; break;
1068 case 'J': function_name = "operator->*"; break;
1069 case 'K': function_name = "operator/"; break;
1070 case 'L': function_name = "operator%"; break;
1071 case 'M': function_name = "operator<"; break;
1072 case 'N': function_name = "operator<="; break;
1073 case 'O': function_name = "operator>"; break;
1074 case 'P': function_name = "operator>="; break;
1075 case 'Q': function_name = "operator,"; break;
1076 case 'R': function_name = "operator()"; break;
1077 case 'S': function_name = "operator~"; break;
1078 case 'T': function_name = "operator^"; break;
1079 case 'U': function_name = "operator|"; break;
1080 case 'V': function_name = "operator&&"; break;
1081 case 'W': function_name = "operator||"; break;
1082 case 'X': function_name = "operator*="; break;
1083 case 'Y': function_name = "operator+="; break;
1084 case 'Z': function_name = "operator-="; break;
1085 case '_':
1086 switch (*++sym->current)
1088 case '0': function_name = "operator/="; break;
1089 case '1': function_name = "operator%="; break;
1090 case '2': function_name = "operator>>="; break;
1091 case '3': function_name = "operator<<="; break;
1092 case '4': function_name = "operator&="; break;
1093 case '5': function_name = "operator|="; break;
1094 case '6': function_name = "operator^="; break;
1095 case '7': function_name = "`vftable'"; break;
1096 case '8': function_name = "`vbtable'"; break;
1097 case '9': function_name = "`vcall'"; break;
1098 case 'A': function_name = "`typeof'"; break;
1099 case 'B': function_name = "`local static guard'"; break;
1100 case 'C': function_name = "`string'"; do_after = 4; break;
1101 case 'D': function_name = "`vbase destructor'"; break;
1102 case 'E': function_name = "`vector deleting destructor'"; break;
1103 case 'F': function_name = "`default constructor closure'"; break;
1104 case 'G': function_name = "`scalar deleting destructor'"; break;
1105 case 'H': function_name = "`vector constructor iterator'"; break;
1106 case 'I': function_name = "`vector destructor iterator'"; break;
1107 case 'J': function_name = "`vector vbase constructor iterator'"; break;
1108 case 'K': function_name = "`virtual displacement map'"; break;
1109 case 'L': function_name = "`eh vector constructor iterator'"; break;
1110 case 'M': function_name = "`eh vector destructor iterator'"; break;
1111 case 'N': function_name = "`eh vector vbase constructor iterator'"; break;
1112 case 'O': function_name = "`copy constructor closure'"; break;
1113 case 'S': function_name = "`local vftable'"; break;
1114 case 'T': function_name = "`local vftable constructor closure'"; break;
1115 case 'U': function_name = "operator new[]"; break;
1116 case 'V': function_name = "operator delete[]"; break;
1117 case 'X': function_name = "`placement delete closure'"; break;
1118 case 'Y': function_name = "`placement delete[] closure'"; break;
1119 default:
1120 ERR("Unknown operator: _%c\n", *sym->current);
1121 return FALSE;
1123 break;
1124 default:
1125 /* FIXME: Other operators */
1126 ERR("Unknown operator: %c\n", *sym->current);
1127 return FALSE;
1129 sym->current++;
1130 switch (do_after)
1132 case 1: case 2:
1133 sym->stack.num = sym->stack.max = 1;
1134 sym->stack.elts[0] = "--null--";
1135 break;
1136 case 4:
1137 sym->result = (char*)function_name;
1138 ret = TRUE;
1139 goto done;
1140 default:
1141 str_array_push(sym, function_name, -1, &sym->stack);
1142 break;
1144 sym->stack.start = 1;
1147 /* Either a class name, or '@' if the symbol is not a class member */
1148 if (*sym->current != '@')
1150 /* Class the function is associated with, terminated by '@@' */
1151 if (!get_class(sym)) goto done;
1153 else sym->current++;
1155 switch (do_after)
1157 case 0: default: break;
1158 case 1: case 2:
1159 /* it's time to set the member name for ctor & dtor */
1160 if (sym->stack.num <= 1) goto done;
1161 if (do_after == 1)
1162 sym->stack.elts[0] = sym->stack.elts[1];
1163 else
1164 sym->stack.elts[0] = str_printf(sym, "~%s", sym->stack.elts[1]);
1165 /* ctors and dtors don't have return type */
1166 sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;
1167 break;
1168 case 3:
1169 sym->flags &= ~UNDNAME_NO_FUNCTION_RETURNS;
1170 break;
1173 /* Function/Data type and access level */
1174 if (*sym->current >= '0' && *sym->current <= '7')
1175 ret = handle_data(sym);
1176 else if (*sym->current >= 'A' && *sym->current <= 'Z')
1177 ret = handle_method(sym, do_after == 3);
1178 else ret = FALSE;
1179 done:
1180 if (ret) assert(sym->result);
1181 else WARN("Failed at %s\n", sym->current);
1183 return ret;
1186 /*********************************************************************
1187 * __unDNameEx (MSVCRT.@)
1189 * Demangle a C++ identifier.
1191 * PARAMS
1192 * buffer [O] If not NULL, the place to put the demangled string
1193 * mangled [I] Mangled name of the function
1194 * buflen [I] Length of buffer
1195 * memget [I] Function to allocate memory with
1196 * memfree [I] Function to free memory with
1197 * unknown [?] Unknown, possibly a call back
1198 * flags [I] Flags determining demangled format
1200 * RETURNS
1201 * Success: A string pointing to the unmangled name, allocated with memget.
1202 * Failure: NULL.
1204 char* __unDNameEx(char* buffer, const char* mangled, int buflen,
1205 malloc_func_t memget, free_func_t memfree,
1206 void* unknown, unsigned short int flags)
1208 struct parsed_symbol sym;
1209 const char* result;
1211 TRACE("(%p,%s,%d,%p,%p,%p,%x)\n",
1212 buffer, mangled, buflen, memget, memfree, unknown, flags);
1214 /* The flags details is not documented by MS. However, it looks exactly
1215 * like the UNDNAME_ manifest constants from imagehlp.h and dbghelp.h
1216 * So, we copied those (on top of the file)
1218 memset(&sym, 0, sizeof(struct parsed_symbol));
1219 if (flags & UNDNAME_NAME_ONLY)
1220 flags |= UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_ACCESS_SPECIFIERS |
1221 UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_ALLOCATION_LANGUAGE |
1222 UNDNAME_NO_COMPLEX_TYPE;
1224 sym.flags = flags;
1225 sym.mem_alloc_ptr = memget;
1226 sym.mem_free_ptr = memfree;
1227 sym.current = mangled;
1229 result = symbol_demangle(&sym) ? sym.result : mangled;
1230 if (buffer && buflen)
1232 memcpy(buffer, result, buflen - 1);
1233 buffer[buflen - 1] = '\0';
1235 else
1237 buffer = memget(strlen(result) + 1);
1238 if (buffer) strcpy(buffer, result);
1241 und_free_all(&sym);
1243 return buffer;
1247 /*********************************************************************
1248 * __unDName (MSVCRT.@)
1250 char* __unDName(char* buffer, const char* mangled, int buflen,
1251 malloc_func_t memget, free_func_t memfree,
1252 unsigned short int flags)
1254 return __unDNameEx(buffer, mangled, buflen, memget, memfree, NULL, flags);