1//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
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#include "lldb/Core/Mangled.h"
10
11#include "lldb/Core/RichManglingContext.h"
12#include "lldb/Utility/ConstString.h"
13#include "lldb/Utility/Log.h"
14#include "lldb/Utility/Logging.h"
15#include "lldb/Utility/RegularExpression.h"
16#include "lldb/Utility/Stream.h"
17#include "lldb/Utility/Timer.h"
18#include "lldb/lldb-enumerations.h"
19
20#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
21#include "Plugins/Language/ObjC/ObjCLanguage.h"
22
23#include "llvm/ADT/StringRef.h"
24#include "llvm/Demangle/Demangle.h"
25#include "llvm/Support/Compiler.h"
26
27#include <mutex>
28#include <string>
29#include <utility>
30
31#include <stdlib.h>
32#include <string.h>
33using namespace lldb_private;
34
35static inline bool cstring_is_mangled(llvm::StringRef s) {
36  return Mangled::GetManglingScheme(s) != Mangled::eManglingSchemeNone;
37}
38
39static ConstString
40get_demangled_name_without_arguments(ConstString mangled,
41                                     ConstString demangled) {
42  // This pair is <mangled name, demangled name without function arguments>
43  static std::pair<ConstString, ConstString>
44      g_most_recent_mangled_to_name_sans_args;
45
46  // Need to have the mangled & demangled names we're currently examining as
47  // statics so we can return a const ref to them at the end of the func if we
48  // don't have anything better.
49  static ConstString g_last_mangled;
50  static ConstString g_last_demangled;
51
52  if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled) {
53    return g_most_recent_mangled_to_name_sans_args.second;
54  }
55
56  g_last_demangled = demangled;
57  g_last_mangled = mangled;
58
59  const char *mangled_name_cstr = mangled.GetCString();
60
61  if (demangled && mangled_name_cstr && mangled_name_cstr[0]) {
62    if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
63        (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure,
64                                        // typeinfo structure, and typeinfo
65                                        // mangled_name
66         mangled_name_cstr[2] != 'G' && // avoid guard variables
67         mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually
68                                       // handle eSymbolTypeData, we will want
69                                       // this back)
70    {
71      CPlusPlusLanguage::MethodName cxx_method(demangled);
72      if (!cxx_method.GetBasename().empty()) {
73        std::string shortname;
74        if (!cxx_method.GetContext().empty())
75          shortname = cxx_method.GetContext().str() + "::";
76        shortname += cxx_method.GetBasename().str();
77        ConstString result(shortname.c_str());
78        g_most_recent_mangled_to_name_sans_args.first = mangled;
79        g_most_recent_mangled_to_name_sans_args.second = result;
80        return g_most_recent_mangled_to_name_sans_args.second;
81      }
82    }
83  }
84
85  if (demangled)
86    return g_last_demangled;
87  return g_last_mangled;
88}
89
90#pragma mark Mangled
91
92Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) {
93  if (name.empty())
94    return Mangled::eManglingSchemeNone;
95
96  if (name.startswith("?"))
97    return Mangled::eManglingSchemeMSVC;
98
99  if (name.startswith("_Z"))
100    return Mangled::eManglingSchemeItanium;
101
102  // ___Z is a clang extension of block invocations
103  if (name.startswith("___Z"))
104    return Mangled::eManglingSchemeItanium;
105
106  return Mangled::eManglingSchemeNone;
107}
108
109Mangled::Mangled(ConstString s) : m_mangled(), m_demangled() {
110  if (s)
111    SetValue(s);
112}
113
114Mangled::Mangled(llvm::StringRef name) {
115  if (!name.empty())
116    SetValue(ConstString(name));
117}
118
119// Convert to pointer operator. This allows code to check any Mangled objects
120// to see if they contain anything valid using code such as:
121//
122//  Mangled mangled(...);
123//  if (mangled)
124//  { ...
125Mangled::operator void *() const {
126  return (m_mangled) ? const_cast<Mangled *>(this) : nullptr;
127}
128
129// Logical NOT operator. This allows code to check any Mangled objects to see
130// if they are invalid using code such as:
131//
132//  Mangled mangled(...);
133//  if (!file_spec)
134//  { ...
135bool Mangled::operator!() const { return !m_mangled; }
136
137// Clear the mangled and demangled values.
138void Mangled::Clear() {
139  m_mangled.Clear();
140  m_demangled.Clear();
141}
142
143// Compare the string values.
144int Mangled::Compare(const Mangled &a, const Mangled &b) {
145  return ConstString::Compare(
146      a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled),
147      b.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
148}
149
150// Set the string value in this objects. If "mangled" is true, then the mangled
151// named is set with the new value in "s", else the demangled name is set.
152void Mangled::SetValue(ConstString s, bool mangled) {
153  if (s) {
154    if (mangled) {
155      m_demangled.Clear();
156      m_mangled = s;
157    } else {
158      m_demangled = s;
159      m_mangled.Clear();
160    }
161  } else {
162    m_demangled.Clear();
163    m_mangled.Clear();
164  }
165}
166
167void Mangled::SetValue(ConstString name) {
168  if (name) {
169    if (cstring_is_mangled(name.GetStringRef())) {
170      m_demangled.Clear();
171      m_mangled = name;
172    } else {
173      m_demangled = name;
174      m_mangled.Clear();
175    }
176  } else {
177    m_demangled.Clear();
178    m_mangled.Clear();
179  }
180}
181
182// Local helpers for different demangling implementations.
183static char *GetMSVCDemangledStr(const char *M) {
184  char *demangled_cstr = llvm::microsoftDemangle(
185      M, nullptr, nullptr, nullptr,
186      llvm::MSDemangleFlags(llvm::MSDF_NoAccessSpecifier |
187                            llvm::MSDF_NoCallingConvention |
188                            llvm::MSDF_NoMemberType));
189
190  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
191    if (demangled_cstr && demangled_cstr[0])
192      LLDB_LOGF(log, "demangled msvc: %s -> \"%s\"", M, demangled_cstr);
193    else
194      LLDB_LOGF(log, "demangled msvc: %s -> error", M);
195  }
196
197  return demangled_cstr;
198}
199
200static char *GetItaniumDemangledStr(const char *M) {
201  char *demangled_cstr = nullptr;
202
203  llvm::ItaniumPartialDemangler ipd;
204  bool err = ipd.partialDemangle(M);
205  if (!err) {
206    // Default buffer and size (will realloc in case it's too small).
207    size_t demangled_size = 80;
208    demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
209    demangled_cstr = ipd.finishDemangle(demangled_cstr, &demangled_size);
210
211    assert(demangled_cstr &&
212           "finishDemangle must always succeed if partialDemangle did");
213    assert(demangled_cstr[demangled_size - 1] == '\0' &&
214           "Expected demangled_size to return length including trailing null");
215  }
216
217  if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
218    if (demangled_cstr)
219      LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr);
220    else
221      LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M);
222  }
223
224  return demangled_cstr;
225}
226
227// Explicit demangling for scheduled requests during batch processing. This
228// makes use of ItaniumPartialDemangler's rich demangle info
229bool Mangled::DemangleWithRichManglingInfo(
230    RichManglingContext &context, SkipMangledNameFn *skip_mangled_name) {
231  // We need to generate and cache the demangled name.
232  static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
233  Timer scoped_timer(func_cat,
234                     "Mangled::DemangleWithRichNameIndexInfo (m_mangled = %s)",
235                     m_mangled.GetCString());
236
237  // Others are not meant to arrive here. ObjC names or C's main() for example
238  // have their names stored in m_demangled, while m_mangled is empty.
239  assert(m_mangled);
240
241  // Check whether or not we are interested in this name at all.
242  ManglingScheme scheme = GetManglingScheme(m_mangled.GetStringRef());
243  if (skip_mangled_name && skip_mangled_name(m_mangled.GetStringRef(), scheme))
244    return false;
245
246  switch (scheme) {
247  case eManglingSchemeNone:
248    // The current mangled_name_filter would allow llvm_unreachable here.
249    return false;
250
251  case eManglingSchemeItanium:
252    // We want the rich mangling info here, so we don't care whether or not
253    // there is a demangled string in the pool already.
254    if (context.FromItaniumName(m_mangled)) {
255      // If we got an info, we have a name. Copy to string pool and connect the
256      // counterparts to accelerate later access in GetDemangledName().
257      context.ParseFullName();
258      m_demangled.SetStringWithMangledCounterpart(context.GetBufferRef(),
259                                                  m_mangled);
260      return true;
261    } else {
262      m_demangled.SetCString("");
263      return false;
264    }
265
266  case eManglingSchemeMSVC: {
267    // We have no rich mangling for MSVC-mangled names yet, so first try to
268    // demangle it if necessary.
269    if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) {
270      if (char *d = GetMSVCDemangledStr(m_mangled.GetCString())) {
271        // If we got an info, we have a name. Copy to string pool and connect
272        // the counterparts to accelerate later access in GetDemangledName().
273        m_demangled.SetStringWithMangledCounterpart(llvm::StringRef(d),
274                                                    m_mangled);
275        ::free(d);
276      } else {
277        m_demangled.SetCString("");
278      }
279    }
280
281    if (m_demangled.IsEmpty()) {
282      // Cannot demangle it, so don't try parsing.
283      return false;
284    } else {
285      // Demangled successfully, we can try and parse it with
286      // CPlusPlusLanguage::MethodName.
287      return context.FromCxxMethodName(m_demangled);
288    }
289  }
290  }
291  llvm_unreachable("Fully covered switch above!");
292}
293
294// Generate the demangled name on demand using this accessor. Code in this
295// class will need to use this accessor if it wishes to decode the demangled
296// name. The result is cached and will be kept until a new string value is
297// supplied to this object, or until the end of the object's lifetime.
298ConstString
299Mangled::GetDemangledName(lldb::LanguageType language) const {
300  // Check to make sure we have a valid mangled name and that we haven't
301  // already decoded our mangled name.
302  if (m_mangled && m_demangled.IsNull()) {
303    // We need to generate and cache the demangled name.
304    static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
305    Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
306                       m_mangled.GetCString());
307
308    // Don't bother running anything that isn't mangled
309    const char *mangled_name = m_mangled.GetCString();
310    ManglingScheme mangling_scheme = GetManglingScheme(m_mangled.GetStringRef());
311    if (mangling_scheme != eManglingSchemeNone &&
312        !m_mangled.GetMangledCounterpart(m_demangled)) {
313      // We didn't already mangle this name, demangle it and if all goes well
314      // add it to our map.
315      char *demangled_name = nullptr;
316      switch (mangling_scheme) {
317      case eManglingSchemeMSVC:
318        demangled_name = GetMSVCDemangledStr(mangled_name);
319        break;
320      case eManglingSchemeItanium: {
321        demangled_name = GetItaniumDemangledStr(mangled_name);
322        break;
323      }
324      case eManglingSchemeNone:
325        llvm_unreachable("eManglingSchemeNone was handled already");
326      }
327      if (demangled_name) {
328        m_demangled.SetStringWithMangledCounterpart(
329            llvm::StringRef(demangled_name), m_mangled);
330        free(demangled_name);
331      }
332    }
333    if (m_demangled.IsNull()) {
334      // Set the demangled string to the empty string to indicate we tried to
335      // parse it once and failed.
336      m_demangled.SetCString("");
337    }
338  }
339
340  return m_demangled;
341}
342
343ConstString
344Mangled::GetDisplayDemangledName(lldb::LanguageType language) const {
345  return GetDemangledName(language);
346}
347
348bool Mangled::NameMatches(const RegularExpression &regex,
349                          lldb::LanguageType language) const {
350  if (m_mangled && regex.Execute(m_mangled.AsCString()))
351    return true;
352
353  ConstString demangled = GetDemangledName(language);
354  return demangled && regex.Execute(demangled.AsCString());
355}
356
357// Get the demangled name if there is one, else return the mangled name.
358ConstString Mangled::GetName(lldb::LanguageType language,
359                             Mangled::NamePreference preference) const {
360  if (preference == ePreferMangled && m_mangled)
361    return m_mangled;
362
363  ConstString demangled = GetDemangledName(language);
364
365  if (preference == ePreferDemangledWithoutArguments) {
366    return get_demangled_name_without_arguments(m_mangled, demangled);
367  }
368  if (preference == ePreferDemangled) {
369    // Call the accessor to make sure we get a demangled name in case it hasn't
370    // been demangled yet...
371    if (demangled)
372      return demangled;
373    return m_mangled;
374  }
375  return demangled;
376}
377
378// Dump a Mangled object to stream "s". We don't force our demangled name to be
379// computed currently (we don't use the accessor).
380void Mangled::Dump(Stream *s) const {
381  if (m_mangled) {
382    *s << ", mangled = " << m_mangled;
383  }
384  if (m_demangled) {
385    const char *demangled = m_demangled.AsCString();
386    s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");
387  }
388}
389
390// Dumps a debug version of this string with extra object and state information
391// to stream "s".
392void Mangled::DumpDebug(Stream *s) const {
393  s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2),
394            static_cast<const void *>(this));
395  m_mangled.DumpDebug(s);
396  s->Printf(", demangled = ");
397  m_demangled.DumpDebug(s);
398}
399
400// Return the size in byte that this object takes in memory. The size includes
401// the size of the objects it owns, and not the strings that it references
402// because they are shared strings.
403size_t Mangled::MemorySize() const {
404  return m_mangled.MemorySize() + m_demangled.MemorySize();
405}
406
407// We "guess" the language because we can't determine a symbol's language from
408// it's name.  For example, a Pascal symbol can be mangled using the C++
409// Itanium scheme, and defined in a compilation unit within the same module as
410// other C++ units.  In addition, different targets could have different ways
411// of mangling names from a given language, likewise the compilation units
412// within those targets.
413lldb::LanguageType Mangled::GuessLanguage() const {
414  ConstString mangled = GetMangledName();
415
416  if (mangled) {
417    const char *mangled_name = mangled.GetCString();
418    if (CPlusPlusLanguage::IsCPPMangledName(mangled_name))
419      return lldb::eLanguageTypeC_plus_plus;
420    else if (ObjCLanguage::IsPossibleObjCMethodName(mangled_name))
421      return lldb::eLanguageTypeObjC;
422  } else {
423    // ObjC names aren't really mangled, so they won't necessarily be in the
424    // mangled name slot.
425    ConstString demangled_name = GetDemangledName(lldb::eLanguageTypeUnknown);
426    if (demangled_name
427        && ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString()))
428      return lldb::eLanguageTypeObjC;
429
430  }
431  return lldb::eLanguageTypeUnknown;
432}
433
434// Dump OBJ to the supplied stream S.
435Stream &operator<<(Stream &s, const Mangled &obj) {
436  if (obj.GetMangledName())
437    s << "mangled = '" << obj.GetMangledName() << "'";
438
439  ConstString demangled =
440      obj.GetDemangledName(lldb::eLanguageTypeUnknown);
441  if (demangled)
442    s << ", demangled = '" << demangled << '\'';
443  else
444    s << ", demangled = <error>";
445  return s;
446}
447