Path: blob/main/contrib/llvm-project/llvm/lib/Demangle/ItaniumDemangle.cpp
35233 views
//===------------------------- ItaniumDemangle.cpp ------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78// FIXME: (possibly) incomplete list of features that clang mangles that this9// file does not yet support:10// - C++ modules TS1112#include "llvm/Demangle/Demangle.h"13#include "llvm/Demangle/ItaniumDemangle.h"1415#include <cassert>16#include <cctype>17#include <cstdio>18#include <cstdlib>19#include <cstring>20#include <exception>21#include <functional>22#include <utility>2324using namespace llvm;25using namespace llvm::itanium_demangle;2627constexpr const char *itanium_demangle::FloatData<float>::spec;28constexpr const char *itanium_demangle::FloatData<double>::spec;29constexpr const char *itanium_demangle::FloatData<long double>::spec;3031// <discriminator> := _ <non-negative number> # when number < 1032// := __ <non-negative number> _ # when number >= 1033// extension := decimal-digit+ # at the end of string34const char *itanium_demangle::parse_discriminator(const char *first,35const char *last) {36// parse but ignore discriminator37if (first != last) {38if (*first == '_') {39const char *t1 = first + 1;40if (t1 != last) {41if (std::isdigit(*t1))42first = t1 + 1;43else if (*t1 == '_') {44for (++t1; t1 != last && std::isdigit(*t1); ++t1)45;46if (t1 != last && *t1 == '_')47first = t1 + 1;48}49}50} else if (std::isdigit(*first)) {51const char *t1 = first + 1;52for (; t1 != last && std::isdigit(*t1); ++t1)53;54if (t1 == last)55first = last;56}57}58return first;59}6061#ifndef NDEBUG62namespace {63struct DumpVisitor {64unsigned Depth = 0;65bool PendingNewline = false;6667template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {68return true;69}70static bool wantsNewline(NodeArray A) { return !A.empty(); }71static constexpr bool wantsNewline(...) { return false; }7273template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {74for (bool B : {wantsNewline(Vs)...})75if (B)76return true;77return false;78}7980void printStr(const char *S) { fprintf(stderr, "%s", S); }81void print(std::string_view SV) {82fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.data());83}84void print(const Node *N) {85if (N)86N->visit(std::ref(*this));87else88printStr("<null>");89}90void print(NodeArray A) {91++Depth;92printStr("{");93bool First = true;94for (const Node *N : A) {95if (First)96print(N);97else98printWithComma(N);99First = false;100}101printStr("}");102--Depth;103}104105// Overload used when T is exactly 'bool', not merely convertible to 'bool'.106void print(bool B) { printStr(B ? "true" : "false"); }107108template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) {109fprintf(stderr, "%llu", (unsigned long long)N);110}111112template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) {113fprintf(stderr, "%lld", (long long)N);114}115116void print(ReferenceKind RK) {117switch (RK) {118case ReferenceKind::LValue:119return printStr("ReferenceKind::LValue");120case ReferenceKind::RValue:121return printStr("ReferenceKind::RValue");122}123}124void print(FunctionRefQual RQ) {125switch (RQ) {126case FunctionRefQual::FrefQualNone:127return printStr("FunctionRefQual::FrefQualNone");128case FunctionRefQual::FrefQualLValue:129return printStr("FunctionRefQual::FrefQualLValue");130case FunctionRefQual::FrefQualRValue:131return printStr("FunctionRefQual::FrefQualRValue");132}133}134void print(Qualifiers Qs) {135if (!Qs) return printStr("QualNone");136struct QualName { Qualifiers Q; const char *Name; } Names[] = {137{QualConst, "QualConst"},138{QualVolatile, "QualVolatile"},139{QualRestrict, "QualRestrict"},140};141for (QualName Name : Names) {142if (Qs & Name.Q) {143printStr(Name.Name);144Qs = Qualifiers(Qs & ~Name.Q);145if (Qs) printStr(" | ");146}147}148}149void print(SpecialSubKind SSK) {150switch (SSK) {151case SpecialSubKind::allocator:152return printStr("SpecialSubKind::allocator");153case SpecialSubKind::basic_string:154return printStr("SpecialSubKind::basic_string");155case SpecialSubKind::string:156return printStr("SpecialSubKind::string");157case SpecialSubKind::istream:158return printStr("SpecialSubKind::istream");159case SpecialSubKind::ostream:160return printStr("SpecialSubKind::ostream");161case SpecialSubKind::iostream:162return printStr("SpecialSubKind::iostream");163}164}165void print(TemplateParamKind TPK) {166switch (TPK) {167case TemplateParamKind::Type:168return printStr("TemplateParamKind::Type");169case TemplateParamKind::NonType:170return printStr("TemplateParamKind::NonType");171case TemplateParamKind::Template:172return printStr("TemplateParamKind::Template");173}174}175void print(Node::Prec P) {176switch (P) {177case Node::Prec::Primary:178return printStr("Node::Prec::Primary");179case Node::Prec::Postfix:180return printStr("Node::Prec::Postfix");181case Node::Prec::Unary:182return printStr("Node::Prec::Unary");183case Node::Prec::Cast:184return printStr("Node::Prec::Cast");185case Node::Prec::PtrMem:186return printStr("Node::Prec::PtrMem");187case Node::Prec::Multiplicative:188return printStr("Node::Prec::Multiplicative");189case Node::Prec::Additive:190return printStr("Node::Prec::Additive");191case Node::Prec::Shift:192return printStr("Node::Prec::Shift");193case Node::Prec::Spaceship:194return printStr("Node::Prec::Spaceship");195case Node::Prec::Relational:196return printStr("Node::Prec::Relational");197case Node::Prec::Equality:198return printStr("Node::Prec::Equality");199case Node::Prec::And:200return printStr("Node::Prec::And");201case Node::Prec::Xor:202return printStr("Node::Prec::Xor");203case Node::Prec::Ior:204return printStr("Node::Prec::Ior");205case Node::Prec::AndIf:206return printStr("Node::Prec::AndIf");207case Node::Prec::OrIf:208return printStr("Node::Prec::OrIf");209case Node::Prec::Conditional:210return printStr("Node::Prec::Conditional");211case Node::Prec::Assign:212return printStr("Node::Prec::Assign");213case Node::Prec::Comma:214return printStr("Node::Prec::Comma");215case Node::Prec::Default:216return printStr("Node::Prec::Default");217}218}219220void newLine() {221printStr("\n");222for (unsigned I = 0; I != Depth; ++I)223printStr(" ");224PendingNewline = false;225}226227template<typename T> void printWithPendingNewline(T V) {228print(V);229if (wantsNewline(V))230PendingNewline = true;231}232233template<typename T> void printWithComma(T V) {234if (PendingNewline || wantsNewline(V)) {235printStr(",");236newLine();237} else {238printStr(", ");239}240241printWithPendingNewline(V);242}243244struct CtorArgPrinter {245DumpVisitor &Visitor;246247template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {248if (Visitor.anyWantNewline(V, Vs...))249Visitor.newLine();250Visitor.printWithPendingNewline(V);251int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };252(void)PrintInOrder;253}254};255256template<typename NodeT> void operator()(const NodeT *Node) {257Depth += 2;258fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());259Node->match(CtorArgPrinter{*this});260fprintf(stderr, ")");261Depth -= 2;262}263264void operator()(const ForwardTemplateReference *Node) {265Depth += 2;266fprintf(stderr, "ForwardTemplateReference(");267if (Node->Ref && !Node->Printing) {268Node->Printing = true;269CtorArgPrinter{*this}(Node->Ref);270Node->Printing = false;271} else {272CtorArgPrinter{*this}(Node->Index);273}274fprintf(stderr, ")");275Depth -= 2;276}277};278}279280void itanium_demangle::Node::dump() const {281DumpVisitor V;282visit(std::ref(V));283V.newLine();284}285#endif286287namespace {288class BumpPointerAllocator {289struct BlockMeta {290BlockMeta* Next;291size_t Current;292};293294static constexpr size_t AllocSize = 4096;295static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);296297alignas(long double) char InitialBuffer[AllocSize];298BlockMeta* BlockList = nullptr;299300void grow() {301char* NewMeta = static_cast<char *>(std::malloc(AllocSize));302if (NewMeta == nullptr)303std::terminate();304BlockList = new (NewMeta) BlockMeta{BlockList, 0};305}306307void* allocateMassive(size_t NBytes) {308NBytes += sizeof(BlockMeta);309BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));310if (NewMeta == nullptr)311std::terminate();312BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};313return static_cast<void*>(NewMeta + 1);314}315316public:317BumpPointerAllocator()318: BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}319320void* allocate(size_t N) {321N = (N + 15u) & ~15u;322if (N + BlockList->Current >= UsableAllocSize) {323if (N > UsableAllocSize)324return allocateMassive(N);325grow();326}327BlockList->Current += N;328return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +329BlockList->Current - N);330}331332void reset() {333while (BlockList) {334BlockMeta* Tmp = BlockList;335BlockList = BlockList->Next;336if (reinterpret_cast<char*>(Tmp) != InitialBuffer)337std::free(Tmp);338}339BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};340}341342~BumpPointerAllocator() { reset(); }343};344345class DefaultAllocator {346BumpPointerAllocator Alloc;347348public:349void reset() { Alloc.reset(); }350351template<typename T, typename ...Args> T *makeNode(Args &&...args) {352return new (Alloc.allocate(sizeof(T)))353T(std::forward<Args>(args)...);354}355356void *allocateNodeArray(size_t sz) {357return Alloc.allocate(sizeof(Node *) * sz);358}359};360} // unnamed namespace361362//===----------------------------------------------------------------------===//363// Code beyond this point should not be synchronized with libc++abi.364//===----------------------------------------------------------------------===//365366using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;367368char *llvm::itaniumDemangle(std::string_view MangledName, bool ParseParams) {369if (MangledName.empty())370return nullptr;371372Demangler Parser(MangledName.data(),373MangledName.data() + MangledName.length());374Node *AST = Parser.parse(ParseParams);375if (!AST)376return nullptr;377378OutputBuffer OB;379assert(Parser.ForwardTemplateRefs.empty());380AST->print(OB);381OB += '\0';382return OB.getBuffer();383}384385ItaniumPartialDemangler::ItaniumPartialDemangler()386: RootNode(nullptr), Context(new Demangler{nullptr, nullptr}) {}387388ItaniumPartialDemangler::~ItaniumPartialDemangler() {389delete static_cast<Demangler *>(Context);390}391392ItaniumPartialDemangler::ItaniumPartialDemangler(393ItaniumPartialDemangler &&Other)394: RootNode(Other.RootNode), Context(Other.Context) {395Other.Context = Other.RootNode = nullptr;396}397398ItaniumPartialDemangler &ItaniumPartialDemangler::399operator=(ItaniumPartialDemangler &&Other) {400std::swap(RootNode, Other.RootNode);401std::swap(Context, Other.Context);402return *this;403}404405// Demangle MangledName into an AST, storing it into this->RootNode.406bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {407Demangler *Parser = static_cast<Demangler *>(Context);408size_t Len = std::strlen(MangledName);409Parser->reset(MangledName, MangledName + Len);410RootNode = Parser->parse();411return RootNode == nullptr;412}413414static char *printNode(const Node *RootNode, char *Buf, size_t *N) {415OutputBuffer OB(Buf, N);416RootNode->print(OB);417OB += '\0';418if (N != nullptr)419*N = OB.getCurrentPosition();420return OB.getBuffer();421}422423char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {424if (!isFunction())425return nullptr;426427const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();428429while (true) {430switch (Name->getKind()) {431case Node::KAbiTagAttr:432Name = static_cast<const AbiTagAttr *>(Name)->Base;433continue;434case Node::KModuleEntity:435Name = static_cast<const ModuleEntity *>(Name)->Name;436continue;437case Node::KNestedName:438Name = static_cast<const NestedName *>(Name)->Name;439continue;440case Node::KLocalName:441Name = static_cast<const LocalName *>(Name)->Entity;442continue;443case Node::KNameWithTemplateArgs:444Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;445continue;446default:447return printNode(Name, Buf, N);448}449}450}451452char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,453size_t *N) const {454if (!isFunction())455return nullptr;456const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();457458OutputBuffer OB(Buf, N);459460KeepGoingLocalFunction:461while (true) {462if (Name->getKind() == Node::KAbiTagAttr) {463Name = static_cast<const AbiTagAttr *>(Name)->Base;464continue;465}466if (Name->getKind() == Node::KNameWithTemplateArgs) {467Name = static_cast<const NameWithTemplateArgs *>(Name)->Name;468continue;469}470break;471}472473if (Name->getKind() == Node::KModuleEntity)474Name = static_cast<const ModuleEntity *>(Name)->Name;475476switch (Name->getKind()) {477case Node::KNestedName:478static_cast<const NestedName *>(Name)->Qual->print(OB);479break;480case Node::KLocalName: {481auto *LN = static_cast<const LocalName *>(Name);482LN->Encoding->print(OB);483OB += "::";484Name = LN->Entity;485goto KeepGoingLocalFunction;486}487default:488break;489}490OB += '\0';491if (N != nullptr)492*N = OB.getCurrentPosition();493return OB.getBuffer();494}495496char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {497if (!isFunction())498return nullptr;499auto *Name = static_cast<FunctionEncoding *>(RootNode)->getName();500return printNode(Name, Buf, N);501}502503char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,504size_t *N) const {505if (!isFunction())506return nullptr;507NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();508509OutputBuffer OB(Buf, N);510511OB += '(';512Params.printWithComma(OB);513OB += ')';514OB += '\0';515if (N != nullptr)516*N = OB.getCurrentPosition();517return OB.getBuffer();518}519520char *ItaniumPartialDemangler::getFunctionReturnType(521char *Buf, size_t *N) const {522if (!isFunction())523return nullptr;524525OutputBuffer OB(Buf, N);526527if (const Node *Ret =528static_cast<const FunctionEncoding *>(RootNode)->getReturnType())529Ret->print(OB);530531OB += '\0';532if (N != nullptr)533*N = OB.getCurrentPosition();534return OB.getBuffer();535}536537char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {538assert(RootNode != nullptr && "must call partialDemangle()");539return printNode(static_cast<Node *>(RootNode), Buf, N);540}541542bool ItaniumPartialDemangler::hasFunctionQualifiers() const {543assert(RootNode != nullptr && "must call partialDemangle()");544if (!isFunction())545return false;546auto *E = static_cast<const FunctionEncoding *>(RootNode);547return E->getCVQuals() != QualNone || E->getRefQual() != FrefQualNone;548}549550bool ItaniumPartialDemangler::isCtorOrDtor() const {551const Node *N = static_cast<const Node *>(RootNode);552while (N) {553switch (N->getKind()) {554default:555return false;556case Node::KCtorDtorName:557return true;558559case Node::KAbiTagAttr:560N = static_cast<const AbiTagAttr *>(N)->Base;561break;562case Node::KFunctionEncoding:563N = static_cast<const FunctionEncoding *>(N)->getName();564break;565case Node::KLocalName:566N = static_cast<const LocalName *>(N)->Entity;567break;568case Node::KNameWithTemplateArgs:569N = static_cast<const NameWithTemplateArgs *>(N)->Name;570break;571case Node::KNestedName:572N = static_cast<const NestedName *>(N)->Name;573break;574case Node::KModuleEntity:575N = static_cast<const ModuleEntity *>(N)->Name;576break;577}578}579return false;580}581582bool ItaniumPartialDemangler::isFunction() const {583assert(RootNode != nullptr && "must call partialDemangle()");584return static_cast<const Node *>(RootNode)->getKind() ==585Node::KFunctionEncoding;586}587588bool ItaniumPartialDemangler::isSpecialName() const {589assert(RootNode != nullptr && "must call partialDemangle()");590auto K = static_cast<const Node *>(RootNode)->getKind();591return K == Node::KSpecialName || K == Node::KCtorVtableSpecialName;592}593594bool ItaniumPartialDemangler::isData() const {595return !isFunction() && !isSpecialName();596}597598599