2 * Demangle VC++ symbols into C function prototypes
4 * Copyright 2000 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
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
63 * {<D>}: "const volatile "
70 * same as for arguments and also the following
75 #define MAX_ARRAY_ELTS 32
78 unsigned start
; /* first valid reference in array */
79 unsigned num
; /* total number of used elts */
81 char* elts
[MAX_ARRAY_ELTS
];
84 /* Structure holding a 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 */
108 /******************************************************************
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
)
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*);
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
;
152 /******************************************************************
154 * Frees all the blocks in the list of large blocks allocated by
157 static void und_free_all(struct parsed_symbol
* sym
)
161 while (sym
->alloc_list
)
163 next
= *(void**)sym
->alloc_list
;
164 if(sym
->mem_free_ptr
) sym
->mem_free_ptr(sym
->alloc_list
);
165 sym
->alloc_list
= next
;
167 sym
->avail_in_first
= 0;
170 /******************************************************************
172 * Initialises an array of strings
174 static void str_array_init(struct array
* a
)
176 a
->start
= a
->num
= a
->max
= 0;
179 /******************************************************************
181 * Adding a new string to an array
183 static void str_array_push(struct parsed_symbol
* sym
, const char* ptr
, size_t len
,
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
;
199 for (i
= a
->max
- 1; i
>= 0; i
--)
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 /******************************************************************
211 * Extracts a reference from an existing array (doing proper type
214 static char* str_array_get_ref(struct array
* cref
, unsigned idx
)
217 if (cref
->start
+ idx
>= cref
->max
)
219 WARN("Out of bounds: %p %d + %d >= %d\n",
220 cref
, cref
->start
, idx
, cref
->max
);
223 TRACE("Returning %p[%d] => %s\n",
224 cref
, idx
, cref
->elts
[cref
->start
+ idx
]);
225 return cref
->elts
[cref
->start
+ idx
];
228 /******************************************************************
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
, ...)
236 size_t len
= 1, i
, sz
;
241 va_start(args
, format
);
242 for (i
= 0; format
[i
]; i
++)
244 if (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;
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
] == '%')
266 t
= va_arg(args
, char*);
275 *p
++ = (char)va_arg(args
, int);
277 default: i
--; /* fall thru */
278 case '%': *p
++ = '%'; break;
281 else *p
++ = format
[i
];
288 /* forward declaration */
289 static BOOL
demangle_datatype(struct parsed_symbol
* sym
, struct datatype_t
* ct
,
290 struct array
* pmt
, BOOL in_args
);
292 /******************************************************************
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
;
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
== '@')
317 if (!demangle_datatype(sym
, &ct
, pmt_ref
, TRUE
))
319 /* 'void' terminates an argument list */
320 if (!strcmp(ct
.left
, "void"))
322 if (!z_term
&& *sym
->current
== '@') sym
->current
++;
325 str_array_push(sym
, str_printf(sym
, "%s%s", ct
.left
, ct
.right
), -1,
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
);
346 args_str
= str_printf(sym
, "%c%s%s%c",
347 open_char
, arg_collect
.elts
[0], args_str
, close_char
);
352 /******************************************************************
354 * Parses the type modifier. Always returns a static string
356 static BOOL
get_modifier(char ch
, const char** ret
)
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
;
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
;
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
))
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
;
403 /******************************************************************
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
410 static char* get_literal_string(struct parsed_symbol
* sym
)
412 const char *ptr
= sym
->current
;
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
);
422 } while (*++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 /******************************************************************
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
439 * For each of this class name componets a string will be allocated in the
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':
455 name
= str_array_get_ref(&sym
->names
, *sym
->current
++ - '0');
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. */
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
;
472 if (!(name
= get_literal_string(sym
)))
474 args
= get_args(sym
, NULL
, FALSE
, '<', '>');
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
);
487 name
= get_literal_string(sym
);
492 str_array_push(sym
, name
, -1, &sym
->stack
);
498 /******************************************************************
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
)
508 struct array
*a
= &sym
->stack
;
510 for (len
= 0, i
= start
; i
< a
->num
; 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
);
531 /******************************************************************
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
;
541 s
= get_class_string(sym
, mark
);
542 sym
->stack
.num
= mark
;
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 ";
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;
569 default: ERR("Unknown calling convention %c\n", ch
); return FALSE
;
574 if (((ch
- 'A') % 2) == 1) *exported
= "__dll_export ";
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;
583 default: ERR("Unknown calling convention %c\n", ch
); return FALSE
;
590 /*******************************************************************
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
;
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;
619 /*******************************************************************
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
;
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;
646 /*******************************************************************
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
)
661 ct
->left
= ct
->right
= NULL
;
663 switch (dt
= *sym
->current
++)
666 /* MS type: __int8,__int16 etc */
667 ct
->left
= get_extended_type(*sym
->current
++);
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
);
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
)))
686 if (!(sym
->flags
& UNDNAME_NO_COMPLEX_TYPE
))
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
);
699 /* not all the time is seems */
700 if (!(ct
->left
= get_modified_type(sym
, '?'))) goto done
;
702 case 'A': /* reference */
703 case 'B': /* volatile reference */
704 if (!(ct
->left
= get_modified_type(sym
, dt
))) goto done
;
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
;
711 case 'P': /* Pointer */
712 if (isdigit(*sym
->current
))
714 /* FIXME: P6 = Function pointer, others who knows.. */
715 if (*sym
->current
++ == '6')
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
))
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
);
739 else if (!(ct
->left
= get_modified_type(sym
, 'P'))) goto done
;
742 if (*sym
->current
== '4')
746 if (!(enum_name
= get_class_name(sym
)))
748 if (sym
->flags
& UNDNAME_NO_COMPLEX_TYPE
)
749 ct
->left
= enum_name
;
751 ct
->left
= str_printf(sym
, "enum %s", enum_name
);
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
;
763 if (sym
->current
[0] != '0') goto done
;
764 if (sym
->current
[1] >= '0' && sym
->current
[1] <= '9')
767 ptr
= und_alloc(sym
, 2);
768 ptr
[0] = sym
->current
[1] + 1;
773 else if (sym
->current
[1] >= 'A' && sym
->current
[1] <= 'P')
775 while (sym
->current
[1] >= 'A' && sym
->current
[1] <= 'P')
778 num_args
+= sym
->current
[1] - 'A';
781 if(sym
->current
[1] == '@')
784 ptr
= und_alloc(sym
, 17);
785 sprintf(ptr
,"%d",num_args
);
793 ERR("Unknown type %c\n", dt
);
796 if (add_pmt
&& pmt_ref
&& in_args
)
797 str_array_push(sym
, str_printf(sym
, "%s%s", ct
->left
, ct
->right
),
801 return ct
->left
!= NULL
;
804 /******************************************************************
806 * Does the final parsing and handling for a variable or a field in
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
;
822 * 3 private non-static
823 * 4 protected non-static
824 * 5 public non-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
;
856 str_array_init(&pmt
);
858 if (!demangle_datatype(sym
, &ct
, &pmt
, FALSE
)) goto done
;
859 if (!get_modifier(*sym
->current
++, &modifier
)) goto done
;
860 sym
->stack
.num
= mark
;
863 case '6' : /* compiler generated static */
864 case '7' : /* compiler generated static */
865 ct
.left
= ct
.right
= NULL
;
866 if (!get_modifier(*sym
->current
++, &modifier
)) goto done
;
867 if (*sym
->current
!= '@')
871 if (!(cls
= get_class_name(sym
)))
873 ct
.right
= str_printf(sym
, "{for `%s'}", cls
);
878 if (sym
->flags
& UNDNAME_NAME_ONLY
) ct
.left
= ct
.right
= modifier
= NULL
;
879 sym
->result
= str_printf(sym
, "%s%s%s%s%s%s%s%s", access
,
880 member_type
, ct
.left
,
881 modifier
&& ct
.left
? " " : NULL
, modifier
,
882 modifier
|| ct
.left
? " " : NULL
, name
, ct
.right
);
888 /******************************************************************
890 * Does the final parsing and handling for a function or a method in
893 static BOOL
handle_method(struct parsed_symbol
* sym
, BOOL cast_op
)
895 const char* access
= NULL
;
896 const char* member_type
= NULL
;
897 struct datatype_t ct_ret
;
898 const char* call_conv
;
899 const char* modifier
= NULL
;
900 const char* exported
;
901 const char* args_str
= NULL
;
902 const char* name
= NULL
;
905 struct array array_pmt
;
907 /* FIXME: why 2 possible letters for each option?
910 * 'C' private: static
911 * 'D' private: static
912 * 'E' private: virtual
913 * 'F' private: virtual
918 * 'K' protected: static
919 * 'L' protected: static
920 * 'M' protected: virtual
921 * 'N' protected: virtual
922 * 'O' protected: thunk
923 * 'P' protected: thunk
928 * 'U' public: virtual
929 * 'V' public: virtual
936 if (!(sym
->flags
& UNDNAME_NO_ACCESS_SPECIFIERS
))
938 switch ((*sym
->current
- 'A') / 8)
940 case 0: access
= "private: "; break;
941 case 1: access
= "protected: "; break;
942 case 2: access
= "public: "; break;
945 if (!(sym
->flags
& UNDNAME_NO_MEMBER_TYPE
))
947 if (*sym
->current
>= 'A' && *sym
->current
<= 'X')
949 switch ((*sym
->current
- 'A') % 8)
951 case 2: case 3: member_type
= "static "; break;
952 case 4: case 5: member_type
= "virtual "; break;
953 case 6: case 7: member_type
= "thunk "; break;
958 if (*sym
->current
>= 'A' && *sym
->current
<= 'X')
960 if (!((*sym
->current
- 'A') & 2))
962 /* Implicit 'this' pointer */
963 /* If there is an implicit this pointer, const modifier follows */
964 if (!get_modifier(*++sym
->current
, &modifier
)) goto done
;
967 else if (*sym
->current
< 'A' || *sym
->current
> 'Z') goto done
;
970 name
= get_class_string(sym
, 0);
972 if (!get_calling_convention(*sym
->current
++, &call_conv
, &exported
,
976 str_array_init(&array_pmt
);
978 /* Return type, or @ if 'void' */
979 if (*sym
->current
== '@')
981 ct_ret
.left
= "void";
987 if (!demangle_datatype(sym
, &ct_ret
, &array_pmt
, FALSE
))
990 if (sym
->flags
& UNDNAME_NO_FUNCTION_RETURNS
)
991 ct_ret
.left
= ct_ret
.right
= NULL
;
994 name
= str_printf(sym
, "%s%s%s", name
, ct_ret
.left
, ct_ret
.right
);
995 ct_ret
.left
= ct_ret
.right
= NULL
;
998 mark
= sym
->stack
.num
;
999 if (!(args_str
= get_args(sym
, &array_pmt
, TRUE
, '(', ')'))) goto done
;
1000 if (sym
->flags
& UNDNAME_NAME_ONLY
) args_str
= modifier
= NULL
;
1001 sym
->stack
.num
= mark
;
1003 /* Note: '()' after 'Z' means 'throws', but we don't care here
1006 sym
->result
= str_printf(sym
, "%s%s%s%s%s%s%s%s%s%s%s%s",
1007 access
, member_type
, ct_ret
.left
,
1008 (ct_ret
.left
&& !ct_ret
.right
) ? " " : NULL
,
1009 call_conv
, call_conv
? " " : NULL
, exported
,
1010 name
, args_str
, modifier
,
1011 modifier
? " " : NULL
, ct_ret
.right
);
1017 /*******************************************************************
1019 * Demangle a C++ linker symbol
1021 static BOOL
symbol_demangle(struct parsed_symbol
* sym
)
1024 unsigned do_after
= 0;
1025 static CHAR dashed_null
[] = "--null--";
1027 /* FIXME seems wrong as name, as it demangles a simple data type */
1028 if (sym
->flags
& UNDNAME_NO_ARGUMENTS
)
1030 struct datatype_t ct
;
1032 if (demangle_datatype(sym
, &ct
, NULL
, FALSE
))
1034 sym
->result
= str_printf(sym
, "%s%s", ct
.left
, ct
.right
);
1040 /* MS mangled names always begin with '?' */
1041 if (*sym
->current
!= '?') return FALSE
;
1042 str_array_init(&sym
->names
);
1043 str_array_init(&sym
->stack
);
1046 /* Then function name or operator code */
1047 if (*sym
->current
== '?' && sym
->current
[1] != '$')
1049 const char* function_name
= NULL
;
1051 /* C++ operator code (one character, or two if the first is '_') */
1052 switch (*++sym
->current
)
1054 case '0': do_after
= 1; break;
1055 case '1': do_after
= 2; break;
1056 case '2': function_name
= "operator new"; break;
1057 case '3': function_name
= "operator delete"; break;
1058 case '4': function_name
= "operator="; break;
1059 case '5': function_name
= "operator>>"; break;
1060 case '6': function_name
= "operator<<"; break;
1061 case '7': function_name
= "operator!"; break;
1062 case '8': function_name
= "operator=="; break;
1063 case '9': function_name
= "operator!="; break;
1064 case 'A': function_name
= "operator[]"; break;
1065 case 'B': function_name
= "operator "; do_after
= 3; break;
1066 case 'C': function_name
= "operator->"; break;
1067 case 'D': function_name
= "operator*"; break;
1068 case 'E': function_name
= "operator++"; break;
1069 case 'F': function_name
= "operator--"; break;
1070 case 'G': function_name
= "operator-"; break;
1071 case 'H': function_name
= "operator+"; break;
1072 case 'I': function_name
= "operator&"; break;
1073 case 'J': function_name
= "operator->*"; break;
1074 case 'K': function_name
= "operator/"; break;
1075 case 'L': function_name
= "operator%"; break;
1076 case 'M': function_name
= "operator<"; break;
1077 case 'N': function_name
= "operator<="; break;
1078 case 'O': function_name
= "operator>"; break;
1079 case 'P': function_name
= "operator>="; break;
1080 case 'Q': function_name
= "operator,"; break;
1081 case 'R': function_name
= "operator()"; break;
1082 case 'S': function_name
= "operator~"; break;
1083 case 'T': function_name
= "operator^"; break;
1084 case 'U': function_name
= "operator|"; break;
1085 case 'V': function_name
= "operator&&"; break;
1086 case 'W': function_name
= "operator||"; break;
1087 case 'X': function_name
= "operator*="; break;
1088 case 'Y': function_name
= "operator+="; break;
1089 case 'Z': function_name
= "operator-="; break;
1091 switch (*++sym
->current
)
1093 case '0': function_name
= "operator/="; break;
1094 case '1': function_name
= "operator%="; break;
1095 case '2': function_name
= "operator>>="; break;
1096 case '3': function_name
= "operator<<="; break;
1097 case '4': function_name
= "operator&="; break;
1098 case '5': function_name
= "operator|="; break;
1099 case '6': function_name
= "operator^="; break;
1100 case '7': function_name
= "`vftable'"; break;
1101 case '8': function_name
= "`vbtable'"; break;
1102 case '9': function_name
= "`vcall'"; break;
1103 case 'A': function_name
= "`typeof'"; break;
1104 case 'B': function_name
= "`local static guard'"; break;
1105 case 'C': function_name
= "`string'"; do_after
= 4; break;
1106 case 'D': function_name
= "`vbase destructor'"; break;
1107 case 'E': function_name
= "`vector deleting destructor'"; break;
1108 case 'F': function_name
= "`default constructor closure'"; break;
1109 case 'G': function_name
= "`scalar deleting destructor'"; break;
1110 case 'H': function_name
= "`vector constructor iterator'"; break;
1111 case 'I': function_name
= "`vector destructor iterator'"; break;
1112 case 'J': function_name
= "`vector vbase constructor iterator'"; break;
1113 case 'K': function_name
= "`virtual displacement map'"; break;
1114 case 'L': function_name
= "`eh vector constructor iterator'"; break;
1115 case 'M': function_name
= "`eh vector destructor iterator'"; break;
1116 case 'N': function_name
= "`eh vector vbase constructor iterator'"; break;
1117 case 'O': function_name
= "`copy constructor closure'"; break;
1118 case 'S': function_name
= "`local vftable'"; break;
1119 case 'T': function_name
= "`local vftable constructor closure'"; break;
1120 case 'U': function_name
= "operator new[]"; break;
1121 case 'V': function_name
= "operator delete[]"; break;
1122 case 'X': function_name
= "`placement delete closure'"; break;
1123 case 'Y': function_name
= "`placement delete[] closure'"; break;
1125 ERR("Unknown operator: _%c\n", *sym
->current
);
1130 /* FIXME: Other operators */
1131 ERR("Unknown operator: %c\n", *sym
->current
);
1138 sym
->stack
.num
= sym
->stack
.max
= 1;
1139 sym
->stack
.elts
[0] = dashed_null
;
1142 sym
->result
= (char*)function_name
;
1146 str_array_push(sym
, function_name
, -1, &sym
->stack
);
1149 sym
->stack
.start
= 1;
1152 /* Either a class name, or '@' if the symbol is not a class member */
1153 if (*sym
->current
!= '@')
1155 /* Class the function is associated with, terminated by '@@' */
1156 if (!get_class(sym
)) goto done
;
1158 else sym
->current
++;
1162 case 0: default: break;
1164 /* it's time to set the member name for ctor & dtor */
1165 if (sym
->stack
.num
<= 1) goto done
;
1167 sym
->stack
.elts
[0] = sym
->stack
.elts
[1];
1169 sym
->stack
.elts
[0] = str_printf(sym
, "~%s", sym
->stack
.elts
[1]);
1170 /* ctors and dtors don't have return type */
1171 sym
->flags
|= UNDNAME_NO_FUNCTION_RETURNS
;
1174 sym
->flags
&= ~UNDNAME_NO_FUNCTION_RETURNS
;
1178 /* Function/Data type and access level */
1179 if (*sym
->current
>= '0' && *sym
->current
<= '7')
1180 ret
= handle_data(sym
);
1181 else if (*sym
->current
>= 'A' && *sym
->current
<= 'Z')
1182 ret
= handle_method(sym
, do_after
== 3);
1185 if (ret
) assert(sym
->result
);
1186 else WARN("Failed at %s\n", sym
->current
);
1191 /*********************************************************************
1192 * __unDNameEx (MSVCRT.@)
1194 * Demangle a C++ identifier.
1197 * buffer [O] If not NULL, the place to put the demangled string
1198 * mangled [I] Mangled name of the function
1199 * buflen [I] Length of buffer
1200 * memget [I] Function to allocate memory with
1201 * memfree [I] Function to free memory with
1202 * unknown [?] Unknown, possibly a call back
1203 * flags [I] Flags determining demangled format
1206 * Success: A string pointing to the unmangled name, allocated with memget.
1209 char* CDECL
__unDNameEx(char* buffer
, const char* mangled
, int buflen
,
1210 malloc_func_t memget
, free_func_t memfree
,
1211 void* unknown
, unsigned short int flags
)
1213 struct parsed_symbol sym
;
1216 TRACE("(%p,%s,%d,%p,%p,%p,%x)\n",
1217 buffer
, mangled
, buflen
, memget
, memfree
, unknown
, flags
);
1219 /* The flags details is not documented by MS. However, it looks exactly
1220 * like the UNDNAME_ manifest constants from imagehlp.h and dbghelp.h
1221 * So, we copied those (on top of the file)
1223 memset(&sym
, 0, sizeof(struct parsed_symbol
));
1224 if (flags
& UNDNAME_NAME_ONLY
)
1225 flags
|= UNDNAME_NO_FUNCTION_RETURNS
| UNDNAME_NO_ACCESS_SPECIFIERS
|
1226 UNDNAME_NO_MEMBER_TYPE
| UNDNAME_NO_ALLOCATION_LANGUAGE
|
1227 UNDNAME_NO_COMPLEX_TYPE
;
1230 sym
.mem_alloc_ptr
= memget
;
1231 sym
.mem_free_ptr
= memfree
;
1232 sym
.current
= mangled
;
1234 result
= symbol_demangle(&sym
) ? sym
.result
: mangled
;
1235 if (buffer
&& buflen
)
1237 lstrcpynA( buffer
, result
, buflen
);
1241 buffer
= memget(strlen(result
) + 1);
1242 if (buffer
) strcpy(buffer
, result
);
1251 /*********************************************************************
1252 * __unDName (MSVCRT.@)
1254 char* CDECL
__unDName(char* buffer
, const char* mangled
, int buflen
,
1255 malloc_func_t memget
, free_func_t memfree
,
1256 unsigned short int flags
)
1258 return __unDNameEx(buffer
, mangled
, buflen
, memget
, memfree
, NULL
, flags
);