1 //===-------------------------- cxa_demangle.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 #define _LIBCPP_NO_EXCEPTIONS
16 #include "__cxxabi_config.h"
18 #include "demangle/ItaniumDemangle.h"
30 using namespace itanium_demangle
;
32 constexpr const char *itanium_demangle::FloatData
<float>::spec
;
33 constexpr const char *itanium_demangle::FloatData
<double>::spec
;
34 constexpr const char *itanium_demangle::FloatData
<long double>::spec
;
36 // <discriminator> := _ <non-negative number> # when number < 10
37 // := __ <non-negative number> _ # when number >= 10
38 // extension := decimal-digit+ # at the end of string
39 const char *itanium_demangle::parse_discriminator(const char *first
,
41 // parse but ignore discriminator
44 const char *t1
= first
+ 1;
46 if (std::isdigit(*t1
))
48 else if (*t1
== '_') {
49 for (++t1
; t1
!= last
&& std::isdigit(*t1
); ++t1
)
51 if (t1
!= last
&& *t1
== '_')
55 } else if (std::isdigit(*first
)) {
56 const char *t1
= first
+ 1;
57 for (; t1
!= last
&& std::isdigit(*t1
); ++t1
)
70 bool PendingNewline
= false;
72 template<typename NodeT
> static constexpr bool wantsNewline(const NodeT
*) {
75 static bool wantsNewline(NodeArray A
) { return !A
.empty(); }
76 static constexpr bool wantsNewline(...) { return false; }
78 template<typename
...Ts
> static bool anyWantNewline(Ts
...Vs
) {
79 for (bool B
: {wantsNewline(Vs
)...})
85 void printStr(const char *S
) { fprintf(stderr
, "%s", S
); }
86 void print(StringView SV
) {
87 fprintf(stderr
, "\"%.*s\"", (int)SV
.size(), SV
.begin());
89 void print(const Node
*N
) {
91 N
->visit(std::ref(*this));
95 void print(NodeOrString NS
) {
98 else if (NS
.isString())
101 printStr("NodeOrString()");
103 void print(NodeArray A
) {
107 for (const Node
*N
: A
) {
118 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
119 void print(bool B
) { printStr(B
? "true" : "false"); }
122 typename
std::enable_if
<std::is_unsigned
<T
>::value
>::type
print(T N
) {
123 fprintf(stderr
, "%llu", (unsigned long long)N
);
127 typename
std::enable_if
<std::is_signed
<T
>::value
>::type
print(T N
) {
128 fprintf(stderr
, "%lld", (long long)N
);
131 void print(ReferenceKind RK
) {
133 case ReferenceKind::LValue
:
134 return printStr("ReferenceKind::LValue");
135 case ReferenceKind::RValue
:
136 return printStr("ReferenceKind::RValue");
139 void print(FunctionRefQual RQ
) {
141 case FunctionRefQual::FrefQualNone
:
142 return printStr("FunctionRefQual::FrefQualNone");
143 case FunctionRefQual::FrefQualLValue
:
144 return printStr("FunctionRefQual::FrefQualLValue");
145 case FunctionRefQual::FrefQualRValue
:
146 return printStr("FunctionRefQual::FrefQualRValue");
149 void print(Qualifiers Qs
) {
150 if (!Qs
) return printStr("QualNone");
151 struct QualName
{ Qualifiers Q
; const char *Name
; } Names
[] = {
152 {QualConst
, "QualConst"},
153 {QualVolatile
, "QualVolatile"},
154 {QualRestrict
, "QualRestrict"},
156 for (QualName Name
: Names
) {
159 Qs
= Qualifiers(Qs
& ~Name
.Q
);
160 if (Qs
) printStr(" | ");
164 void print(SpecialSubKind SSK
) {
166 case SpecialSubKind::allocator
:
167 return printStr("SpecialSubKind::allocator");
168 case SpecialSubKind::basic_string
:
169 return printStr("SpecialSubKind::basic_string");
170 case SpecialSubKind::string
:
171 return printStr("SpecialSubKind::string");
172 case SpecialSubKind::istream
:
173 return printStr("SpecialSubKind::istream");
174 case SpecialSubKind::ostream
:
175 return printStr("SpecialSubKind::ostream");
176 case SpecialSubKind::iostream
:
177 return printStr("SpecialSubKind::iostream");
183 for (unsigned I
= 0; I
!= Depth
; ++I
)
185 PendingNewline
= false;
188 template<typename T
> void printWithPendingNewline(T V
) {
191 PendingNewline
= true;
194 template<typename T
> void printWithComma(T V
) {
195 if (PendingNewline
|| wantsNewline(V
)) {
202 printWithPendingNewline(V
);
205 struct CtorArgPrinter
{
206 DumpVisitor
&Visitor
;
208 template<typename T
, typename
...Rest
> void operator()(T V
, Rest
...Vs
) {
209 if (Visitor
.anyWantNewline(V
, Vs
...))
211 Visitor
.printWithPendingNewline(V
);
212 int PrintInOrder
[] = { (Visitor
.printWithComma(Vs
), 0)..., 0 };
217 template<typename NodeT
> void operator()(const NodeT
*Node
) {
219 fprintf(stderr
, "%s(", itanium_demangle::NodeKind
<NodeT
>::name());
220 Node
->match(CtorArgPrinter
{*this});
221 fprintf(stderr
, ")");
225 void operator()(const ForwardTemplateReference
*Node
) {
227 fprintf(stderr
, "ForwardTemplateReference(");
228 if (Node
->Ref
&& !Node
->Printing
) {
229 Node
->Printing
= true;
230 CtorArgPrinter
{*this}(Node
->Ref
);
231 Node
->Printing
= false;
233 CtorArgPrinter
{*this}(Node
->Index
);
235 fprintf(stderr
, ")");
241 void itanium_demangle::Node::dump() const {
249 class BumpPointerAllocator
{
255 static constexpr size_t AllocSize
= 4096;
256 static constexpr size_t UsableAllocSize
= AllocSize
- sizeof(BlockMeta
);
258 alignas(long double) char InitialBuffer
[AllocSize
];
259 BlockMeta
* BlockList
= nullptr;
262 char* NewMeta
= static_cast<char *>(std::malloc(AllocSize
));
263 if (NewMeta
== nullptr)
265 BlockList
= new (NewMeta
) BlockMeta
{BlockList
, 0};
268 void* allocateMassive(size_t NBytes
) {
269 NBytes
+= sizeof(BlockMeta
);
270 BlockMeta
* NewMeta
= reinterpret_cast<BlockMeta
*>(std::malloc(NBytes
));
271 if (NewMeta
== nullptr)
273 BlockList
->Next
= new (NewMeta
) BlockMeta
{BlockList
->Next
, 0};
274 return static_cast<void*>(NewMeta
+ 1);
278 BumpPointerAllocator()
279 : BlockList(new (InitialBuffer
) BlockMeta
{nullptr, 0}) {}
281 void* allocate(size_t N
) {
282 N
= (N
+ 15u) & ~15u;
283 if (N
+ BlockList
->Current
>= UsableAllocSize
) {
284 if (N
> UsableAllocSize
)
285 return allocateMassive(N
);
288 BlockList
->Current
+= N
;
289 return static_cast<void*>(reinterpret_cast<char*>(BlockList
+ 1) +
290 BlockList
->Current
- N
);
295 BlockMeta
* Tmp
= BlockList
;
296 BlockList
= BlockList
->Next
;
297 if (reinterpret_cast<char*>(Tmp
) != InitialBuffer
)
300 BlockList
= new (InitialBuffer
) BlockMeta
{nullptr, 0};
303 ~BumpPointerAllocator() { reset(); }
306 class DefaultAllocator
{
307 BumpPointerAllocator Alloc
;
310 void reset() { Alloc
.reset(); }
312 template<typename T
, typename
...Args
> T
*makeNode(Args
&&...args
) {
313 return new (Alloc
.allocate(sizeof(T
)))
314 T(std::forward
<Args
>(args
)...);
317 void *allocateNodeArray(size_t sz
) {
318 return Alloc
.allocate(sizeof(Node
*) * sz
);
321 } // unnamed namespace
323 //===----------------------------------------------------------------------===//
324 // Code beyond this point should not be synchronized with LLVM.
325 //===----------------------------------------------------------------------===//
327 using Demangler
= itanium_demangle::ManglingParser
<DefaultAllocator
>;
331 demangle_invalid_args
= -3,
332 demangle_invalid_mangled_name
= -2,
333 demangle_memory_alloc_failure
= -1,
334 demangle_success
= 0,
338 namespace __cxxabiv1
{
339 extern "C" _LIBCXXABI_FUNC_VIS
char *
340 __cxa_demangle(const char *MangledName
, char *Buf
, size_t *N
, int *Status
) {
341 if (MangledName
== nullptr || (Buf
!= nullptr && N
== nullptr)) {
343 *Status
= demangle_invalid_args
;
347 int InternalStatus
= demangle_success
;
348 Demangler
Parser(MangledName
, MangledName
+ std::strlen(MangledName
));
351 Node
*AST
= Parser
.parse();
354 InternalStatus
= demangle_invalid_mangled_name
;
355 else if (!initializeOutputStream(Buf
, N
, S
, 1024))
356 InternalStatus
= demangle_memory_alloc_failure
;
358 assert(Parser
.ForwardTemplateRefs
.empty());
362 *N
= S
.getCurrentPosition();
367 *Status
= InternalStatus
;
368 return InternalStatus
== demangle_success
? Buf
: nullptr;