1 //===------------------------- ItaniumDemangle.cpp ------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // FIXME: (possibly) incomplete list of features that clang mangles that this
11 // file does not yet support:
14 #include "llvm/Demangle/Demangle.h"
15 #include "llvm/Demangle/ItaniumDemangle.h"
28 using namespace llvm::itanium_demangle
;
30 constexpr const char *itanium_demangle::FloatData
<float>::spec
;
31 constexpr const char *itanium_demangle::FloatData
<double>::spec
;
32 constexpr const char *itanium_demangle::FloatData
<long double>::spec
;
34 // <discriminator> := _ <non-negative number> # when number < 10
35 // := __ <non-negative number> _ # when number >= 10
36 // extension := decimal-digit+ # at the end of string
37 const char *itanium_demangle::parse_discriminator(const char *first
,
39 // parse but ignore discriminator
42 const char *t1
= first
+ 1;
44 if (std::isdigit(*t1
))
46 else if (*t1
== '_') {
47 for (++t1
; t1
!= last
&& std::isdigit(*t1
); ++t1
)
49 if (t1
!= last
&& *t1
== '_')
53 } else if (std::isdigit(*first
)) {
54 const char *t1
= first
+ 1;
55 for (; t1
!= last
&& std::isdigit(*t1
); ++t1
)
68 bool PendingNewline
= false;
70 template<typename NodeT
> static constexpr bool wantsNewline(const NodeT
*) {
73 static bool wantsNewline(NodeArray A
) { return !A
.empty(); }
74 static constexpr bool wantsNewline(...) { return false; }
76 template<typename
...Ts
> static bool anyWantNewline(Ts
...Vs
) {
77 for (bool B
: {wantsNewline(Vs
)...})
83 void printStr(const char *S
) { fprintf(stderr
, "%s", S
); }
84 void print(StringView SV
) {
85 fprintf(stderr
, "\"%.*s\"", (int)SV
.size(), SV
.begin());
87 void print(const Node
*N
) {
89 N
->visit(std::ref(*this));
93 void print(NodeOrString NS
) {
96 else if (NS
.isString())
99 printStr("NodeOrString()");
101 void print(NodeArray A
) {
105 for (const Node
*N
: A
) {
115 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
116 template<typename T
, T
* = (bool*)nullptr>
118 printStr(B
? "true" : "false");
120 void print(size_t N
) {
121 fprintf(stderr
, "%zu", N
);
123 void print(ReferenceKind RK
) {
125 case ReferenceKind::LValue
:
126 return printStr("ReferenceKind::LValue");
127 case ReferenceKind::RValue
:
128 return printStr("ReferenceKind::RValue");
131 void print(FunctionRefQual RQ
) {
133 case FunctionRefQual::FrefQualNone
:
134 return printStr("FunctionRefQual::FrefQualNone");
135 case FunctionRefQual::FrefQualLValue
:
136 return printStr("FunctionRefQual::FrefQualLValue");
137 case FunctionRefQual::FrefQualRValue
:
138 return printStr("FunctionRefQual::FrefQualRValue");
141 void print(Qualifiers Qs
) {
142 if (!Qs
) return printStr("QualNone");
143 struct QualName
{ Qualifiers Q
; const char *Name
; } Names
[] = {
144 {QualConst
, "QualConst"},
145 {QualVolatile
, "QualVolatile"},
146 {QualRestrict
, "QualRestrict"},
148 for (QualName Name
: Names
) {
151 Qs
= Qualifiers(Qs
& ~Name
.Q
);
152 if (Qs
) printStr(" | ");
156 void print(SpecialSubKind SSK
) {
158 case SpecialSubKind::allocator
:
159 return printStr("SpecialSubKind::allocator");
160 case SpecialSubKind::basic_string
:
161 return printStr("SpecialSubKind::basic_string");
162 case SpecialSubKind::string
:
163 return printStr("SpecialSubKind::string");
164 case SpecialSubKind::istream
:
165 return printStr("SpecialSubKind::istream");
166 case SpecialSubKind::ostream
:
167 return printStr("SpecialSubKind::ostream");
168 case SpecialSubKind::iostream
:
169 return printStr("SpecialSubKind::iostream");
175 for (unsigned I
= 0; I
!= Depth
; ++I
)
177 PendingNewline
= false;
180 template<typename T
> void printWithPendingNewline(T V
) {
183 PendingNewline
= true;
186 template<typename T
> void printWithComma(T V
) {
187 if (PendingNewline
|| wantsNewline(V
)) {
194 printWithPendingNewline(V
);
197 struct CtorArgPrinter
{
198 DumpVisitor
&Visitor
;
200 template<typename T
, typename
...Rest
> void operator()(T V
, Rest
...Vs
) {
201 if (Visitor
.anyWantNewline(V
, Vs
...))
203 Visitor
.printWithPendingNewline(V
);
204 int PrintInOrder
[] = { (Visitor
.printWithComma(Vs
), 0)..., 0 };
209 template<typename NodeT
> void operator()(const NodeT
*Node
) {
211 fprintf(stderr
, "%s(", itanium_demangle::NodeKind
<NodeT
>::name());
212 Node
->match(CtorArgPrinter
{*this});
213 fprintf(stderr
, ")");
217 void operator()(const ForwardTemplateReference
*Node
) {
219 fprintf(stderr
, "ForwardTemplateReference(");
220 if (Node
->Ref
&& !Node
->Printing
) {
221 Node
->Printing
= true;
222 CtorArgPrinter
{*this}(Node
->Ref
);
223 Node
->Printing
= false;
225 CtorArgPrinter
{*this}(Node
->Index
);
227 fprintf(stderr
, ")");
233 void itanium_demangle::Node::dump() const {
241 class BumpPointerAllocator
{
247 static constexpr size_t AllocSize
= 4096;
248 static constexpr size_t UsableAllocSize
= AllocSize
- sizeof(BlockMeta
);
250 alignas(long double) char InitialBuffer
[AllocSize
];
251 BlockMeta
* BlockList
= nullptr;
254 char* NewMeta
= static_cast<char *>(std::malloc(AllocSize
));
255 if (NewMeta
== nullptr)
257 BlockList
= new (NewMeta
) BlockMeta
{BlockList
, 0};
260 void* allocateMassive(size_t NBytes
) {
261 NBytes
+= sizeof(BlockMeta
);
262 BlockMeta
* NewMeta
= reinterpret_cast<BlockMeta
*>(std::malloc(NBytes
));
263 if (NewMeta
== nullptr)
265 BlockList
->Next
= new (NewMeta
) BlockMeta
{BlockList
->Next
, 0};
266 return static_cast<void*>(NewMeta
+ 1);
270 BumpPointerAllocator()
271 : BlockList(new (InitialBuffer
) BlockMeta
{nullptr, 0}) {}
273 void* allocate(size_t N
) {
274 N
= (N
+ 15u) & ~15u;
275 if (N
+ BlockList
->Current
>= UsableAllocSize
) {
276 if (N
> UsableAllocSize
)
277 return allocateMassive(N
);
280 BlockList
->Current
+= N
;
281 return static_cast<void*>(reinterpret_cast<char*>(BlockList
+ 1) +
282 BlockList
->Current
- N
);
287 BlockMeta
* Tmp
= BlockList
;
288 BlockList
= BlockList
->Next
;
289 if (reinterpret_cast<char*>(Tmp
) != InitialBuffer
)
292 BlockList
= new (InitialBuffer
) BlockMeta
{nullptr, 0};
295 ~BumpPointerAllocator() { reset(); }
298 class DefaultAllocator
{
299 BumpPointerAllocator Alloc
;
302 void reset() { Alloc
.reset(); }
304 template<typename T
, typename
...Args
> T
*makeNode(Args
&&...args
) {
305 return new (Alloc
.allocate(sizeof(T
)))
306 T(std::forward
<Args
>(args
)...);
309 void *allocateNodeArray(size_t sz
) {
310 return Alloc
.allocate(sizeof(Node
*) * sz
);
313 } // unnamed namespace
315 //===----------------------------------------------------------------------===//
316 // Code beyond this point should not be synchronized with libc++abi.
317 //===----------------------------------------------------------------------===//
319 using Demangler
= itanium_demangle::Db
<DefaultAllocator
>;
321 char *llvm::itaniumDemangle(const char *MangledName
, char *Buf
,
322 size_t *N
, int *Status
) {
323 if (MangledName
== nullptr || (Buf
!= nullptr && N
== nullptr)) {
325 *Status
= demangle_invalid_args
;
329 int InternalStatus
= demangle_success
;
330 Demangler
Parser(MangledName
, MangledName
+ std::strlen(MangledName
));
333 Node
*AST
= Parser
.parse();
336 InternalStatus
= demangle_invalid_mangled_name
;
337 else if (initializeOutputStream(Buf
, N
, S
, 1024))
338 InternalStatus
= demangle_memory_alloc_failure
;
340 assert(Parser
.ForwardTemplateRefs
.empty());
344 *N
= S
.getCurrentPosition();
349 *Status
= InternalStatus
;
350 return InternalStatus
== demangle_success
? Buf
: nullptr;
353 bool llvm::itaniumFindTypesInMangledName(const char *MangledName
, void *Ctx
,
354 void (*Callback
)(void *,
356 Demangler
Parser(MangledName
, MangledName
+ std::strlen(MangledName
));
357 Parser
.TypeCallback
= Callback
;
358 Parser
.TypeCallbackContext
= Ctx
;
359 return Parser
.parse() == nullptr;
362 ItaniumPartialDemangler::ItaniumPartialDemangler()
363 : RootNode(nullptr), Context(new Demangler
{nullptr, nullptr}) {}
365 ItaniumPartialDemangler::~ItaniumPartialDemangler() {
366 delete static_cast<Demangler
*>(Context
);
369 ItaniumPartialDemangler::ItaniumPartialDemangler(
370 ItaniumPartialDemangler
&&Other
)
371 : RootNode(Other
.RootNode
), Context(Other
.Context
) {
372 Other
.Context
= Other
.RootNode
= nullptr;
375 ItaniumPartialDemangler
&ItaniumPartialDemangler::
376 operator=(ItaniumPartialDemangler
&&Other
) {
377 std::swap(RootNode
, Other
.RootNode
);
378 std::swap(Context
, Other
.Context
);
382 // Demangle MangledName into an AST, storing it into this->RootNode.
383 bool ItaniumPartialDemangler::partialDemangle(const char *MangledName
) {
384 Demangler
*Parser
= static_cast<Demangler
*>(Context
);
385 size_t Len
= std::strlen(MangledName
);
386 Parser
->reset(MangledName
, MangledName
+ Len
);
387 RootNode
= Parser
->parse();
388 return RootNode
== nullptr;
391 static char *printNode(const Node
*RootNode
, char *Buf
, size_t *N
) {
393 if (initializeOutputStream(Buf
, N
, S
, 128))
398 *N
= S
.getCurrentPosition();
399 return S
.getBuffer();
402 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf
, size_t *N
) const {
406 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
409 switch (Name
->getKind()) {
410 case Node::KAbiTagAttr
:
411 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
413 case Node::KStdQualifiedName
:
414 Name
= static_cast<const StdQualifiedName
*>(Name
)->Child
;
416 case Node::KNestedName
:
417 Name
= static_cast<const NestedName
*>(Name
)->Name
;
419 case Node::KLocalName
:
420 Name
= static_cast<const LocalName
*>(Name
)->Entity
;
422 case Node::KNameWithTemplateArgs
:
423 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
426 return printNode(Name
, Buf
, N
);
431 char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf
,
435 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
438 if (initializeOutputStream(Buf
, N
, S
, 128))
441 KeepGoingLocalFunction
:
443 if (Name
->getKind() == Node::KAbiTagAttr
) {
444 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
447 if (Name
->getKind() == Node::KNameWithTemplateArgs
) {
448 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
454 switch (Name
->getKind()) {
455 case Node::KStdQualifiedName
:
458 case Node::KNestedName
:
459 static_cast<const NestedName
*>(Name
)->Qual
->print(S
);
461 case Node::KLocalName
: {
462 auto *LN
= static_cast<const LocalName
*>(Name
);
463 LN
->Encoding
->print(S
);
466 goto KeepGoingLocalFunction
;
473 *N
= S
.getCurrentPosition();
474 return S
.getBuffer();
477 char *ItaniumPartialDemangler::getFunctionName(char *Buf
, size_t *N
) const {
480 auto *Name
= static_cast<FunctionEncoding
*>(RootNode
)->getName();
481 return printNode(Name
, Buf
, N
);
484 char *ItaniumPartialDemangler::getFunctionParameters(char *Buf
,
488 NodeArray Params
= static_cast<FunctionEncoding
*>(RootNode
)->getParams();
491 if (initializeOutputStream(Buf
, N
, S
, 128))
495 Params
.printWithComma(S
);
499 *N
= S
.getCurrentPosition();
500 return S
.getBuffer();
503 char *ItaniumPartialDemangler::getFunctionReturnType(
504 char *Buf
, size_t *N
) const {
509 if (initializeOutputStream(Buf
, N
, S
, 128))
512 if (const Node
*Ret
=
513 static_cast<const FunctionEncoding
*>(RootNode
)->getReturnType())
518 *N
= S
.getCurrentPosition();
519 return S
.getBuffer();
522 char *ItaniumPartialDemangler::finishDemangle(char *Buf
, size_t *N
) const {
523 assert(RootNode
!= nullptr && "must call partialDemangle()");
524 return printNode(static_cast<Node
*>(RootNode
), Buf
, N
);
527 bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
528 assert(RootNode
!= nullptr && "must call partialDemangle()");
531 auto *E
= static_cast<const FunctionEncoding
*>(RootNode
);
532 return E
->getCVQuals() != QualNone
|| E
->getRefQual() != FrefQualNone
;
535 bool ItaniumPartialDemangler::isCtorOrDtor() const {
536 const Node
*N
= static_cast<const Node
*>(RootNode
);
538 switch (N
->getKind()) {
541 case Node::KCtorDtorName
:
544 case Node::KAbiTagAttr
:
545 N
= static_cast<const AbiTagAttr
*>(N
)->Base
;
547 case Node::KFunctionEncoding
:
548 N
= static_cast<const FunctionEncoding
*>(N
)->getName();
550 case Node::KLocalName
:
551 N
= static_cast<const LocalName
*>(N
)->Entity
;
553 case Node::KNameWithTemplateArgs
:
554 N
= static_cast<const NameWithTemplateArgs
*>(N
)->Name
;
556 case Node::KNestedName
:
557 N
= static_cast<const NestedName
*>(N
)->Name
;
559 case Node::KStdQualifiedName
:
560 N
= static_cast<const StdQualifiedName
*>(N
)->Child
;
567 bool ItaniumPartialDemangler::isFunction() const {
568 assert(RootNode
!= nullptr && "must call partialDemangle()");
569 return static_cast<const Node
*>(RootNode
)->getKind() ==
570 Node::KFunctionEncoding
;
573 bool ItaniumPartialDemangler::isSpecialName() const {
574 assert(RootNode
!= nullptr && "must call partialDemangle()");
575 auto K
= static_cast<const Node
*>(RootNode
)->getKind();
576 return K
== Node::KSpecialName
|| K
== Node::KCtorVtableSpecialName
;
579 bool ItaniumPartialDemangler::isData() const {
580 return !isFunction() && !isSpecialName();