1 //===------------------------- ItaniumDemangle.cpp ------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 // FIXME: (possibly) incomplete list of features that clang mangles that this 10 // file does not yet support: 11 // - C++ modules TS 12 13 #include "llvm/Demangle/Demangle.h" 14 #include "llvm/Demangle/ItaniumDemangle.h" 15 16 #include <cassert> 17 #include <cctype> 18 #include <cstdio> 19 #include <cstdlib> 20 #include <cstring> 21 #include <functional> 22 #include <utility> 23 24 using namespace llvm; 25 using namespace llvm::itanium_demangle; 26 27 constexpr const char *itanium_demangle::FloatData<float>::spec; 28 constexpr const char *itanium_demangle::FloatData<double>::spec; 29 constexpr const char *itanium_demangle::FloatData<long double>::spec; 30 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, 35 const char *last) { 36 // parse but ignore discriminator 37 if (first != last) { 38 if (*first == '_') { 39 const char *t1 = first + 1; 40 if (t1 != last) { 41 if (std::isdigit(*t1)) 42 first = t1 + 1; 43 else if (*t1 == '_') { 44 for (++t1; t1 != last && std::isdigit(*t1); ++t1) 45 ; 46 if (t1 != last && *t1 == '_') 47 first = t1 + 1; 48 } 49 } 50 } else if (std::isdigit(*first)) { 51 const char *t1 = first + 1; 52 for (; t1 != last && std::isdigit(*t1); ++t1) 53 ; 54 if (t1 == last) 55 first = last; 56 } 57 } 58 return first; 59 } 60 61 #ifndef NDEBUG 62 namespace { 63 struct DumpVisitor { 64 unsigned Depth = 0; 65 bool PendingNewline = false; 66 67 template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) { 68 return true; 69 } 70 static bool wantsNewline(NodeArray A) { return !A.empty(); } 71 static constexpr bool wantsNewline(...) { return false; } 72 73 template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) { 74 for (bool B : {wantsNewline(Vs)...}) 75 if (B) 76 return true; 77 return false; 78 } 79 80 void printStr(const char *S) { fprintf(stderr, "%s", S); } 81 void print(StringView SV) { 82 fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); 83 } 84 void print(const Node *N) { 85 if (N) 86 N->visit(std::ref(*this)); 87 else 88 printStr("<null>"); 89 } 90 void print(NodeArray A) { 91 ++Depth; 92 printStr("{"); 93 bool First = true; 94 for (const Node *N : A) { 95 if (First) 96 print(N); 97 else 98 printWithComma(N); 99 First = false; 100 } 101 printStr("}"); 102 --Depth; 103 } 104 105 // Overload used when T is exactly 'bool', not merely convertible to 'bool'. 106 void print(bool B) { printStr(B ? "true" : "false"); } 107 108 template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) { 109 fprintf(stderr, "%llu", (unsigned long long)N); 110 } 111 112 template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) { 113 fprintf(stderr, "%lld", (long long)N); 114 } 115 116 void print(ReferenceKind RK) { 117 switch (RK) { 118 case ReferenceKind::LValue: 119 return printStr("ReferenceKind::LValue"); 120 case ReferenceKind::RValue: 121 return printStr("ReferenceKind::RValue"); 122 } 123 } 124 void print(FunctionRefQual RQ) { 125 switch (RQ) { 126 case FunctionRefQual::FrefQualNone: 127 return printStr("FunctionRefQual::FrefQualNone"); 128 case FunctionRefQual::FrefQualLValue: 129 return printStr("FunctionRefQual::FrefQualLValue"); 130 case FunctionRefQual::FrefQualRValue: 131 return printStr("FunctionRefQual::FrefQualRValue"); 132 } 133 } 134 void print(Qualifiers Qs) { 135 if (!Qs) return printStr("QualNone"); 136 struct QualName { Qualifiers Q; const char *Name; } Names[] = { 137 {QualConst, "QualConst"}, 138 {QualVolatile, "QualVolatile"}, 139 {QualRestrict, "QualRestrict"}, 140 }; 141 for (QualName Name : Names) { 142 if (Qs & Name.Q) { 143 printStr(Name.Name); 144 Qs = Qualifiers(Qs & ~Name.Q); 145 if (Qs) printStr(" | "); 146 } 147 } 148 } 149 void print(SpecialSubKind SSK) { 150 switch (SSK) { 151 case SpecialSubKind::allocator: 152 return printStr("SpecialSubKind::allocator"); 153 case SpecialSubKind::basic_string: 154 return printStr("SpecialSubKind::basic_string"); 155 case SpecialSubKind::string: 156 return printStr("SpecialSubKind::string"); 157 case SpecialSubKind::istream: 158 return printStr("SpecialSubKind::istream"); 159 case SpecialSubKind::ostream: 160 return printStr("SpecialSubKind::ostream"); 161 case SpecialSubKind::iostream: 162 return printStr("SpecialSubKind::iostream"); 163 } 164 } 165 void print(TemplateParamKind TPK) { 166 switch (TPK) { 167 case TemplateParamKind::Type: 168 return printStr("TemplateParamKind::Type"); 169 case TemplateParamKind::NonType: 170 return printStr("TemplateParamKind::NonType"); 171 case TemplateParamKind::Template: 172 return printStr("TemplateParamKind::Template"); 173 } 174 } 175 176 void newLine() { 177 printStr("\n"); 178 for (unsigned I = 0; I != Depth; ++I) 179 printStr(" "); 180 PendingNewline = false; 181 } 182 183 template<typename T> void printWithPendingNewline(T V) { 184 print(V); 185 if (wantsNewline(V)) 186 PendingNewline = true; 187 } 188 189 template<typename T> void printWithComma(T V) { 190 if (PendingNewline || wantsNewline(V)) { 191 printStr(","); 192 newLine(); 193 } else { 194 printStr(", "); 195 } 196 197 printWithPendingNewline(V); 198 } 199 200 struct CtorArgPrinter { 201 DumpVisitor &Visitor; 202 203 template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) { 204 if (Visitor.anyWantNewline(V, Vs...)) 205 Visitor.newLine(); 206 Visitor.printWithPendingNewline(V); 207 int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; 208 (void)PrintInOrder; 209 } 210 }; 211 212 template<typename NodeT> void operator()(const NodeT *Node) { 213 Depth += 2; 214 fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name()); 215 Node->match(CtorArgPrinter{*this}); 216 fprintf(stderr, ")"); 217 Depth -= 2; 218 } 219 220 void operator()(const ForwardTemplateReference *Node) { 221 Depth += 2; 222 fprintf(stderr, "ForwardTemplateReference("); 223 if (Node->Ref && !Node->Printing) { 224 Node->Printing = true; 225 CtorArgPrinter{*this}(Node->Ref); 226 Node->Printing = false; 227 } else { 228 CtorArgPrinter{*this}(Node->Index); 229 } 230 fprintf(stderr, ")"); 231 Depth -= 2; 232 } 233 }; 234 } 235 236 void itanium_demangle::Node::dump() const { 237 DumpVisitor V; 238 visit(std::ref(V)); 239 V.newLine(); 240 } 241 #endif 242 243 namespace { 244 class BumpPointerAllocator { 245 struct BlockMeta { 246 BlockMeta* Next; 247 size_t Current; 248 }; 249 250 static constexpr size_t AllocSize = 4096; 251 static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); 252 253 alignas(long double) char InitialBuffer[AllocSize]; 254 BlockMeta* BlockList = nullptr; 255 256 void grow() { 257 char* NewMeta = static_cast<char *>(std::malloc(AllocSize)); 258 if (NewMeta == nullptr) 259 std::terminate(); 260 BlockList = new (NewMeta) BlockMeta{BlockList, 0}; 261 } 262 263 void* allocateMassive(size_t NBytes) { 264 NBytes += sizeof(BlockMeta); 265 BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes)); 266 if (NewMeta == nullptr) 267 std::terminate(); 268 BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; 269 return static_cast<void*>(NewMeta + 1); 270 } 271 272 public: 273 BumpPointerAllocator() 274 : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} 275 276 void* allocate(size_t N) { 277 N = (N + 15u) & ~15u; 278 if (N + BlockList->Current >= UsableAllocSize) { 279 if (N > UsableAllocSize) 280 return allocateMassive(N); 281 grow(); 282 } 283 BlockList->Current += N; 284 return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) + 285 BlockList->Current - N); 286 } 287 288 void reset() { 289 while (BlockList) { 290 BlockMeta* Tmp = BlockList; 291 BlockList = BlockList->Next; 292 if (reinterpret_cast<char*>(Tmp) != InitialBuffer) 293 std::free(Tmp); 294 } 295 BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; 296 } 297 298 ~BumpPointerAllocator() { reset(); } 299 }; 300 301 class DefaultAllocator { 302 BumpPointerAllocator Alloc; 303 304 public: 305 void reset() { Alloc.reset(); } 306 307 template<typename T, typename ...Args> T *makeNode(Args &&...args) { 308 return new (Alloc.allocate(sizeof(T))) 309 T(std::forward<Args>(args)...); 310 } 311 312 void *allocateNodeArray(size_t sz) { 313 return Alloc.allocate(sizeof(Node *) * sz); 314 } 315 }; 316 } // unnamed namespace 317 318 //===----------------------------------------------------------------------===// 319 // Code beyond this point should not be synchronized with libc++abi. 320 //===----------------------------------------------------------------------===// 321 322 using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; 323 324 char *llvm::itaniumDemangle(const char *MangledName, char *Buf, 325 size_t *N, int *Status) { 326 if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { 327 if (Status) 328 *Status = demangle_invalid_args; 329 return nullptr; 330 } 331 332 int InternalStatus = demangle_success; 333 Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); 334 OutputBuffer OB; 335 336 Node *AST = Parser.parse(); 337 338 if (AST == nullptr) 339 InternalStatus = demangle_invalid_mangled_name; 340 else if (!initializeOutputBuffer(Buf, N, OB, 1024)) 341 InternalStatus = demangle_memory_alloc_failure; 342 else { 343 assert(Parser.ForwardTemplateRefs.empty()); 344 AST->print(OB); 345 OB += '\0'; 346 if (N != nullptr) 347 *N = OB.getCurrentPosition(); 348 Buf = OB.getBuffer(); 349 } 350 351 if (Status) 352 *Status = InternalStatus; 353 return InternalStatus == demangle_success ? Buf : nullptr; 354 } 355 356 ItaniumPartialDemangler::ItaniumPartialDemangler() 357 : RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {} 358 359 ItaniumPartialDemangler::~ItaniumPartialDemangler() { 360 delete static_cast<Demangler *>(Context); 361 } 362 363 ItaniumPartialDemangler::ItaniumPartialDemangler( 364 ItaniumPartialDemangler &&Other) 365 : RootNode(Other.RootNode), Context(Other.Context) { 366 Other.Context = Other.RootNode = nullptr; 367 } 368 369 ItaniumPartialDemangler &ItaniumPartialDemangler:: 370 operator=(ItaniumPartialDemangler &&Other) { 371 std::swap(RootNode, Other.RootNode); 372 std::swap(Context, Other.Context); 373 return *this; 374 } 375 376 // Demangle MangledName into an AST, storing it into this->RootNode. 377 bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { 378 Demangler *Parser = static_cast<Demangler *>(Context); 379 size_t Len = std::strlen(MangledName); 380 Parser->reset(MangledName, MangledName + Len); 381 RootNode = Parser->parse(); 382 return RootNode == nullptr; 383 } 384 385 static char *printNode(const Node *RootNode, char *Buf, size_t *N) { 386 OutputBuffer OB; 387 if (!initializeOutputBuffer(Buf, N, OB, 128)) 388 return nullptr; 389 RootNode->print(OB); 390 OB += '\0'; 391 if (N != nullptr) 392 *N = OB.getCurrentPosition(); 393 return OB.getBuffer(); 394 } 395 396 char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { 397 if (!isFunction()) 398 return nullptr; 399 400 const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); 401 402 while (true) { 403 switch (Name->getKind()) { 404 case Node::KAbiTagAttr: 405 Name = static_cast<const AbiTagAttr *>(Name)->Base; 406 continue; 407 case Node::KStdQualifiedName: 408 Name = static_cast<const StdQualifiedName *>(Name)->Child; 409 continue; 410 case Node::KNestedName: 411 Name = static_cast<const NestedName *>(Name)->Name; 412 continue; 413 case Node::KLocalName: 414 Name = static_cast<const LocalName *>(Name)->Entity; 415 continue; 416 case Node::KNameWithTemplateArgs: 417 Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; 418 continue; 419 default: 420 return printNode(Name, Buf, N); 421 } 422 } 423 } 424 425 char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, 426 size_t *N) const { 427 if (!isFunction()) 428 return nullptr; 429 const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); 430 431 OutputBuffer OB; 432 if (!initializeOutputBuffer(Buf, N, OB, 128)) 433 return nullptr; 434 435 KeepGoingLocalFunction: 436 while (true) { 437 if (Name->getKind() == Node::KAbiTagAttr) { 438 Name = static_cast<const AbiTagAttr *>(Name)->Base; 439 continue; 440 } 441 if (Name->getKind() == Node::KNameWithTemplateArgs) { 442 Name = static_cast<const NameWithTemplateArgs *>(Name)->Name; 443 continue; 444 } 445 break; 446 } 447 448 switch (Name->getKind()) { 449 case Node::KStdQualifiedName: 450 OB += "std"; 451 break; 452 case Node::KNestedName: 453 static_cast<const NestedName *>(Name)->Qual->print(OB); 454 break; 455 case Node::KLocalName: { 456 auto *LN = static_cast<const LocalName *>(Name); 457 LN->Encoding->print(OB); 458 OB += "::"; 459 Name = LN->Entity; 460 goto KeepGoingLocalFunction; 461 } 462 default: 463 break; 464 } 465 OB += '\0'; 466 if (N != nullptr) 467 *N = OB.getCurrentPosition(); 468 return OB.getBuffer(); 469 } 470 471 char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { 472 if (!isFunction()) 473 return nullptr; 474 auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName(); 475 return printNode(Name, Buf, N); 476 } 477 478 char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, 479 size_t *N) const { 480 if (!isFunction()) 481 return nullptr; 482 NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); 483 484 OutputBuffer OB; 485 if (!initializeOutputBuffer(Buf, N, OB, 128)) 486 return nullptr; 487 488 OB += '('; 489 Params.printWithComma(OB); 490 OB += ')'; 491 OB += '\0'; 492 if (N != nullptr) 493 *N = OB.getCurrentPosition(); 494 return OB.getBuffer(); 495 } 496 497 char *ItaniumPartialDemangler::getFunctionReturnType( 498 char *Buf, size_t *N) const { 499 if (!isFunction()) 500 return nullptr; 501 502 OutputBuffer OB; 503 if (!initializeOutputBuffer(Buf, N, OB, 128)) 504 return nullptr; 505 506 if (const Node *Ret = 507 static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) 508 Ret->print(OB); 509 510 OB += '\0'; 511 if (N != nullptr) 512 *N = OB.getCurrentPosition(); 513 return OB.getBuffer(); 514 } 515 516 char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { 517 assert(RootNode != nullptr && "must call partialDemangle()"); 518 return printNode(static_cast<Node *>(RootNode), Buf, N); 519 } 520 521 bool ItaniumPartialDemangler::hasFunctionQualifiers() const { 522 assert(RootNode != nullptr && "must call partialDemangle()"); 523 if (!isFunction()) 524 return false; 525 auto *E = static_cast<const FunctionEncoding *>(RootNode); 526 return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone; 527 } 528 529 bool ItaniumPartialDemangler::isCtorOrDtor() const { 530 const Node *N = static_cast<const Node *>(RootNode); 531 while (N) { 532 switch (N->getKind()) { 533 default: 534 return false; 535 case Node::KCtorDtorName: 536 return true; 537 538 case Node::KAbiTagAttr: 539 N = static_cast<const AbiTagAttr *>(N)->Base; 540 break; 541 case Node::KFunctionEncoding: 542 N = static_cast<const FunctionEncoding *>(N)->getName(); 543 break; 544 case Node::KLocalName: 545 N = static_cast<const LocalName *>(N)->Entity; 546 break; 547 case Node::KNameWithTemplateArgs: 548 N = static_cast<const NameWithTemplateArgs *>(N)->Name; 549 break; 550 case Node::KNestedName: 551 N = static_cast<const NestedName *>(N)->Name; 552 break; 553 case Node::KStdQualifiedName: 554 N = static_cast<const StdQualifiedName *>(N)->Child; 555 break; 556 } 557 } 558 return false; 559 } 560 561 bool ItaniumPartialDemangler::isFunction() const { 562 assert(RootNode != nullptr && "must call partialDemangle()"); 563 return static_cast<const Node *>(RootNode)->getKind() == 564 Node::KFunctionEncoding; 565 } 566 567 bool ItaniumPartialDemangler::isSpecialName() const { 568 assert(RootNode != nullptr && "must call partialDemangle()"); 569 auto K = static_cast<const Node *>(RootNode)->getKind(); 570 return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName; 571 } 572 573 bool ItaniumPartialDemangler::isData() const { 574 return !isFunction() && !isSpecialName(); 575 } 576