The Pedigree Project  0.1
demangle.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "pedigree/kernel/utilities/demangle.h"
21 #include "pedigree/kernel/utilities/StaticString.h"
22 #include "pedigree/kernel/utilities/utility.h"
23 
24 // Uncomment these if running standalone.
25 // include <stdio.h>
26 // include <stdlib.h>
27 // define uintptr_t unsigned int
28 // include "StaticString.h"
29 
30 // typedef StaticString<128> LargeStaticString;
31 typedef struct demangle
32 {
33  demangle()
34  : nSubstitutions(0), nTemplateParams(0), nParams(0), nLevel(0),
35  nNameParseLevel(0)
36  {
37  }
38  LargeStaticString substitutions[16];
39  size_t nSubstitutions;
40  LargeStaticString templateParams[8];
41  size_t nTemplateParams;
42  LargeStaticString params[16];
43  size_t nParams;
44  size_t nLevel;
45  size_t nNameParseLevel;
46 } demangle_t;
47 
48 #define FAIL 1
49 #define SUCCESS 0
50 
51 #define DECLARE(id) \
52  static int parse##id(LargeStaticString &, LargeStaticString &, demangle_t &)
53 #define DECLARE_LVAL(id) \
54  static int parse##id( \
55  LargeStaticString &, LargeStaticString &, demangle_t &, int &)
56 #define DECLARE_SVAL(id) \
57  static int parse##id( \
58  LargeStaticString &, LargeStaticString &, demangle_t &, \
59  LargeStaticString &)
60 DECLARE(MangledName);
61 DECLARE(Name);
62 DECLARE(UnscopedName);
63 DECLARE(UnscopedTemplateName);
64 DECLARE(NestedName);
65 // DECLARE(TemplatePrefix);
66 DECLARE(UnqualifiedName);
67 DECLARE(SourceName);
68 DECLARE(CvQualifiers);
69 DECLARE(Type);
70 DECLARE(BuiltinType);
71 DECLARE(FunctionType);
72 // DECLARE(BareFunctionType);
73 DECLARE(ArrayType);
74 DECLARE(PointerToMemberType);
75 DECLARE(TemplateParam);
76 DECLARE(TemplateTemplateParam);
77 DECLARE(TemplateArgs);
78 DECLARE(TemplateArg);
79 DECLARE(Expression);
80 DECLARE(ExprPrimary);
81 DECLARE(Substitution);
82 DECLARE_LVAL(SeqId);
83 DECLARE(OperatorName);
84 DECLARE(CtorDtorName);
85 DECLARE_SVAL(Prefix);
86 DECLARE_LVAL(Number);
87 DECLARE_LVAL(Identifier);
88 
89 #undef MANGLE_DEBUG
90 #ifdef MANGLE_DEBUG
91 #define END_SUCCESS(id) \
92  do \
93  { \
94  printf( \
95  "[%d] Success:\t %s, \t%s -> %s\n", data.nLevel--, id, \
96  (const char *) src, (const char *) dest); \
97  return SUCCESS; \
98  } while (0)
99 #define END_FAIL(id) \
100  do \
101  { \
102  printf( \
103  "[%d] Fail:\t %s, \t%s -> %s\n", data.nLevel--, id, \
104  (const char *) src, (const char *) dest); \
105  return FAIL; \
106  } while (0)
107 #define START(id) \
108  do \
109  { \
110  printf( \
111  "[%d] Start:\t %s, \t%s -> %s\n", ++data.nLevel, id, \
112  (const char *) src, (const char *) dest); \
113  } while (0)
114 #else // DEBUG
115 #define END_SUCCESS(id) return SUCCESS
116 #define END_FAIL(id) return FAIL
117 #define START(id)
118 #endif
119 
120 // Adds a string to the substitution index.
121 static void addSubstitution(LargeStaticString str, demangle_t &data)
122 {
123  for (size_t i = 0; i < data.nSubstitutions; i++)
124  if (!StringCompare(data.substitutions[i], str))
125  return;
126 
127  // HACK:: Bit of a hack here - we prepend "::" to every identifier. It looks
128  // a bit ugly.
129  if (str[0] == ':' && str[1] == ':')
130  str.stripFirst(2);
131 
132  data.substitutions[data.nSubstitutions++] = str;
133 }
134 
135 /*
136 <mangled_name> ::= _Z <name> [<type> (if template params > 0)] <type>+
137 */
138 static int parseMangledName(
140 {
141  START("MangledName");
142  // Does the string begin with _Z?
143  if (src[0] != '_' || src[1] != 'Z')
144  END_FAIL("MangledName");
145  src.stripFirst(2);
146  if (parseName(src, dest, data) == FAIL)
147  END_FAIL("MangledName");
148 
149  // HACK:: Bit of a hack here - we add the entire function name (foo::bar) to
150  // the substitution index, when it shouldn't be. Here we decrement the
151  // number of substitutions so it is wiped.
152  if (data.nSubstitutions)
153  data.nSubstitutions--;
154 
155  // HACK:: OK here we go, hack again. We manually increase the
156  // data.nNameParseLevel member so that our template parameters don't get
157  // accidentally overwritten.
158  data.nNameParseLevel = 5;
159 
160  // If we have some template params we should expect a type next (for return
161  // type).
162  LargeStaticString tmp; // Just completely ignore the return type.
163  if (data.nTemplateParams > 0)
164  if (parseType(src, tmp, data) == FAIL)
165  END_FAIL("MangledName");
166 
167  data.nParams = 0;
168  do
169  {
170  if (parseType(src, data.params[data.nParams], data) == FAIL)
171  END_FAIL("MangledName");
172  data.nParams++;
173  } while (src.length() > 0);
174  END_SUCCESS("MangledName");
175 }
176 
177 /*
178 <name> ::= <nested-name>
179  ::= <unscoped-name>
180  ::= <unscoped-template-name> <template-args>
181  ::= <local-name> <--- ignored.
182 */
183 static int
184 parseName(LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
185 {
186  START("Name");
187  data.nNameParseLevel++;
188 
189  LargeStaticString origsrc = src;
190  LargeStaticString origdest = dest;
191  // Nested names are the easiest, they start with a 'N'.
192  if (src[0] == 'N')
193  {
194  size_t ret = parseNestedName(src, dest, data);
195  data.nNameParseLevel--;
196  return ret;
197  }
198 
199  // The prefix 'L' means 'static linkage'. We should handle this.
200  if (src[0] == 'L')
201  src.stripFirst(1);
202 
203  // Here we try and parse a template name, with arguments following.
204  if (parseUnscopedTemplateName(src, dest, data) == SUCCESS &&
205  parseTemplateArgs(src, dest, data) == SUCCESS)
206  {
207  data.nNameParseLevel--;
208  END_SUCCESS("Name");
209  }
210  else // Template parseage failed, try normal unscoped name.
211  {
212  src = origsrc; // Restore src.
213  dest = origdest; // Restore dest;
214  if (parseUnscopedName(src, dest, data) == SUCCESS)
215  {
216  data.nNameParseLevel--;
217  END_SUCCESS("Name");
218  }
219  else
220  {
221  data.nNameParseLevel--;
222  END_FAIL("Name");
223  }
224  }
225 }
226 
227 /*
228 <unscoped_name> ::= <unqualified_name>
229  ::= St <unqualified_name> // ::std::
230 */
231 static int parseUnscopedName(
233 {
234  START("UnscopedName");
235  if (parseUnqualifiedName(src, dest, data) == SUCCESS)
236  END_SUCCESS("UnscopedName");
237  else
238  END_FAIL("UnscopedName");
239 }
240 
241 /*
242 <unscoped_template_name> ::= <unscoped_name>
243  ::= <substitution>
244 */
245 static int parseUnscopedTemplateName(
247 {
248  START("UnscopedTemplateName");
249  LargeStaticString origsrc = src;
250  LargeStaticString origdest = dest;
251 
252  // Try substitution first.
253  if (parseSubstitution(src, dest, data) == SUCCESS)
254  END_SUCCESS("UnscopedTemplateName");
255 
256  src = origsrc;
257  dest = origdest;
258 
259  if (parseUnqualifiedName(src, dest, data) == SUCCESS)
260  END_SUCCESS("UnscopedTemplateName");
261  else
262  END_FAIL("UnscopedTemplateName");
263 }
264 
265 /*
266 <nested_name> ::= N [<CV-qualifiers>] <prefix> <unqualified_name> E
267  ::= N [<CV-qualifiers>] <template-prefix> <template_args> E
268 =============== CHANGED TO
269 <nested_name> ::= N [<CV-qualifiers>] <prefix> E
270 */
271 static int parseNestedName(
273 {
274  START("NestedName");
275 
276  if (src[0] != 'N')
277  END_FAIL("NestedName");
278  src.stripFirst(1);
279 
280  // Check CV qualifiers.
281  if (src[0] == 'r' || src[0] == 'K' || src[0] == 'V')
282  {
283  if (parseCvQualifiers(src, dest, data) == FAIL)
284  END_FAIL("NestedName");
285  }
286 
287  LargeStaticString thePrefix;
288  if (parsePrefix(src, dest, data, thePrefix) == FAIL)
289  END_FAIL("NestedName");
290 
291  if (src[0] != 'E')
292  END_FAIL("NestedName");
293  src.stripFirst(1);
294 
295  END_SUCCESS("NestedName");
296 }
297 
298 /*
299 <prefix> ::= <prefix> <unqualified_name>
300  ::= <template_prefix> <template_args>
301  ::= <template_param>
302  ::= # empty
303  ::= <substitution>
304 =============== CHANGED TO
305 <prefix> ::= <unqualified_name> <prefix>
306  ::= <unqualified_name> <template_args> <prefix>
307  ::= <template_param>
308  ::= # empty
309  ::= <substitution>
310 */
311 static int parsePrefix(
313  LargeStaticString &thisPrefix)
314 {
315  START("Prefix");
316 
317  LargeStaticString origsrc = src;
318  LargeStaticString origdest = dest;
319 
320  // Check for a template_param.
321  // if (parseTemplateParam(src, dest, data) == SUCCESS)
322  // END_SUCCESS("Prefix");
323 
324  src = origsrc;
325  dest = origdest;
326 
327  // Check for a substitution.
328  if (parseSubstitution(src, dest, data) == SUCCESS)
329  END_SUCCESS("Prefix");
330 
331  src = origsrc;
332  dest = origdest;
333 
334  // Check for an unqualified name
335  LargeStaticString unqualName;
336  if (parseUnqualifiedName(src, unqualName, data) == SUCCESS)
337  {
338  dest += "::";
339  dest += unqualName;
340  origsrc = src;
341  origdest = dest; // Checkpoint!
342 
343  thisPrefix += "::";
344  thisPrefix += unqualName;
345 
346  addSubstitution(thisPrefix, data);
347 
348  // Do we have a template_args?
349  unqualName = "";
350  if (parseTemplateArgs(src, unqualName, data) == FAIL)
351  {
352  src = origsrc;
353  dest = origdest;
354  }
355  else
356  {
357  dest += unqualName;
358  thisPrefix += unqualName;
359  addSubstitution(thisPrefix, data);
360  }
361 
362  // Recurse.
363  if (parsePrefix(src, dest, data, thisPrefix) == SUCCESS)
364  END_SUCCESS("Prefix");
365  else
366  END_FAIL("Prefix");
367  }
368 
369  src = origsrc;
370  dest = origdest;
371 
372  // Empty rule.
373  END_SUCCESS("Prefix");
374 }
375 
376 /*
377 <template_prefix> ::= <prefix> <unqualified_name>
378  ::= <template_param>
379  ::= <substitution>
380 */
381 // static int parseTemplatePrefix(LargeStaticString &src, LargeStaticString
382 // &dest, demangle_t &data)
383 // {
384 // Unused.
385 // }
386 
387 /*
388 <unqualified_name> ::= <operator_name>
389  ::= <ctor_dtor_name>
390  ::= <source_name>
391 */
392 static int parseUnqualifiedName(
394 {
395  START("UnqualifiedName");
396  LargeStaticString origsrc = src;
397  LargeStaticString origdest = dest;
398 
399  if (parseOperatorName(src, dest, data) == SUCCESS)
400  END_SUCCESS("UnqualifiedName");
401 
402  src = origsrc;
403  dest = origdest;
404 
405  if (parseCtorDtorName(src, dest, data) == SUCCESS)
406  END_SUCCESS("UnqualifiedName");
407 
408  src = origsrc;
409  dest = origdest;
410 
411  if (parseSourceName(src, dest, data) == SUCCESS)
412  END_SUCCESS("UnqualifiedName");
413 
414  END_FAIL("UnqualifiedName");
415 }
416 
417 /*
418 <ctor_dtor_name> ::= C {0,1,2}
419  ::= D {0,1,2}
420 */
421 static int parseCtorDtorName(
423 {
424  START("CtorDtorName");
425  if (src[0] == 'C' && (src[1] == '0' || src[1] == '1' || src[1] == '2'))
426  {
427  src.stripFirst(2);
428  dest += "`ctor'";
429  }
430  else if (src[0] == 'D' && (src[1] == '0' || src[1] == '1' || src[1] == '2'))
431  {
432  src.stripFirst(2);
433  dest += "`dtor'";
434  }
435  else
436  END_FAIL("CtorDtorName");
437  END_SUCCESS("CtorDtorName");
438 }
439 
440 /*
441 <operator-name> ::= nw # new
442  ::= na # new[]
443  ::= dl # delete
444  ::= da # delete[]
445  ::= ps # + (unary)
446  ::= ng # - (unary)
447  ::= ad # & (unary)
448  ::= de # * (unary)
449  ::= co # ~
450  ::= pl # +
451  ::= mi # -
452  ::= ml # *
453  ::= dv # /
454  ::= rm # %
455  ::= an # &
456  ::= or # |
457  ::= eo # ^
458  ::= aS # =
459  ::= pL # +=
460  ::= mI # -=
461  ::= mL # *=
462  ::= dV # /=
463  ::= rM # %=
464  ::= aN # &=
465  ::= oR # |=
466  ::= eO # ^=
467  ::= ls # <<
468  ::= rs # >>
469  ::= lS # <<=
470  ::= rS # >>=
471  ::= eq # ==
472  ::= ne # !=
473  ::= lt # <
474  ::= gt # >
475  ::= le # <=
476  ::= ge # >=
477  ::= nt # !
478  ::= aa # &&
479  ::= oo # ||
480  ::= pp # ++
481  ::= mm # --
482  ::= cm # ,
483  ::= pm # ->*
484  ::= pt # ->
485  ::= cl # ()
486  ::= ix # []
487  ::= qu # ?
488  ::= st # sizeof (a type)
489  ::= sz # sizeof (an expression)
490  ::= cv <type> # (cast)
491 */
492 static int parseOperatorName(
494 {
495  START("OperatorName");
496 
497  LargeStaticString op = src.left(2);
498  src.stripFirst(2);
499 
500  if (op == "nw")
501  dest += "operator new";
502  else if (op == "na")
503  dest += "operator new[]";
504  else if (op == "dl")
505  dest += "operator delete";
506  else if (op == "da")
507  dest += "operator delete[]";
508  else if (op == "ps")
509  dest += "operator+(unary)";
510  else if (op == "ng")
511  dest += "operator-(unary)";
512  else if (op == "ad")
513  dest += "operator&(unary)";
514  else if (op == "de")
515  dest += "operator*(unary)";
516  else if (op == "co")
517  dest += "operator~";
518  else if (op == "pl")
519  dest += "operator+";
520  else if (op == "mi")
521  dest += "operator-";
522  else if (op == "ml")
523  dest += "operator*";
524  else if (op == "dv")
525  dest += "operator/";
526  else if (op == "rm")
527  dest += "operator%";
528  else if (op == "an")
529  dest += "operator&";
530  else if (op == "or")
531  dest += "operator|";
532  else if (op == "eo")
533  dest += "operator^";
534  else if (op == "aS")
535  dest += "operator=";
536  else if (op == "pL")
537  dest += "operator+=";
538  else if (op == "mI")
539  dest += "operator-=";
540  else if (op == "mL")
541  dest += "operator*=";
542  else if (op == "dV")
543  dest += "operator/=";
544  else if (op == "rM")
545  dest += "operator%=";
546  else if (op == "aN")
547  dest += "operator&=";
548  else if (op == "oR")
549  dest += "operator|=";
550  else if (op == "eO")
551  dest += "operator^=";
552  else if (op == "ls")
553  dest += "operator<<";
554  else if (op == "rs")
555  dest += "operator>>";
556  else if (op == "lS")
557  dest += "operator<<=";
558  else if (op == "rS")
559  dest += "operator>>=";
560  else if (op == "eq")
561  dest += "operator==";
562  else if (op == "ne")
563  dest += "operator!=";
564  else if (op == "lt")
565  dest += "operator<";
566  else if (op == "gt")
567  dest += "operator>";
568  else if (op == "le")
569  dest += "operator<=";
570  else if (op == "ge")
571  dest += "operator>=";
572  else if (op == "nt")
573  dest += "operator!";
574  else if (op == "aa")
575  dest += "operator&&";
576  else if (op == "oo")
577  dest += "operator||";
578  else if (op == "pp")
579  dest += "operator++";
580  else if (op == "mm")
581  dest += "operator--";
582  else if (op == "cm")
583  dest += "operator,";
584  else if (op == "pm")
585  dest += "operator->*";
586  else if (op == "pt")
587  dest += "operator->";
588  else if (op == "cl")
589  dest += "operator()";
590  else if (op == "ix")
591  dest += "operator[]";
592  else if (op == "qu")
593  dest += "operator?";
594  else if (op == "st")
595  dest += "operator sizeof";
596  else if (op == "sz")
597  dest += "operator sizeof";
598  else if (op == "cv")
599  {
600  dest += "operator ";
601  if (parseType(src, dest, data) == FAIL)
602  END_FAIL("OperatorName");
603  }
604  else
605  END_FAIL("OperatorName");
606 
607  END_SUCCESS("OperatorName");
608 }
609 
610 /*
611 <source_name> ::= <number> <identifier>
612 */
613 static int parseSourceName(
615 {
616  START("SourceName");
617 
618  int lval;
619  if (parseNumber(src, dest, data, lval) == SUCCESS && lval >= 0 &&
620  parseIdentifier(src, dest, data, lval) == SUCCESS)
621  END_SUCCESS("SourceName");
622 
623  END_FAIL("SourceName");
624 }
625 
626 /*
627 <number> ::= [n] <non negative decimal integer>
628 */
629 static int parseNumber(
631  int &lval)
632 {
633  START("Number");
634 
635  // Negative?
636  bool bNegative = false;
637  if (src[0] == 'n')
638  {
639  bNegative = true;
640  src.stripFirst(1);
641  }
642 
643  // Non numeric?
644  if (src[0] < '0' || src[0] > '9')
645  END_FAIL("Number");
646 
647  size_t nLength = 0;
648  char str[32];
649  while (src[nLength] >= '0' && src[nLength] <= '9')
650  {
651  str[nLength] = src[nLength];
652  nLength++;
653  }
654  str[nLength] = '\0';
655  lval = StringToUnsignedLong(str, 0, 10);
656  if (bNegative)
657  lval = -lval;
658 
659  src.stripFirst(nLength);
660 
661  END_SUCCESS("Number");
662 }
663 
664 /*
665 <identifier> ::= <unqualified source code identifier>
666 */
667 static int parseIdentifier(
669  int &lval)
670 {
671  START("Identifier");
672  if (static_cast<int>(src.length()) < lval)
673  END_FAIL("Identifier");
674  for (int i = 0; i < lval; i++)
675  dest += src[i];
676  src.stripFirst(lval);
677  END_SUCCESS("Identifier");
678 }
679 
680 /*
681 <CV-qualifiers> ::= [r] [V] [K]
682 */
683 static int parseCvQualifiers(
685 {
686  START("CvQualifiers");
687  bool bParsedOne = false;
688  if (src[0] == 'r')
689  {
690  bParsedOne = true;
691  dest += "restrict ";
692  src.stripFirst(1);
693  }
694  if (src[0] == 'V')
695  {
696  bParsedOne = true;
697  dest += "volatile ";
698  src.stripFirst(1);
699  }
700  if (src[0] == 'K')
701  {
702  bParsedOne = true;
703  dest += "const ";
704  src.stripFirst(1);
705  }
706  if (!bParsedOne)
707  END_FAIL("CvQualifiers");
708  else
709  END_SUCCESS("CvQualifiers");
710 }
711 
712 /*
713 <type> ::= <CV-qualifiers> <type>
714  ::= P <type>
715  ::= R <type>
716  ::= <builtin-type>
717  ::= <function-type>
718  ::= <name> # class-enum-type
719  ::= <array-type>
720  ::= <pointer-to-member-type>
721  ::= <template-param>
722  ::= <template-template-param> <template-args>
723  ::= <substitution>
724 */
725 static int
726 parseType(LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
727 {
728  START("Type");
729 
730  // CV-qualifiers?
731  if (src[0] == 'r' || src[0] == 'V' || src[0] == 'K')
732  {
733  LargeStaticString tmp;
734  if (parseCvQualifiers(src, tmp, data) == FAIL)
735  END_FAIL("Type");
736  if (parseType(src, tmp, data) == FAIL)
737  END_FAIL("Type");
738  dest += tmp;
739  addSubstitution(tmp, data);
740  END_SUCCESS("Type");
741  }
742  // Pointer?
743  else if (src[0] == 'P')
744  {
745  src.stripFirst(1);
746  LargeStaticString tmp;
747  if (parseType(src, tmp, data) == FAIL)
748  END_FAIL("Type");
749  dest += tmp;
750  tmp += "*";
751  dest += "*";
752  addSubstitution(tmp, data);
753  END_SUCCESS("Type");
754  }
755  // Reference?
756  else if (src[0] == 'R')
757  {
758  src.stripFirst(1);
759  LargeStaticString tmp;
760  if (parseType(src, tmp, data) == FAIL)
761  END_FAIL("Type");
762  dest += tmp;
763  tmp += "&";
764  dest += "&";
765  addSubstitution(tmp, data);
766  END_SUCCESS("Type");
767  }
768  // Function-type?
769  else if (src[0] == 'F')
770  {
771  if (parseFunctionType(src, dest, data) == FAIL)
772  END_FAIL("Type");
773  END_SUCCESS("Type");
774  }
775  // Array type?
776  else if (src[0] == 'A')
777  {
778  if (parseArrayType(src, dest, data) == FAIL)
779  END_FAIL("Type");
780  END_SUCCESS("Type");
781  }
782  // Pointer-to-member type?
783  else if (src[0] == 'M')
784  {
785  if (parsePointerToMemberType(src, dest, data) == FAIL)
786  END_FAIL("Type");
787  END_SUCCESS("Type");
788  }
789  // Template parameter type?
790  else if (src[0] == 'T')
791  {
792  // Try the template-template-type first, if it fails fall back.
793  LargeStaticString origsrc = src;
794  LargeStaticString origdest = dest;
795  if (parseTemplateTemplateParam(src, dest, data) == SUCCESS &&
796  parseTemplateArgs(src, dest, data) == SUCCESS)
797  END_SUCCESS("Type");
798 
799  src = origsrc;
800  dest = origdest;
801 
802  if (parseTemplateParam(src, dest, data) == FAIL)
803  END_FAIL("Type");
804 
805  END_SUCCESS("Type");
806  }
807  else
808  {
809  // OK then, try a builtin-type.
810  LargeStaticString origsrc = src;
811  LargeStaticString origdest = dest;
812  if (parseBuiltinType(src, dest, data) == SUCCESS)
813  END_SUCCESS("Type");
814 
815  src = origsrc;
816  dest = origdest;
817 
818  LargeStaticString tmp;
819  if (parseName(src, tmp, data) == SUCCESS)
820  {
821  dest += tmp;
822  addSubstitution(tmp, data);
823  END_SUCCESS("Type");
824  }
825 
826  if (src[0] == 'S')
827  {
828  src = origsrc;
829  dest = origdest;
830  if (parseSubstitution(src, dest, data) == FAIL)
831  END_FAIL("Type");
832  END_SUCCESS("Type");
833  }
834 
835  END_FAIL("Type");
836  }
837 }
838 
839 /*
840 <builtin-type> ::= v # void
841  ::= w # wchar_t
842  ::= b # bool
843  ::= c # char
844  ::= a # signed char
845  ::= h # unsigned char
846  ::= s # short
847  ::= t # unsigned short
848  ::= i # int
849  ::= j # unsigned int
850  ::= l # long
851  ::= m # unsigned long
852  ::= x # long long, __int64
853  ::= y # unsigned long long, __int64
854  ::= n # __int128
855  ::= o # unsigned __int128
856  ::= f # float
857  ::= d # double
858  ::= e # long double, __float80
859  ::= g # __float128
860  ::= z # ellipsis
861 */
862 static int parseBuiltinType(
864 {
865  START("BuiltinType");
866  switch (src[0])
867  {
868  case 'v':
869  dest += "void";
870  break;
871  case 'w':
872  dest += "wchar_t";
873  break;
874  case 'b':
875  dest += "bool";
876  break;
877  case 'c':
878  dest += "char";
879  break;
880  case 'a':
881  dest += "char";
882  break;
883  case 'h':
884  dest += "unsigned char";
885  break;
886  case 's':
887  dest += "short";
888  break;
889  case 't':
890  dest += "unsigned short";
891  break;
892  case 'i':
893  dest += "int";
894  break;
895  case 'j':
896  dest += "unsigned int";
897  break;
898  case 'l':
899  dest += "long";
900  break;
901  case 'm':
902  dest += "unsigned long";
903  break;
904  case 'x':
905  dest += "__int64";
906  break;
907  case 'y':
908  dest += "unsigned __int64";
909  break;
910  case 'n':
911  dest += "__int128";
912  break;
913  case 'o':
914  dest += "unsigned __int128";
915  break;
916  case 'f':
917  dest += "float";
918  break;
919  case 'd':
920  dest += "double";
921  break;
922  case 'z':
923  dest += "...";
924  break;
925  default:
926  END_FAIL("BuiltinType");
927  }
928  src.stripFirst(1);
929  END_SUCCESS("BuiltinType");
930 }
931 
932 /*
933 <function_type> ::= F [Y] <type> <type>+ E
934 */
935 static int parseFunctionType(
937 {
938  START("FunctionType");
939 
940  // Should start with an 'F'.
941  if (src[0] != 'F')
942  END_FAIL("FunctionType");
943 
944  src.stripFirst(1);
945  // Do we have a 'Y'?
946  if (src[0] == 'Y')
947  src.stripFirst(1); // Ignore it.
948 
949  // Return type.
950  if (parseType(src, dest, data) == FAIL)
951  END_FAIL("FunctionType");
952 
953  dest += " ()(";
954  bool bIsFirst = true;
955  do
956  {
957  if (bIsFirst)
958  bIsFirst = false;
959  else
960  dest += ", ";
961  if (parseType(src, dest, data) == FAIL)
962  END_FAIL("FunctionType");
963  } while (src[0] != 'E');
964 
965  dest += ")";
966  src.stripFirst(1);
967  END_SUCCESS("FunctionType");
968 }
969 
970 /*
971 <bare_function_type> ::= <type>+
972 */
973 // static int parseBareFunctionType(LargeStaticString &src, LargeStaticString
974 // &dest, demangle_t &data)
975 // {
976 // Unused.
977 // }
978 
979 /*
980 <array_type> ::= A <number> _ <type>
981  ::= A <expression> _ <type>
982 */
983 static int parseArrayType(
985 {
986  START("Array");
987 
988  // We should start with an 'A'.
989  if (src[0] != 'A')
990  END_FAIL("Array");
991 
992  src.stripFirst(1);
993  LargeStaticString bound;
994  // Number?
995  if (src[0] >= '0' && src[0] <= '9')
996  {
997  size_t nLength = 0;
998  while (src[nLength] >= '0' && src[nLength] <= '9')
999  bound += src[nLength++];
1000  src.stripFirst(nLength);
1001  }
1002  else if (parseExpression(src, bound, data) == FAIL)
1003  END_FAIL("Array");
1004 
1005  // We should be looking at a '_'.
1006  if (src[0] != '_')
1007  END_FAIL("Array");
1008 
1009  src.stripFirst(1);
1010 
1011  // Get the type.
1012  if (parseType(src, dest, data) == FAIL)
1013  END_FAIL("Array");
1014 
1015  // Append the bound.
1016  dest += " [";
1017  dest += bound;
1018  dest += "]";
1019 
1020  END_SUCCESS("Array");
1021 }
1022 
1023 /*
1024 <pointer_to_member_type> ::= M <class type> <member type>
1025 */
1026 static int parsePointerToMemberType(
1027  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1028 {
1029  START("PointerToMemberType");
1030 
1031  // We should start with an 'M'.
1032  if (src[0] != 'M')
1033  END_FAIL("PointerToMemberType");
1034 
1035  src.stripFirst(1);
1036 
1037  LargeStaticString classType;
1038  if (parseType(src, classType, data) == FAIL)
1039  END_FAIL("PointerToMemberType");
1040 
1041  // If the next thing is a function, we cheat a little to get a decent
1042  // looking member member function.
1046  if (src[0] == 'F')
1047  {
1048  LargeStaticString function;
1049  if (parseFunctionType(src, function, data) == FAIL)
1050  END_FAIL("PointerToMemberType");
1051  // find the bit before the parameter list "()".
1052  size_t nLength = 0;
1053  while (function[nLength] != '(' || function[nLength + 1] != ')')
1054  nLength++; // NOTE unsafe!
1055 
1056  dest += function.left(nLength + 1);
1057  dest += classType;
1058  dest += "::*";
1059  dest += function.right(function.length() - nLength - 1);
1060  }
1061  else
1062  {
1063  if (parseType(src, dest, data) == FAIL)
1064  END_FAIL("PointerToMemberType");
1065  dest += " ";
1066  dest += classType;
1067  dest += "::*";
1068  }
1069  END_SUCCESS("PointerToMemberType");
1070 }
1071 
1072 /*
1073 <template_param> ::= T_ # first parameter
1074  ::= T <parameter-2 non negative number> _
1075 */
1076 static int parseTemplateParam(
1077  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1078 {
1079  START("TemplateParam");
1080 
1081  // Must start with a T.
1082  if (src[0] != 'T')
1083  END_FAIL("TemplateParam");
1084 
1085  src.stripFirst(1);
1086  // If we don't start with _, there's a number first.
1087  int nId = 0;
1088  if (src[0] != '_')
1089  {
1090  parseNumber(src, dest, data, nId);
1091  nId++; // T_ is 0, T0_ is 1, etc etc.
1092  }
1093 
1094  // Now we should DEFINATELY be looking at a '_'.
1095  if (src[0] != '_')
1096  END_FAIL("TemplateParam");
1097 
1098  src.stripFirst(1);
1099 
1100  // Now, look up the substitution.
1101  if (nId >= static_cast<int>(data.nTemplateParams))
1102  END_FAIL("TemplateParam");
1103 
1104  // Else, stick it in!
1105  dest += data.templateParams[nId];
1106  END_SUCCESS("TemplateParam");
1107 }
1108 
1109 /*
1110 <template_template_param> ::= <template-param> # first parameter
1111  ::= <substitution>
1112 */
1113 static int parseTemplateTemplateParam(
1114  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1115 {
1116  START("TemplateTemplateParam");
1117  if (parseTemplateParam(src, dest, data) == SUCCESS)
1118  END_SUCCESS("TemplateTemplateParam");
1119  else
1120  END_FAIL("TemplateTemplateParam");
1121 }
1122 
1123 /*
1124 <template_args> ::= I <template_arg>+ E
1125 */
1126 static int parseTemplateArgs(
1127  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1128 {
1129  START("TemplateArgs");
1130 
1131  LargeStaticString tmp;
1132  if (data.nNameParseLevel == 1)
1133  data.nTemplateParams = 0;
1134 
1135  if (src[0] != 'I')
1136  END_FAIL("TemplateArgs");
1137 
1138  src.stripFirst(1);
1139  bool bIsFirst = true;
1140  dest += "<";
1141  do
1142  {
1143  tmp = "";
1144  if (!bIsFirst)
1145  dest += ", ";
1146  bIsFirst = false;
1147  if (parseTemplateArg(src, tmp, data) == FAIL)
1148  END_FAIL("TemplateArgs");
1149  dest += tmp;
1150  if (data.nNameParseLevel == 1)
1151  {
1152  data.templateParams[data.nTemplateParams] = tmp;
1153  data.nTemplateParams++;
1154  }
1155  } while (src[0] != 'E');
1156  dest += ">";
1157  src.stripFirst(1);
1158 
1159  END_SUCCESS("TemplateArgs");
1160 }
1161 
1162 /*
1163 <template_arg> ::= <type>
1164  ::= X <expression> E
1165  ::= <expr-primary>
1166 */
1167 static int parseTemplateArg(
1168  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1169 {
1170  START("TemplateArg");
1171  LargeStaticString origsrc = src;
1172  LargeStaticString origdest = dest;
1173 
1174  if (parseType(src, dest, data) == SUCCESS)
1175  END_SUCCESS("TemplateArg");
1176 
1177  src = origsrc;
1178  dest = origdest;
1179 
1180  if (src[0] == 'X')
1181  {
1182  src.stripFirst(1);
1183  if (parseExpression(src, dest, data) == FAIL)
1184  END_FAIL("TemplateArg");
1185  if (src[0] != 'E')
1186  END_FAIL("TemplateArg");
1187  src.stripFirst(1);
1188  END_SUCCESS("TemplateArg");
1189  }
1190 
1191  src = origsrc;
1192  dest = origdest;
1193 
1194  if (parseExprPrimary(src, dest, data) == SUCCESS)
1195  END_SUCCESS("TemplateArg");
1196 
1197  END_FAIL("TemplateArg");
1198 }
1199 
1200 /*
1201 <expression> ::= <unary operator-name> <expression>
1202  ::= <binary operator-name> <expression> <expression>
1203  ::= <trinary operator-name> <expression> <expression> <expression>
1204  ::= st <type>
1205  ::= <template-param>
1206  ::= sr <type> <unqualified-name> # dependent name
1207  ::= sr <type> <unqualified-name> <template-args> # dependent template-id
1208  ::= <expr-primary>
1209 */
1210 static int parseExpression(
1211  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1212 {
1213  START("Expression");
1214 
1215  if (src[0] == 'T')
1216  {
1217  if (parseTemplateParam(src, dest, data) == FAIL)
1218  END_FAIL("Expression");
1219  else
1220  END_SUCCESS("Expression");
1221  }
1222  else if (src[0] == 'L')
1223  {
1224  if (parseExprPrimary(src, dest, data) == FAIL)
1225  END_FAIL("Expression");
1226  else
1227  END_SUCCESS("Expression");
1228  }
1229 
1230  LargeStaticString op = src.left(2);
1231  src.stripFirst(2);
1232 
1233 #define UNARY_OP(prefix) \
1234  { \
1235  dest += prefix; \
1236  if (parseExpression(src, dest, data) == FAIL) \
1237  END_FAIL("Expression"); \
1238  else \
1239  END_SUCCESS("Expression"); \
1240  }
1241 #define BINARY_OP(infix) \
1242  { \
1243  dest += "("; \
1244  if (parseExpression(src, dest, data) == FAIL) \
1245  END_FAIL("Expression"); \
1246  dest += infix; \
1247  if (parseExpression(src, dest, data) == FAIL) \
1248  END_FAIL("Expression"); \
1249  else \
1250  { \
1251  dest += ")"; \
1252  END_SUCCESS("Expression"); \
1253  } \
1254  }
1255  if (op == "ps")
1256  UNARY_OP("+")
1257  else if (op == "ng")
1258  UNARY_OP("-")
1259  else if (op == "ad")
1260  UNARY_OP("&")
1261  else if (op == "de")
1262  UNARY_OP("*")
1263  else if (op == "co")
1264  UNARY_OP("~")
1265  else if (op == "nt")
1266  UNARY_OP("!")
1267  else if (op == "pl")
1268  BINARY_OP("+")
1269  else if (op == "mi")
1270  BINARY_OP("-")
1271  else if (op == "ml")
1272  BINARY_OP("*")
1273  else if (op == "dv")
1274  BINARY_OP("/")
1275  else if (op == "rm")
1276  BINARY_OP("%")
1277  else if (op == "an")
1278  BINARY_OP("&")
1279  else if (op == "or")
1280  BINARY_OP("|")
1281  else if (op == "eo")
1282  BINARY_OP("^")
1283  else if (op == "ls")
1284  BINARY_OP("<<")
1285  else if (op == "rs")
1286  BINARY_OP(">>")
1287  else if (op == "st")
1288  {
1289  dest += "sizeof (";
1290  if (parseType(src, dest, data) == FAIL)
1291  END_FAIL("Expression");
1292  dest += ")";
1293  END_SUCCESS("Expression");
1294  }
1295 
1296  END_FAIL("Expression");
1297 }
1298 
1299 /*
1300 <expr-primary> ::= L <type> <value number> E # integer literal
1301  ::= L <type> <value float> E # floating literal (ignored)
1302  ::= L <mangled-name> E # external name
1303 */
1304 static int parseExprPrimary(
1305  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1306 {
1307  START("ExprPrimary");
1308 
1309  // We should be looking at an 'L'.
1310  if (src[0] != 'L')
1311  END_FAIL("ExprPrimary");
1312 
1313  src.stripFirst(1);
1314 
1315  // HACK:: We don't want the full "unsigned int" nonsense, if it's a builtin
1316  // type we use our own handlers. Else we fall back on parseType.
1317  const char *cookie = 0;
1318  switch (src[0])
1319  {
1320  case 'i':
1321  src.stripFirst(1);
1322  break;
1323  case 'j':
1324  cookie = "u";
1325  src.stripFirst(1);
1326  break;
1327  case 'l':
1328  cookie = "l";
1329  src.stripFirst(1);
1330  break;
1331  case 'm':
1332  cookie = "ul";
1333  src.stripFirst(1);
1334  break;
1335  default:
1336  {
1337  dest += '(';
1338  if (parseType(src, dest, data) == FAIL)
1339  END_FAIL("ExprPrimary");
1340  dest += ')';
1341  }
1342  }
1343 
1344  int n;
1345  if (parseNumber(src, dest, data, n) == FAIL)
1346  END_FAIL("ExprPrimary");
1347  dest += static_cast<ssize_t>(n);
1348  dest += cookie;
1349  if (src[0] != 'E')
1350  END_FAIL("ExprPrimary");
1351  src.stripFirst(1);
1353 
1354  END_SUCCESS("ExprPrimary");
1355 }
1356 
1357 /*
1358 <substitution> ::= S <seq_id> _
1359  ::= S_
1360 */
1361 static int parseSubstitution(
1362  LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
1363 {
1364  START("Substitution");
1365 
1366  // Must start with an S.
1367  if (src[0] != 'S')
1368  END_FAIL("Substitution");
1369 
1370  src.stripFirst(1);
1371  // If we don't start with _, there's a number first.
1372  int nId = 0;
1373  if (src[0] != '_')
1374  {
1375  parseSeqId(src, dest, data, nId);
1376  nId++; // S_ is 0, S0_ is 1, etc etc.
1377  }
1378 
1379  // Now we should DEFINATELY be looking at a '_'.
1380  if (src[0] != '_')
1381  END_FAIL("Substitution");
1382 
1383  src.stripFirst(1);
1384 
1385  // Now, look up the substitution.
1386  if (nId >= static_cast<int>(data.nSubstitutions))
1387  END_FAIL("Substitution");
1388 
1389  // Else, stick it in!
1390  dest += data.substitutions[nId];
1391 
1392  END_SUCCESS("Substitution");
1393 }
1394 
1395 /*
1396 <seq_id> ::= <base 36 number>
1397 */
1398 static int parseSeqId(
1399  LargeStaticString &src, LargeStaticString &dest, demangle_t &data,
1400  int &lval)
1401 {
1402  START("SeqId");
1403  size_t nLength = 0;
1404  char str[32];
1405  while ((src[nLength] >= '0' && src[nLength] <= '9') ||
1406  ((src[nLength] >= 'A') && src[nLength] <= 'Z'))
1407  {
1408  str[nLength] = src[nLength];
1409  nLength++;
1410  }
1411  str[nLength] = '\0';
1412  lval = StringToUnsignedLong(str, 0, 36);
1413 
1414  src.stripFirst(nLength);
1415  END_SUCCESS("SeqId");
1416 }
1417 
1418 // If you want to run this standalone, uncomment this function.
1419 // int main(char argc, char **argv)
1420 // {
1421 // LargeStaticString src = LargeStaticString(argv[1]);
1422 // LargeStaticString dest;
1423 // demangle_t data;
1424 // data.nLevel = 0;
1425 // data.nSubstitutions = 0;
1426 // data.nNameParseLevel = 0;
1427 // int code = parseMangledName(src, dest, data);
1428 //
1429 // // HACK:: Bit of a hack here - we prepend "::" to every identifier. It
1430 // looks a bit ugly. if (dest[0] == ':' && dest[1] == ':')
1431 // dest.stripFirst(2);
1432 //
1433 // // Parse parameter list.
1434 // LargeStaticString params;
1435 // params += "(";
1436 // for (int i = 0; i < data.nParams; i++)
1437 // {
1438 // if (i > 0)
1439 // params += ", ";
1440 //
1441 // params += data.params[i];
1442 // };
1443 // params += ")";
1444 //
1445 // if (code == FAIL)
1446 // printf("Failed.\n");
1447 // else
1448 // printf("%s -> %s%s\n", (const char*)argv[1], (const char*)dest, (const
1449 // char*)params);
1450 //
1451 // printf("Substitutions:\n");
1452 // for (int i = 0; i < data.nSubstitutions; i++)
1453 // {
1454 // if (i == 0)
1455 // printf("\t S_: %s\n", (const char*)data.substitutions[0]);
1456 // else
1457 // printf("\t S%d_: %s\n", i-1, (const char*)data.substitutions[i]);
1458 // }
1459 //
1460 // printf("Template params:\n");
1461 // for (int i = 0; i < data.nTemplateParams; i++)
1462 // {
1463 // if (i == 0)
1464 // printf("\t T_: %s\n", (const char*)data.templateParams[0]);
1465 // else
1466 // printf("\t T%d_: %s\n", i-1, (const char*)data.templateParams[i]);
1467 // }
1468 // return 0;
1469 // }
1470 
1472 void demangle(LargeStaticString src, symbol_t *sym)
1473 {
1474  static demangle_t data;
1475  data.nLevel = 0;
1476  data.nSubstitutions = 0;
1477  data.nNameParseLevel = 0;
1478  int code = parseMangledName(src, sym->name, data);
1479  // HACK:: Bit of a hack here - we prepend "::" to every identifier. It looks
1480  // a bit ugly.
1481  if (sym->name[0] == ':' && sym->name[1] == ':')
1482  sym->name.stripFirst(2);
1483 
1484  if (code == FAIL)
1485  {
1486  sym->name = src;
1487  sym->nParams = 0;
1488  return;
1489  }
1490 
1491  sym->nParams = data.nParams;
1492  for (size_t i = 0; i < data.nParams; i++)
1493  sym->params[i] = data.params[i];
1494 }
1495 
1497 void demangle_full(LargeStaticString src, LargeStaticString &dest)
1498 {
1499  static demangle_t data;
1500  data.nLevel = 0;
1501  data.nSubstitutions = 0;
1502  data.nNameParseLevel = 0;
1503  data.nParams = 0;
1504 
1505  int code = parseMangledName(src, dest, data);
1506  // HACK:: Bit of a hack here - we prepend "::" to every identifier. It looks
1507  // a bit ugly.
1508  if (dest[0] == ':' && dest[1] == ':')
1509  dest.stripFirst(2);
1510 
1511  if (code == FAIL)
1512  {
1513  dest = src;
1514  return;
1515  }
1516 
1517  dest += "(";
1518  for (size_t i = 0; i < data.nParams; i++)
1519  {
1520  if (i > 0)
1521  dest += ", ";
1522 
1523  dest += data.params[i];
1524  };
1525  dest += ")";
1526 }
StaticString right(int n) const
Definition: StaticString.h:249