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");
180 for (unsigned I
= 0; I
!= Depth
; ++I
)
182 PendingNewline
= false;
185 template<typename T
> void printWithPendingNewline(T V
) {
188 PendingNewline
= true;
191 template<typename T
> void printWithComma(T V
) {
192 if (PendingNewline
|| wantsNewline(V
)) {
199 printWithPendingNewline(V
);
202 struct CtorArgPrinter
{
203 DumpVisitor
&Visitor
;
205 template<typename T
, typename
...Rest
> void operator()(T V
, Rest
...Vs
) {
206 if (Visitor
.anyWantNewline(V
, Vs
...))
208 Visitor
.printWithPendingNewline(V
);
209 int PrintInOrder
[] = { (Visitor
.printWithComma(Vs
), 0)..., 0 };
214 template<typename NodeT
> void operator()(const NodeT
*Node
) {
216 fprintf(stderr
, "%s(", itanium_demangle::NodeKind
<NodeT
>::name());
217 Node
->match(CtorArgPrinter
{*this});
218 fprintf(stderr
, ")");
222 void operator()(const ForwardTemplateReference
*Node
) {
224 fprintf(stderr
, "ForwardTemplateReference(");
225 if (Node
->Ref
&& !Node
->Printing
) {
226 Node
->Printing
= true;
227 CtorArgPrinter
{*this}(Node
->Ref
);
228 Node
->Printing
= false;
230 CtorArgPrinter
{*this}(Node
->Index
);
232 fprintf(stderr
, ")");
238 void itanium_demangle::Node::dump() const {
246 class BumpPointerAllocator
{
252 static constexpr size_t AllocSize
= 4096;
253 static constexpr size_t UsableAllocSize
= AllocSize
- sizeof(BlockMeta
);
255 alignas(long double) char InitialBuffer
[AllocSize
];
256 BlockMeta
* BlockList
= nullptr;
259 char* NewMeta
= static_cast<char *>(std::malloc(AllocSize
));
260 if (NewMeta
== nullptr)
262 BlockList
= new (NewMeta
) BlockMeta
{BlockList
, 0};
265 void* allocateMassive(size_t NBytes
) {
266 NBytes
+= sizeof(BlockMeta
);
267 BlockMeta
* NewMeta
= reinterpret_cast<BlockMeta
*>(std::malloc(NBytes
));
268 if (NewMeta
== nullptr)
270 BlockList
->Next
= new (NewMeta
) BlockMeta
{BlockList
->Next
, 0};
271 return static_cast<void*>(NewMeta
+ 1);
275 BumpPointerAllocator()
276 : BlockList(new (InitialBuffer
) BlockMeta
{nullptr, 0}) {}
278 void* allocate(size_t N
) {
279 N
= (N
+ 15u) & ~15u;
280 if (N
+ BlockList
->Current
>= UsableAllocSize
) {
281 if (N
> UsableAllocSize
)
282 return allocateMassive(N
);
285 BlockList
->Current
+= N
;
286 return static_cast<void*>(reinterpret_cast<char*>(BlockList
+ 1) +
287 BlockList
->Current
- N
);
292 BlockMeta
* Tmp
= BlockList
;
293 BlockList
= BlockList
->Next
;
294 if (reinterpret_cast<char*>(Tmp
) != InitialBuffer
)
297 BlockList
= new (InitialBuffer
) BlockMeta
{nullptr, 0};
300 ~BumpPointerAllocator() { reset(); }
303 class DefaultAllocator
{
304 BumpPointerAllocator Alloc
;
307 void reset() { Alloc
.reset(); }
309 template<typename T
, typename
...Args
> T
*makeNode(Args
&&...args
) {
310 return new (Alloc
.allocate(sizeof(T
)))
311 T(std::forward
<Args
>(args
)...);
314 void *allocateNodeArray(size_t sz
) {
315 return Alloc
.allocate(sizeof(Node
*) * sz
);
318 } // unnamed namespace
320 //===----------------------------------------------------------------------===//
321 // Code beyond this point should not be synchronized with libc++abi.
322 //===----------------------------------------------------------------------===//
324 using Demangler
= itanium_demangle::ManglingParser
<DefaultAllocator
>;
326 char *llvm::itaniumDemangle(const char *MangledName
, char *Buf
,
327 size_t *N
, int *Status
) {
328 if (MangledName
== nullptr || (Buf
!= nullptr && N
== nullptr)) {
330 *Status
= demangle_invalid_args
;
334 int InternalStatus
= demangle_success
;
335 Demangler
Parser(MangledName
, MangledName
+ std::strlen(MangledName
));
338 Node
*AST
= Parser
.parse();
341 InternalStatus
= demangle_invalid_mangled_name
;
342 else if (!initializeOutputStream(Buf
, N
, S
, 1024))
343 InternalStatus
= demangle_memory_alloc_failure
;
345 assert(Parser
.ForwardTemplateRefs
.empty());
349 *N
= S
.getCurrentPosition();
354 *Status
= InternalStatus
;
355 return InternalStatus
== demangle_success
? Buf
: nullptr;
358 ItaniumPartialDemangler::ItaniumPartialDemangler()
359 : RootNode(nullptr), Context(new Demangler
{nullptr, nullptr}) {}
361 ItaniumPartialDemangler::~ItaniumPartialDemangler() {
362 delete static_cast<Demangler
*>(Context
);
365 ItaniumPartialDemangler::ItaniumPartialDemangler(
366 ItaniumPartialDemangler
&&Other
)
367 : RootNode(Other
.RootNode
), Context(Other
.Context
) {
368 Other
.Context
= Other
.RootNode
= nullptr;
371 ItaniumPartialDemangler
&ItaniumPartialDemangler::
372 operator=(ItaniumPartialDemangler
&&Other
) {
373 std::swap(RootNode
, Other
.RootNode
);
374 std::swap(Context
, Other
.Context
);
378 // Demangle MangledName into an AST, storing it into this->RootNode.
379 bool ItaniumPartialDemangler::partialDemangle(const char *MangledName
) {
380 Demangler
*Parser
= static_cast<Demangler
*>(Context
);
381 size_t Len
= std::strlen(MangledName
);
382 Parser
->reset(MangledName
, MangledName
+ Len
);
383 RootNode
= Parser
->parse();
384 return RootNode
== nullptr;
387 static char *printNode(const Node
*RootNode
, char *Buf
, size_t *N
) {
389 if (!initializeOutputStream(Buf
, N
, S
, 128))
394 *N
= S
.getCurrentPosition();
395 return S
.getBuffer();
398 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf
, size_t *N
) const {
402 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
405 switch (Name
->getKind()) {
406 case Node::KAbiTagAttr
:
407 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
409 case Node::KStdQualifiedName
:
410 Name
= static_cast<const StdQualifiedName
*>(Name
)->Child
;
412 case Node::KNestedName
:
413 Name
= static_cast<const NestedName
*>(Name
)->Name
;
415 case Node::KLocalName
:
416 Name
= static_cast<const LocalName
*>(Name
)->Entity
;
418 case Node::KNameWithTemplateArgs
:
419 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
422 return printNode(Name
, Buf
, N
);
427 char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf
,
431 const Node
*Name
= static_cast<const FunctionEncoding
*>(RootNode
)->getName();
434 if (!initializeOutputStream(Buf
, N
, S
, 128))
437 KeepGoingLocalFunction
:
439 if (Name
->getKind() == Node::KAbiTagAttr
) {
440 Name
= static_cast<const AbiTagAttr
*>(Name
)->Base
;
443 if (Name
->getKind() == Node::KNameWithTemplateArgs
) {
444 Name
= static_cast<const NameWithTemplateArgs
*>(Name
)->Name
;
450 switch (Name
->getKind()) {
451 case Node::KStdQualifiedName
:
454 case Node::KNestedName
:
455 static_cast<const NestedName
*>(Name
)->Qual
->print(S
);
457 case Node::KLocalName
: {
458 auto *LN
= static_cast<const LocalName
*>(Name
);
459 LN
->Encoding
->print(S
);
462 goto KeepGoingLocalFunction
;
469 *N
= S
.getCurrentPosition();
470 return S
.getBuffer();
473 char *ItaniumPartialDemangler::getFunctionName(char *Buf
, size_t *N
) const {
476 auto *Name
= static_cast<FunctionEncoding
*>(RootNode
)->getName();
477 return printNode(Name
, Buf
, N
);
480 char *ItaniumPartialDemangler::getFunctionParameters(char *Buf
,
484 NodeArray Params
= static_cast<FunctionEncoding
*>(RootNode
)->getParams();
487 if (!initializeOutputStream(Buf
, N
, S
, 128))
491 Params
.printWithComma(S
);
495 *N
= S
.getCurrentPosition();
496 return S
.getBuffer();
499 char *ItaniumPartialDemangler::getFunctionReturnType(
500 char *Buf
, size_t *N
) const {
505 if (!initializeOutputStream(Buf
, N
, S
, 128))
508 if (const Node
*Ret
=
509 static_cast<const FunctionEncoding
*>(RootNode
)->getReturnType())
514 *N
= S
.getCurrentPosition();
515 return S
.getBuffer();
518 char *ItaniumPartialDemangler::finishDemangle(char *Buf
, size_t *N
) const {
519 assert(RootNode
!= nullptr && "must call partialDemangle()");
520 return printNode(static_cast<Node
*>(RootNode
), Buf
, N
);
523 bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
524 assert(RootNode
!= nullptr && "must call partialDemangle()");
527 auto *E
= static_cast<const FunctionEncoding
*>(RootNode
);
528 return E
->getCVQuals() != QualNone
|| E
->getRefQual() != FrefQualNone
;
531 bool ItaniumPartialDemangler::isCtorOrDtor() const {
532 const Node
*N
= static_cast<const Node
*>(RootNode
);
534 switch (N
->getKind()) {
537 case Node::KCtorDtorName
:
540 case Node::KAbiTagAttr
:
541 N
= static_cast<const AbiTagAttr
*>(N
)->Base
;
543 case Node::KFunctionEncoding
:
544 N
= static_cast<const FunctionEncoding
*>(N
)->getName();
546 case Node::KLocalName
:
547 N
= static_cast<const LocalName
*>(N
)->Entity
;
549 case Node::KNameWithTemplateArgs
:
550 N
= static_cast<const NameWithTemplateArgs
*>(N
)->Name
;
552 case Node::KNestedName
:
553 N
= static_cast<const NestedName
*>(N
)->Name
;
555 case Node::KStdQualifiedName
:
556 N
= static_cast<const StdQualifiedName
*>(N
)->Child
;
563 bool ItaniumPartialDemangler::isFunction() const {
564 assert(RootNode
!= nullptr && "must call partialDemangle()");
565 return static_cast<const Node
*>(RootNode
)->getKind() ==
566 Node::KFunctionEncoding
;
569 bool ItaniumPartialDemangler::isSpecialName() const {
570 assert(RootNode
!= nullptr && "must call partialDemangle()");
571 auto K
= static_cast<const Node
*>(RootNode
)->getKind();
572 return K
== Node::KSpecialName
|| K
== Node::KCtorVtableSpecialName
;
575 bool ItaniumPartialDemangler::isData() const {
576 return !isFunction() && !isSpecialName();