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"
27 using namespace llvm::itanium_demangle
;
29 constexpr const char *itanium_demangle::FloatData
<float>::spec
;
30 constexpr const char *itanium_demangle::FloatData
<double>::spec
;
31 constexpr const char *itanium_demangle::FloatData
<long double>::spec
;
33 // <discriminator> := _ <non-negative number> # when number < 10
34 // := __ <non-negative number> _ # when number >= 10
35 // extension := decimal-digit+ # at the end of string
36 const char *itanium_demangle::parse_discriminator(const char *first
,
38 // parse but ignore discriminator
41 const char *t1
= first
+ 1;
43 if (std::isdigit(*t1
))
45 else if (*t1
== '_') {
46 for (++t1
; t1
!= last
&& std::isdigit(*t1
); ++t1
)
48 if (t1
!= last
&& *t1
== '_')
52 } else if (std::isdigit(*first
)) {
53 const char *t1
= first
+ 1;
54 for (; t1
!= last
&& std::isdigit(*t1
); ++t1
)
67 bool PendingNewline
= false;
69 template<typename NodeT
> static constexpr bool wantsNewline(const NodeT
*) {
72 static bool wantsNewline(NodeArray A
) { return !A
.empty(); }
73 static constexpr bool wantsNewline(...) { return false; }
75 template<typename
...Ts
> static bool anyWantNewline(Ts
...Vs
) {
76 for (bool B
: {wantsNewline(Vs
)...})
82 void printStr(const char *S
) { fprintf(stderr
, "%s", S
); }
83 void print(StringView SV
) {
84 fprintf(stderr
, "\"%.*s\"", (int)SV
.size(), SV
.begin());
86 void print(const Node
*N
) {
88 N
->visit(std::ref(*this));
92 void print(NodeOrString NS
) {
95 else if (NS
.isString())
98 printStr("NodeOrString()");
100 void print(NodeArray A
) {
104 for (const Node
*N
: A
) {
115 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
116 void print(bool B
) { printStr(B
? "true" : "false"); }
119 typename
std::enable_if
<std::is_unsigned
<T
>::value
>::type
print(T N
) {
120 fprintf(stderr
, "%llu", (unsigned long long)N
);
124 typename
std::enable_if
<std::is_signed
<T
>::value
>::type
print(T N
) {
125 fprintf(stderr
, "%lld", (long long)N
);
128 void print(ReferenceKind RK
) {
130 case ReferenceKind::LValue
:
131 return printStr("ReferenceKind::LValue");
132 case ReferenceKind::RValue
:
133 return printStr("ReferenceKind::RValue");
136 void print(FunctionRefQual RQ
) {
138 case FunctionRefQual::FrefQualNone
:
139 return printStr("FunctionRefQual::FrefQualNone");
140 case FunctionRefQual::FrefQualLValue
:
141 return printStr("FunctionRefQual::FrefQualLValue");
142 case FunctionRefQual::FrefQualRValue
:
143 return printStr("FunctionRefQual::FrefQualRValue");
146 void print(Qualifiers Qs
) {
147 if (!Qs
) return printStr("QualNone");
148 struct QualName
{ Qualifiers Q
; const char *Name
; } Names
[] = {
149 {QualConst
, "QualConst"},
150 {QualVolatile
, "QualVolatile"},
151 {QualRestrict
, "QualRestrict"},
153 for (QualName Name
: Names
) {
156 Qs
= Qualifiers(Qs
& ~Name
.Q
);
157 if (Qs
) printStr(" | ");
161 void print(SpecialSubKind SSK
) {
163 case SpecialSubKind::allocator
:
164 return printStr("SpecialSubKind::allocator");
165 case SpecialSubKind::basic_string
:
166 return printStr("SpecialSubKind::basic_string");
167 case SpecialSubKind::string
:
168 return printStr("SpecialSubKind::string");
169 case SpecialSubKind::istream
:
170 return printStr("SpecialSubKind::istream");
171 case SpecialSubKind::ostream
:
172 return printStr("SpecialSubKind::ostream");
173 case SpecialSubKind::iostream
:
174 return printStr("SpecialSubKind::iostream");
177 void print(TemplateParamKind TPK
) {
179 case TemplateParamKind::Type
:
180 return printStr("TemplateParamKind::Type");
181 case TemplateParamKind::NonType
:
182 return printStr("TemplateParamKind::NonType");
183 case TemplateParamKind::Template
:
184 return printStr("TemplateParamKind::Template");
190 for (unsigned I
= 0; I
!= Depth
; ++I
)
192 PendingNewline
= false;
195 template<typename T
> void printWithPendingNewline(T V
) {
198 PendingNewline
= true;
201 template<typename T
> void printWithComma(T V
) {
202 if (PendingNewline
|| wantsNewline(V
)) {
209 printWithPendingNewline(V
);
212 struct CtorArgPrinter
{
213 DumpVisitor
&Visitor
;
215 template<typename T
, typename
...Rest
> void operator()(T V
, Rest
...Vs
) {
216 if (Visitor
.anyWantNewline(V
, Vs
...))
218 Visitor
.printWithPendingNewline(V
);
219 int PrintInOrder
[] = { (Visitor
.printWithComma(Vs
), 0)..., 0 };
224 template<typename NodeT
> void operator()(const NodeT
*Node
) {
226 fprintf(stderr
, "%s(", itanium_demangle::NodeKind
<NodeT
>::name());
227 Node
->match(CtorArgPrinter
{*this});
228 fprintf(stderr
, ")");
232 void operator()(const ForwardTemplateReference
*Node
) {
234 fprintf(stderr
, "ForwardTemplateReference(");
235 if (Node
->Ref
&& !Node
->Printing
) {
236 Node
->Printing
= true;
237 CtorArgPrinter
{*this}(Node
->Ref
);
238 Node
->Printing
= false;
240 CtorArgPrinter
{*this}(Node
->Index
);
242 fprintf(stderr
, ")");
248 void itanium_demangle::Node::dump() const {
256 class BumpPointerAllocator
{
262 static constexpr size_t AllocSize
= 4096;
263 static constexpr size_t UsableAllocSize
= AllocSize
- sizeof(BlockMeta
);
265 alignas(long double) char InitialBuffer
[AllocSize
];
266 BlockMeta
* BlockList
= nullptr;
269 char* NewMeta
= static_cast<char *>(std::malloc(AllocSize
));
270 if (NewMeta
== nullptr)
272 BlockList
= new (NewMeta
) BlockMeta
{BlockList
, 0};
275 void* allocateMassive(size_t NBytes
) {
276 NBytes
+= sizeof(BlockMeta
);
277 BlockMeta
* NewMeta
= reinterpret_cast<BlockMeta
*>(std::malloc(NBytes
));
278 if (NewMeta
== nullptr)
280 BlockList
->Next
= new (NewMeta
) BlockMeta
{BlockList
->Next
, 0};
281 return static_cast<void*>(NewMeta
+ 1);
285 BumpPointerAllocator()
286 : BlockList(new (InitialBuffer
) BlockMeta
{nullptr, 0}) {}
288 void* allocate(size_t N
) {
289 N
= (N
+ 15u) & ~15u;
290 if (N
+ BlockList
->Current
>= UsableAllocSize
) {
291 if (N
> UsableAllocSize
)
292 return allocateMassive(N
);
295 BlockList
->Current
+= N
;
296 return static_cast<void*>(reinterpret_cast<char*>(BlockList
+ 1) +
297 BlockList
->Current
- N
);
302 BlockMeta
* Tmp
= BlockList
;
303 BlockList
= BlockList
->Next
;
304 if (reinterpret_cast<char*>(Tmp
) != InitialBuffer
)
307 BlockList
= new (InitialBuffer
) BlockMeta
{nullptr, 0};
310 ~BumpPointerAllocator() { reset(); }
313 class DefaultAllocator
{
314 BumpPointerAllocator Alloc
;
317 void reset() { Alloc
.reset(); }
319 template<typename T
, typename
...Args
> T
*makeNode(Args
&&...args
) {
320 return new (Alloc
.allocate(sizeof(T
)))
321 T(std::forward
<Args
>(args
)...);
324 void *allocateNodeArray(size_t sz
) {
325 return Alloc
.allocate(sizeof(Node
*) * sz
);
328 } // unnamed namespace
330 //===----------------------------------------------------------------------===//
331 // Code beyond this point should not be synchronized with libc++abi.
332 //===----------------------------------------------------------------------===//
334 using Demangler
= itanium_demangle::ManglingParser
<DefaultAllocator
>;
336 char *llvm::itaniumDemangle(const char *MangledName
, char *Buf
,
337 size_t *N
, int *Status
) {
338 if (MangledName
== nullptr || (Buf
!= nullptr && N
== nullptr)) {
340 *Status
= demangle_invalid_args
;
344 int InternalStatus
= demangle_success
;
345 Demangler
Parser(MangledName
, MangledName
+ std::strlen(MangledName
));
348 Node
*AST
= Parser
.parse();
351 InternalStatus
= demangle_invalid_mangled_name
;
352 else if (!initializeOutputStream(Buf
, N
, S
, 1024))
353 InternalStatus
= demangle_memory_alloc_failure
;
355 assert(Parser
.ForwardTemplateRefs
.empty());
359 *N
= S
.getCurrentPosition();
364 *Status
= InternalStatus
;
365 return InternalStatus
== demangle_success
? Buf
: nullptr;
368 ItaniumPartialDemangler::ItaniumPartialDemangler()
369 : RootNode(nullptr), Context(new Demangler
{nullptr, nullptr}) {}
371 ItaniumPartialDemangler::~ItaniumPartialDemangler() {
372 delete static_cast<Demangler
*>(Context
);
375 ItaniumPartialDemangler::ItaniumPartialDemangler(
376 ItaniumPartialDemangler
&&Other
)
377 : RootNode(Other
.RootNode
), Context(Other
.Context
) {
378 Other
.Context
= Other
.RootNode
= nullptr;
381 ItaniumPartialDemangler
&ItaniumPartialDemangler::
382 operator=(ItaniumPartialDemangler
&&Other
) {
383 std::swap(RootNode
, Other
.RootNode
);
384 std::swap(Context
, Other
.Context
);
388 // Demangle MangledName into an AST, storing it into this->RootNode.
389 bool ItaniumPartialDemangler::partialDemangle(const char *MangledName
) {
390 Demangler
*Parser
= static_cast<Demangler
*>(Context
);
391 size_t Len
= std::strlen(MangledName
);
392 Parser
->reset(MangledName
, MangledName
+ Len
);
393 RootNode
= Parser
->parse();
394 return RootNode
== nullptr;
397 static char *printNode(const Node
*RootNode
, char *Buf
, size_t *N
) {
399 if (!initializeOutputStream(Buf
, N
, S
, 128))
404 *N
= S
.getCurrentPosition();
405 return S
.getBuffer();
408 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf
, size_t *N
) const {
412 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
415 switch (Name
->getKind()) {
416 case Node::KAbiTagAttr
:
417 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
419 case Node::KStdQualifiedName
:
420 Name
= static_cast<const StdQualifiedName
*>(Name
)->Child
;
422 case Node::KNestedName
:
423 Name
= static_cast<const NestedName
*>(Name
)->Name
;
425 case Node::KLocalName
:
426 Name
= static_cast<const LocalName
*>(Name
)->Entity
;
428 case Node::KNameWithTemplateArgs
:
429 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
432 return printNode(Name
, Buf
, N
);
437 char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf
,
441 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
444 if (!initializeOutputStream(Buf
, N
, S
, 128))
447 KeepGoingLocalFunction
:
449 if (Name
->getKind() == Node::KAbiTagAttr
) {
450 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
453 if (Name
->getKind() == Node::KNameWithTemplateArgs
) {
454 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
460 switch (Name
->getKind()) {
461 case Node::KStdQualifiedName
:
464 case Node::KNestedName
:
465 static_cast<const NestedName
*>(Name
)->Qual
->print(S
);
467 case Node::KLocalName
: {
468 auto *LN
= static_cast<const LocalName
*>(Name
);
469 LN
->Encoding
->print(S
);
472 goto KeepGoingLocalFunction
;
479 *N
= S
.getCurrentPosition();
480 return S
.getBuffer();
483 char *ItaniumPartialDemangler::getFunctionName(char *Buf
, size_t *N
) const {
486 auto *Name
= static_cast<FunctionEncoding
*>(RootNode
)->getName();
487 return printNode(Name
, Buf
, N
);
490 char *ItaniumPartialDemangler::getFunctionParameters(char *Buf
,
494 NodeArray Params
= static_cast<FunctionEncoding
*>(RootNode
)->getParams();
497 if (!initializeOutputStream(Buf
, N
, S
, 128))
501 Params
.printWithComma(S
);
505 *N
= S
.getCurrentPosition();
506 return S
.getBuffer();
509 char *ItaniumPartialDemangler::getFunctionReturnType(
510 char *Buf
, size_t *N
) const {
515 if (!initializeOutputStream(Buf
, N
, S
, 128))
518 if (const Node
*Ret
=
519 static_cast<const FunctionEncoding
*>(RootNode
)->getReturnType())
524 *N
= S
.getCurrentPosition();
525 return S
.getBuffer();
528 char *ItaniumPartialDemangler::finishDemangle(char *Buf
, size_t *N
) const {
529 assert(RootNode
!= nullptr && "must call partialDemangle()");
530 return printNode(static_cast<Node
*>(RootNode
), Buf
, N
);
533 bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
534 assert(RootNode
!= nullptr && "must call partialDemangle()");
537 auto *E
= static_cast<const FunctionEncoding
*>(RootNode
);
538 return E
->getCVQuals() != QualNone
|| E
->getRefQual() != FrefQualNone
;
541 bool ItaniumPartialDemangler::isCtorOrDtor() const {
542 const Node
*N
= static_cast<const Node
*>(RootNode
);
544 switch (N
->getKind()) {
547 case Node::KCtorDtorName
:
550 case Node::KAbiTagAttr
:
551 N
= static_cast<const AbiTagAttr
*>(N
)->Base
;
553 case Node::KFunctionEncoding
:
554 N
= static_cast<const FunctionEncoding
*>(N
)->getName();
556 case Node::KLocalName
:
557 N
= static_cast<const LocalName
*>(N
)->Entity
;
559 case Node::KNameWithTemplateArgs
:
560 N
= static_cast<const NameWithTemplateArgs
*>(N
)->Name
;
562 case Node::KNestedName
:
563 N
= static_cast<const NestedName
*>(N
)->Name
;
565 case Node::KStdQualifiedName
:
566 N
= static_cast<const StdQualifiedName
*>(N
)->Child
;
573 bool ItaniumPartialDemangler::isFunction() const {
574 assert(RootNode
!= nullptr && "must call partialDemangle()");
575 return static_cast<const Node
*>(RootNode
)->getKind() ==
576 Node::KFunctionEncoding
;
579 bool ItaniumPartialDemangler::isSpecialName() const {
580 assert(RootNode
!= nullptr && "must call partialDemangle()");
581 auto K
= static_cast<const Node
*>(RootNode
)->getKind();
582 return K
== Node::KSpecialName
|| K
== Node::KCtorVtableSpecialName
;
585 bool ItaniumPartialDemangler::isData() const {
586 return !isFunction() && !isSpecialName();