llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: nerix (Nerixyz) <details> <summary>Changes</summary> In order to support the Microsoft ABI alongside the Itanium one in the same process from different DLLs, this moves the Itanium ABI runtime plugin to the C++ language runtime (see https://github.com/llvm/llvm-project/pull/168941#discussion_r2547684264). Before this PR, the C++ language runtime wasn't a plugin. Instead, its functionality was provided by the Itanium ABI plugin. All Itanium specific methods are moved to a new class `ItaniumABIRuntime`. This includes resolving the dynamic type, setting exception filters, and getting the exception object. The other methods were added to `CPPLanguageRuntime`. `language cplusplus demangle` moved to `CommandObjectCPlusPlus`. The Clang REPL depended on the C++ runtime. Now that it's a plugin, this failed the layering check. Since the REPL doesn't use the C++ runtime, I removed the dependency. --- Patch is 48.16 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169225.diff 10 Files Affected: - (modified) lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt (+7-4) - (modified) lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp (+185) - (modified) lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h (+57-3) - (added) lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.cpp (+68) - (added) lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.h (+30) - (removed) lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt (-13) - (removed) lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h (-127) - (renamed) lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.cpp (+54-294) - (added) lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.h (+64) - (modified) lldb/source/Plugins/REPL/Clang/CMakeLists.txt (-1) ``````````diff diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt index 727c8290bceb4..ca54601d99cff 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt @@ -1,14 +1,17 @@ -add_lldb_library(lldbPluginCPPRuntime +add_lldb_library(lldbPluginCPPRuntime PLUGIN + CommandObjectCPlusPlus.cpp CPPLanguageRuntime.cpp + ItaniumABIRuntime.cpp VerboseTrapFrameRecognizer.cpp LINK_LIBS + lldbBreakpoint lldbCore + lldbInterpreter + lldbPluginTypeSystemClang lldbSymbol lldbTarget + lldbValueObject CLANG_LIBS clangCodeGen ) - -add_subdirectory(ItaniumABI) -#add_subdirectory(MicrosoftABI) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 913678b629f2f..3c127616f2d24 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -12,6 +12,7 @@ #include <memory> #include "CPPLanguageRuntime.h" +#include "CommandObjectCPlusPlus.h" #include "VerboseTrapFrameRecognizer.h" #include "llvm/ADT/StringRef.h" @@ -36,6 +37,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE_ADV(CPPLanguageRuntime, CPPRuntime) + static ConstString g_this = ConstString("this"); // Artificial coroutine-related variables emitted by clang. static ConstString g_promise = ConstString("__promise"); @@ -491,3 +494,185 @@ bool CPPLanguageRuntime::IsSymbolARuntimeThunk(const Symbol &symbol) { return mangled_name.starts_with("_ZTh") || mangled_name.starts_with("_ZTv") || mangled_name.starts_with("_ZTc"); } + +bool CPPLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { + const bool check_cxx = true; + const bool check_objc = false; + return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx, + check_objc); +} + +bool CPPLanguageRuntime::GetDynamicTypeAndAddress( + ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &dynamic_address, + Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) { + class_type_or_name.Clear(); + value_type = Value::ValueType::Scalar; + + if (!CouldHaveDynamicValue(in_value)) + return false; + + return m_itanium_runtime.GetDynamicTypeAndAddress( + in_value, use_dynamic, class_type_or_name, dynamic_address, value_type, + *m_process); +} + +TypeAndOrName +CPPLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) { + CompilerType static_type(static_value.GetCompilerType()); + Flags static_type_flags(static_type.GetTypeInfo()); + + TypeAndOrName ret(type_and_or_name); + if (type_and_or_name.HasType()) { + // The type will always be the type of the dynamic object. If our parent's + // type was a pointer, then our type should be a pointer to the type of the + // dynamic object. If a reference, then the original type should be + // okay... + CompilerType orig_type = type_and_or_name.GetCompilerType(); + CompilerType corrected_type = orig_type; + if (static_type_flags.AllSet(eTypeIsPointer)) + corrected_type = orig_type.GetPointerType(); + else if (static_type_flags.AllSet(eTypeIsReference)) + corrected_type = orig_type.GetLValueReferenceType(); + ret.SetCompilerType(corrected_type); + } else { + // If we are here we need to adjust our dynamic type name to include the + // correct & or * symbol + std::string corrected_name(type_and_or_name.GetName().GetCString()); + if (static_type_flags.AllSet(eTypeIsPointer)) + corrected_name.append(" *"); + else if (static_type_flags.AllSet(eTypeIsReference)) + corrected_name.append(" &"); + // the parent type should be a correctly pointer'ed or referenc'ed type + ret.SetCompilerType(static_type); + ret.SetName(corrected_name.c_str()); + } + return ret; +} + +LanguageRuntime * +CPPLanguageRuntime::CreateInstance(Process *process, + lldb::LanguageType language) { + if (language == eLanguageTypeC_plus_plus || + language == eLanguageTypeC_plus_plus_03 || + language == eLanguageTypeC_plus_plus_11 || + language == eLanguageTypeC_plus_plus_14) + return new CPPLanguageRuntime(process); + else + return nullptr; +} + +void CPPLanguageRuntime::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "C++ language runtime", CreateInstance, + [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP { + return CommandObjectSP(new CommandObjectCPlusPlus(interpreter)); + }); +} + +void CPPLanguageRuntime::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +llvm::Expected<LanguageRuntime::VTableInfo> +CPPLanguageRuntime::GetVTableInfo(ValueObject &in_value, bool check_type) { + return m_itanium_runtime.GetVTableInfo(in_value, check_type); +} + +BreakpointResolverSP +CPPLanguageRuntime::CreateExceptionResolver(const BreakpointSP &bkpt, + bool catch_bp, bool throw_bp) { + return CreateExceptionResolver(bkpt, catch_bp, throw_bp, false); +} + +BreakpointResolverSP +CPPLanguageRuntime::CreateExceptionResolver(const BreakpointSP &bkpt, + bool catch_bp, bool throw_bp, + bool for_expressions) { + std::vector<const char *> exception_names; + m_itanium_runtime.AppendExceptionBreakpointFunctions( + exception_names, catch_bp, throw_bp, for_expressions); + + BreakpointResolverSP resolver_sp(new BreakpointResolverName( + bkpt, exception_names.data(), exception_names.size(), + eFunctionNameTypeBase, eLanguageTypeUnknown, 0, eLazyBoolNo)); + + return resolver_sp; +} + +lldb::SearchFilterSP CPPLanguageRuntime::CreateExceptionSearchFilter() { + Target &target = m_process->GetTarget(); + + FileSpecList filter_modules; + m_itanium_runtime.AppendExceptionBreakpointFilterModules(filter_modules, + target); + return target.GetSearchFilterForModuleList(&filter_modules); +} + +lldb::BreakpointSP CPPLanguageRuntime::CreateExceptionBreakpoint( + bool catch_bp, bool throw_bp, bool for_expressions, bool is_internal) { + Target &target = m_process->GetTarget(); + FileSpecList filter_modules; + BreakpointResolverSP exception_resolver_sp = + CreateExceptionResolver(nullptr, catch_bp, throw_bp, for_expressions); + SearchFilterSP filter_sp(CreateExceptionSearchFilter()); + const bool hardware = false; + const bool resolve_indirect_functions = false; + return target.CreateBreakpoint(filter_sp, exception_resolver_sp, is_internal, + hardware, resolve_indirect_functions); +} + +void CPPLanguageRuntime::SetExceptionBreakpoints() { + if (!m_process) + return; + + const bool catch_bp = false; + const bool throw_bp = true; + const bool is_internal = true; + const bool for_expressions = true; + + // For the exception breakpoints set by the Expression parser, we'll be a + // little more aggressive and stop at exception allocation as well. + + if (m_cxx_exception_bp_sp) { + m_cxx_exception_bp_sp->SetEnabled(true); + } else { + m_cxx_exception_bp_sp = CreateExceptionBreakpoint( + catch_bp, throw_bp, for_expressions, is_internal); + if (m_cxx_exception_bp_sp) + m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception"); + } +} + +void CPPLanguageRuntime::ClearExceptionBreakpoints() { + if (!m_process) + return; + + if (m_cxx_exception_bp_sp) { + m_cxx_exception_bp_sp->SetEnabled(false); + } +} + +bool CPPLanguageRuntime::ExceptionBreakpointsAreSet() { + return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled(); +} + +bool CPPLanguageRuntime::ExceptionBreakpointsExplainStop( + lldb::StopInfoSP stop_reason) { + if (!m_process) + return false; + + if (!stop_reason || stop_reason->GetStopReason() != eStopReasonBreakpoint) + return false; + + uint64_t break_site_id = stop_reason->GetValue(); + return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint( + break_site_id, m_cxx_exception_bp_sp->GetID()); +} + +lldb::ValueObjectSP +CPPLanguageRuntime::GetExceptionObjectForThread(lldb::ThreadSP thread_sp) { + return m_itanium_runtime.GetExceptionObjectForThread(std::move(thread_sp), + *m_process); +} diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index 05639e9798917..7c3dade76d703 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -13,6 +13,7 @@ #include "llvm/ADT/StringMap.h" +#include "ItaniumABIRuntime.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/lldb-private.h" @@ -42,6 +43,19 @@ class CPPLanguageRuntime : public LanguageRuntime { static char ID; + static void Initialize(); + + static void Terminate(); + + static lldb_private::LanguageRuntime * + CreateInstance(Process *process, lldb::LanguageType language); + + static llvm::StringRef GetPluginNameStatic() { + return "cpp-language-runtime"; + } + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + bool isA(const void *ClassID) const override { return ClassID == &ID || LanguageRuntime::isA(ClassID); } @@ -81,15 +95,55 @@ class CPPLanguageRuntime : public LanguageRuntime { bool IsSymbolARuntimeThunk(const Symbol &symbol) override; -protected: - // Classes that inherit from CPPLanguageRuntime can see and modify these - CPPLanguageRuntime(Process *process); + llvm::Expected<LanguageRuntime::VTableInfo> + GetVTableInfo(ValueObject &in_value, bool check_type) override; + + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, Value::ValueType &value_type, + llvm::ArrayRef<uint8_t> &local_buffer) override; + + TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) override; + + bool CouldHaveDynamicValue(ValueObject &in_value) override; + + void SetExceptionBreakpoints() override; + + void ClearExceptionBreakpoints() override; + + bool ExceptionBreakpointsAreSet() override; + + bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; + + lldb::BreakpointResolverSP + CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp, + bool throw_bp) override; + + lldb::SearchFilterSP CreateExceptionSearchFilter() override; + + lldb::ValueObjectSP + GetExceptionObjectForThread(lldb::ThreadSP thread_sp) override; private: + CPPLanguageRuntime(Process *process); + + lldb::BreakpointResolverSP + CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp, + bool throw_bp, bool for_expressions); + + lldb::BreakpointSP CreateExceptionBreakpoint(bool catch_bp, bool throw_bp, + bool for_expressions, + bool is_internal); + using OperatorStringToCallableInfoMap = llvm::StringMap<CPPLanguageRuntime::LibCppStdFunctionCallableInfo>; OperatorStringToCallableInfoMap CallableLookupCache; + + lldb::BreakpointSP m_cxx_exception_bp_sp; + ItaniumABIRuntime m_itanium_runtime; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.cpp new file mode 100644 index 0000000000000..9d6903f0903cf --- /dev/null +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// 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 "CommandObjectCPlusPlus.h" + +#include "lldb/Core/Mangled.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +CommandObjectCPlusPlusDemangle::CommandObjectCPlusPlusDemangle( + CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "demangle", + "Demangle a C++ mangled name.", + "language cplusplus demangle [<mangled-name> ...]") { + AddSimpleArgumentList(eArgTypeSymbol, eArgRepeatPlus); +} + +void CommandObjectCPlusPlusDemangle::DoExecute(Args &command, + CommandReturnObject &result) { + bool demangled_any = false; + bool error_any = false; + for (auto &entry : command.entries()) { + if (entry.ref().empty()) + continue; + + // the actual Mangled class should be strict about this, but on the + // command line if you're copying mangled names out of 'nm' on Darwin, + // they will come out with an extra underscore - be willing to strip this + // on behalf of the user. This is the moral equivalent of the -_/-n + // options to c++filt + auto name = entry.ref(); + if (name.starts_with("__Z")) + name = name.drop_front(); + + Mangled mangled(name); + if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus) { + ConstString demangled(mangled.GetDisplayDemangledName()); + demangled_any = true; + result.AppendMessageWithFormat("%s ---> %s\n", entry.c_str(), + demangled.GetCString()); + } else { + error_any = true; + result.AppendErrorWithFormat("%s is not a valid C++ mangled name\n", + entry.ref().str().c_str()); + } + } + + result.SetStatus( + error_any ? lldb::eReturnStatusFailed + : (demangled_any ? lldb::eReturnStatusSuccessFinishResult + : lldb::eReturnStatusSuccessFinishNoResult)); +} + +CommandObjectCPlusPlus::CommandObjectCPlusPlus(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "cplusplus", + "Commands for operating on the C++ language runtime.", + "cplusplus <subcommand> [<subcommand-options>]") { + LoadSubCommand("demangle", CommandObjectSP(new CommandObjectCPlusPlusDemangle( + interpreter))); +} diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.h new file mode 100644 index 0000000000000..f95bf7ae85389 --- /dev/null +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommandObjectCPlusPlus.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_COMMANDOBJECTCPLUSPLUS_H +#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_COMMANDOBJECTCPLUSPLUS_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" +namespace lldb_private { + +class CommandObjectCPlusPlusDemangle : public CommandObjectParsed { +public: + CommandObjectCPlusPlusDemangle(CommandInterpreter &interpreter); + +protected: + void DoExecute(Args &command, CommandReturnObject &result) override; +}; + +class CommandObjectCPlusPlus : public CommandObjectMultiword { +public: + CommandObjectCPlusPlus(CommandInterpreter &interpreter); +}; + +} // namespace lldb_private + +#endif diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt deleted file mode 100644 index a5406c73be933..0000000000000 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_lldb_library(lldbPluginCXXItaniumABI PLUGIN - ItaniumABILanguageRuntime.cpp - - LINK_LIBS - lldbBreakpoint - lldbCore - lldbInterpreter - lldbSymbol - lldbTarget - lldbValueObject - lldbPluginCPPRuntime - lldbPluginTypeSystemClang - ) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h deleted file mode 100644 index 7abf2f8547cd5..0000000000000 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h +++ /dev/null @@ -1,127 +0,0 @@ -//===-- ItaniumABILanguageRuntime.h -----------------------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_ITANIUMABI_ITANIUMABILANGUAGERUNTIME_H -#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_ITANIUMABI_ITANIUMABILANGUAGERUNTIME_H - -#include <map> -#include <mutex> -#include <vector> - -#include "lldb/Breakpoint/BreakpointResolver.h" -#include "lldb/Core/Value.h" -#include "lldb/Symbol/Type.h" -#include "lldb/Target/LanguageRuntime.h" -#include "lldb/lldb-private.h" - -#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" - -namespace lldb_private { - -class ItaniumABILanguageRuntime : public lldb_private::CPPLanguageRuntime { -public: - ~ItaniumABILanguageRuntime() override = default; - - // Static Functions - static void Initialize(); - - static void Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); - - static llvm::StringRef GetPluginNameStatic() { return "itanium"; } - - static char ID; - - bool isA(const void *ClassID) const override { - return ClassID == &ID || CPPLanguageRuntime::isA(ClassID); - } - - static bool classof(const LanguageRuntime *runtime) { - return runtime->isA(&ID); - } - - - llvm::Expected<LanguageRuntime::VTableInfo> - GetVTableInfo(ValueObject &in_value, bool check_type) override; - - bool GetDynamicTypeAndAddress(ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, Value::ValueType &value_type, - llvm::ArrayRef<uint8_t> &local_buffer) override; - - TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, - ValueObject &static_value) override; - - bool CouldHaveDynamicValue(ValueObject &in_value) override; - - void SetExceptionBreakpoints() override; - - void ClearExceptionBreakpoints() override; - - bool ExceptionBreakpointsAreSet() override; - - bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; - - lldb::BreakpointResolverSP - CreateExceptionResolver(const lldb::BreakpointSP &bkpt, - bool catch_bp, bool throw_bp) override; - - lldb::SearchFilterSP CreateExceptionSearchFilter() override; - - lldb::ValueObjectSP GetExceptionObjectForThread( - lldb::ThreadSP thread_sp) override; - - // PluginInterface protocol - llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } - -protected: - lldb::Breakpoi... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/169225 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
