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