180814287SRaphael Isemann //===-- RichManglingContext.cpp -------------------------------------------===//
2f1a98df6SStefan Granitz //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f1a98df6SStefan Granitz //
7f1a98df6SStefan Granitz //===----------------------------------------------------------------------===//
8f1a98df6SStefan Granitz 
9f1a98df6SStefan Granitz #include "lldb/Core/RichManglingContext.h"
10f1a98df6SStefan Granitz #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
11c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
12f1a98df6SStefan Granitz 
13f1a98df6SStefan Granitz #include "llvm/ADT/StringRef.h"
14f1a98df6SStefan Granitz 
15f1a98df6SStefan Granitz using namespace lldb;
16f1a98df6SStefan Granitz using namespace lldb_private;
17f1a98df6SStefan Granitz 
18f1a98df6SStefan Granitz // RichManglingContext
~RichManglingContext()19eb5e11f4SJordan Rupprecht RichManglingContext::~RichManglingContext() {
20eb5e11f4SJordan Rupprecht   std::free(m_ipd_buf);
21eb5e11f4SJordan Rupprecht   ResetCxxMethodParser();
22eb5e11f4SJordan Rupprecht }
23eb5e11f4SJordan Rupprecht 
ResetCxxMethodParser()24eb5e11f4SJordan Rupprecht void RichManglingContext::ResetCxxMethodParser() {
25f1a98df6SStefan Granitz   // If we want to support parsers for other languages some day, we need a
26f1a98df6SStefan Granitz   // switch here to delete the correct parser type.
27f1a98df6SStefan Granitz   if (m_cxx_method_parser.hasValue()) {
28f1a98df6SStefan Granitz     assert(m_provider == PluginCxxLanguage);
29f1a98df6SStefan Granitz     delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
30f1a98df6SStefan Granitz     m_cxx_method_parser.reset();
31f1a98df6SStefan Granitz   }
32eb5e11f4SJordan Rupprecht }
33eb5e11f4SJordan Rupprecht 
ResetProvider(InfoProvider new_provider)34eb5e11f4SJordan Rupprecht void RichManglingContext::ResetProvider(InfoProvider new_provider) {
35eb5e11f4SJordan Rupprecht   ResetCxxMethodParser();
36f1a98df6SStefan Granitz 
37f1a98df6SStefan Granitz   assert(new_provider != None && "Only reset to a valid provider");
38f1a98df6SStefan Granitz   m_provider = new_provider;
39f1a98df6SStefan Granitz }
40f1a98df6SStefan Granitz 
FromItaniumName(ConstString mangled)410e4c4821SAdrian Prantl bool RichManglingContext::FromItaniumName(ConstString mangled) {
42f1a98df6SStefan Granitz   bool err = m_ipd.partialDemangle(mangled.GetCString());
43f1a98df6SStefan Granitz   if (!err) {
44f1a98df6SStefan Granitz     ResetProvider(ItaniumPartialDemangler);
45f1a98df6SStefan Granitz   }
46f1a98df6SStefan Granitz 
47a007a6d8SPavel Labath   if (Log *log = GetLog(LLDBLog::Demangle)) {
48f1a98df6SStefan Granitz     if (!err) {
49f1a98df6SStefan Granitz       ParseFullName();
50f1a98df6SStefan Granitz       LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
51f1a98df6SStefan Granitz     } else {
52f1a98df6SStefan Granitz       LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
53f1a98df6SStefan Granitz                mangled);
54f1a98df6SStefan Granitz     }
55f1a98df6SStefan Granitz   }
56f1a98df6SStefan Granitz 
57f1a98df6SStefan Granitz   return !err; // true == success
58f1a98df6SStefan Granitz }
59f1a98df6SStefan Granitz 
FromCxxMethodName(ConstString demangled)600e4c4821SAdrian Prantl bool RichManglingContext::FromCxxMethodName(ConstString demangled) {
61f1a98df6SStefan Granitz   ResetProvider(PluginCxxLanguage);
62f1a98df6SStefan Granitz   m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
63f1a98df6SStefan Granitz   return true;
64f1a98df6SStefan Granitz }
65f1a98df6SStefan Granitz 
IsCtorOrDtor() const66f1a98df6SStefan Granitz bool RichManglingContext::IsCtorOrDtor() const {
67f1a98df6SStefan Granitz   assert(m_provider != None && "Initialize a provider first");
68f1a98df6SStefan Granitz   switch (m_provider) {
69f1a98df6SStefan Granitz   case ItaniumPartialDemangler:
70f1a98df6SStefan Granitz     return m_ipd.isCtorOrDtor();
71f1a98df6SStefan Granitz   case PluginCxxLanguage: {
72f1a98df6SStefan Granitz     // We can only check for destructors here.
73f1a98df6SStefan Granitz     auto base_name =
74f1a98df6SStefan Granitz         get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
75f1a98df6SStefan Granitz     return base_name.startswith("~");
76f1a98df6SStefan Granitz   }
77f1a98df6SStefan Granitz   case None:
78f1a98df6SStefan Granitz     return false;
79f1a98df6SStefan Granitz   }
80d5fa57ebSPavel Labath   llvm_unreachable("Fully covered switch above!");
81f1a98df6SStefan Granitz }
82f1a98df6SStefan Granitz 
processIPDStrResult(char * ipd_res,size_t res_size)83fa52788bSJonas Devlieghere llvm::StringRef RichManglingContext::processIPDStrResult(char *ipd_res,
84fa52788bSJonas Devlieghere                                                          size_t res_size) {
85d0514164SStefan Granitz   // Error case: Clear the buffer.
86f1a98df6SStefan Granitz   if (LLVM_UNLIKELY(ipd_res == nullptr)) {
87f1a98df6SStefan Granitz     assert(res_size == m_ipd_buf_size &&
88f1a98df6SStefan Granitz            "Failed IPD queries keep the original size in the N parameter");
89f1a98df6SStefan Granitz 
90d0514164SStefan Granitz     m_ipd_buf[0] = '\0';
91fa52788bSJonas Devlieghere     return llvm::StringRef(m_ipd_buf, 0);
92d0514164SStefan Granitz   }
93d0514164SStefan Granitz 
94f1a98df6SStefan Granitz   // IPD's res_size includes null terminator.
95d0514164SStefan Granitz   assert(ipd_res[res_size - 1] == '\0' &&
96f1a98df6SStefan Granitz          "IPD returns null-terminated strings and we rely on that");
97f1a98df6SStefan Granitz 
98d0514164SStefan Granitz   // Update buffer/size on realloc.
99d0514164SStefan Granitz   if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) {
100f1a98df6SStefan Granitz     m_ipd_buf = ipd_res;       // std::realloc freed or reused the old buffer.
101d0514164SStefan Granitz     m_ipd_buf_size = res_size; // May actually be bigger, but we can't know.
102f1a98df6SStefan Granitz 
103a007a6d8SPavel Labath     if (Log *log = GetLog(LLDBLog::Demangle))
104d0514164SStefan Granitz       LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}",
105f1a98df6SStefan Granitz                m_ipd_buf_size);
106f1a98df6SStefan Granitz   }
107f1a98df6SStefan Granitz 
108d0514164SStefan Granitz   // 99% case: Just remember the string length.
109fa52788bSJonas Devlieghere   return llvm::StringRef(m_ipd_buf, res_size - 1);
110f1a98df6SStefan Granitz }
111f1a98df6SStefan Granitz 
ParseFunctionBaseName()112fa52788bSJonas Devlieghere llvm::StringRef RichManglingContext::ParseFunctionBaseName() {
113f1a98df6SStefan Granitz   assert(m_provider != None && "Initialize a provider first");
114f1a98df6SStefan Granitz   switch (m_provider) {
115f1a98df6SStefan Granitz   case ItaniumPartialDemangler: {
116f1a98df6SStefan Granitz     auto n = m_ipd_buf_size;
117f1a98df6SStefan Granitz     auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
118fa52788bSJonas Devlieghere     return processIPDStrResult(buf, n);
119f1a98df6SStefan Granitz   }
120f1a98df6SStefan Granitz   case PluginCxxLanguage:
121fa52788bSJonas Devlieghere     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
122fa52788bSJonas Devlieghere         ->GetBasename();
123f1a98df6SStefan Granitz   case None:
124fa52788bSJonas Devlieghere     return {};
125f1a98df6SStefan Granitz   }
126*f20f9f5aSDave Lee   llvm_unreachable("Fully covered switch above!");
127f1a98df6SStefan Granitz }
128f1a98df6SStefan Granitz 
ParseFunctionDeclContextName()129fa52788bSJonas Devlieghere llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() {
130f1a98df6SStefan Granitz   assert(m_provider != None && "Initialize a provider first");
131f1a98df6SStefan Granitz   switch (m_provider) {
132f1a98df6SStefan Granitz   case ItaniumPartialDemangler: {
133f1a98df6SStefan Granitz     auto n = m_ipd_buf_size;
134f1a98df6SStefan Granitz     auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
135fa52788bSJonas Devlieghere     return processIPDStrResult(buf, n);
136f1a98df6SStefan Granitz   }
137f1a98df6SStefan Granitz   case PluginCxxLanguage:
138fa52788bSJonas Devlieghere     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
139fa52788bSJonas Devlieghere         ->GetContext();
140f1a98df6SStefan Granitz   case None:
141fa52788bSJonas Devlieghere     return {};
142f1a98df6SStefan Granitz   }
143*f20f9f5aSDave Lee   llvm_unreachable("Fully covered switch above!");
144f1a98df6SStefan Granitz }
145f1a98df6SStefan Granitz 
ParseFullName()146fa52788bSJonas Devlieghere llvm::StringRef RichManglingContext::ParseFullName() {
147f1a98df6SStefan Granitz   assert(m_provider != None && "Initialize a provider first");
148f1a98df6SStefan Granitz   switch (m_provider) {
149f1a98df6SStefan Granitz   case ItaniumPartialDemangler: {
150f1a98df6SStefan Granitz     auto n = m_ipd_buf_size;
151f1a98df6SStefan Granitz     auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
152fa52788bSJonas Devlieghere     return processIPDStrResult(buf, n);
153f1a98df6SStefan Granitz   }
154f1a98df6SStefan Granitz   case PluginCxxLanguage:
155fa52788bSJonas Devlieghere     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
156f1a98df6SStefan Granitz         ->GetFullName()
157f1a98df6SStefan Granitz         .GetStringRef();
158f1a98df6SStefan Granitz   case None:
159fa52788bSJonas Devlieghere     return {};
160f1a98df6SStefan Granitz   }
161*f20f9f5aSDave Lee   llvm_unreachable("Fully covered switch above!");
162f1a98df6SStefan Granitz }
163