msvcrt: Added some assembly glue for the asm bits of __CxxFrameHandler
[wine] / dlls / msvcrt / undname.c
1 /*
2  *  Demangle VC++ symbols into C function prototypes
3  *
4  *  Copyright 2000 Jon Griffiths
5  *            2004 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include "msvcrt.h"
28
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
32
33 /* TODO:
34  * - document a bit (grammar + fonctions)
35  * - back-port this new code into tools/winedump/msmangle.c
36  */
37
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)
56
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 "
64  *
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
72  *              
73  */
74
75 #define MAX_ARRAY_ELTS  32
76 struct array
77 {
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];
82 };
83
84 /* Structure holding a parsed symbol */
85 struct parsed_symbol
86 {
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 */
90
91     const char*         current;        /* pointer in input (mangled) string */
92     char*               result;         /* demangled string */
93
94     struct array        stack;          /* stack of parsed strings */
95
96     void*               alloc_list;     /* linked list of allocated blocks */
97     unsigned            avail_in_first; /* number of available bytes in head block */
98 };
99
100 /* Type for parsing mangled types */
101 struct datatype_t
102 {
103     const char*         left;
104     const char*         right;
105 };
106
107 /******************************************************************
108  *              und_alloc
109  *
110  * Internal allocator. Uses a simple linked list of large blocks
111  * where we use a poor-man allocator. It's fast, and since all
112  * allocation is pool, memory management is easy (esp. freeing).
113  */
114 static void*    und_alloc(struct parsed_symbol* sym, size_t len)
115 {
116     void*       ptr;
117
118 #define BLOCK_SIZE      1024
119 #define AVAIL_SIZE      (1024 - sizeof(void*))
120
121     if (len > AVAIL_SIZE)
122     {
123         /* allocate a specific block */
124         ptr = sym->mem_alloc_ptr(sizeof(void*) + len);
125         if (!ptr) return NULL;
126         *(void**)ptr = sym->alloc_list;
127         sym->alloc_list = ptr;
128         sym->avail_in_first = 0;
129         ptr = (char*)sym->alloc_list + sizeof(void*);
130     }
131     else 
132     {
133         if (len > sym->avail_in_first)
134         {
135             /* add a new block */
136             ptr = sym->mem_alloc_ptr(BLOCK_SIZE);
137             if (!ptr) return NULL;
138             *(void**)ptr = sym->alloc_list;
139             sym->alloc_list = ptr;
140             sym->avail_in_first = AVAIL_SIZE;
141         }
142         /* grab memory from head block */
143         ptr = (char*)sym->alloc_list + BLOCK_SIZE - sym->avail_in_first;
144         sym->avail_in_first -= len;
145     }
146     return ptr;
147 #undef BLOCK_SIZE
148 #undef AVAIL_SIZE
149 }
150
151 /******************************************************************
152  *              und_free
153  * Frees all the blocks in the list of large blocks allocated by
154  * und_alloc.
155  */
156 static void und_free_all(struct parsed_symbol* sym)
157 {
158     void*       next;
159
160     while (sym->alloc_list)
161     {
162         next = *(void**)sym->alloc_list;
163         sym->mem_free_ptr(sym->alloc_list);
164         sym->alloc_list = next;
165     }
166     sym->avail_in_first = 0;
167 }
168
169 /******************************************************************
170  *              str_array_init
171  * Initialises an array of strings
172  */
173 static void str_array_init(struct array* a)
174 {
175     a->start = a->num = a->max = 0;
176 }
177
178 /******************************************************************
179  *              str_array_push
180  * Adding a new string to an array
181  */
182 static void str_array_push(struct parsed_symbol* sym, const char* ptr, size_t len, 
183                            struct array* a)
184 {
185     assert(ptr);
186     assert(a);
187     assert(a->num < MAX_ARRAY_ELTS);
188     if (len == -1) len = strlen(ptr);
189     a->elts[a->num] = und_alloc(sym, len + 1);
190     assert(a->elts[a->num]);
191     memcpy(a->elts[a->num], ptr, len);
192     a->elts[a->num][len] = '\0'; 
193     if (++a->num >= a->max) a->max = a->num;
194     {
195         int i;
196         char c;
197
198         for (i = a->max - 1; i >= 0; i--)
199         {
200             c = '>';
201             if (i < a->start) c = '-';
202             else if (i >= a->num) c = '}';
203             TRACE("\t%d%c %s\n", i, c, a->elts[i]);
204         }
205     }
206 }
207
208 /******************************************************************
209  *              str_array_get_ref
210  * Extracts a reference from an existing array (doing proper type
211  * checking)
212  */
213 static char* str_array_get_ref(struct array* cref, unsigned idx)
214 {
215     assert(cref);
216     if (cref->start + idx >= cref->max)
217     {
218         WARN("Out of bounds: %p %d + %d >= %d\n", 
219               cref, cref->start, idx, cref->max);
220         return NULL;
221     }
222     TRACE("Returning %p[%d] => %s\n", 
223           cref, idx, cref->elts[cref->start + idx]);
224     return cref->elts[cref->start + idx];
225 }
226
227 /******************************************************************
228  *              str_printf
229  * Helper for printf type of command (only %s and %c are implemented) 
230  * while dynamically allocating the buffer
231  */
232 static char* str_printf(struct parsed_symbol* sym, const char* format, ...)
233 {
234     va_list     args;
235     size_t      len = 1, i, sz;
236     char*       tmp;
237     char*       p;
238     char*       t;
239
240     va_start(args, format);
241     for (i = 0; format[i]; i++)
242     {
243         if (format[i] == '%')
244         {
245             switch (format[++i])
246             {
247             case 's': t = va_arg(args, char*); if (t) len += strlen(t); break;
248             case 'c': (void)va_arg(args, int); len++; break;
249             default: i--; /* fall thru */
250             case '%': len++; break;
251             }
252         }
253         else len++;
254     }
255     va_end(args);
256     if (!(tmp = (char*)und_alloc(sym, len))) return NULL;
257     va_start(args, format);
258     for (p = tmp, i = 0; format[i]; i++)
259     {
260         if (format[i] == '%')
261         {
262             switch (format[++i])
263             {
264             case 's':
265                 t = va_arg(args, char*);
266                 if (t)
267                 {
268                     sz = strlen(t);
269                     memcpy(p, t, sz);
270                     p += sz;
271                 }
272                 break;
273             case 'c':
274                 *p++ = (char)va_arg(args, int);
275                 break;
276             default: i--; /* fall thru */
277             case '%': *p++ = '%'; break;
278             }
279         }
280         else *p++ = format[i];
281     }
282     va_end(args);
283     *p = '\0';
284     return tmp;
285 }
286
287 /* forward declaration */
288 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
289                               struct array* pmt, BOOL in_args);
290
291 /******************************************************************
292  *              get_args
293  * Parses a list of function/method arguments, creates a string corresponding
294  * to the arguments' list.
295  */
296 static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_term, 
297                       char open_char, char close_char)
298
299 {
300     struct datatype_t   ct;
301     struct array        arg_collect;
302     char*               args_str = NULL;
303     int                 i;
304
305     str_array_init(&arg_collect);
306
307     /* Now come the function arguments */
308     while (*sym->current)
309     {
310         /* Decode each data type and append it to the argument list */
311         if (*sym->current == '@')
312         {
313             sym->current++;
314             break;
315         }
316         if (!demangle_datatype(sym, &ct, pmt_ref, TRUE))
317             return NULL;
318         /* 'void' terminates an argument list */
319         if (!strcmp(ct.left, "void"))
320         {
321             if (!z_term && *sym->current == '@') sym->current++;
322             break;
323         }
324         str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1, 
325                        &arg_collect);
326         if (!strcmp(ct.left, "...")) break;
327     }
328     /* Functions are always terminated by 'Z'. If we made it this far and
329      * don't find it, we have incorrectly identified a data type.
330      */
331     if (z_term && *sym->current++ != 'Z') return NULL;
332
333     if (arg_collect.num == 0 || 
334         (arg_collect.num == 1 && !strcmp(arg_collect.elts[0], "void")))        
335         return str_printf(sym, "%cvoid%c", open_char, close_char);
336     for (i = 1; i < arg_collect.num; i++)
337     {
338         args_str = str_printf(sym, "%s,%s", args_str, arg_collect.elts[i]);
339     }
340
341     if (close_char == '>' && args_str && args_str[strlen(args_str) - 1] == '>')
342         args_str = str_printf(sym, "%c%s%s %c", 
343                               open_char, arg_collect.elts[0], args_str, close_char);
344     else
345         args_str = str_printf(sym, "%c%s%s%c", 
346                               open_char, arg_collect.elts[0], args_str, close_char);
347     
348     return args_str;
349 }
350
351 /******************************************************************
352  *              get_modifier
353  * Parses the type modifier. Always returns a static string
354  */
355 static BOOL get_modifier(char ch, const char** ret)
356 {
357     switch (ch)
358     {
359     case 'A': *ret = NULL; break;
360     case 'B': *ret = "const"; break;
361     case 'C': *ret = "volatile"; break;
362     case 'D': *ret = "const volatile"; break;
363     default: return FALSE;
364     }
365     return TRUE;
366 }
367
368 static const char* get_modified_type(struct parsed_symbol* sym, char modif)
369 {
370     const char* modifier;
371     const char* ret = NULL;
372     const char* str_modif;
373
374     switch (modif)
375     {
376     case 'A': str_modif = " &"; break;
377     case 'P': str_modif = " *"; break;
378     case 'Q': str_modif = " * const"; break;
379     case '?': str_modif = ""; break;
380     default: return NULL;
381     }
382
383     if (get_modifier(*sym->current++, &modifier))
384     {
385         unsigned            mark = sym->stack.num;
386         struct datatype_t   sub_ct;
387
388         /* Recurse to get the referred-to type */
389         if (!demangle_datatype(sym, &sub_ct, NULL, FALSE))
390             return NULL;
391         ret = str_printf(sym, "%s%s%s%s%s", 
392                          sub_ct.left, sub_ct.left && modifier ? " " : NULL, 
393                          modifier, sub_ct.right, str_modif);
394         sym->stack.num = mark;
395     }
396     return ret;
397 }
398
399 /******************************************************************
400  *              get_class
401  * Parses class as a list of parent-classes, separated by '@', terminated by '@@'
402  * and stores the result in 'a' array. Each parent-classes, as well as the inner
403  * element (either field/method name or class name), are stored as allocated
404  * strings in the array.
405  */
406 static BOOL get_class(struct parsed_symbol* sym)
407 {
408     const char* ptr;
409
410     while (*sym->current != '@')
411     {
412         switch (*sym->current)
413         {
414         case '\0': return FALSE;
415
416         case '0': case '1': case '2': case '3':
417         case '4': case '5': case '6': case '7':
418         case '8': case '9':
419             ptr = str_array_get_ref(&sym->stack, *sym->current++ - '0');
420             if (!ptr) return FALSE;
421             str_array_push(sym, ptr, -1, &sym->stack);
422             break;
423         case '?':
424             if (*++sym->current == '$') 
425             {
426                 const char*     name = ++sym->current;
427                 char*           full = NULL;
428                 char*           args = NULL;
429                 unsigned        num_mark = sym->stack.num;
430                 unsigned        start_mark = sym->stack.start;
431
432                 while (*sym->current++ != '@');
433
434                 sym->stack.start = sym->stack.num;
435                 str_array_push(sym, name, sym->current - name -1, &sym->stack);
436                 args = get_args(sym, NULL, FALSE, '<', '>');
437                 if (args != NULL)
438                 {
439                     full = str_printf(sym, "%s%s", sym->stack.elts[num_mark], args);
440                 }
441                 if (!full) return FALSE;
442                 sym->stack.elts[num_mark] = full;
443                 sym->stack.num = num_mark + 1;
444                 sym->stack.start = start_mark;
445             }
446             break;
447         default:
448             ptr = sym->current;
449             while (*sym->current++ != '@');
450             str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->stack);
451             break;
452         }
453     }
454     sym->current++;
455     return TRUE;
456 }
457
458 /******************************************************************
459  *              get_class_string
460  * From an array collected by get_class, constructs the corresponding (allocated) 
461  * string
462  */
463 static char* get_class_string(struct parsed_symbol* sym, /*const struct array* a, */int start)
464 {
465     int         i;
466     size_t      len, sz;
467     char*       ret;
468     struct array *a = &sym->stack;
469     for (len = 0, i = start; i < a->num; i++)
470     {
471         assert(a->elts[i]);
472         len += 2 + strlen(a->elts[i]);
473     }
474     if (!(ret = und_alloc(sym, len - 1))) return NULL;
475     for (len = 0, i = a->num - 1; i >= start; i--)
476     {
477         sz = strlen(a->elts[i]);
478         memcpy(ret + len, a->elts[i], sz);
479         len += sz;
480         if (i > start)
481         {
482             ret[len++] = ':';
483             ret[len++] = ':';
484         }
485     }
486     ret[len] = '\0';
487     return ret;
488 }
489
490 /******************************************************************
491  *              get_calling_convention
492  * Returns a static string corresponding to the calling convention described
493  * by char 'ch'. Sets export to TRUE iff the calling convention is exported.
494  */
495 static BOOL get_calling_convention(struct parsed_symbol* sym, char ch, 
496                                    const char** call_conv, const char** exported,
497                                    unsigned flags)
498 {
499     *call_conv = *exported = NULL;
500
501     if (!(flags & (UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ALLOCATION_LANGUAGE)))
502     {
503         if (flags & UNDNAME_NO_LEADING_UNDERSCORES)
504         {
505             if (((ch - 'A') % 2) == 1) *exported = "dll_export ";
506             switch (ch)
507             {
508             case 'A': case 'B': *call_conv = "cdecl"; break;
509             case 'C': case 'D': *call_conv = "pascal"; break;
510             case 'E': case 'F': *call_conv = "thiscall"; break;
511             case 'G': case 'H': *call_conv = "stdcall"; break;
512             case 'I': case 'J': *call_conv = "fastcall"; break;
513             case 'K': break;
514             default: ERR("Unknown calling convention %c\n", ch); return FALSE;
515             }
516         }
517         else
518         {
519             if (((ch - 'A') % 2) == 1) *exported = "__dll_export ";
520             switch (ch)
521             {
522             case 'A': case 'B': *call_conv = "__cdecl"; break;
523             case 'C': case 'D': *call_conv = "__pascal"; break;
524             case 'E': case 'F': *call_conv = "__thiscall"; break;
525             case 'G': case 'H': *call_conv = "__stdcall"; break;
526             case 'I': case 'J': *call_conv = "__fastcall"; break;
527             case 'K': break;
528             default: ERR("Unknown calling convention %c\n", ch); return FALSE;
529             }
530         }
531     }
532     return TRUE;
533 }
534
535 /*******************************************************************
536  *         get_simple_type
537  * Return a string containing an allocated string for a simple data type
538  */
539 static const char* get_simple_type(struct parsed_symbol* sym, char c)
540 {
541     const char* type_string;
542     
543     switch (c)
544     {
545     case 'C': type_string = "signed char"; break;
546     case 'D': type_string = "char"; break;
547     case 'E': type_string = "unsigned char"; break;
548     case 'F': type_string = "short"; break;
549     case 'G': type_string = "unsigned short"; break;
550     case 'H': type_string = "int"; break;
551     case 'I': type_string = "unsigned int"; break;
552     case 'J': type_string = "long"; break;
553     case 'K': type_string = "unsigned long"; break;
554     case 'M': type_string = "float"; break;
555     case 'N': type_string = "double"; break;
556     case 'O': type_string = "long double"; break;
557     case 'X': type_string = "void"; break;
558     case 'Z': type_string = "..."; break;
559     default:  type_string = NULL; break;
560     }
561     return type_string;
562 }
563 /*******************************************************************
564  *         get_extented_type
565  * Return a string containing an allocated string for a simple data type
566  */
567 static const char* get_extended_type(struct parsed_symbol* sym, char c)
568 {
569     const char* type_string;
570     
571     switch (c)
572     {
573     case 'D': type_string = "__int8"; break;
574     case 'E': type_string = "unsigned __int8"; break;
575     case 'F': type_string = "__int16"; break;
576     case 'G': type_string = "unsigned __int16"; break;
577     case 'H': type_string = "__int32"; break;
578     case 'I': type_string = "unsigned __int32"; break;
579     case 'J': type_string = "__int64"; break;
580     case 'K': type_string = "unsigned __int64"; break;
581     case 'L': type_string = "__int128"; break;
582     case 'M': type_string = "unsigned __int128"; break;
583     case 'N': type_string = "bool"; break;
584     case 'W': type_string = "wchar_t"; break;
585     default:  type_string = NULL; break;
586     }
587     return type_string;
588 }
589
590 /*******************************************************************
591  *         demangle_datatype
592  *
593  * Attempt to demangle a C++ data type, which may be datatype.
594  * a datatype type is made up of a number of simple types. e.g:
595  * char** = (pointer to (pointer to (char)))
596  */
597 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
598                               struct array* pmt_ref, BOOL in_args)
599 {
600     char                dt;
601     BOOL                add_pmt = TRUE;
602     int                 num_args=0;
603
604     assert(ct);
605     ct->left = ct->right = NULL;
606     
607     switch (dt = *sym->current++)
608     {
609     case '_':
610         /* MS type: __int8,__int16 etc */
611         ct->left = get_extended_type(sym, *sym->current++);
612         break;
613     case 'C': case 'D': case 'E': case 'F': case 'G':
614     case 'H': case 'I': case 'J': case 'K': case 'M':
615     case 'N': case 'O': case 'X': case 'Z':
616         /* Simple data types */
617         ct->left = get_simple_type(sym, dt);
618         add_pmt = FALSE;
619         break;
620     case 'T': /* union */
621     case 'U': /* struct */
622     case 'V': /* class */
623         /* Class/struct/union */
624         {
625             unsigned    mark = sym->stack.num;
626             const char* struct_name = NULL;
627             const char* type_name = NULL;
628
629             if (!get_class(sym) ||
630                 !(struct_name = get_class_string(sym, mark))) goto done;
631             sym->stack.num = mark;
632             if (!(sym->flags & UNDNAME_NO_COMPLEX_TYPE)) 
633             {
634                 switch (dt)
635                 {
636                 case 'T': type_name = "union ";  break;
637                 case 'U': type_name = "struct "; break;
638                 case 'V': type_name = "class ";  break;
639                 }
640             }
641             ct->left = str_printf(sym, "%s%s", type_name, struct_name);
642         }
643         break;
644     case '?':
645         /* not all the time is seems */
646         if (!(ct->left = get_modified_type(sym, '?'))) goto done;
647         break;
648     case 'A':
649         if (!(ct->left = get_modified_type(sym, 'A'))) goto done;
650         break;
651     case 'Q':
652         if (!(ct->left = get_modified_type(sym, in_args ? 'Q' : 'P'))) goto done;
653         break;
654     case 'P': /* Pointer */
655         if (isdigit(*sym->current))
656         {
657             /* FIXME: P6 = Function pointer, others who knows.. */
658             if (*sym->current++ == '6')
659             {
660                 char*                   args = NULL;
661                 const char*             call_conv;
662                 const char*             exported;
663                 struct datatype_t       sub_ct;
664                 unsigned                mark = sym->stack.num;
665
666                 if (!get_calling_convention(sym, *sym->current++, 
667                                             &call_conv, &exported, 
668                                             sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
669                     !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
670                     goto done;
671
672                 args = get_args(sym, pmt_ref, TRUE, '(', ')');
673                 if (!args) goto done;
674                 sym->stack.num = mark;
675
676                 ct->left  = str_printf(sym, "%s%s (%s*", 
677                                        sub_ct.left, sub_ct.right, call_conv);
678                 ct->right = str_printf(sym, ")%s", args);
679             }
680             else goto done;
681         }
682         else if (!(ct->left = get_modified_type(sym, 'P'))) goto done;
683         break;
684     case 'W':
685         if (*sym->current == '4')
686         {
687             char*               enum_name;
688             unsigned            mark = sym->stack.num;
689             sym->current++;
690             if (!get_class(sym) ||
691                 !(enum_name = get_class_string(sym, mark))) goto done;
692             sym->stack.num = mark;
693             if (sym->flags & UNDNAME_NO_COMPLEX_TYPE)
694                 ct->left = enum_name;
695             else
696                 ct->left = str_printf(sym, "enum %s", enum_name);
697         }
698         else goto done;
699         break;
700     case '0': case '1': case '2': case '3': case '4':
701     case '5': case '6': case '7': case '8': case '9':
702         /* Referring back to previously parsed type */
703         ct->left = str_array_get_ref(pmt_ref, dt - '0');
704         if (!ct->left) goto done;
705         add_pmt = FALSE;
706         break;
707     case '$':
708         if (sym->current[0] != '0') goto done;
709         if (sym->current[1] >= '0' && sym->current[1] <= '9')
710         {
711             char*       ptr;
712             ptr = und_alloc(sym, 2);
713             ptr[0] = sym->current[1] + 1;
714             ptr[1] = 0;
715             ct->left = ptr;
716             sym->current += 2;
717         }
718         else if (sym->current[1] >= 'A' && sym->current[1] <= 'P')
719         {
720             while (sym->current[1] >= 'A' && sym->current[1] <= 'P')
721             {
722                 num_args *= 16;
723                 num_args += sym->current[1] - 'A';
724                 sym->current += 1;
725             }
726             if(sym->current[1] == '@')
727             {
728                 char *ptr;
729                 ptr = und_alloc(sym, 17);
730                 sprintf(ptr,"%d",num_args);
731                 ct->left = ptr;
732                 sym->current += 1;
733             }
734         }
735         else goto done;
736         break;
737     default :
738         ERR("Unknown type %c\n", dt);
739         break;
740     }
741     if (add_pmt && pmt_ref && in_args)
742         str_array_push(sym, str_printf(sym, "%s%s", ct->left, ct->right), 
743                        -1, pmt_ref);
744 done:
745     
746     return ct->left != NULL;
747 }
748
749 /******************************************************************
750  *              handle_data
751  * Does the final parsing and handling for a variable or a field in
752  * a class.
753  */
754 static BOOL handle_data(struct parsed_symbol* sym)
755 {
756     const char*         access = NULL;
757     const char*         member_type = NULL;
758     const char*         modifier = NULL;
759     struct datatype_t   ct;
760     char*               name = NULL;
761     BOOL                ret = FALSE;
762     char                dt;
763
764     /* 0 private static
765      * 1 protected static
766      * 2 public static
767      * 3 private non-static
768      * 4 protected non-static
769      * 5 public non-static
770      * 6 ?? static
771      * 7 ?? static
772      */
773
774     if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
775     {
776         /* we only print the access for static members */
777         switch (*sym->current)
778         {
779         case '0': access = "private: "; break;
780         case '1': access = "protected: "; break;
781         case '2': access = "public: "; break;
782         } 
783     }
784
785     if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
786     {
787         if (*sym->current >= '0' && *sym->current <= '2')
788             member_type = "static ";
789     }
790
791     name = get_class_string(sym, 0);
792
793     switch (dt = *sym->current++)
794     {
795     case '0': case '1': case '2':
796     case '3': case '4': case '5':
797         {
798             unsigned mark = sym->stack.num;
799             if (!demangle_datatype(sym, &ct, NULL, FALSE)) goto done;
800             if (!get_modifier(*sym->current++, &modifier)) goto done;
801             sym->stack.num = mark;
802         }
803         break;
804     case '6' : /* compiler generated static */
805     case '7' : /* compiler generated static */
806         ct.left = ct.right = NULL;
807         if (!get_modifier(*sym->current++, &modifier)) goto done;
808         if (*sym->current != '@')
809         {
810             unsigned    mark = sym->stack.num;
811             char*       cls = NULL;
812
813             if (!get_class(sym) ||
814                 !(cls = get_class_string(sym, mark))) goto done;
815             sym->stack.num = mark;
816             ct.right = str_printf(sym, "{for `%s'}", cls);
817         }
818         break;
819     default: goto done;
820     }
821     if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = modifier = NULL;
822     sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s", access,
823                              member_type, ct.left, 
824                              modifier && ct.left ? " " : NULL, modifier, 
825                              modifier || ct.left ? " " : NULL, name, ct.right);
826     ret = TRUE;
827 done:
828     return ret;
829 }
830
831 /******************************************************************
832  *              handle_method
833  * Does the final parsing and handling for a function or a method in
834  * a class.
835  */
836 static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op)
837 {
838     const char*         access = NULL;
839     const char*         member_type = NULL;
840     struct datatype_t   ct_ret;
841     const char*         call_conv;
842     const char*         modifier = NULL;
843     const char*         exported;
844     const char*         args_str = NULL;
845     const char*         name = NULL;
846     BOOL                ret = FALSE;
847     unsigned            mark;
848     struct array        array_pmt;
849
850     /* FIXME: why 2 possible letters for each option?
851      * 'A' private:
852      * 'B' private:
853      * 'C' private: static
854      * 'D' private: static
855      * 'E' private: virtual
856      * 'F' private: virtual
857      * 'G' private: thunk
858      * 'H' private: thunk
859      * 'I' protected:
860      * 'J' protected:
861      * 'K' protected: static
862      * 'L' protected: static
863      * 'M' protected: virtual
864      * 'N' protected: virtual
865      * 'O' protected: thunk
866      * 'P' protected: thunk
867      * 'Q' public:
868      * 'R' public:
869      * 'S' public: static
870      * 'T' public: static
871      * 'U' public: virtual
872      * 'V' public: virtual
873      * 'W' public: thunk
874      * 'X' public: thunk
875      * 'Y'
876      * 'Z'
877      */
878
879     if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
880     {
881         switch ((*sym->current - 'A') / 8)
882         {
883         case 0: access = "private: "; break;
884         case 1: access = "protected: "; break;
885         case 2: access = "public: "; break;
886         }
887     }
888     if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
889     {
890         if (*sym->current >= 'A' && *sym->current <= 'X')
891         {
892             switch ((*sym->current - 'A') % 8)
893             {
894             case 2: case 3: member_type = "static "; break;
895             case 4: case 5: member_type = "virtual "; break;
896             case 6: case 7: member_type = "thunk "; break;
897             }
898         }
899     }
900
901     if (*sym->current >= 'A' && *sym->current <= 'X')
902     {
903         if (!((*sym->current - 'A') & 2))
904         {
905             /* Implicit 'this' pointer */
906             /* If there is an implicit this pointer, const modifier follows */
907             if (!get_modifier(*++sym->current, &modifier)) goto done;
908         }
909     }
910     else if (*sym->current < 'A' || *sym->current > 'Z') goto done;
911     sym->current++;
912
913     name = get_class_string(sym, 0);
914   
915     if (!get_calling_convention(sym, *sym->current++, 
916                                 &call_conv, &exported, sym->flags))
917         goto done;
918
919     str_array_init(&array_pmt);
920
921     /* Return type, or @ if 'void' */
922     if (*sym->current == '@')
923     {
924         ct_ret.left = "void";
925         ct_ret.right = NULL;
926         sym->current++;
927     }
928     else
929     {
930         if (!demangle_datatype(sym, &ct_ret, &array_pmt, FALSE))
931             goto done;
932     }
933     if (sym->flags & UNDNAME_NO_FUNCTION_RETURNS)
934         ct_ret.left = ct_ret.right = NULL;
935     if (cast_op)
936     {
937         name = str_printf(sym, "%s%s%s", name, ct_ret.left, ct_ret.right);
938         ct_ret.left = ct_ret.right = NULL;
939     }
940
941     mark = sym->stack.num;
942     if (!(args_str = get_args(sym, &array_pmt, TRUE, '(', ')'))) goto done;
943     if (sym->flags & UNDNAME_NAME_ONLY) args_str = modifier = NULL;
944     sym->stack.num = mark;
945
946     /* Note: '()' after 'Z' means 'throws', but we don't care here
947      * Yet!!! FIXME
948      */
949     sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s%s%s%s%s",
950                              access, member_type, ct_ret.left, 
951                              (ct_ret.left && !ct_ret.right) ? " " : NULL,
952                              call_conv, call_conv ? " " : NULL, exported,
953                              name, args_str, modifier, 
954                              modifier ? " " : NULL, ct_ret.right);
955     ret = TRUE;
956 done:
957     return ret;
958 }
959
960 /*******************************************************************
961  *         demangle_symbol
962  * Demangle a C++ linker symbol
963  */
964 static BOOL symbol_demangle(struct parsed_symbol* sym)
965 {
966     BOOL                ret = FALSE;
967     unsigned            do_after = 0;
968
969     /* FIXME seems wrong as name, as it demangles a simple data type */
970     if (sym->flags & UNDNAME_NO_ARGUMENTS)
971     {
972         struct datatype_t   ct;
973
974         if (demangle_datatype(sym, &ct, NULL, FALSE))
975         {
976             sym->result = str_printf(sym, "%s%s", ct.left, ct.right);
977             ret = TRUE;
978         }
979         goto done;
980     }
981
982     /* MS mangled names always begin with '?' */
983     if (*sym->current != '?') return FALSE;
984     str_array_init(&sym->stack);
985     sym->current++;
986
987     /* Then function name or operator code */
988     if (*sym->current == '?' && sym->current[1] != '$')
989     {
990         const char* function_name = NULL;
991
992         /* C++ operator code (one character, or two if the first is '_') */
993         switch (*++sym->current)
994         {
995         case '0': do_after = 1; break;
996         case '1': do_after = 2; break;
997         case '2': function_name = "operator new"; break;
998         case '3': function_name = "operator delete"; break;
999         case '4': function_name = "operator="; break;
1000         case '5': function_name = "operator>>"; break;
1001         case '6': function_name = "operator<<"; break;
1002         case '7': function_name = "operator!"; break;
1003         case '8': function_name = "operator=="; break;
1004         case '9': function_name = "operator!="; break;
1005         case 'A': function_name = "operator[]"; break;
1006         case 'B': function_name = "operator "; do_after = 3; break;
1007         case 'C': function_name = "operator->"; break;
1008         case 'D': function_name = "operator*"; break;
1009         case 'E': function_name = "operator++"; break;
1010         case 'F': function_name = "operator--"; break;
1011         case 'G': function_name = "operator-"; break;
1012         case 'H': function_name = "operator+"; break;
1013         case 'I': function_name = "operator&"; break;
1014         case 'J': function_name = "operator->*"; break;
1015         case 'K': function_name = "operator/"; break;
1016         case 'L': function_name = "operator%"; break;
1017         case 'M': function_name = "operator<"; break;
1018         case 'N': function_name = "operator<="; break;
1019         case 'O': function_name = "operator>"; break;
1020         case 'P': function_name = "operator>="; break;
1021         case 'Q': function_name = "operator,"; break;
1022         case 'R': function_name = "operator()"; break;
1023         case 'S': function_name = "operator~"; break;
1024         case 'T': function_name = "operator^"; break;
1025         case 'U': function_name = "operator|"; break;
1026         case 'V': function_name = "operator&&"; break;
1027         case 'W': function_name = "operator||"; break;
1028         case 'X': function_name = "operator*="; break;
1029         case 'Y': function_name = "operator+="; break;
1030         case 'Z': function_name = "operator-="; break;
1031         case '_':
1032             switch (*++sym->current)
1033             {
1034             case '0': function_name = "operator/="; break;
1035             case '1': function_name = "operator%="; break;
1036             case '2': function_name = "operator>>="; break;
1037             case '3': function_name = "operator<<="; break;
1038             case '4': function_name = "operator&="; break;
1039             case '5': function_name = "operator|="; break;
1040             case '6': function_name = "operator^="; break;
1041             case '7': function_name = "`vftable'"; break;
1042             case '8': function_name = "`vbtable'"; break;
1043             case '9': function_name = "`vcall'"; break;
1044             case 'A': function_name = "`typeof'"; break;
1045             case 'B': function_name = "`local static guard'"; break;
1046             case 'C': function_name = "`string'"; do_after = 4; break;
1047             case 'D': function_name = "`vbase destructor'"; break;
1048             case 'E': function_name = "`vector deleting destructor'"; break;
1049             case 'F': function_name = "`default constructor closure'"; break;
1050             case 'G': function_name = "`scalar deleting destructor'"; break;
1051             case 'H': function_name = "`vector constructor iterator'"; break;
1052             case 'I': function_name = "`vector destructor iterator'"; break;
1053             case 'J': function_name = "`vector vbase constructor iterator'"; break;
1054             case 'K': function_name = "`virtual displacement map'"; break;
1055             case 'L': function_name = "`eh vector constructor iterator'"; break;
1056             case 'M': function_name = "`eh vector destructor iterator'"; break;
1057             case 'N': function_name = "`eh vector vbase constructor iterator'"; break;
1058             case 'O': function_name = "`copy constructor closure'"; break;
1059             case 'S': function_name = "`local vftable'"; break;
1060             case 'T': function_name = "`local vftable constructor closure'"; break;
1061             case 'U': function_name = "operator new[]"; break;
1062             case 'V': function_name = "operator delete[]"; break;
1063             case 'X': function_name = "`placement delete closure'"; break;
1064             case 'Y': function_name = "`placement delete[] closure'"; break;
1065             default:
1066                 ERR("Unknown operator: _%c\n", *sym->current);
1067                 return FALSE;
1068             }
1069             break;
1070         default:
1071             /* FIXME: Other operators */
1072             ERR("Unknown operator: %c\n", *sym->current);
1073             return FALSE;
1074         }
1075         sym->current++;
1076         switch (do_after)
1077         {
1078         case 1: case 2:
1079             sym->stack.num = sym->stack.max = 1;
1080             sym->stack.elts[0] = "--null--";
1081             break;
1082         case 4:
1083             sym->result = (char*)function_name;
1084             ret = TRUE;
1085             goto done;
1086         default:
1087             str_array_push(sym, function_name, -1, &sym->stack);
1088             break;
1089         }
1090         sym->stack.start = 1;
1091     }
1092
1093     /* Either a class name, or '@' if the symbol is not a class member */
1094     if (*sym->current != '@')
1095     {
1096         /* Class the function is associated with, terminated by '@@' */
1097         if (!get_class(sym)) goto done;
1098     }
1099     else sym->current++;
1100
1101     switch (do_after)
1102     {
1103     case 0: default: break;
1104     case 1: case 2:
1105         /* it's time to set the member name for ctor & dtor */
1106         if (sym->stack.num <= 1) goto done;
1107         if (do_after == 1)
1108             sym->stack.elts[0] = sym->stack.elts[1];
1109         else
1110             sym->stack.elts[0] = str_printf(sym, "~%s", sym->stack.elts[1]);
1111         /* ctors and dtors don't have return type */
1112         sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;
1113         break;
1114     case 3:
1115         sym->flags &= ~UNDNAME_NO_FUNCTION_RETURNS;
1116         break;
1117     }
1118
1119     /* Function/Data type and access level */
1120     if (*sym->current >= '0' && *sym->current <= '7')
1121         ret = handle_data(sym);
1122     else if (*sym->current >= 'A' && *sym->current <= 'Z')
1123         ret = handle_method(sym, do_after == 3);
1124     else ret = FALSE;
1125 done:
1126     if (ret) assert(sym->result);
1127     else WARN("Failed at %s\n", sym->current);
1128
1129     return ret;
1130 }
1131
1132 /*********************************************************************
1133  *              __unDNameEx (MSVCRT.@)
1134  *
1135  * Demangle a C++ identifier.
1136  *
1137  * PARAMS
1138  *  buffer   [O] If not NULL, the place to put the demangled string
1139  *  mangled  [I] Mangled name of the function
1140  *  buflen   [I] Length of buffer
1141  *  memget   [I] Function to allocate memory with
1142  *  memfree  [I] Function to free memory with
1143  *  unknown  [?] Unknown, possibly a call back
1144  *  flags    [I] Flags determining demangled format
1145  *
1146  * RETURNS
1147  *  Success: A string pointing to the unmangled name, allocated with memget.
1148  *  Failure: NULL.
1149  */
1150 char* __unDNameEx(char* buffer, const char* mangled, int buflen,
1151                   malloc_func_t memget, free_func_t memfree,
1152                   void* unknown, unsigned short int flags)
1153 {
1154     struct parsed_symbol        sym;
1155     const char*                 result;
1156
1157     TRACE("(%p,%s,%d,%p,%p,%p,%x) stub!\n",
1158           buffer, mangled, buflen, memget, memfree, unknown, flags);
1159     
1160     /* The flags details is not documented by MS. However, it looks exactly
1161      * like the UNDNAME_ manifest constants from imagehlp.h and dbghelp.h
1162      * So, we copied those (on top of the file)
1163      */
1164     memset(&sym, 0, sizeof(struct parsed_symbol));
1165     if (flags & UNDNAME_NAME_ONLY)
1166         flags |= UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_ACCESS_SPECIFIERS |
1167             UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_ALLOCATION_LANGUAGE |
1168             UNDNAME_NO_COMPLEX_TYPE;
1169
1170     sym.flags         = flags;
1171     sym.mem_alloc_ptr = memget;
1172     sym.mem_free_ptr  = memfree;
1173     sym.current       = mangled;
1174
1175     result = symbol_demangle(&sym) ? sym.result : mangled;
1176     if (buffer && buflen)
1177     {
1178         memcpy(buffer, result, buflen - 1);
1179         buffer[buflen - 1] = '\0';
1180     }
1181     else
1182     {
1183         buffer = memget(strlen(result) + 1);
1184         if (buffer) strcpy(buffer, result);
1185     }
1186
1187     und_free_all(&sym);
1188
1189     return buffer;
1190 }
1191
1192
1193 /*********************************************************************
1194  *              __unDName (MSVCRT.@)
1195  */
1196 char* __unDName(char* buffer, const char* mangled, int buflen,
1197                 malloc_func_t memget, free_func_t memfree,
1198                 unsigned short int flags)
1199 {
1200     return __unDNameEx(buffer, mangled, buflen, memget, memfree, NULL, flags);
1201 }