1 //===----------------------------------------------------------------------===//
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 "abort_message.h"
14 #define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)
16 #include "demangle/DemangleConfig.h"
17 #include "demangle/ItaniumDemangle.h"
18 #include "__cxxabi_config.h"
26 #include <string_view>
29 using namespace itanium_demangle
;
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(std::string_view 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"); }
109 typename
std::enable_if
<std::is_unsigned
<T
>::value
>::type
print(T N
) {
110 fprintf(stderr
, "%llu", (unsigned long long)N
);
114 typename
std::enable_if
<std::is_signed
<T
>::value
>::type
print(T N
) {
115 fprintf(stderr
, "%lld", (long long)N
);
118 void print(ReferenceKind RK
) {
120 case ReferenceKind::LValue
:
121 return printStr("ReferenceKind::LValue");
122 case ReferenceKind::RValue
:
123 return printStr("ReferenceKind::RValue");
126 void print(FunctionRefQual RQ
) {
128 case FunctionRefQual::FrefQualNone
:
129 return printStr("FunctionRefQual::FrefQualNone");
130 case FunctionRefQual::FrefQualLValue
:
131 return printStr("FunctionRefQual::FrefQualLValue");
132 case FunctionRefQual::FrefQualRValue
:
133 return printStr("FunctionRefQual::FrefQualRValue");
136 void print(Qualifiers Qs
) {
137 if (!Qs
) return printStr("QualNone");
138 struct QualName
{ Qualifiers Q
; const char *Name
; } Names
[] = {
139 {QualConst
, "QualConst"},
140 {QualVolatile
, "QualVolatile"},
141 {QualRestrict
, "QualRestrict"},
143 for (QualName Name
: Names
) {
146 Qs
= Qualifiers(Qs
& ~Name
.Q
);
147 if (Qs
) printStr(" | ");
151 void print(SpecialSubKind SSK
) {
153 case SpecialSubKind::allocator
:
154 return printStr("SpecialSubKind::allocator");
155 case SpecialSubKind::basic_string
:
156 return printStr("SpecialSubKind::basic_string");
157 case SpecialSubKind::string
:
158 return printStr("SpecialSubKind::string");
159 case SpecialSubKind::istream
:
160 return printStr("SpecialSubKind::istream");
161 case SpecialSubKind::ostream
:
162 return printStr("SpecialSubKind::ostream");
163 case SpecialSubKind::iostream
:
164 return printStr("SpecialSubKind::iostream");
167 void print(TemplateParamKind TPK
) {
169 case TemplateParamKind::Type
:
170 return printStr("TemplateParamKind::Type");
171 case TemplateParamKind::NonType
:
172 return printStr("TemplateParamKind::NonType");
173 case TemplateParamKind::Template
:
174 return printStr("TemplateParamKind::Template");
177 void print(Node::Prec P
) {
179 case Node::Prec::Primary
:
180 return printStr("Node::Prec::Primary");
181 case Node::Prec::Postfix
:
182 return printStr("Node::Prec::Postfix");
183 case Node::Prec::Unary
:
184 return printStr("Node::Prec::Unary");
185 case Node::Prec::Cast
:
186 return printStr("Node::Prec::Cast");
187 case Node::Prec::PtrMem
:
188 return printStr("Node::Prec::PtrMem");
189 case Node::Prec::Multiplicative
:
190 return printStr("Node::Prec::Multiplicative");
191 case Node::Prec::Additive
:
192 return printStr("Node::Prec::Additive");
193 case Node::Prec::Shift
:
194 return printStr("Node::Prec::Shift");
195 case Node::Prec::Spaceship
:
196 return printStr("Node::Prec::Spaceship");
197 case Node::Prec::Relational
:
198 return printStr("Node::Prec::Relational");
199 case Node::Prec::Equality
:
200 return printStr("Node::Prec::Equality");
201 case Node::Prec::And
:
202 return printStr("Node::Prec::And");
203 case Node::Prec::Xor
:
204 return printStr("Node::Prec::Xor");
205 case Node::Prec::Ior
:
206 return printStr("Node::Prec::Ior");
207 case Node::Prec::AndIf
:
208 return printStr("Node::Prec::AndIf");
209 case Node::Prec::OrIf
:
210 return printStr("Node::Prec::OrIf");
211 case Node::Prec::Conditional
:
212 return printStr("Node::Prec::Conditional");
213 case Node::Prec::Assign
:
214 return printStr("Node::Prec::Assign");
215 case Node::Prec::Comma
:
216 return printStr("Node::Prec::Comma");
217 case Node::Prec::Default
:
218 return printStr("Node::Prec::Default");
224 for (unsigned I
= 0; I
!= Depth
; ++I
)
226 PendingNewline
= false;
229 template<typename T
> void printWithPendingNewline(T V
) {
232 PendingNewline
= true;
235 template<typename T
> void printWithComma(T V
) {
236 if (PendingNewline
|| wantsNewline(V
)) {
243 printWithPendingNewline(V
);
246 struct CtorArgPrinter
{
247 DumpVisitor
&Visitor
;
249 template<typename T
, typename
...Rest
> void operator()(T V
, Rest
...Vs
) {
250 if (Visitor
.anyWantNewline(V
, Vs
...))
252 Visitor
.printWithPendingNewline(V
);
253 int PrintInOrder
[] = { (Visitor
.printWithComma(Vs
), 0)..., 0 };
258 template<typename NodeT
> void operator()(const NodeT
*Node
) {
260 fprintf(stderr
, "%s(", itanium_demangle::NodeKind
<NodeT
>::name());
261 Node
->match(CtorArgPrinter
{*this});
262 fprintf(stderr
, ")");
266 void operator()(const ForwardTemplateReference
*Node
) {
268 fprintf(stderr
, "ForwardTemplateReference(");
269 if (Node
->Ref
&& !Node
->Printing
) {
270 Node
->Printing
= true;
271 CtorArgPrinter
{*this}(Node
->Ref
);
272 Node
->Printing
= false;
274 CtorArgPrinter
{*this}(Node
->Index
);
276 fprintf(stderr
, ")");
282 void itanium_demangle::Node::dump() const {
290 class BumpPointerAllocator
{
296 static constexpr size_t AllocSize
= 4096;
297 static constexpr size_t UsableAllocSize
= AllocSize
- sizeof(BlockMeta
);
299 alignas(long double) char InitialBuffer
[AllocSize
];
300 BlockMeta
* BlockList
= nullptr;
303 char* NewMeta
= static_cast<char *>(std::malloc(AllocSize
));
304 if (NewMeta
== nullptr)
306 BlockList
= new (NewMeta
) BlockMeta
{BlockList
, 0};
309 void* allocateMassive(size_t NBytes
) {
310 NBytes
+= sizeof(BlockMeta
);
311 BlockMeta
* NewMeta
= reinterpret_cast<BlockMeta
*>(std::malloc(NBytes
));
312 if (NewMeta
== nullptr)
314 BlockList
->Next
= new (NewMeta
) BlockMeta
{BlockList
->Next
, 0};
315 return static_cast<void*>(NewMeta
+ 1);
319 BumpPointerAllocator()
320 : BlockList(new (InitialBuffer
) BlockMeta
{nullptr, 0}) {}
322 void* allocate(size_t N
) {
323 N
= (N
+ 15u) & ~15u;
324 if (N
+ BlockList
->Current
>= UsableAllocSize
) {
325 if (N
> UsableAllocSize
)
326 return allocateMassive(N
);
329 BlockList
->Current
+= N
;
330 return static_cast<void*>(reinterpret_cast<char*>(BlockList
+ 1) +
331 BlockList
->Current
- N
);
336 BlockMeta
* Tmp
= BlockList
;
337 BlockList
= BlockList
->Next
;
338 if (reinterpret_cast<char*>(Tmp
) != InitialBuffer
)
341 BlockList
= new (InitialBuffer
) BlockMeta
{nullptr, 0};
344 ~BumpPointerAllocator() { reset(); }
347 class DefaultAllocator
{
348 BumpPointerAllocator Alloc
;
351 void reset() { Alloc
.reset(); }
353 template<typename T
, typename
...Args
> T
*makeNode(Args
&&...args
) {
354 return new (Alloc
.allocate(sizeof(T
)))
355 T(std::forward
<Args
>(args
)...);
358 void *allocateNodeArray(size_t sz
) {
359 return Alloc
.allocate(sizeof(Node
*) * sz
);
362 } // unnamed namespace
364 //===----------------------------------------------------------------------===//
365 // Code beyond this point should not be synchronized with LLVM.
366 //===----------------------------------------------------------------------===//
368 using Demangler
= itanium_demangle::ManglingParser
<DefaultAllocator
>;
372 demangle_invalid_args
= -3,
373 demangle_invalid_mangled_name
= -2,
374 demangle_memory_alloc_failure
= -1,
375 demangle_success
= 0,
379 namespace __cxxabiv1
{
380 extern "C" _LIBCXXABI_FUNC_VIS
char *
381 __cxa_demangle(const char *MangledName
, char *Buf
, size_t *N
, int *Status
) {
382 if (MangledName
== nullptr || (Buf
!= nullptr && N
== nullptr)) {
384 *Status
= demangle_invalid_args
;
388 int InternalStatus
= demangle_success
;
389 Demangler
Parser(MangledName
, MangledName
+ std::strlen(MangledName
));
390 Node
*AST
= Parser
.parse();
393 InternalStatus
= demangle_invalid_mangled_name
;
395 OutputBuffer
O(Buf
, N
);
396 DEMANGLE_ASSERT(Parser
.ForwardTemplateRefs
.empty(), "");
400 *N
= O
.getCurrentPosition();
405 *Status
= InternalStatus
;
406 return InternalStatus
== demangle_success
? Buf
: nullptr;