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