| //===-- 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/LLDBLog.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) { | |
| assert(m_provider == PluginCxxLanguage); | |
| 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 = GetLog(LLDBLog::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) { | |
| auto *lang = Language::FindPlugin(eLanguageTypeC_plus_plus); | |
| if (!lang) | |
| return false; | |
| ResetProvider(PluginCxxLanguage); | |
| m_cxx_method_parser = lang->GetMethodName(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 = m_cxx_method_parser->GetBasename(); | |
| return base_name.starts_with("~"); | |
| } | |
| case None: | |
| return false; | |
| } | |
| llvm_unreachable("Fully covered switch above!"); | |
| } | |
| llvm::StringRef 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'; | |
| return llvm::StringRef(m_ipd_buf, 0); | |
| } | |
| // 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 = GetLog(LLDBLog::Demangle)) | |
| LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}", | |
| m_ipd_buf_size); | |
| } | |
| // 99% case: Just remember the string length. | |
| return llvm::StringRef(m_ipd_buf, res_size - 1); | |
| } | |
| llvm::StringRef 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); | |
| return processIPDStrResult(buf, n); | |
| } | |
| case PluginCxxLanguage: | |
| return m_cxx_method_parser->GetBasename(); | |
| case None: | |
| return {}; | |
| } | |
| llvm_unreachable("Fully covered switch above!"); | |
| } | |
| llvm::StringRef 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); | |
| return processIPDStrResult(buf, n); | |
| } | |
| case PluginCxxLanguage: | |
| return m_cxx_method_parser->GetContext(); | |
| case None: | |
| return {}; | |
| } | |
| llvm_unreachable("Fully covered switch above!"); | |
| } | |
| llvm::StringRef 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); | |
| return processIPDStrResult(buf, n); | |
| } | |
| case PluginCxxLanguage: | |
| return llvm::StringRef(m_cxx_method_parser->GetFullName()); | |
| case None: | |
| return {}; | |
| } | |
| llvm_unreachable("Fully covered switch above!"); | |
| } |