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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 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
;
854 if (!demangle_datatype(sym
, &ct
, NULL
, FALSE
)) goto done
;
855 if (!get_modifier(*sym
->current
++, &modifier
)) goto done
;
856 sym
->stack
.num
= mark
;
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
!= '@')
867 if (!(cls
= get_class_name(sym
)))
869 ct
.right
= str_printf(sym
, "{for `%s'}", cls
);
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
);
884 /******************************************************************
886 * Does the final parsing and handling for a function or a method in
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
;
901 struct array array_pmt
;
903 /* FIXME: why 2 possible letters for each option?
906 * 'C' private: static
907 * 'D' private: static
908 * 'E' private: virtual
909 * 'F' private: virtual
914 * 'K' protected: static
915 * 'L' protected: static
916 * 'M' protected: virtual
917 * 'N' protected: virtual
918 * 'O' protected: thunk
919 * 'P' protected: thunk
924 * 'U' public: virtual
925 * 'V' public: virtual
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
;
966 name
= get_class_string(sym
, 0);
968 if (!get_calling_convention(*sym
->current
++, &call_conv
, &exported
,
972 str_array_init(&array_pmt
);
974 /* Return type, or @ if 'void' */
975 if (*sym
->current
== '@')
977 ct_ret
.left
= "void";
983 if (!demangle_datatype(sym
, &ct_ret
, &array_pmt
, FALSE
))
986 if (sym
->flags
& UNDNAME_NO_FUNCTION_RETURNS
)
987 ct_ret
.left
= ct_ret
.right
= NULL
;
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
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
);
1013 /*******************************************************************
1015 * Demangle a C++ linker symbol
1017 static BOOL
symbol_demangle(struct parsed_symbol
* sym
)
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
);
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
);
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;
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;
1120 ERR("Unknown operator: _%c\n", *sym
->current
);
1125 /* FIXME: Other operators */
1126 ERR("Unknown operator: %c\n", *sym
->current
);
1133 sym
->stack
.num
= sym
->stack
.max
= 1;
1134 sym
->stack
.elts
[0] = "--null--";
1137 sym
->result
= (char*)function_name
;
1141 str_array_push(sym
, function_name
, -1, &sym
->stack
);
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
++;
1157 case 0: default: break;
1159 /* it's time to set the member name for ctor & dtor */
1160 if (sym
->stack
.num
<= 1) goto done
;
1162 sym
->stack
.elts
[0] = sym
->stack
.elts
[1];
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
;
1169 sym
->flags
&= ~UNDNAME_NO_FUNCTION_RETURNS
;
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);
1180 if (ret
) assert(sym
->result
);
1181 else WARN("Failed at %s\n", sym
->current
);
1186 /*********************************************************************
1187 * __unDNameEx (MSVCRT.@)
1189 * Demangle a C++ identifier.
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
1201 * Success: A string pointing to the unmangled name, allocated with memget.
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
;
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
;
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';
1237 buffer
= memget(strlen(result
) + 1);
1238 if (buffer
) strcpy(buffer
, result
);
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
);