Author: Nerixyz Date: 2026-06-30T20:01:09Z New Revision: 6b5c27376a275ce34464631be3caed65967ab161
URL: https://github.com/llvm/llvm-project/commit/6b5c27376a275ce34464631be3caed65967ab161 DIFF: https://github.com/llvm/llvm-project/commit/6b5c27376a275ce34464631be3caed65967ab161.diff LOG: Revert "[lldb] Move common functionality out of Itanium ABI runtime (#191275)" (#206816) This reverts commit 0f51760a342cd8fed1c657e6ca134097c9e8f88c. A test fails with the commit (https://github.com/llvm/llvm-project/pull/191275#issuecomment-4846936554): ``` Traceback (most recent call last): File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 596, in test_python_source_frames self.assertNotIn("0xffffffffffffffff", output.lower()) AssertionError: '0xffffffffffffffff' unexpectedly found in "* thread #2, name = 'a.out', stop reason = breakpoint 1.1\n * frame #0: compute_fibonacci at python_helper.py:7 [synthetic]\n frame #1: process_data at python_helper.py:16 [synthetic]\n frame #2: main at python_helper.py:27 [synthetic]\n frame #3: 0x0000badc2de81358 a.out`thread_func(thread_num=0) at main.cpp:44:13\n frame #4: 0x0000badc2de81f9c a.out`void std::__invoke_impl<void, void (*)(int), int>((null)=__invoke_other @ 0x0000f1555ebae74f, __f=0x0000badc66845ec0, __args=0x0000badc66845eb8) at invoke.h:61:14\n frame #5: 0x0000badc2de81f18 a.out`std::__invoke_result<void (*)(int), int>::type std::__invoke<void (*)(int), int>(__fn=0x0000badc66845ec0, __args=0x0000badc66845eb8) at invoke.h:96:14\n frame #6: 0x0000badc2de81ee4 a.out`void std::thread::_invoker<std::tuple<void (*)(int), int>>::_m_invoke<0ul, 1ul>(this=0x0000badc66845eb8, (null)=_index_tuple<0ul, 1ul> @ 0x0000f1555ebae7af) at std_thread.h:259:13\n frame #7: 0x0000badc2de81e98 a.out`std::thread::_invoker<std::tuple<void (*)(int), int>>::operator()(this=0x0000badc66845eb8) at std_thread.h:266:11\n frame #8: 0x0000badc2de81d70 a.out`std::thread::_state_impl<std::thread::_invoker<std::tuple<void (*)(int), int>>>::_m_run(this=0xffffffffffffffff) at std_thread.h:211:13\n frame #9: 0x0000f1555ef029cc libstdc++.so.6`___lldb_unnamed_symbol_d29b0 + 28\n frame #10: 0x0000f1555ec30398 libc.so.6`___lldb_unnamed_symbol_800c0 + 728\n frame #11: 0x0000f1555ec99e9c libc.so.6`___lldb_unnamed_symbol_e9e90 + 12\n" ``` I don't know why this test fails with the PR, but I don't have time to fix it now, so revert it to unblock CI. The backtrace was ``` frame #0: compute_fibonacci at python_helper.py:7 [synthetic] frame #1: process_data at python_helper.py:16 [synthetic] frame #2: main at python_helper.py:27 [synthetic] frame #3: 0x0000badc2de81358 a.out`thread_func(thread_num=0) at main.cpp:44:13 frame #4: 0x0000badc2de81f9c a.out`void std::__invoke_impl<void, void (*)(int), int>((null)=__invoke_other @ 0x0000f1555ebae74f, __f=0x0000badc66845ec0, __args=0x0000badc66845eb8) at invoke.h:61:14 frame #5: 0x0000badc2de81f18 a.out`std::__invoke_result<void (*)(int), int>::type std::__invoke<void (*)(int), int>(__fn=0x0000badc66845ec0, __args=0x0000badc66845eb8) at invoke.h:96:14 frame #6: 0x0000badc2de81ee4 a.out`void std::thread::_invoker<std::tuple<void (*)(int), int>>::_m_invoke<0ul, 1ul>(this=0x0000badc66845eb8, (null)=_index_tuple<0ul, 1ul> @ 0x0000f1555ebae7af) at std_thread.h:259:13 frame #7: 0x0000badc2de81e98 a.out`std::thread::_invoker<std::tuple<void (*)(int), int>>::operator()(this=0x0000badc66845eb8) at std_thread.h:266:11 frame #8: 0x0000badc2de81d70 a.out`std::thread::_state_impl<std::thread::_invoker<std::tuple<void (*)(int), int>>>::_m_run(this=0xffffffffffffffff) at std_thread.h:211:13 frame #9: 0x0000f1555ef029cc libstdc++.so.6`___lldb_unnamed_symbol_d29b0 + 28 frame #10: 0x0000f1555ec30398 libc.so.6`___lldb_unnamed_symbol_800c0 + 728 frame #11: 0x0000f1555ec99e9c libc.so.6`___lldb_unnamed_symbol_e9e90 + 12 ``` This contains 0xffffffffffffffff in frame 8. Added: Modified: lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.cpp lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.h Removed: lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.cpp lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.h ################################################################################ diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt index dcf8fcd850db5..ca54601d99cff 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt @@ -1,6 +1,5 @@ add_lldb_library(lldbPluginCPPRuntime PLUGIN CommandObjectCPlusPlus.cpp - CommonABIRuntime.cpp CPPLanguageRuntime.cpp ItaniumABIRuntime.cpp VerboseTrapFrameRecognizer.cpp diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 2b657796c4f5e..c517ec8611932 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -13,7 +13,6 @@ #include "CPPLanguageRuntime.h" #include "CommandObjectCPlusPlus.h" -#include "ItaniumABIRuntime.h" #include "VerboseTrapFrameRecognizer.h" #include "llvm/ADT/StringRef.h" @@ -33,7 +32,6 @@ #include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/ThreadPlanRunToAddress.h" #include "lldb/Target/ThreadPlanStepInRange.h" -#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Timer.h" using namespace lldb; @@ -112,7 +110,7 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer { }; CPPLanguageRuntime::CPPLanguageRuntime(Process *process) - : LanguageRuntime(process) { + : LanguageRuntime(process), m_itanium_runtime(process) { if (process) { process->GetTarget().GetFrameRecognizerManager().AddRecognizer( StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {}, @@ -122,7 +120,6 @@ CPPLanguageRuntime::CPPLanguageRuntime(Process *process) RegisterVerboseTrapFrameRecognizer(*process); } - m_abi_runtimes.emplace_back(std::make_unique<ItaniumABIRuntime>(process)); } bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { @@ -527,15 +524,8 @@ bool CPPLanguageRuntime::GetDynamicTypeAndAddress( if (!CouldHaveDynamicValue(in_value)) return false; - llvm::Expected<VTableInfoEntry> entry = - GetVTableInfoEntry(in_value, /*check_type=*/false); - if (!entry) { - llvm::consumeError(entry.takeError()); - return false; - } - - return entry->runtime->GetDynamicTypeAndAddress( - in_value, use_dynamic, entry->info, class_type_or_name, dynamic_address); + return m_itanium_runtime.GetDynamicTypeAndAddress( + in_value, use_dynamic, class_type_or_name, dynamic_address, value_type); } TypeAndOrName @@ -598,11 +588,7 @@ void CPPLanguageRuntime::Terminate() { llvm::Expected<LanguageRuntime::VTableInfo> CPPLanguageRuntime::GetVTableInfo(ValueObject &in_value, bool check_type) { - llvm::Expected<VTableInfoEntry> entry = - GetVTableInfoEntry(in_value, check_type); - if (!entry) - return entry.takeError(); - return entry->info; + return m_itanium_runtime.GetVTableInfo(in_value, check_type); } BreakpointResolverSP @@ -616,10 +602,8 @@ CPPLanguageRuntime::CreateExceptionResolver(const BreakpointSP &bkpt, bool catch_bp, bool throw_bp, bool for_expressions) { std::vector<const char *> exception_names; - for (const auto &runtime : m_abi_runtimes) { - runtime->AppendExceptionBreakpointFunctions(exception_names, catch_bp, - throw_bp, for_expressions); - } + m_itanium_runtime.AppendExceptionBreakpointFunctions( + exception_names, catch_bp, throw_bp, for_expressions); BreakpointResolverSP resolver_sp(new BreakpointResolverName( bkpt, exception_names.data(), exception_names.size(), @@ -632,9 +616,8 @@ lldb::SearchFilterSP CPPLanguageRuntime::CreateExceptionSearchFilter() { Target &target = m_process->GetTarget(); FileSpecList filter_modules; - for (const auto &runtime : m_abi_runtimes) - runtime->AppendExceptionBreakpointFilterModules(filter_modules, target); - + m_itanium_runtime.AppendExceptionBreakpointFilterModules(filter_modules, + target); return target.GetSearchFilterForModuleList(&filter_modules); } @@ -701,127 +684,5 @@ bool CPPLanguageRuntime::ExceptionBreakpointsExplainStop( lldb::ValueObjectSP CPPLanguageRuntime::GetExceptionObjectForThread(lldb::ThreadSP thread_sp) { - for (auto &runtime : m_abi_runtimes) { - ValueObjectSP valobj = runtime->GetExceptionObjectForThread(thread_sp); - if (valobj) - return valobj; - } - return {}; -} - -static llvm::Error typeHasVTable(CompilerType type) { - // Check to make sure the class has a vtable. - CompilerType original_type = type; - if (type.IsPointerOrReferenceType()) { - CompilerType pointee_type = type.GetPointeeType(); - if (pointee_type) - type = pointee_type; - } - - // Make sure this is a class or a struct first by checking the type class - // bitfield that gets returned. - if ((type.GetTypeClass() & (eTypeClassStruct | eTypeClassClass)) == 0) { - return llvm::createStringError( - std::errc::invalid_argument, - "type \"%s\" is not a class or struct or a pointer to one", - original_type.GetTypeName().AsCString("<invalid>")); - } - - // Check if the type has virtual functions by asking it if it is polymorphic. - if (!type.IsPolymorphicClass()) { - return llvm::createStringError(std::errc::invalid_argument, - "type \"%s\" doesn't have a vtable", - type.GetTypeName().AsCString("<invalid>")); - } - return llvm::Error::success(); -} - -// This function can accept both pointers or references to classes as well as -// instances of classes. If you are using this function during dynamic type -// detection, only valid ValueObjects that return true to -// CouldHaveDynamicValue(...) should call this function and \a check_type -// should be set to false. This function is also used by ValueObjectVTable -// and is can pass in instances of classes which is not suitable for dynamic -// type detection, these cases should pass true for \a check_type. -llvm::Expected<CPPLanguageRuntime::VTableInfoEntry> -CPPLanguageRuntime::GetVTableInfoEntry(ValueObject &in_value, bool check_type) { - CompilerType type = in_value.GetCompilerType(); - if (check_type) { - if (llvm::Error err = typeHasVTable(type)) - return std::move(err); - } - ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process == nullptr) - return llvm::createStringError(std::errc::invalid_argument, - "invalid process"); - - auto [original_ptr, address_type] = - type.IsPointerOrReferenceType() - ? in_value.GetPointerValue() - : in_value.GetAddressOf(/*scalar_is_load_address=*/true); - if (original_ptr == LLDB_INVALID_ADDRESS || address_type != eAddressTypeLoad) - return llvm::createStringError(std::errc::invalid_argument, - "failed to get the address of the value"); - - Status error; - lldb::addr_t vtable_load_addr = - process->ReadPointerFromMemory(original_ptr, error); - - if (!error.Success() || vtable_load_addr == LLDB_INVALID_ADDRESS) - return llvm::createStringError( - std::errc::invalid_argument, - "failed to read vtable pointer from memory at 0x%" PRIx64, - original_ptr); - - // The vtable load address can have authentication bits with - // AArch64 targets on Darwin. - vtable_load_addr = process->FixDataAddress(vtable_load_addr); - - // Find the symbol that contains the "vtable_load_addr" address - Address vtable_addr; - if (!process->GetTarget().ResolveLoadAddress(vtable_load_addr, vtable_addr)) - return llvm::createStringError(std::errc::invalid_argument, - "failed to resolve vtable pointer 0x%" PRIx64 - " to a section", - vtable_load_addr); - - // Check our cache first to see if we already have this info - { - std::lock_guard<std::mutex> locker(m_vtable_mutex); - auto pos = m_vtable_info_map.find(vtable_addr); - if (pos != m_vtable_info_map.end()) - return pos->second; - } - - Symbol *symbol = vtable_addr.CalculateSymbolContextSymbol(); - if (symbol == nullptr) - return llvm::createStringError(std::errc::invalid_argument, - "no symbol found for 0x%" PRIx64, - vtable_load_addr); - Mangled &mangled = symbol->GetMangled(); - Log *log = GetLog(LLDBLog::Object); - for (const auto &runtime : m_abi_runtimes) { - if (runtime->IsVTableSymbol(mangled)) { - LLDB_LOG(log, "{0:x16} ({1}): symbol='{2}' matches {3}", original_ptr, - in_value.GetTypeName(), mangled.GetDemangledName(), - runtime->GetName()); - - VTableInfoEntry entry{ - /*info=*/VTableInfo{vtable_addr, symbol}, - /*runtime=*/runtime.get(), - }; - std::lock_guard<std::mutex> locker(m_vtable_mutex); - m_vtable_info_map[vtable_addr] = entry; - return entry; - } - } - - LLDB_LOG(log, "{0:x16} ({1}): symbol='{2}' does not match any runtime", - original_ptr, in_value.GetTypeName(), mangled.GetDemangledName()); - - return llvm::createStringError(std::errc::invalid_argument, - "symbol found that contains 0x%" PRIx64 - " is not a vtable symbol", - vtable_load_addr); + return m_itanium_runtime.GetExceptionObjectForThread(std::move(thread_sp)); } diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index 823a968cbad8c..7c3dade76d703 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -13,7 +13,7 @@ #include "llvm/ADT/StringMap.h" -#include "CommonABIRuntime.h" +#include "ItaniumABIRuntime.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/lldb-private.h" @@ -143,18 +143,7 @@ class CPPLanguageRuntime : public LanguageRuntime { OperatorStringToCallableInfoMap CallableLookupCache; lldb::BreakpointSP m_cxx_exception_bp_sp; - std::vector<std::unique_ptr<CommonABIRuntime>> m_abi_runtimes; - - struct VTableInfoEntry { - VTableInfo info; - CommonABIRuntime *runtime; - }; - - llvm::Expected<VTableInfoEntry> GetVTableInfoEntry(ValueObject &in_value, - bool check_type); - - std::map<Address, VTableInfoEntry> m_vtable_info_map; - std::mutex m_vtable_mutex; + ItaniumABIRuntime m_itanium_runtime; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.cpp deleted file mode 100644 index e1241c0b583aa..0000000000000 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.cpp +++ /dev/null @@ -1,139 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 "CommonABIRuntime.h" - -#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Core/Module.h" -#include "lldb/Utility/LLDBLog.h" - -using namespace lldb; -using namespace lldb_private; - -CommonABIRuntime::CommonABIRuntime(Process *process) : m_process(process) {} - -bool CommonABIRuntime::IsVTableSymbol(Mangled &mangled) const { return false; } - -bool CommonABIRuntime::GetDynamicTypeAndAddress( - ValueObject &in_value, lldb::DynamicValueType use_dynamic, - const LanguageRuntime::VTableInfo &vtable_info, - TypeAndOrName &class_type_or_name, Address &dynamic_address) { - return false; -} - -void CommonABIRuntime::AppendExceptionBreakpointFunctions( - std::vector<const char *> &names, bool catch_bp, bool throw_bp, - bool for_expressions) {} - -void CommonABIRuntime::AppendExceptionBreakpointFilterModules( - FileSpecList &list, const Target &target) {} - -lldb::ValueObjectSP -CommonABIRuntime::GetExceptionObjectForThread(lldb::ThreadSP thread_sp) { - return {}; -} - -lldb::TypeSP -CommonABIRuntime::LookupTypeByName(llvm::StringRef type_name, - lldb::ModuleSP preferred_module) const { - Log *log = GetLog(LLDBLog::Object); - - TypeList class_types; - // We know the class name is absolute, so tell FindTypes that by - // prefixing it with the root namespace: - std::string lookup_name("::"); - lookup_name.append(type_name.data(), type_name.size()); - ConstString const_lookup_name(lookup_name); - // First look in the module that the vtable symbol came from and - // look for a single exact match. - TypeResults results; - TypeQuery query(const_lookup_name.GetStringRef(), - TypeQueryOptions::e_exact_match | - TypeQueryOptions::e_strict_namespaces | - TypeQueryOptions::e_find_one); - if (preferred_module) { - preferred_module->FindTypes(query, results); - TypeSP type_sp = results.GetFirstType(); - if (type_sp) - class_types.Insert(type_sp); - } - - // If we didn't find a symbol, then move on to the entire module - // list in the target and get as many unique matches as possible - if (class_types.Empty()) { - query.SetFindOne(false); - m_process->GetTarget().GetImages().FindTypes(nullptr, query, results); - for (const auto &type_sp : results.GetTypeMap().Types()) - class_types.Insert(type_sp); - } - - lldb::TypeSP type_sp; - if (class_types.Empty()) { - LLDB_LOG(log, "Failed to find '{0}'", type_name); - return {}; - } - - if (class_types.GetSize() == 1) { - type_sp = class_types.GetTypeAtIndex(0); - if (!type_sp) - return {}; - - if (!TypeSystemClang::IsCXXClassType(type_sp->GetForwardCompilerType())) - return {}; - return type_sp; - } - - size_t i; - if (log) { - LLDB_LOG(log, - "'{0}' has multiple matching dynamic " - "types:", - type_name); - for (i = 0; i < class_types.GetSize(); i++) { - type_sp = class_types.GetTypeAtIndex(i); - if (type_sp) { - LLDB_LOG(log, "[{0}]: uid={1:x}, type-name='{2}'", i, type_sp->GetID(), - type_sp->GetName()); - } - } - } - - for (i = 0; i < class_types.GetSize(); i++) { - type_sp = class_types.GetTypeAtIndex(i); - if (type_sp) { - if (TypeSystemClang::IsCXXClassType(type_sp->GetForwardCompilerType())) { - LLDB_LOG(log, - "'{0}' has multiple matching dynamic types, " - "picking this one: [{1}] uid={2:x}, type-name='{3}'\n", - type_name, i, type_sp->GetID(), type_sp->GetName()); - return type_sp; - } - } - } - - LLDB_LOG(log, - "'{0}' has multiple matching dynamic types, didn't find a C++ match", - type_name); - return {}; -} - -TypeAndOrName -CommonABIRuntime::GetDynamicTypeInfo(const lldb_private::Address &vtable_addr) { - std::lock_guard<std::mutex> locker(m_mutex); - DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr); - if (pos == m_dynamic_type_map.end()) - return TypeAndOrName(); - - return pos->second; -} - -void CommonABIRuntime::SetDynamicTypeInfo( - const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) { - std::lock_guard<std::mutex> locker(m_mutex); - m_dynamic_type_map[vtable_addr] = type_info; -} diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.h deleted file mode 100644 index b387ff0f8da8e..0000000000000 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CommonABIRuntime.h +++ /dev/null @@ -1,68 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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_COMMONABIRUNTIME_H -#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_COMMONABIRUNTIME_H - -#include "lldb/Target/LanguageRuntime.h" -#include "lldb/Target/Process.h" -#include "lldb/ValueObject/ValueObject.h" - -#include <map> -#include <mutex> - -namespace lldb_private { - -class CommonABIRuntime { -public: - virtual ~CommonABIRuntime() = default; - - virtual llvm::StringRef GetName() const = 0; - - virtual bool IsVTableSymbol(Mangled &mangled) const; - - virtual bool GetDynamicTypeAndAddress( - ValueObject &in_value, lldb::DynamicValueType use_dynamic, - const LanguageRuntime::VTableInfo &vtable_info, - TypeAndOrName &class_type_or_name, Address &dynamic_address); - - virtual void - AppendExceptionBreakpointFunctions(std::vector<const char *> &names, - bool catch_bp, bool throw_bp, - bool for_expressions); - - virtual void AppendExceptionBreakpointFilterModules(FileSpecList &list, - const Target &target); - - virtual lldb::ValueObjectSP - GetExceptionObjectForThread(lldb::ThreadSP thread_sp); - -protected: - CommonABIRuntime(Process *process); - - lldb::TypeSP LookupTypeByName(llvm::StringRef type_name, - lldb::ModuleSP preferred_module) const; - - TypeAndOrName GetDynamicTypeInfo(const lldb_private::Address &vtable_addr); - - void SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, - const TypeAndOrName &type_info); - -protected: - Process *m_process; - std::mutex m_mutex; - -private: - using DynamicTypeCache = std::map<Address, TypeAndOrName>; - - DynamicTypeCache m_dynamic_type_map; -}; - -} // namespace lldb_private - -#endif diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.cpp index 1fc835fa834db..4d9cf31c8904d 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.cpp @@ -19,13 +19,7 @@ using namespace lldb_private; static const char *vtable_demangled_prefix = "vtable for "; -ItaniumABIRuntime::ItaniumABIRuntime(Process *process) - : CommonABIRuntime(process) {} - -bool ItaniumABIRuntime::IsVTableSymbol(Mangled &mangled) const { - return mangled.GetDemangledName().GetStringRef().starts_with( - vtable_demangled_prefix); -} +ItaniumABIRuntime::ItaniumABIRuntime(Process *process) : m_process(process) {} TypeAndOrName ItaniumABIRuntime::GetTypeInfo(ValueObject &in_value, @@ -55,16 +49,94 @@ ItaniumABIRuntime::GetTypeInfo(ValueObject &in_value, lookup_name.append(class_name.data(), class_name.size()); type_info.SetName(class_name); - TypeSP type_sp = LookupTypeByName( - class_name, vtable_info.symbol->CalculateSymbolContextModule()); - if (type_sp) { - LLDB_LOG( - log, - "static-type = '{0}' has dynamic type: uid={1:x}, type-name='{2}'", - in_value.GetTypeName(), type_sp->GetID(), type_sp->GetName()); - type_info.SetTypeSP(std::move(type_sp)); + ConstString const_lookup_name(lookup_name); + TypeList class_types; + ModuleSP module_sp = vtable_info.symbol->CalculateSymbolContextModule(); + // First look in the module that the vtable symbol came from and + // look for a single exact match. + TypeResults results; + TypeQuery query(const_lookup_name.GetStringRef(), + TypeQueryOptions::e_exact_match | + TypeQueryOptions::e_strict_namespaces | + TypeQueryOptions::e_find_one); + if (module_sp) { + module_sp->FindTypes(query, results); + TypeSP type_sp = results.GetFirstType(); + if (type_sp) + class_types.Insert(type_sp); + } + + // If we didn't find a symbol, then move on to the entire module + // list in the target and get as many unique matches as possible + if (class_types.Empty()) { + query.SetFindOne(false); + m_process->GetTarget().GetImages().FindTypes(nullptr, query, results); + for (const auto &type_sp : results.GetTypeMap().Types()) + class_types.Insert(type_sp); } + lldb::TypeSP type_sp; + if (class_types.Empty()) { + LLDB_LOGF(log, "0x%16.16" PRIx64 ": is not dynamic\n", + in_value.GetPointerValue().address); + return TypeAndOrName(); + } + if (class_types.GetSize() == 1) { + type_sp = class_types.GetTypeAtIndex(0); + if (type_sp) { + if (TypeSystemClang::IsCXXClassType( + type_sp->GetForwardCompilerType())) { + LLDB_LOGF(log, + "0x%16.16" PRIx64 + ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 + "}, type-name='%s'\n", + in_value.GetPointerValue().address, + in_value.GetTypeName().AsCString(""), type_sp->GetID(), + type_sp->GetName().GetCString()); + type_info.SetTypeSP(type_sp); + } + } + } else { + size_t i; + if (log) { + for (i = 0; i < class_types.GetSize(); i++) { + type_sp = class_types.GetTypeAtIndex(i); + if (type_sp) { + LLDB_LOGF(log, + "0x%16.16" PRIx64 + ": static-type = '%s' has multiple matching dynamic " + "types: uid={0x%" PRIx64 "}, type-name='%s'\n", + in_value.GetPointerValue().address, + in_value.GetTypeName().AsCString(""), type_sp->GetID(), + type_sp->GetName().GetCString()); + } + } + } + + for (i = 0; i < class_types.GetSize(); i++) { + type_sp = class_types.GetTypeAtIndex(i); + if (type_sp) { + if (TypeSystemClang::IsCXXClassType( + type_sp->GetForwardCompilerType())) { + LLDB_LOGF(log, + "0x%16.16" PRIx64 ": static-type = '%s' has multiple " + "matching dynamic types, picking " + "this one: uid={0x%" PRIx64 "}, type-name='%s'\n", + in_value.GetPointerValue().address, + in_value.GetTypeName().AsCString(""), type_sp->GetID(), + type_sp->GetName().GetCString()); + type_info.SetTypeSP(type_sp); + } + } + } + + LLDB_LOGF(log, + "0x%16.16" PRIx64 + ": static-type = '%s' has multiple matching dynamic " + "types, didn't find a C++ match\n", + in_value.GetPointerValue().address, + in_value.GetTypeName().AsCString("")); + } if (type_info) SetDynamicTypeInfo(vtable_info.addr, type_info); return type_info; @@ -73,10 +145,114 @@ ItaniumABIRuntime::GetTypeInfo(ValueObject &in_value, return TypeAndOrName(); } +llvm::Error ItaniumABIRuntime::TypeHasVTable(CompilerType type) { + // Check to make sure the class has a vtable. + CompilerType original_type = type; + if (type.IsPointerOrReferenceType()) { + CompilerType pointee_type = type.GetPointeeType(); + if (pointee_type) + type = pointee_type; + } + + // Make sure this is a class or a struct first by checking the type class + // bitfield that gets returned. + if ((type.GetTypeClass() & (eTypeClassStruct | eTypeClassClass)) == 0) { + return llvm::createStringError( + std::errc::invalid_argument, + "type \"%s\" is not a class or struct or a pointer to one", + original_type.GetTypeName().AsCString("<invalid>")); + } + + // Check if the type has virtual functions by asking it if it is polymorphic. + if (!type.IsPolymorphicClass()) { + return llvm::createStringError(std::errc::invalid_argument, + "type \"%s\" doesn't have a vtable", + type.GetTypeName().AsCString("<invalid>")); + } + return llvm::Error::success(); +} + +// This function can accept both pointers or references to classes as well as +// instances of classes. If you are using this function during dynamic type +// detection, only valid ValueObjects that return true to +// CouldHaveDynamicValue(...) should call this function and \a check_type +// should be set to false. This function is also used by ValueObjectVTable +// and is can pass in instances of classes which is not suitable for dynamic +// type detection, these cases should pass true for \a check_type. +llvm::Expected<LanguageRuntime::VTableInfo> +ItaniumABIRuntime::GetVTableInfo(ValueObject &in_value, bool check_type) { + + CompilerType type = in_value.GetCompilerType(); + if (check_type) { + if (llvm::Error err = TypeHasVTable(type)) + return std::move(err); + } + ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); + Process *process = exe_ctx.GetProcessPtr(); + if (process == nullptr) + return llvm::createStringError(std::errc::invalid_argument, + "invalid process"); + + auto [original_ptr, address_type] = + type.IsPointerOrReferenceType() + ? in_value.GetPointerValue() + : in_value.GetAddressOf(/*scalar_is_load_address=*/true); + if (original_ptr == LLDB_INVALID_ADDRESS || address_type != eAddressTypeLoad) + return llvm::createStringError(std::errc::invalid_argument, + "failed to get the address of the value"); + + Status error; + lldb::addr_t vtable_load_addr = + process->ReadPointerFromMemory(original_ptr, error); + + if (!error.Success() || vtable_load_addr == LLDB_INVALID_ADDRESS) + return llvm::createStringError( + std::errc::invalid_argument, + "failed to read vtable pointer from memory at 0x%" PRIx64, + original_ptr); + + // The vtable load address can have authentication bits with + // AArch64 targets on Darwin. + vtable_load_addr = process->FixDataAddress(vtable_load_addr); + + // Find the symbol that contains the "vtable_load_addr" address + Address vtable_addr; + if (!process->GetTarget().ResolveLoadAddress(vtable_load_addr, vtable_addr)) + return llvm::createStringError(std::errc::invalid_argument, + "failed to resolve vtable pointer 0x%" PRIx64 + "to a section", + vtable_load_addr); + + // Check our cache first to see if we already have this info + { + std::lock_guard<std::mutex> locker(m_mutex); + auto pos = m_vtable_info_map.find(vtable_addr); + if (pos != m_vtable_info_map.end()) + return pos->second; + } + + Symbol *symbol = vtable_addr.CalculateSymbolContextSymbol(); + if (symbol == nullptr) + return llvm::createStringError(std::errc::invalid_argument, + "no symbol found for 0x%" PRIx64, + vtable_load_addr); + llvm::StringRef name = symbol->GetMangled().GetDemangledName().GetStringRef(); + if (name.starts_with(vtable_demangled_prefix)) { + LanguageRuntime::VTableInfo info = {vtable_addr, symbol}; + std::lock_guard<std::mutex> locker(m_mutex); + auto pos = m_vtable_info_map[vtable_addr] = info; + return info; + } + return llvm::createStringError(std::errc::invalid_argument, + "symbol found that contains 0x%" PRIx64 + " is not a vtable symbol", + vtable_load_addr); +} + bool ItaniumABIRuntime::GetDynamicTypeAndAddress( ValueObject &in_value, lldb::DynamicValueType use_dynamic, - const LanguageRuntime::VTableInfo &vtable_info, - TypeAndOrName &class_type_or_name, Address &dynamic_address) { + TypeAndOrName &class_type_or_name, Address &dynamic_address, + Value::ValueType &value_type) { // For Itanium, if the type has a vtable pointer in the object, it will be at // offset 0 in the object. That will point to the "address point" within the // vtable (not the beginning of the vtable.) We can then look up the symbol @@ -90,6 +266,14 @@ bool ItaniumABIRuntime::GetDynamicTypeAndAddress( // want GetVTableInfo to check the type since we accept void * as a possible // dynamic type and that won't pass the type check. We already checked the // type above in CouldHaveDynamicValue(...). + llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err = + GetVTableInfo(in_value, /*check_type=*/false); + if (!vtable_info_or_err) { + llvm::consumeError(vtable_info_or_err.takeError()); + return false; + } + + const LanguageRuntime::VTableInfo &vtable_info = vtable_info_or_err.get(); class_type_or_name = GetTypeInfo(in_value, vtable_info); if (!class_type_or_name) @@ -248,3 +432,19 @@ ItaniumABIRuntime::GetExceptionObjectForThread(ThreadSP thread_sp) { return exception; } + +TypeAndOrName ItaniumABIRuntime::GetDynamicTypeInfo( + const lldb_private::Address &vtable_addr) { + std::lock_guard<std::mutex> locker(m_mutex); + DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr); + if (pos == m_dynamic_type_map.end()) + return TypeAndOrName(); + else + return pos->second; +} + +void ItaniumABIRuntime::SetDynamicTypeInfo( + const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) { + std::lock_guard<std::mutex> locker(m_mutex); + m_dynamic_type_map[vtable_addr] = type_info; +} diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.h index e44e958da4067..75a8142b26d93 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABIRuntime.h @@ -9,7 +9,6 @@ #ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_ITANIUMABIRUNTIME_H #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_CPLUSPLUS_ITANIUMABIRUNTIME_H -#include "CommonABIRuntime.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/ValueObject/ValueObject.h" @@ -17,40 +16,47 @@ namespace lldb_private { -class ItaniumABIRuntime : public CommonABIRuntime { +class ItaniumABIRuntime { public: ItaniumABIRuntime(Process *process); - llvm::StringRef GetName() const override { return "Itanium ABI runtime"; } - - bool IsVTableSymbol(Mangled &manged) const override; - llvm::Expected<LanguageRuntime::VTableInfo> GetVTableInfo(ValueObject &in_value, bool check_type); bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - const LanguageRuntime::VTableInfo &vtable_info, TypeAndOrName &class_type_or_name, - Address &dynamic_address) override; + Address &dynamic_address, + Value::ValueType &value_type); void AppendExceptionBreakpointFunctions(std::vector<const char *> &names, bool catch_bp, bool throw_bp, - bool for_expressions) override; + bool for_expressions); void AppendExceptionBreakpointFilterModules(FileSpecList &list, - const Target &target) override; + const Target &target); - lldb::ValueObjectSP - GetExceptionObjectForThread(lldb::ThreadSP thread_sp) override; + lldb::ValueObjectSP GetExceptionObjectForThread(lldb::ThreadSP thread_sp); private: TypeAndOrName GetTypeInfo(ValueObject &in_value, const LanguageRuntime::VTableInfo &vtable_info); + llvm::Error TypeHasVTable(CompilerType type); + + TypeAndOrName GetDynamicTypeInfo(const lldb_private::Address &vtable_addr); + + void SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, + const TypeAndOrName &type_info); + + using DynamicTypeCache = std::map<Address, TypeAndOrName>; using VTableInfoCache = std::map<Address, LanguageRuntime::VTableInfo>; + DynamicTypeCache m_dynamic_type_map; VTableInfoCache m_vtable_info_map; + std::mutex m_mutex; + + Process *m_process; }; } // namespace lldb_private _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
