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