Michael137 updated this revision to Diff 450992.
Michael137 added a comment.
Herald added a subscriber: JDevlieghere.
- Reword commit message
- Replace `SymbolNameFitsToLanguage` check
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D131335/new/
https://reviews.llvm.org/D131335
Files:
lldb/packages/Python/lldbsuite/test/make/Makefile.rules
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
lldb/test/API/lang/cpp/abi_tag_lookup/Makefile
lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py
lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp
Index: lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp
@@ -0,0 +1,69 @@
+#include <cstdio>
+
+namespace A {
+template <typename T> bool operator<(const T &, const T &) { return true; }
+
+template <typename T>
+[[gnu::abi_tag("Two", "Tags")]] bool operator>(const T &, const T &) {
+ return true;
+}
+
+template <typename T>
+[[gnu::abi_tag("OneTag")]] bool operator==(const T &, const T &) {
+ return true;
+}
+
+[[gnu::abi_tag("Foo")]] int withAbiTagInNS(const int &, const int &) {
+ return 1;
+}
+
+template <typename T>
+[[gnu::abi_tag("Bar")]] int withAbiTagInNS(const T &, const T &) {
+ return 2;
+}
+
+struct B {};
+} // namespace A
+
+template <typename T>
+[[gnu::abi_tag("Baz")]] int withAbiTag(const T &, const T &) {
+ return 3;
+}
+
+struct Simple {
+ int mem;
+};
+
+struct [[gnu::abi_tag("Qux")]] Tagged {
+ int mem;
+
+ int const &Value() const { return mem; }
+};
+
+template <typename T> struct [[gnu::abi_tag("Quux", "Quuux")]] TaggedTemplate {
+ T mem;
+
+ T const &Value() const { return mem; }
+};
+
+// clang-format off
+inline namespace [[gnu::abi_tag("Inline", "NS")]] v1 {
+template <typename T> int withImplicitTag(T const &t) { return t.mem; }
+} // namespace
+// clang-format on
+
+int main() {
+ A::B b1;
+ A::B b2;
+ Tagged t{.mem = 4};
+ TaggedTemplate<int> tt{.mem = 5};
+
+ int result = (b1 < b2) + (b1 > b2) + (b1 == b2) + withAbiTag(b1, b2) +
+ A::withAbiTagInNS(1.0, 2.0) + withAbiTagInNS(b1, b2) +
+ A::withAbiTagInNS(1, 2) + withImplicitTag(Tagged{.mem = 6}) +
+ withImplicitTag(Simple{.mem = 6}) + t.Value() + tt.Value();
+
+ std::puts("Break here");
+
+ return result;
+}
Index: lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py
@@ -0,0 +1,55 @@
+"""
+Test that we can call functions and use types
+annotated (and thus mangled) with ABI tags.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class AbiTagLookupTestCase(TestBase):
+
+ @skipIfWindows
+ @expectedFailureAll(debug_info=["dwarf", "gmodules", "dwo"])
+ def test_abi_tag_lookup(self):
+ self.build()
+ lldbutil.run_to_source_breakpoint(self, 'Break here',
+ lldb.SBFileSpec("main.cpp", False))
+
+ # Qualified/unqualified lookup to templates in namespace
+ self.expect_expr("operator<(b1, b2)", result_type="bool", result_value="true")
+ self.expect_expr("A::operator<(b1, b2)", result_type="bool", result_value="true")
+ self.expect_expr("b1 < b2", result_type="bool", result_value="true")
+
+ # Qualified/unqualified lookup to templates with ABI tags in namespace
+ self.expect_expr("operator>(b1, b2)", result_type="bool", result_value="true")
+ self.expect_expr("A::operator>(b1, b2)", result_type="bool", result_value="true")
+ self.expect_expr("b1 > b2", result_type="bool", result_value="true")
+
+ # Call non-operator templates with ABI tags
+ self.expect_expr("A::withAbiTagInNS(1, 1)", result_type="int", result_value="1")
+
+ self.expect_expr("A::withAbiTagInNS(1.0, 1.0)", result_type="int", result_value="2")
+ self.expect_expr("withAbiTagInNS(b1, b2)", result_type="int", result_value="2")
+ self.expect_expr("A::withAbiTagInNS(b1, b2)", result_type="int", result_value="2")
+
+ self.expect_expr("withAbiTag(b1, b2)", result_type="int", result_value="3")
+
+ # Structures with ABI tags
+ self.expect_expr("t.Value()", result_type="const int", result_value="4")
+ self.expect_expr("tt.Value()", result_type="const int", result_value="5")
+
+ self.expect_expr("Tagged{.mem = 6}", result_type="Tagged",
+ result_children=[ValueCheck(name="mem", value="6")])
+
+ # Inline namespaces with ABI tags
+ self.expect_expr("v1::withImplicitTag(Simple{.mem = 6})", result_type="int", result_value="6")
+ self.expect_expr("withImplicitTag(Simple{.mem = 6})", result_type="int", result_value="6")
+
+ # FIXME: this currently fails because CPlusPlusLanguage::FindBestAlternateFunctionMangledName
+ # requires at least the parameters of the symbols it compares to match. However,
+ # the IR we generate doesn't include ABI tags on the parameter. To fix this we need
+ # to add ABI tag attributes to the decls that DWARFASTParserClang generates.
+ self.expect("expr v1::withImplicitTag(Tagged{.mem = 6})", error=True, substrs=["error: Couldn't lookup symbols:"])
+ self.expect("expr withImplicitTag(Tagged{.mem = 6})", error=True, substrs=["error: Couldn't lookup symbols:"])
Index: lldb/test/API/lang/cpp/abi_tag_lookup/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/abi_tag_lookup/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -107,7 +107,7 @@
static llvm::StringRef GetPluginNameStatic() { return "cplusplus"; }
bool SymbolNameFitsToLanguage(Mangled mangled) const override;
-
+
bool DemangledNameContainsPath(llvm::StringRef path,
ConstString demangled) const override;
@@ -142,6 +142,16 @@
// PluginInterface protocol
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+private:
+ void
+ CollectAlternateFunctionNamesFromMangled(std::vector<ConstString> &results,
+ ConstString name,
+ const SymbolContext &sc) const;
+
+ void CollectAlternateFunctionNamesItanium(std::vector<ConstString> &results,
+ ConstString name,
+ const SymbolContext &sc) const;
};
} // namespace lldb_private
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -18,6 +18,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Demangle/ItaniumDemangle.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
@@ -510,6 +512,22 @@
return alternates;
}
+char const *printNode(const llvm::itanium_demangle::Node *RootNode) {
+ llvm::itanium_demangle::OutputBuffer OB;
+ if (!initializeOutputBuffer(nullptr, nullptr, OB, 128))
+ return nullptr;
+ RootNode->print(OB);
+ OB += '\0';
+ return OB.getBuffer();
+}
+
+char const *getFunctionName(llvm::itanium_demangle::Node const *root) {
+ auto *Name =
+ static_cast<llvm::itanium_demangle::FunctionEncoding const *>(root)
+ ->getName();
+ return printNode(Name);
+}
+
static ConstString FindBestAlternateFunctionMangledName(
const Mangled mangled, const SymbolContext &sym_ctx) {
ConstString demangled = mangled.GetDemangledName();
@@ -560,6 +578,71 @@
return ConstString();
}
+ConstString
+FindBestAlternateFunctionMangledName(llvm::itanium_demangle::Node const *node,
+ const SymbolContext &sym_ctx) {
+ if (!sym_ctx.module_sp)
+ return ConstString();
+
+ lldb_private::SymbolFile *sym_file = sym_ctx.module_sp->GetSymbolFile();
+ if (!sym_file)
+ return ConstString();
+
+ using namespace llvm::itanium_demangle;
+ assert(node != nullptr);
+
+ if (node->getKind() != Node::KFunctionEncoding)
+ return ConstString();
+
+ std::vector<ConstString> alternates;
+ sym_file->GetMangledNamesForFunction(getFunctionName(node), alternates);
+
+ auto const *encoding = static_cast<FunctionEncoding const *>(node);
+ Qualifiers quals = encoding->getCVQuals();
+ FunctionRefQual refQual = encoding->getRefQual();
+ NodeArray params = encoding->getParams();
+ auto const *attrs = encoding->getAttrs();
+
+ std::vector<ConstString> param_matches;
+ for (size_t i = 0; i < alternates.size(); i++) {
+ ConstString alternate_mangled_name = alternates[i];
+ char const *alternate = alternate_mangled_name.AsCString();
+
+ ManglingParser<NodeAllocator> alternate_parser(
+ alternate, alternate + std::strlen(alternate));
+ if (auto const *alt_node = alternate_parser.parse()) {
+ assert(alt_node->getKind() == Node::KFunctionEncoding);
+ auto const *alt_encoding =
+ static_cast<FunctionEncoding const *>(alt_node);
+ Qualifiers alt_quals = alt_encoding->getCVQuals();
+ FunctionRefQual alt_refQual = alt_encoding->getRefQual();
+ NodeArray alt_params = alt_encoding->getParams();
+ auto const *alt_attrs = alt_encoding->getAttrs();
+
+ if (params == alt_params) {
+ if (quals == alt_quals && refQual == alt_refQual) {
+ if ((attrs && alt_attrs && attrs->equals(alt_attrs)) ||
+ (!attrs && !alt_attrs)) {
+ // Perfect match. Return it.
+ return alternate_mangled_name;
+ }
+ }
+
+ // Not a perfect match, but count matching parameters
+ // as an approximate match.
+ param_matches.push_back(alternate_mangled_name);
+ }
+ }
+ }
+
+ // No perfect match. Return one of the approximate
+ // matches as a best match
+ if (param_matches.size())
+ return param_matches[0];
+
+ // No matches.
+ return ConstString();
+}
static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
@@ -1407,27 +1490,78 @@
return file_path.contains("/usr/include/c++/");
}
+void CPlusPlusLanguage::CollectAlternateFunctionNamesFromMangled(
+ std::vector<ConstString> &results, ConstString name,
+ const SymbolContext &sc) const {
+ Mangled mangled(name);
+ if (SymbolNameFitsToLanguage(mangled)) {
+ if (ConstString best_alternate =
+ FindBestAlternateFunctionMangledName(mangled, sc)) {
+ results.push_back(best_alternate);
+ }
+ }
+
+ std::vector<ConstString> alternates =
+ GenerateAlternateFunctionManglings(name);
+ results.insert(results.end(), alternates.begin(), alternates.end());
+
+ // As a last-ditch fallback, try the base name for C++ names. It's
+ // terrible, but the DWARF doesn't always encode "extern C" correctly.
+ ConstString basename = GetDemangledFunctionNameWithoutArguments(mangled);
+ results.push_back(basename);
+}
+
+void CPlusPlusLanguage::CollectAlternateFunctionNamesItanium(
+ std::vector<ConstString> &results, ConstString name,
+ const SymbolContext &sc) const {
+ if (!name)
+ return;
+
+ char const *mangled = name.GetCString();
+ using namespace llvm::itanium_demangle;
+ ManglingParser<NodeAllocator> parser(mangled, mangled + std::strlen(mangled));
+ auto const *node = parser.parse();
+
+ if (node && CPlusPlusLanguage::IsCPPMangledName(name.GetStringRef())) {
+ if (ConstString best_alternate =
+ FindBestAlternateFunctionMangledName(node, sc)) {
+ results.push_back(best_alternate);
+ }
+ }
+
+ std::vector<ConstString> alternates =
+ GenerateAlternateFunctionManglings(name);
+ results.insert(results.end(), alternates.begin(), alternates.end());
+
+ // As a last-ditch fallback, try the base name for C++ names. It's
+ // terrible, but the DWARF doesn't always encode "extern C" correctly.
+ if (node) {
+ ConstString basename(getFunctionName(node));
+ results.push_back(basename);
+ }
+}
+
void CPlusPlusLanguage::CollectAlternateFunctionNames(
std::vector<ConstString> &results,
const std::vector<ConstString> &mangled_names,
const SymbolContext &sc) const {
for (const ConstString &name : mangled_names) {
- Mangled mangled(name);
- if (SymbolNameFitsToLanguage(mangled)) {
- if (ConstString best_alternate =
- FindBestAlternateFunctionMangledName(mangled, sc)) {
- results.push_back(best_alternate);
+ auto scheme = Mangled::GetManglingScheme(name.GetStringRef());
+ switch (scheme) {
+ case Mangled::ManglingScheme::eManglingSchemeItanium:
+ CollectAlternateFunctionNamesItanium(results, name, sc);
+ break;
+ case Mangled::ManglingScheme::eManglingSchemeNone:
+ if (name.GetStringRef().startswith("__Z")) {
+ CollectAlternateFunctionNamesItanium(results, name, sc);
+ break;
}
+ LLVM_FALLTHROUGH;
+ case Mangled::ManglingScheme::eManglingSchemeMSVC:
+ case Mangled::ManglingScheme::eManglingSchemeRustV0:
+ case Mangled::ManglingScheme::eManglingSchemeD:
+ CollectAlternateFunctionNamesFromMangled(results, name, sc);
+ break;
}
-
- std::vector<ConstString> alternates =
- GenerateAlternateFunctionManglings(name);
- results.insert(results.end(), alternates.begin(), alternates.end());
-
- // As a last-ditch fallback, try the base name for C++ names. It's
- // terrible, but the DWARF doesn't always encode "extern C" correctly.
- ConstString basename =
- GetDemangledFunctionNameWithoutArguments(mangled);
- results.push_back(basename);
}
}
Index: lldb/packages/Python/lldbsuite/test/make/Makefile.rules
===================================================================
--- lldb/packages/Python/lldbsuite/test/make/Makefile.rules
+++ lldb/packages/Python/lldbsuite/test/make/Makefile.rules
@@ -387,8 +387,7 @@
endif
ifeq (1,$(USE_LIBCPP))
- # TODO: Teach LLDB to handle ABI tags in libc++ namespaces.
- CXXFLAGS += -DLLDB_USING_LIBCPP -D_LIBCPP_NO_ABI_TAG
+ CXXFLAGS += -DLLDB_USING_LIBCPP
ifeq "$(OS)" "Android"
# Nothing to do, this is already handled in
# Android.rules.
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits