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"
25 using namespace llvm::itanium_demangle
;
27 constexpr const char *itanium_demangle::FloatData
<float>::spec
;
28 constexpr const char *itanium_demangle::FloatData
<double>::spec
;
29 constexpr const char *itanium_demangle::FloatData
<long double>::spec
;
31 // <discriminator> := _ <non-negative number> # when number < 10
32 // := __ <non-negative number> _ # when number >= 10
33 // extension := decimal-digit+ # at the end of string
34 const char *itanium_demangle::parse_discriminator(const char *first
,
36 // parse but ignore discriminator
39 const char *t1
= first
+ 1;
41 if (std::isdigit(*t1
))
43 else if (*t1
== '_') {
44 for (++t1
; t1
!= last
&& std::isdigit(*t1
); ++t1
)
46 if (t1
!= last
&& *t1
== '_')
50 } else if (std::isdigit(*first
)) {
51 const char *t1
= first
+ 1;
52 for (; t1
!= last
&& std::isdigit(*t1
); ++t1
)
65 bool PendingNewline
= false;
67 template<typename NodeT
> static constexpr bool wantsNewline(const NodeT
*) {
70 static bool wantsNewline(NodeArray A
) { return !A
.empty(); }
71 static constexpr bool wantsNewline(...) { return false; }
73 template<typename
...Ts
> static bool anyWantNewline(Ts
...Vs
) {
74 for (bool B
: {wantsNewline(Vs
)...})
80 void printStr(const char *S
) { fprintf(stderr
, "%s", S
); }
81 void print(StringView SV
) {
82 fprintf(stderr
, "\"%.*s\"", (int)SV
.size(), SV
.begin());
84 void print(const Node
*N
) {
86 N
->visit(std::ref(*this));
90 void print(NodeArray A
) {
94 for (const Node
*N
: A
) {
105 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
106 void print(bool B
) { printStr(B
? "true" : "false"); }
108 template <class T
> std::enable_if_t
<std::is_unsigned
<T
>::value
> print(T N
) {
109 fprintf(stderr
, "%llu", (unsigned long long)N
);
112 template <class T
> std::enable_if_t
<std::is_signed
<T
>::value
> print(T N
) {
113 fprintf(stderr
, "%lld", (long long)N
);
116 void print(ReferenceKind RK
) {
118 case ReferenceKind::LValue
:
119 return printStr("ReferenceKind::LValue");
120 case ReferenceKind::RValue
:
121 return printStr("ReferenceKind::RValue");
124 void print(FunctionRefQual RQ
) {
126 case FunctionRefQual::FrefQualNone
:
127 return printStr("FunctionRefQual::FrefQualNone");
128 case FunctionRefQual::FrefQualLValue
:
129 return printStr("FunctionRefQual::FrefQualLValue");
130 case FunctionRefQual::FrefQualRValue
:
131 return printStr("FunctionRefQual::FrefQualRValue");
134 void print(Qualifiers Qs
) {
135 if (!Qs
) return printStr("QualNone");
136 struct QualName
{ Qualifiers Q
; const char *Name
; } Names
[] = {
137 {QualConst
, "QualConst"},
138 {QualVolatile
, "QualVolatile"},
139 {QualRestrict
, "QualRestrict"},
141 for (QualName Name
: Names
) {
144 Qs
= Qualifiers(Qs
& ~Name
.Q
);
145 if (Qs
) printStr(" | ");
149 void print(SpecialSubKind SSK
) {
151 case SpecialSubKind::allocator
:
152 return printStr("SpecialSubKind::allocator");
153 case SpecialSubKind::basic_string
:
154 return printStr("SpecialSubKind::basic_string");
155 case SpecialSubKind::string
:
156 return printStr("SpecialSubKind::string");
157 case SpecialSubKind::istream
:
158 return printStr("SpecialSubKind::istream");
159 case SpecialSubKind::ostream
:
160 return printStr("SpecialSubKind::ostream");
161 case SpecialSubKind::iostream
:
162 return printStr("SpecialSubKind::iostream");
165 void print(TemplateParamKind TPK
) {
167 case TemplateParamKind::Type
:
168 return printStr("TemplateParamKind::Type");
169 case TemplateParamKind::NonType
:
170 return printStr("TemplateParamKind::NonType");
171 case TemplateParamKind::Template
:
172 return printStr("TemplateParamKind::Template");
175 void print(Node::Prec P
) {
177 case Node::Prec::Primary
:
178 return printStr("Node::Prec::Primary");
179 case Node::Prec::Postfix
:
180 return printStr("Node::Prec::Postfix");
181 case Node::Prec::Unary
:
182 return printStr("Node::Prec::Unary");
183 case Node::Prec::Cast
:
184 return printStr("Node::Prec::Cast");
185 case Node::Prec::PtrMem
:
186 return printStr("Node::Prec::PtrMem");
187 case Node::Prec::Multiplicative
:
188 return printStr("Node::Prec::Multiplicative");
189 case Node::Prec::Additive
:
190 return printStr("Node::Prec::Additive");
191 case Node::Prec::Shift
:
192 return printStr("Node::Prec::Shift");
193 case Node::Prec::Spaceship
:
194 return printStr("Node::Prec::Spaceship");
195 case Node::Prec::Relational
:
196 return printStr("Node::Prec::Relational");
197 case Node::Prec::Equality
:
198 return printStr("Node::Prec::Equality");
199 case Node::Prec::And
:
200 return printStr("Node::Prec::And");
201 case Node::Prec::Xor
:
202 return printStr("Node::Prec::Xor");
203 case Node::Prec::Ior
:
204 return printStr("Node::Prec::Ior");
205 case Node::Prec::AndIf
:
206 return printStr("Node::Prec::AndIf");
207 case Node::Prec::OrIf
:
208 return printStr("Node::Prec::OrIf");
209 case Node::Prec::Conditional
:
210 return printStr("Node::Prec::Conditional");
211 case Node::Prec::Assign
:
212 return printStr("Node::Prec::Assign");
213 case Node::Prec::Comma
:
214 return printStr("Node::Prec::Comma");
215 case Node::Prec::Default
:
216 return printStr("Node::Prec::Default");
222 for (unsigned I
= 0; I
!= Depth
; ++I
)
224 PendingNewline
= false;
227 template<typename T
> void printWithPendingNewline(T V
) {
230 PendingNewline
= true;
233 template<typename T
> void printWithComma(T V
) {
234 if (PendingNewline
|| wantsNewline(V
)) {
241 printWithPendingNewline(V
);
244 struct CtorArgPrinter
{
245 DumpVisitor
&Visitor
;
247 template<typename T
, typename
...Rest
> void operator()(T V
, Rest
...Vs
) {
248 if (Visitor
.anyWantNewline(V
, Vs
...))
250 Visitor
.printWithPendingNewline(V
);
251 int PrintInOrder
[] = { (Visitor
.printWithComma(Vs
), 0)..., 0 };
256 template<typename NodeT
> void operator()(const NodeT
*Node
) {
258 fprintf(stderr
, "%s(", itanium_demangle::NodeKind
<NodeT
>::name());
259 Node
->match(CtorArgPrinter
{*this});
260 fprintf(stderr
, ")");
264 void operator()(const ForwardTemplateReference
*Node
) {
266 fprintf(stderr
, "ForwardTemplateReference(");
267 if (Node
->Ref
&& !Node
->Printing
) {
268 Node
->Printing
= true;
269 CtorArgPrinter
{*this}(Node
->Ref
);
270 Node
->Printing
= false;
272 CtorArgPrinter
{*this}(Node
->Index
);
274 fprintf(stderr
, ")");
280 void itanium_demangle::Node::dump() const {
288 class BumpPointerAllocator
{
294 static constexpr size_t AllocSize
= 4096;
295 static constexpr size_t UsableAllocSize
= AllocSize
- sizeof(BlockMeta
);
297 alignas(long double) char InitialBuffer
[AllocSize
];
298 BlockMeta
* BlockList
= nullptr;
301 char* NewMeta
= static_cast<char *>(std::malloc(AllocSize
));
302 if (NewMeta
== nullptr)
304 BlockList
= new (NewMeta
) BlockMeta
{BlockList
, 0};
307 void* allocateMassive(size_t NBytes
) {
308 NBytes
+= sizeof(BlockMeta
);
309 BlockMeta
* NewMeta
= reinterpret_cast<BlockMeta
*>(std::malloc(NBytes
));
310 if (NewMeta
== nullptr)
312 BlockList
->Next
= new (NewMeta
) BlockMeta
{BlockList
->Next
, 0};
313 return static_cast<void*>(NewMeta
+ 1);
317 BumpPointerAllocator()
318 : BlockList(new (InitialBuffer
) BlockMeta
{nullptr, 0}) {}
320 void* allocate(size_t N
) {
321 N
= (N
+ 15u) & ~15u;
322 if (N
+ BlockList
->Current
>= UsableAllocSize
) {
323 if (N
> UsableAllocSize
)
324 return allocateMassive(N
);
327 BlockList
->Current
+= N
;
328 return static_cast<void*>(reinterpret_cast<char*>(BlockList
+ 1) +
329 BlockList
->Current
- N
);
334 BlockMeta
* Tmp
= BlockList
;
335 BlockList
= BlockList
->Next
;
336 if (reinterpret_cast<char*>(Tmp
) != InitialBuffer
)
339 BlockList
= new (InitialBuffer
) BlockMeta
{nullptr, 0};
342 ~BumpPointerAllocator() { reset(); }
345 class DefaultAllocator
{
346 BumpPointerAllocator Alloc
;
349 void reset() { Alloc
.reset(); }
351 template<typename T
, typename
...Args
> T
*makeNode(Args
&&...args
) {
352 return new (Alloc
.allocate(sizeof(T
)))
353 T(std::forward
<Args
>(args
)...);
356 void *allocateNodeArray(size_t sz
) {
357 return Alloc
.allocate(sizeof(Node
*) * sz
);
360 } // unnamed namespace
362 //===----------------------------------------------------------------------===//
363 // Code beyond this point should not be synchronized with libc++abi.
364 //===----------------------------------------------------------------------===//
366 using Demangler
= itanium_demangle::ManglingParser
<DefaultAllocator
>;
368 char *llvm::itaniumDemangle(const char *MangledName
, char *Buf
,
369 size_t *N
, int *Status
) {
370 if (MangledName
== nullptr || (Buf
!= nullptr && N
== nullptr)) {
372 *Status
= demangle_invalid_args
;
376 int InternalStatus
= demangle_success
;
377 Demangler
Parser(MangledName
, MangledName
+ std::strlen(MangledName
));
380 Node
*AST
= Parser
.parse();
383 InternalStatus
= demangle_invalid_mangled_name
;
384 else if (!initializeOutputBuffer(Buf
, N
, OB
, 1024))
385 InternalStatus
= demangle_memory_alloc_failure
;
387 assert(Parser
.ForwardTemplateRefs
.empty());
391 *N
= OB
.getCurrentPosition();
392 Buf
= OB
.getBuffer();
396 *Status
= InternalStatus
;
397 return InternalStatus
== demangle_success
? Buf
: nullptr;
400 ItaniumPartialDemangler::ItaniumPartialDemangler()
401 : RootNode(nullptr), Context(new Demangler
{nullptr, nullptr}) {}
403 ItaniumPartialDemangler::~ItaniumPartialDemangler() {
404 delete static_cast<Demangler
*>(Context
);
407 ItaniumPartialDemangler::ItaniumPartialDemangler(
408 ItaniumPartialDemangler
&&Other
)
409 : RootNode(Other
.RootNode
), Context(Other
.Context
) {
410 Other
.Context
= Other
.RootNode
= nullptr;
413 ItaniumPartialDemangler
&ItaniumPartialDemangler::
414 operator=(ItaniumPartialDemangler
&&Other
) {
415 std::swap(RootNode
, Other
.RootNode
);
416 std::swap(Context
, Other
.Context
);
420 // Demangle MangledName into an AST, storing it into this->RootNode.
421 bool ItaniumPartialDemangler::partialDemangle(const char *MangledName
) {
422 Demangler
*Parser
= static_cast<Demangler
*>(Context
);
423 size_t Len
= std::strlen(MangledName
);
424 Parser
->reset(MangledName
, MangledName
+ Len
);
425 RootNode
= Parser
->parse();
426 return RootNode
== nullptr;
429 static char *printNode(const Node
*RootNode
, char *Buf
, size_t *N
) {
431 if (!initializeOutputBuffer(Buf
, N
, OB
, 128))
436 *N
= OB
.getCurrentPosition();
437 return OB
.getBuffer();
440 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf
, size_t *N
) const {
444 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
447 switch (Name
->getKind()) {
448 case Node::KAbiTagAttr
:
449 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
451 case Node::KModuleEntity
:
452 Name
= static_cast<const ModuleEntity
*>(Name
)->Name
;
454 case Node::KNestedName
:
455 Name
= static_cast<const NestedName
*>(Name
)->Name
;
457 case Node::KLocalName
:
458 Name
= static_cast<const LocalName
*>(Name
)->Entity
;
460 case Node::KNameWithTemplateArgs
:
461 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
464 return printNode(Name
, Buf
, N
);
469 char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf
,
473 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
476 if (!initializeOutputBuffer(Buf
, N
, OB
, 128))
479 KeepGoingLocalFunction
:
481 if (Name
->getKind() == Node::KAbiTagAttr
) {
482 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
485 if (Name
->getKind() == Node::KNameWithTemplateArgs
) {
486 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
492 if (Name
->getKind() == Node::KModuleEntity
)
493 Name
= static_cast<const ModuleEntity
*>(Name
)->Name
;
495 switch (Name
->getKind()) {
496 case Node::KNestedName
:
497 static_cast<const NestedName
*>(Name
)->Qual
->print(OB
);
499 case Node::KLocalName
: {
500 auto *LN
= static_cast<const LocalName
*>(Name
);
501 LN
->Encoding
->print(OB
);
504 goto KeepGoingLocalFunction
;
511 *N
= OB
.getCurrentPosition();
512 return OB
.getBuffer();
515 char *ItaniumPartialDemangler::getFunctionName(char *Buf
, size_t *N
) const {
518 auto *Name
= static_cast<FunctionEncoding
*>(RootNode
)->getName();
519 return printNode(Name
, Buf
, N
);
522 char *ItaniumPartialDemangler::getFunctionParameters(char *Buf
,
526 NodeArray Params
= static_cast<FunctionEncoding
*>(RootNode
)->getParams();
529 if (!initializeOutputBuffer(Buf
, N
, OB
, 128))
533 Params
.printWithComma(OB
);
537 *N
= OB
.getCurrentPosition();
538 return OB
.getBuffer();
541 char *ItaniumPartialDemangler::getFunctionReturnType(
542 char *Buf
, size_t *N
) const {
547 if (!initializeOutputBuffer(Buf
, N
, OB
, 128))
550 if (const Node
*Ret
=
551 static_cast<const FunctionEncoding
*>(RootNode
)->getReturnType())
556 *N
= OB
.getCurrentPosition();
557 return OB
.getBuffer();
560 char *ItaniumPartialDemangler::finishDemangle(char *Buf
, size_t *N
) const {
561 assert(RootNode
!= nullptr && "must call partialDemangle()");
562 return printNode(static_cast<Node
*>(RootNode
), Buf
, N
);
565 bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
566 assert(RootNode
!= nullptr && "must call partialDemangle()");
569 auto *E
= static_cast<const FunctionEncoding
*>(RootNode
);
570 return E
->getCVQuals() != QualNone
|| E
->getRefQual() != FrefQualNone
;
573 bool ItaniumPartialDemangler::isCtorOrDtor() const {
574 const Node
*N
= static_cast<const Node
*>(RootNode
);
576 switch (N
->getKind()) {
579 case Node::KCtorDtorName
:
582 case Node::KAbiTagAttr
:
583 N
= static_cast<const AbiTagAttr
*>(N
)->Base
;
585 case Node::KFunctionEncoding
:
586 N
= static_cast<const FunctionEncoding
*>(N
)->getName();
588 case Node::KLocalName
:
589 N
= static_cast<const LocalName
*>(N
)->Entity
;
591 case Node::KNameWithTemplateArgs
:
592 N
= static_cast<const NameWithTemplateArgs
*>(N
)->Name
;
594 case Node::KNestedName
:
595 N
= static_cast<const NestedName
*>(N
)->Name
;
597 case Node::KModuleEntity
:
598 N
= static_cast<const ModuleEntity
*>(N
)->Name
;
605 bool ItaniumPartialDemangler::isFunction() const {
606 assert(RootNode
!= nullptr && "must call partialDemangle()");
607 return static_cast<const Node
*>(RootNode
)->getKind() ==
608 Node::KFunctionEncoding
;
611 bool ItaniumPartialDemangler::isSpecialName() const {
612 assert(RootNode
!= nullptr && "must call partialDemangle()");
613 auto K
= static_cast<const Node
*>(RootNode
)->getKind();
614 return K
== Node::KSpecialName
|| K
== Node::KCtorVtableSpecialName
;
617 bool ItaniumPartialDemangler::isData() const {
618 return !isFunction() && !isSpecialName();