brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.3 KiB · 4756d83 Raw
409 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9// FIXME: (possibly) incomplete list of features that clang mangles that this10// file does not yet support:11//   - C++ modules TS12 13#include "abort_message.h"14#define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)15 16#include "demangle/DemangleConfig.h"17#include "demangle/ItaniumDemangle.h"18#include "__cxxabi_config.h"19#include <cctype>20#include <cstdio>21#include <cstdlib>22#include <cstring>23#include <exception>24#include <functional>25#include <numeric>26#include <string_view>27#include <utility>28 29using namespace itanium_demangle;30 31// <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,35                                                  const char *last) {36  // parse but ignore discriminator37  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 NDEBUG62namespace {63struct 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(std::string_view 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    else88      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      else98        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>109  typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {110    fprintf(stderr, "%llu", (unsigned long long)N);111  }112 113  template <class T>114  typename std::enable_if<std::is_signed<T>::value>::type print(T N) {115    fprintf(stderr, "%lld", (long long)N);116  }117 118  void print(ReferenceKind RK) {119    switch (RK) {120    case ReferenceKind::LValue:121      return printStr("ReferenceKind::LValue");122    case ReferenceKind::RValue:123      return printStr("ReferenceKind::RValue");124    }125  }126  void print(FunctionRefQual RQ) {127    switch (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");134    }135  }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"},142    };143    for (QualName Name : Names) {144      if (Qs & Name.Q) {145        printStr(Name.Name);146        Qs = Qualifiers(Qs & ~Name.Q);147        if (Qs) printStr(" | ");148      }149    }150  }151  void print(SpecialSubKind SSK) {152    switch (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");165    }166  }167  void print(TemplateParamKind TPK) {168    switch (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");175    }176  }177  void print(Node::Prec P) {178    switch (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");219    }220  }221 222  void newLine() {223    printStr("\n");224    for (unsigned I = 0; I != Depth; ++I)225      printStr(" ");226    PendingNewline = false;227  }228 229  template<typename T> void printWithPendingNewline(T V) {230    print(V);231    if (wantsNewline(V))232      PendingNewline = true;233  }234 235  template<typename T> void printWithComma(T V) {236    if (PendingNewline || wantsNewline(V)) {237      printStr(",");238      newLine();239    } else {240      printStr(", ");241    }242 243    printWithPendingNewline(V);244  }245 246  struct CtorArgPrinter {247    DumpVisitor &Visitor;248 249    template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {250      if (Visitor.anyWantNewline(V, Vs...))251        Visitor.newLine();252      Visitor.printWithPendingNewline(V);253      int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };254      (void)PrintInOrder;255    }256  };257 258  template<typename NodeT> void operator()(const NodeT *Node) {259    Depth += 2;260    fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());261    Node->match(CtorArgPrinter{*this});262    fprintf(stderr, ")");263    Depth -= 2;264  }265 266  void operator()(const ForwardTemplateReference *Node) {267    Depth += 2;268    fprintf(stderr, "ForwardTemplateReference(");269    if (Node->Ref && !Node->Printing) {270      Node->Printing = true;271      CtorArgPrinter{*this}(Node->Ref);272      Node->Printing = false;273    } else {274      CtorArgPrinter{*this}(Node->Index);275    }276    fprintf(stderr, ")");277    Depth -= 2;278  }279};280}281 282void itanium_demangle::Node::dump() const {283  DumpVisitor V;284  visit(std::ref(V));285  V.newLine();286}287#endif288 289namespace {290class BumpPointerAllocator {291  struct BlockMeta {292    BlockMeta* Next;293    size_t Current;294  };295 296  static constexpr size_t AllocSize = 4096;297  static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);298 299  alignas(long double) char InitialBuffer[AllocSize];300  BlockMeta* BlockList = nullptr;301 302  void grow() {303    char* NewMeta = static_cast<char *>(std::malloc(AllocSize));304    if (NewMeta == nullptr)305      std::terminate();306    BlockList = new (NewMeta) BlockMeta{BlockList, 0};307  }308 309  void* allocateMassive(size_t NBytes) {310    NBytes += sizeof(BlockMeta);311    BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));312    if (NewMeta == nullptr)313      std::terminate();314    BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};315    return static_cast<void*>(NewMeta + 1);316  }317 318public:319  BumpPointerAllocator()320      : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}321 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);327      grow();328    }329    BlockList->Current += N;330    return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +331                              BlockList->Current - N);332  }333 334  void reset() {335    while (BlockList) {336      BlockMeta* Tmp = BlockList;337      BlockList = BlockList->Next;338      if (reinterpret_cast<char*>(Tmp) != InitialBuffer)339        std::free(Tmp);340    }341    BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};342  }343 344  ~BumpPointerAllocator() { reset(); }345};346 347class DefaultAllocator {348  BumpPointerAllocator Alloc;349 350public:351  void reset() { Alloc.reset(); }352 353  template<typename T, typename ...Args> T *makeNode(Args &&...args) {354    return new (Alloc.allocate(sizeof(T)))355        T(std::forward<Args>(args)...);356  }357 358  void *allocateNodeArray(size_t sz) {359    return Alloc.allocate(sizeof(Node *) * sz);360  }361};362}  // unnamed namespace363 364//===----------------------------------------------------------------------===//365// Code beyond this point should not be synchronized with LLVM.366//===----------------------------------------------------------------------===//367 368using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;369 370namespace {371enum : int {372  demangle_invalid_args = -3,373  demangle_invalid_mangled_name = -2,374  demangle_memory_alloc_failure = -1,375  demangle_success = 0,376};377}378 379namespace __cxxabiv1 {380extern "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)) {383    if (Status)384      *Status = demangle_invalid_args;385    return nullptr;386  }387 388  int InternalStatus = demangle_success;389  Demangler Parser(MangledName, MangledName + std::strlen(MangledName));390  Node *AST = Parser.parse();391 392  if (AST == nullptr)393    InternalStatus = demangle_invalid_mangled_name;394  else {395    OutputBuffer O(Buf, N);396    DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), "");397    AST->print(O);398    O += '\0';399    if (N != nullptr)400      *N = O.getCurrentPosition();401    Buf = O.getBuffer();402  }403 404  if (Status)405    *Status = InternalStatus;406  return InternalStatus == demangle_success ? Buf : nullptr;407}408}  // __cxxabiv1409