Path: blob/main/system/lib/libcxxabi/src/cxa_demangle.cpp
6173 views
//===----------------------------------------------------------------------===//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 "abort_message.h"13#define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)1415#include "demangle/DemangleConfig.h"16#include "demangle/ItaniumDemangle.h"17#include "__cxxabi_config.h"18#include <cctype>19#include <cstdio>20#include <cstdlib>21#include <cstring>22#include <exception>23#include <functional>24#include <numeric>25#include <string_view>26#include <utility>2728using namespace itanium_demangle;2930// <discriminator> := _ <non-negative number> # when number < 1031// := __ <non-negative number> _ # when number >= 1032// extension := decimal-digit+ # at the end of string33const char *itanium_demangle::parse_discriminator(const char *first,34const char *last) {35// parse but ignore discriminator36if (first != last) {37if (*first == '_') {38const char *t1 = first + 1;39if (t1 != last) {40if (std::isdigit(*t1))41first = t1 + 1;42else if (*t1 == '_') {43for (++t1; t1 != last && std::isdigit(*t1); ++t1)44;45if (t1 != last && *t1 == '_')46first = t1 + 1;47}48}49} else if (std::isdigit(*first)) {50const char *t1 = first + 1;51for (; t1 != last && std::isdigit(*t1); ++t1)52;53if (t1 == last)54first = last;55}56}57return first;58}5960#ifndef NDEBUG61namespace {62struct DumpVisitor {63unsigned Depth = 0;64bool PendingNewline = false;6566template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {67return true;68}69static bool wantsNewline(NodeArray A) { return !A.empty(); }70static constexpr bool wantsNewline(...) { return false; }7172template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {73for (bool B : {wantsNewline(Vs)...})74if (B)75return true;76return false;77}7879void printStr(const char *S) { fprintf(stderr, "%s", S); }80void print(std::string_view SV) {81fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin());82}83void print(const Node *N) {84if (N)85N->visit(std::ref(*this));86else87printStr("<null>");88}89void print(NodeArray A) {90++Depth;91printStr("{");92bool First = true;93for (const Node *N : A) {94if (First)95print(N);96else97printWithComma(N);98First = false;99}100printStr("}");101--Depth;102}103104// Overload used when T is exactly 'bool', not merely convertible to 'bool'.105void print(bool B) { printStr(B ? "true" : "false"); }106107template <class T>108typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {109fprintf(stderr, "%llu", (unsigned long long)N);110}111112template <class T>113typename std::enable_if<std::is_signed<T>::value>::type print(T N) {114fprintf(stderr, "%lld", (long long)N);115}116117void print(ReferenceKind RK) {118switch (RK) {119case ReferenceKind::LValue:120return printStr("ReferenceKind::LValue");121case ReferenceKind::RValue:122return printStr("ReferenceKind::RValue");123}124}125void print(FunctionRefQual RQ) {126switch (RQ) {127case FunctionRefQual::FrefQualNone:128return printStr("FunctionRefQual::FrefQualNone");129case FunctionRefQual::FrefQualLValue:130return printStr("FunctionRefQual::FrefQualLValue");131case FunctionRefQual::FrefQualRValue:132return printStr("FunctionRefQual::FrefQualRValue");133}134}135void print(Qualifiers Qs) {136if (!Qs) return printStr("QualNone");137struct QualName { Qualifiers Q; const char *Name; } Names[] = {138{QualConst, "QualConst"},139{QualVolatile, "QualVolatile"},140{QualRestrict, "QualRestrict"},141};142for (QualName Name : Names) {143if (Qs & Name.Q) {144printStr(Name.Name);145Qs = Qualifiers(Qs & ~Name.Q);146if (Qs) printStr(" | ");147}148}149}150void print(SpecialSubKind SSK) {151switch (SSK) {152case SpecialSubKind::allocator:153return printStr("SpecialSubKind::allocator");154case SpecialSubKind::basic_string:155return printStr("SpecialSubKind::basic_string");156case SpecialSubKind::string:157return printStr("SpecialSubKind::string");158case SpecialSubKind::istream:159return printStr("SpecialSubKind::istream");160case SpecialSubKind::ostream:161return printStr("SpecialSubKind::ostream");162case SpecialSubKind::iostream:163return printStr("SpecialSubKind::iostream");164}165}166void print(TemplateParamKind TPK) {167switch (TPK) {168case TemplateParamKind::Type:169return printStr("TemplateParamKind::Type");170case TemplateParamKind::NonType:171return printStr("TemplateParamKind::NonType");172case TemplateParamKind::Template:173return printStr("TemplateParamKind::Template");174}175}176void print(Node::Prec P) {177switch (P) {178case Node::Prec::Primary:179return printStr("Node::Prec::Primary");180case Node::Prec::Postfix:181return printStr("Node::Prec::Postfix");182case Node::Prec::Unary:183return printStr("Node::Prec::Unary");184case Node::Prec::Cast:185return printStr("Node::Prec::Cast");186case Node::Prec::PtrMem:187return printStr("Node::Prec::PtrMem");188case Node::Prec::Multiplicative:189return printStr("Node::Prec::Multiplicative");190case Node::Prec::Additive:191return printStr("Node::Prec::Additive");192case Node::Prec::Shift:193return printStr("Node::Prec::Shift");194case Node::Prec::Spaceship:195return printStr("Node::Prec::Spaceship");196case Node::Prec::Relational:197return printStr("Node::Prec::Relational");198case Node::Prec::Equality:199return printStr("Node::Prec::Equality");200case Node::Prec::And:201return printStr("Node::Prec::And");202case Node::Prec::Xor:203return printStr("Node::Prec::Xor");204case Node::Prec::Ior:205return printStr("Node::Prec::Ior");206case Node::Prec::AndIf:207return printStr("Node::Prec::AndIf");208case Node::Prec::OrIf:209return printStr("Node::Prec::OrIf");210case Node::Prec::Conditional:211return printStr("Node::Prec::Conditional");212case Node::Prec::Assign:213return printStr("Node::Prec::Assign");214case Node::Prec::Comma:215return printStr("Node::Prec::Comma");216case Node::Prec::Default:217return printStr("Node::Prec::Default");218}219}220221void newLine() {222printStr("\n");223for (unsigned I = 0; I != Depth; ++I)224printStr(" ");225PendingNewline = false;226}227228template<typename T> void printWithPendingNewline(T V) {229print(V);230if (wantsNewline(V))231PendingNewline = true;232}233234template<typename T> void printWithComma(T V) {235if (PendingNewline || wantsNewline(V)) {236printStr(",");237newLine();238} else {239printStr(", ");240}241242printWithPendingNewline(V);243}244245struct CtorArgPrinter {246DumpVisitor &Visitor;247248template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {249if (Visitor.anyWantNewline(V, Vs...))250Visitor.newLine();251Visitor.printWithPendingNewline(V);252int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };253(void)PrintInOrder;254}255};256257template<typename NodeT> void operator()(const NodeT *Node) {258Depth += 2;259fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());260Node->match(CtorArgPrinter{*this});261fprintf(stderr, ")");262Depth -= 2;263}264265void operator()(const ForwardTemplateReference *Node) {266Depth += 2;267fprintf(stderr, "ForwardTemplateReference(");268if (Node->Ref && !Node->Printing) {269Node->Printing = true;270CtorArgPrinter{*this}(Node->Ref);271Node->Printing = false;272} else {273CtorArgPrinter{*this}(Node->Index);274}275fprintf(stderr, ")");276Depth -= 2;277}278};279}280281void itanium_demangle::Node::dump() const {282DumpVisitor V;283visit(std::ref(V));284V.newLine();285}286#endif287288namespace {289class BumpPointerAllocator {290struct BlockMeta {291BlockMeta* Next;292size_t Current;293};294295static constexpr size_t AllocSize = 4096;296static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);297298alignas(long double) char InitialBuffer[AllocSize];299BlockMeta* BlockList = nullptr;300301void grow() {302char* NewMeta = static_cast<char *>(std::malloc(AllocSize));303if (NewMeta == nullptr)304std::terminate();305BlockList = new (NewMeta) BlockMeta{BlockList, 0};306}307308void* allocateMassive(size_t NBytes) {309NBytes += sizeof(BlockMeta);310BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));311if (NewMeta == nullptr)312std::terminate();313BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};314return static_cast<void*>(NewMeta + 1);315}316317public:318BumpPointerAllocator()319: BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}320321void* allocate(size_t N) {322N = (N + 15u) & ~15u;323if (N + BlockList->Current >= UsableAllocSize) {324if (N > UsableAllocSize)325return allocateMassive(N);326grow();327}328BlockList->Current += N;329return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +330BlockList->Current - N);331}332333void reset() {334while (BlockList) {335BlockMeta* Tmp = BlockList;336BlockList = BlockList->Next;337if (reinterpret_cast<char*>(Tmp) != InitialBuffer)338std::free(Tmp);339}340BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};341}342343~BumpPointerAllocator() { reset(); }344};345346class DefaultAllocator {347BumpPointerAllocator Alloc;348349public:350void reset() { Alloc.reset(); }351352template<typename T, typename ...Args> T *makeNode(Args &&...args) {353return new (Alloc.allocate(sizeof(T)))354T(std::forward<Args>(args)...);355}356357void *allocateNodeArray(size_t sz) {358return Alloc.allocate(sizeof(Node *) * sz);359}360};361} // unnamed namespace362363//===----------------------------------------------------------------------===//364// Code beyond this point should not be synchronized with LLVM.365//===----------------------------------------------------------------------===//366367using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;368369namespace {370enum : int {371demangle_invalid_args = -3,372demangle_invalid_mangled_name = -2,373demangle_memory_alloc_failure = -1,374demangle_success = 0,375};376}377378namespace __cxxabiv1 {379extern "C" _LIBCXXABI_FUNC_VIS char *380__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {381if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {382if (Status)383*Status = demangle_invalid_args;384return nullptr;385}386387int InternalStatus = demangle_success;388Demangler Parser(MangledName, MangledName + std::strlen(MangledName));389Node *AST = Parser.parse();390391if (AST == nullptr)392InternalStatus = demangle_invalid_mangled_name;393else {394OutputBuffer O(Buf, N);395DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), "");396AST->print(O);397O += '\0';398if (N != nullptr)399*N = O.getCurrentPosition();400Buf = O.getBuffer();401}402403if (Status)404*Status = InternalStatus;405return InternalStatus == demangle_success ? Buf : nullptr;406}407} // __cxxabiv1408409410