1 //===------------------------- ItaniumDemangle.cpp ------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // FIXME: (possibly) incomplete list of features that clang mangles that this
10 // file does not yet support:
13 #include "llvm/Demangle/Demangle.h"
14 #include "llvm/Demangle/ItaniumDemangle.h"
26 using namespace llvm::itanium_demangle
;
28 constexpr const char *itanium_demangle::FloatData
<float>::spec
;
29 constexpr const char *itanium_demangle::FloatData
<double>::spec
;
30 constexpr const char *itanium_demangle::FloatData
<long double>::spec
;
32 // <discriminator> := _ <non-negative number> # when number < 10
33 // := __ <non-negative number> _ # when number >= 10
34 // extension := decimal-digit+ # at the end of string
35 const char *itanium_demangle::parse_discriminator(const char *first
,
37 // parse but ignore discriminator
40 const char *t1
= first
+ 1;
42 if (std::isdigit(*t1
))
44 else if (*t1
== '_') {
45 for (++t1
; t1
!= last
&& std::isdigit(*t1
); ++t1
)
47 if (t1
!= last
&& *t1
== '_')
51 } else if (std::isdigit(*first
)) {
52 const char *t1
= first
+ 1;
53 for (; t1
!= last
&& std::isdigit(*t1
); ++t1
)
66 bool PendingNewline
= false;
68 template<typename NodeT
> static constexpr bool wantsNewline(const NodeT
*) {
71 static bool wantsNewline(NodeArray A
) { return !A
.empty(); }
72 static constexpr bool wantsNewline(...) { return false; }
74 template<typename
...Ts
> static bool anyWantNewline(Ts
...Vs
) {
75 for (bool B
: {wantsNewline(Vs
)...})
81 void printStr(const char *S
) { fprintf(stderr
, "%s", S
); }
82 void print(std::string_view SV
) {
83 fprintf(stderr
, "\"%.*s\"", (int)SV
.size(), SV
.data());
85 void print(const Node
*N
) {
87 N
->visit(std::ref(*this));
91 void print(NodeArray A
) {
95 for (const Node
*N
: A
) {
106 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
107 void print(bool B
) { printStr(B
? "true" : "false"); }
109 template <class T
> std::enable_if_t
<std::is_unsigned
<T
>::value
> print(T N
) {
110 fprintf(stderr
, "%llu", (unsigned long long)N
);
113 template <class T
> std::enable_if_t
<std::is_signed
<T
>::value
> print(T N
) {
114 fprintf(stderr
, "%lld", (long long)N
);
117 void print(ReferenceKind RK
) {
119 case ReferenceKind::LValue
:
120 return printStr("ReferenceKind::LValue");
121 case ReferenceKind::RValue
:
122 return printStr("ReferenceKind::RValue");
125 void print(FunctionRefQual RQ
) {
127 case FunctionRefQual::FrefQualNone
:
128 return printStr("FunctionRefQual::FrefQualNone");
129 case FunctionRefQual::FrefQualLValue
:
130 return printStr("FunctionRefQual::FrefQualLValue");
131 case FunctionRefQual::FrefQualRValue
:
132 return printStr("FunctionRefQual::FrefQualRValue");
135 void print(Qualifiers Qs
) {
136 if (!Qs
) return printStr("QualNone");
137 struct QualName
{ Qualifiers Q
; const char *Name
; } Names
[] = {
138 {QualConst
, "QualConst"},
139 {QualVolatile
, "QualVolatile"},
140 {QualRestrict
, "QualRestrict"},
142 for (QualName Name
: Names
) {
145 Qs
= Qualifiers(Qs
& ~Name
.Q
);
146 if (Qs
) printStr(" | ");
150 void print(SpecialSubKind SSK
) {
152 case SpecialSubKind::allocator
:
153 return printStr("SpecialSubKind::allocator");
154 case SpecialSubKind::basic_string
:
155 return printStr("SpecialSubKind::basic_string");
156 case SpecialSubKind::string
:
157 return printStr("SpecialSubKind::string");
158 case SpecialSubKind::istream
:
159 return printStr("SpecialSubKind::istream");
160 case SpecialSubKind::ostream
:
161 return printStr("SpecialSubKind::ostream");
162 case SpecialSubKind::iostream
:
163 return printStr("SpecialSubKind::iostream");
166 void print(TemplateParamKind TPK
) {
168 case TemplateParamKind::Type
:
169 return printStr("TemplateParamKind::Type");
170 case TemplateParamKind::NonType
:
171 return printStr("TemplateParamKind::NonType");
172 case TemplateParamKind::Template
:
173 return printStr("TemplateParamKind::Template");
176 void print(Node::Prec P
) {
178 case Node::Prec::Primary
:
179 return printStr("Node::Prec::Primary");
180 case Node::Prec::Postfix
:
181 return printStr("Node::Prec::Postfix");
182 case Node::Prec::Unary
:
183 return printStr("Node::Prec::Unary");
184 case Node::Prec::Cast
:
185 return printStr("Node::Prec::Cast");
186 case Node::Prec::PtrMem
:
187 return printStr("Node::Prec::PtrMem");
188 case Node::Prec::Multiplicative
:
189 return printStr("Node::Prec::Multiplicative");
190 case Node::Prec::Additive
:
191 return printStr("Node::Prec::Additive");
192 case Node::Prec::Shift
:
193 return printStr("Node::Prec::Shift");
194 case Node::Prec::Spaceship
:
195 return printStr("Node::Prec::Spaceship");
196 case Node::Prec::Relational
:
197 return printStr("Node::Prec::Relational");
198 case Node::Prec::Equality
:
199 return printStr("Node::Prec::Equality");
200 case Node::Prec::And
:
201 return printStr("Node::Prec::And");
202 case Node::Prec::Xor
:
203 return printStr("Node::Prec::Xor");
204 case Node::Prec::Ior
:
205 return printStr("Node::Prec::Ior");
206 case Node::Prec::AndIf
:
207 return printStr("Node::Prec::AndIf");
208 case Node::Prec::OrIf
:
209 return printStr("Node::Prec::OrIf");
210 case Node::Prec::Conditional
:
211 return printStr("Node::Prec::Conditional");
212 case Node::Prec::Assign
:
213 return printStr("Node::Prec::Assign");
214 case Node::Prec::Comma
:
215 return printStr("Node::Prec::Comma");
216 case Node::Prec::Default
:
217 return printStr("Node::Prec::Default");
223 for (unsigned I
= 0; I
!= Depth
; ++I
)
225 PendingNewline
= false;
228 template<typename T
> void printWithPendingNewline(T V
) {
231 PendingNewline
= true;
234 template<typename T
> void printWithComma(T V
) {
235 if (PendingNewline
|| wantsNewline(V
)) {
242 printWithPendingNewline(V
);
245 struct CtorArgPrinter
{
246 DumpVisitor
&Visitor
;
248 template<typename T
, typename
...Rest
> void operator()(T V
, Rest
...Vs
) {
249 if (Visitor
.anyWantNewline(V
, Vs
...))
251 Visitor
.printWithPendingNewline(V
);
252 int PrintInOrder
[] = { (Visitor
.printWithComma(Vs
), 0)..., 0 };
257 template<typename NodeT
> void operator()(const NodeT
*Node
) {
259 fprintf(stderr
, "%s(", itanium_demangle::NodeKind
<NodeT
>::name());
260 Node
->match(CtorArgPrinter
{*this});
261 fprintf(stderr
, ")");
265 void operator()(const ForwardTemplateReference
*Node
) {
267 fprintf(stderr
, "ForwardTemplateReference(");
268 if (Node
->Ref
&& !Node
->Printing
) {
269 Node
->Printing
= true;
270 CtorArgPrinter
{*this}(Node
->Ref
);
271 Node
->Printing
= false;
273 CtorArgPrinter
{*this}(Node
->Index
);
275 fprintf(stderr
, ")");
281 void itanium_demangle::Node::dump() const {
289 class BumpPointerAllocator
{
295 static constexpr size_t AllocSize
= 4096;
296 static constexpr size_t UsableAllocSize
= AllocSize
- sizeof(BlockMeta
);
298 alignas(long double) char InitialBuffer
[AllocSize
];
299 BlockMeta
* BlockList
= nullptr;
302 char* NewMeta
= static_cast<char *>(std::malloc(AllocSize
));
303 if (NewMeta
== nullptr)
305 BlockList
= new (NewMeta
) BlockMeta
{BlockList
, 0};
308 void* allocateMassive(size_t NBytes
) {
309 NBytes
+= sizeof(BlockMeta
);
310 BlockMeta
* NewMeta
= reinterpret_cast<BlockMeta
*>(std::malloc(NBytes
));
311 if (NewMeta
== nullptr)
313 BlockList
->Next
= new (NewMeta
) BlockMeta
{BlockList
->Next
, 0};
314 return static_cast<void*>(NewMeta
+ 1);
318 BumpPointerAllocator()
319 : BlockList(new (InitialBuffer
) BlockMeta
{nullptr, 0}) {}
321 void* allocate(size_t N
) {
322 N
= (N
+ 15u) & ~15u;
323 if (N
+ BlockList
->Current
>= UsableAllocSize
) {
324 if (N
> UsableAllocSize
)
325 return allocateMassive(N
);
328 BlockList
->Current
+= N
;
329 return static_cast<void*>(reinterpret_cast<char*>(BlockList
+ 1) +
330 BlockList
->Current
- N
);
335 BlockMeta
* Tmp
= BlockList
;
336 BlockList
= BlockList
->Next
;
337 if (reinterpret_cast<char*>(Tmp
) != InitialBuffer
)
340 BlockList
= new (InitialBuffer
) BlockMeta
{nullptr, 0};
343 ~BumpPointerAllocator() { reset(); }
346 class DefaultAllocator
{
347 BumpPointerAllocator Alloc
;
350 void reset() { Alloc
.reset(); }
352 template<typename T
, typename
...Args
> T
*makeNode(Args
&&...args
) {
353 return new (Alloc
.allocate(sizeof(T
)))
354 T(std::forward
<Args
>(args
)...);
357 void *allocateNodeArray(size_t sz
) {
358 return Alloc
.allocate(sizeof(Node
*) * sz
);
361 } // unnamed namespace
363 //===----------------------------------------------------------------------===//
364 // Code beyond this point should not be synchronized with libc++abi.
365 //===----------------------------------------------------------------------===//
367 using Demangler
= itanium_demangle::ManglingParser
<DefaultAllocator
>;
369 char *llvm::itaniumDemangle(std::string_view MangledName
, bool ParseParams
) {
370 if (MangledName
.empty())
373 Demangler
Parser(MangledName
.data(),
374 MangledName
.data() + MangledName
.length());
375 Node
*AST
= Parser
.parse(ParseParams
);
380 assert(Parser
.ForwardTemplateRefs
.empty());
383 return OB
.getBuffer();
386 ItaniumPartialDemangler::ItaniumPartialDemangler()
387 : RootNode(nullptr), Context(new Demangler
{nullptr, nullptr}) {}
389 ItaniumPartialDemangler::~ItaniumPartialDemangler() {
390 delete static_cast<Demangler
*>(Context
);
393 ItaniumPartialDemangler::ItaniumPartialDemangler(
394 ItaniumPartialDemangler
&&Other
)
395 : RootNode(Other
.RootNode
), Context(Other
.Context
) {
396 Other
.Context
= Other
.RootNode
= nullptr;
399 ItaniumPartialDemangler
&ItaniumPartialDemangler::
400 operator=(ItaniumPartialDemangler
&&Other
) {
401 std::swap(RootNode
, Other
.RootNode
);
402 std::swap(Context
, Other
.Context
);
406 // Demangle MangledName into an AST, storing it into this->RootNode.
407 bool ItaniumPartialDemangler::partialDemangle(const char *MangledName
) {
408 Demangler
*Parser
= static_cast<Demangler
*>(Context
);
409 size_t Len
= std::strlen(MangledName
);
410 Parser
->reset(MangledName
, MangledName
+ Len
);
411 RootNode
= Parser
->parse();
412 return RootNode
== nullptr;
415 static char *printNode(const Node
*RootNode
, char *Buf
, size_t *N
) {
416 OutputBuffer
OB(Buf
, N
);
420 *N
= OB
.getCurrentPosition();
421 return OB
.getBuffer();
424 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf
, size_t *N
) const {
428 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
431 switch (Name
->getKind()) {
432 case Node::KAbiTagAttr
:
433 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
435 case Node::KModuleEntity
:
436 Name
= static_cast<const ModuleEntity
*>(Name
)->Name
;
438 case Node::KNestedName
:
439 Name
= static_cast<const NestedName
*>(Name
)->Name
;
441 case Node::KLocalName
:
442 Name
= static_cast<const LocalName
*>(Name
)->Entity
;
444 case Node::KNameWithTemplateArgs
:
445 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
448 return printNode(Name
, Buf
, N
);
453 char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf
,
457 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
459 OutputBuffer
OB(Buf
, N
);
461 KeepGoingLocalFunction
:
463 if (Name
->getKind() == Node::KAbiTagAttr
) {
464 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
467 if (Name
->getKind() == Node::KNameWithTemplateArgs
) {
468 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
474 if (Name
->getKind() == Node::KModuleEntity
)
475 Name
= static_cast<const ModuleEntity
*>(Name
)->Name
;
477 switch (Name
->getKind()) {
478 case Node::KNestedName
:
479 static_cast<const NestedName
*>(Name
)->Qual
->print(OB
);
481 case Node::KLocalName
: {
482 auto *LN
= static_cast<const LocalName
*>(Name
);
483 LN
->Encoding
->print(OB
);
486 goto KeepGoingLocalFunction
;
493 *N
= OB
.getCurrentPosition();
494 return OB
.getBuffer();
497 char *ItaniumPartialDemangler::getFunctionName(char *Buf
, size_t *N
) const {
500 auto *Name
= static_cast<FunctionEncoding
*>(RootNode
)->getName();
501 return printNode(Name
, Buf
, N
);
504 char *ItaniumPartialDemangler::getFunctionParameters(char *Buf
,
508 NodeArray Params
= static_cast<FunctionEncoding
*>(RootNode
)->getParams();
510 OutputBuffer
OB(Buf
, N
);
513 Params
.printWithComma(OB
);
517 *N
= OB
.getCurrentPosition();
518 return OB
.getBuffer();
521 char *ItaniumPartialDemangler::getFunctionReturnType(
522 char *Buf
, size_t *N
) const {
526 OutputBuffer
OB(Buf
, N
);
528 if (const Node
*Ret
=
529 static_cast<const FunctionEncoding
*>(RootNode
)->getReturnType())
534 *N
= OB
.getCurrentPosition();
535 return OB
.getBuffer();
538 char *ItaniumPartialDemangler::finishDemangle(char *Buf
, size_t *N
) const {
539 assert(RootNode
!= nullptr && "must call partialDemangle()");
540 return printNode(static_cast<Node
*>(RootNode
), Buf
, N
);
543 bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
544 assert(RootNode
!= nullptr && "must call partialDemangle()");
547 auto *E
= static_cast<const FunctionEncoding
*>(RootNode
);
548 return E
->getCVQuals() != QualNone
|| E
->getRefQual() != FrefQualNone
;
551 bool ItaniumPartialDemangler::isCtorOrDtor() const {
552 const Node
*N
= static_cast<const Node
*>(RootNode
);
554 switch (N
->getKind()) {
557 case Node::KCtorDtorName
:
560 case Node::KAbiTagAttr
:
561 N
= static_cast<const AbiTagAttr
*>(N
)->Base
;
563 case Node::KFunctionEncoding
:
564 N
= static_cast<const FunctionEncoding
*>(N
)->getName();
566 case Node::KLocalName
:
567 N
= static_cast<const LocalName
*>(N
)->Entity
;
569 case Node::KNameWithTemplateArgs
:
570 N
= static_cast<const NameWithTemplateArgs
*>(N
)->Name
;
572 case Node::KNestedName
:
573 N
= static_cast<const NestedName
*>(N
)->Name
;
575 case Node::KModuleEntity
:
576 N
= static_cast<const ModuleEntity
*>(N
)->Name
;
583 bool ItaniumPartialDemangler::isFunction() const {
584 assert(RootNode
!= nullptr && "must call partialDemangle()");
585 return static_cast<const Node
*>(RootNode
)->getKind() ==
586 Node::KFunctionEncoding
;
589 bool ItaniumPartialDemangler::isSpecialName() const {
590 assert(RootNode
!= nullptr && "must call partialDemangle()");
591 auto K
= static_cast<const Node
*>(RootNode
)->getKind();
592 return K
== Node::KSpecialName
|| K
== Node::KCtorVtableSpecialName
;
595 bool ItaniumPartialDemangler::isData() const {
596 return !isFunction() && !isSpecialName();