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