| //===-- RichManglingContext.cpp -------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/Core/RichManglingContext.h" |
| |
| #include "lldb/Utility/Log.h" |
| #include "lldb/Utility/Logging.h" |
| |
| #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" |
| |
| #include "llvm/ADT/StringRef.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| // RichManglingContext |
| RichManglingContext::~RichManglingContext() { |
| std::free(m_ipd_buf); |
| ResetCxxMethodParser(); |
| } |
| |
| void RichManglingContext::ResetCxxMethodParser() { |
| // If we want to support parsers for other languages some day, we need a |
| // switch here to delete the correct parser type. |
| if (m_cxx_method_parser.hasValue()) { |
| assert(m_provider == PluginCxxLanguage); |
| delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser); |
| m_cxx_method_parser.reset(); |
| } |
| } |
| |
| void RichManglingContext::ResetProvider(InfoProvider new_provider) { |
| ResetCxxMethodParser(); |
| |
| assert(new_provider != None && "Only reset to a valid provider"); |
| m_provider = new_provider; |
| } |
| |
| bool RichManglingContext::FromItaniumName(ConstString mangled) { |
| bool err = m_ipd.partialDemangle(mangled.GetCString()); |
| if (!err) { |
| ResetProvider(ItaniumPartialDemangler); |
| } |
| |
| if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) { |
| if (!err) { |
| ParseFullName(); |
| LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf); |
| } else { |
| LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle", |
| mangled); |
| } |
| } |
| |
| return !err; // true == success |
| } |
| |
| bool RichManglingContext::FromCxxMethodName(ConstString demangled) { |
| ResetProvider(PluginCxxLanguage); |
| m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled); |
| return true; |
| } |
| |
| bool RichManglingContext::IsCtorOrDtor() const { |
| assert(m_provider != None && "Initialize a provider first"); |
| switch (m_provider) { |
| case ItaniumPartialDemangler: |
| return m_ipd.isCtorOrDtor(); |
| case PluginCxxLanguage: { |
| // We can only check for destructors here. |
| auto base_name = |
| get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename(); |
| return base_name.startswith("~"); |
| } |
| case None: |
| return false; |
| } |
| llvm_unreachable("Fully covered switch above!"); |
| } |
| |
| void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) { |
| // Error case: Clear the buffer. |
| if (LLVM_UNLIKELY(ipd_res == nullptr)) { |
| assert(res_size == m_ipd_buf_size && |
| "Failed IPD queries keep the original size in the N parameter"); |
| |
| m_ipd_buf[0] = '\0'; |
| m_buffer = llvm::StringRef(m_ipd_buf, 0); |
| return; |
| } |
| |
| // IPD's res_size includes null terminator. |
| assert(ipd_res[res_size - 1] == '\0' && |
| "IPD returns null-terminated strings and we rely on that"); |
| |
| // Update buffer/size on realloc. |
| if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) { |
| m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer. |
| m_ipd_buf_size = res_size; // May actually be bigger, but we can't know. |
| |
| if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) |
| LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}", |
| m_ipd_buf_size); |
| } |
| |
| // 99% case: Just remember the string length. |
| m_buffer = llvm::StringRef(m_ipd_buf, res_size - 1); |
| } |
| |
| void RichManglingContext::ParseFunctionBaseName() { |
| assert(m_provider != None && "Initialize a provider first"); |
| switch (m_provider) { |
| case ItaniumPartialDemangler: { |
| auto n = m_ipd_buf_size; |
| auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n); |
| processIPDStrResult(buf, n); |
| return; |
| } |
| case PluginCxxLanguage: |
| m_buffer = |
| get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename(); |
| return; |
| case None: |
| return; |
| } |
| } |
| |
| void RichManglingContext::ParseFunctionDeclContextName() { |
| assert(m_provider != None && "Initialize a provider first"); |
| switch (m_provider) { |
| case ItaniumPartialDemangler: { |
| auto n = m_ipd_buf_size; |
| auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n); |
| processIPDStrResult(buf, n); |
| return; |
| } |
| case PluginCxxLanguage: |
| m_buffer = |
| get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext(); |
| return; |
| case None: |
| return; |
| } |
| } |
| |
| void RichManglingContext::ParseFullName() { |
| assert(m_provider != None && "Initialize a provider first"); |
| switch (m_provider) { |
| case ItaniumPartialDemangler: { |
| auto n = m_ipd_buf_size; |
| auto buf = m_ipd.finishDemangle(m_ipd_buf, &n); |
| processIPDStrResult(buf, n); |
| return; |
| } |
| case PluginCxxLanguage: |
| m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) |
| ->GetFullName() |
| .GetStringRef(); |
| return; |
| case None: |
| return; |
| } |
| } |