================
@@ -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)
----------------
Michael137 wrote:
> Okay, I guess this is why. I don't think this will work, for the reasons
> outlined in the other comment. This needs to be a structural match between
> the two DIEs, maybe facilitated by
> DWARFASTParserClang::CopyUniqueClassMethodTypes.
That's a good point. This mainly cropped up in the test-suite for type-units,
but yea this need not be related to them. I guess this is similar to the other
case you pointed out where the declaration DIE might be in a different module
than the definition. For those cases we also ended up falling back on the old
lookup. So the type-unit check is actually redundant because we can just rely
on the fallback lookup. But if we want to support a wider range we'd have to
change this specification check. Happy to try and change it to a structural
match though.
> Given then ABI tags are meant to allow different versions of the same class
> to coexist, then if you want to support these different versions coexisting,
> then the DWARF sort of has to contain the ABI tag information as it relies on
> structural matches to connect DIEs from different compilation units. Maybe
> this is irrelevant as you don't want to support this "coexistence" (I believe
> you just want to "deal with" the presence of ABI tags), but I think this
> might make a reasonable case for encoding the ABI tag information (in one way
> or another) in DWARF.
Hmm interesting point. Trying out the case where we have two ABI-tagged
structures in two TUs, it looks like Clang/ld64 decide to emit two structure
types with the same name only if there is a structural mismatch:
```
// lib.cpp
#include <cassert>
struct [[gnu::abi_tag("Lib")]] A {
A() {}
int mem = 5;
} a;
void func() {
assert (a.mem == 5);
}
// main.cpp
#include <cassert>
struct [[gnu::abi_tag("Main")]] A {
A() {}
int mem = 10;
} a;
void func();
int main(int argc, char **argv) {
func();
assert (a.mem == 10);
return 0;
}
```
Here `a` in `lib.o` would point to the `DW_TAG_structure_type` of `main.o`, but
the subprogram definitions for the constructors are different (and local to
each CU).
If we change the structure layout though we get a `DW_TAG_structure_type` in
each CU. But if they only differ by which methods they carry we only emit 1
definition!
I guess for now the goal of the expression evaluator is to just support two
versions of the same function (with different tags). Which is the easier
version of this problem you outline. I don't think we had reservations about
encoding ABI-tag information into DWARF. The concerns were:
1. debug-info size (libc++ uses these tags on a ton of APIs).
2. whether we want to rely on AST fidelity again
3. libc++ makes no guarantee that they'll continue annotating individual APIs
in the future and might put the tags on namespaces/structures. At which point
LLDB will need to take care to propagate the tags appropriately (maybe this
will be handled by Clang out-of-the-box, though I haven't thought about this
specific point in detail)
Do you prefer us looking into alternatives to the approach in this PR? E.g.,
make DWARF do some of the heavy lifting? We could put e.g., the structor
variant info into DWARF, alleviating the need for demangling, etc.
https://github.com/llvm/llvm-project/pull/149827
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits