================ @@ -2482,6 +2485,134 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } +static int ClangToItaniumCtorKind(clang::CXXCtorType kind) { + switch (kind) { + case clang::CXXCtorType::Ctor_Complete: + return 1; + case clang::CXXCtorType::Ctor_Base: + return 2; + case clang::CXXCtorType::Ctor_CopyingClosure: + case clang::CXXCtorType::Ctor_DefaultClosure: + case clang::CXXCtorType::Ctor_Comdat: + llvm_unreachable("Unexpected constructor kind."); + } +} + +static int ClangToItaniumDtorKind(clang::CXXDtorType kind) { + switch (kind) { + case clang::CXXDtorType::Dtor_Deleting: + return 0; + case clang::CXXDtorType::Dtor_Complete: + return 1; + case clang::CXXDtorType::Dtor_Base: + return 2; + case clang::CXXDtorType::Dtor_Comdat: + llvm_unreachable("Unexpected destructor kind."); + } +} + +static std::optional<int> +GetItaniumCtorDtorVariant(llvm::StringRef discriminator) { + const bool is_ctor = discriminator.consume_front("C"); + if (!is_ctor && !discriminator.consume_front("D")) + return std::nullopt; + + uint64_t structor_kind; + if (!llvm::to_integer(discriminator, structor_kind)) + return std::nullopt; + + if (is_ctor) { + if (structor_kind > clang::CXXCtorType::Ctor_DefaultClosure) + return std::nullopt; + + return ClangToItaniumCtorKind( + static_cast<clang::CXXCtorType>(structor_kind)); + } + + if (structor_kind > clang::CXXDtorType::Dtor_Comdat) + return std::nullopt; + + return ClangToItaniumDtorKind(static_cast<clang::CXXDtorType>(structor_kind)); +} + +DWARFDIE SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label, + const DWARFDIE &declaration) { + DWARFDIE definition; + llvm::DenseMap<int, DWARFDIE> structor_variant_to_die; + + // eFunctionNameTypeFull for mangled name lookup. + // eFunctionNameTypeMethod is required for structor lookups (since we look + // those up by DW_AT_name). + Module::LookupInfo info(ConstString(label.lookup_name), + lldb::eFunctionNameTypeFull | + lldb::eFunctionNameTypeMethod, + lldb::eLanguageTypeUnknown); + + m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) + return IterationAction::Continue; + + auto spec = entry.GetAttributeValueAsReferenceDIE(DW_AT_specification); + if (!spec) + return IterationAction::Continue; + + if (spec != declaration) ---------------- labath wrote:
> Would a structural match here help though? If the declaration DIE for a ctor > got encoded into the AsmLabel but the definition lives in a different CU (and > thus SymbolFile), we wouldn't be able to find it anyway using our approach > right? The scenario I have in mind is this: ``` $ head a.h a.cc b.cc ==> a.h <== struct A { int x; A(); }; ==> a.cc <== #include "a.h" A a; int main() { return a.x; } ==> b.cc <== #include "a.h" A::A() : x(47) {} ``` if you compile this (on linux you need to use -fstandalone-debug to get the definition of `A` in both files, on darwin you need to make sure dsymutil doesn't get run an coalesce the definitions), you will have a definition of `A` in both files, a *declaration* of `A::A` in both files, and a *definition* of `A::A` in `b.o` *only*. The existence of two declarations is the problem. We normally assume, per the ODR rule, that two definitions of the type are equivalent. And they basically are -- the two definitions of `A` (and the declaration of `A::A` contained within them) will have the exact same DIE tree. But of course, only one of those DIEs will be referred to via `DW_AT_specification` from the definition of `A::A`. If lldb parses `A` using the definition from `a.o` (the easiest way to ensure that is do a `target variable a` -- this makes lldb reach the `A` DIE by following the `DW_AT_type` from the variable `a` (which exists only in `a.o`), the type and all of the methods contained within it will be associated with the copies in `a.o`. This will cause a mismatch as that not the DIE you will reach by following `DW_AT_specification` from the constructor definition. Some sort of a structural match is needed to ensure the two DIEs are in fact the same constructor. You're right that this only works if the two types are in the same module (I consider a collection of `.o` modules on Darwin as a single module as there's SymbolFileDWARFDebugMap sitting on top of them), but I hope that's enough for now. We could do it across modules, but we'd have to come up with a way to compare DIE trees across modules (without breaking plugin abstractions). https://github.com/llvm/llvm-project/pull/149827 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits