Author: Michael Buch Date: 2022-08-17T09:02:43+01:00 New Revision: 88d3c1db453189c3c76b5b83e4d47b2c7f4adf1f
URL: https://github.com/llvm/llvm-project/commit/88d3c1db453189c3c76b5b83e4d47b2c7f4adf1f DIFF: https://github.com/llvm/llvm-project/commit/88d3c1db453189c3c76b5b83e4d47b2c7f4adf1f.diff LOG: [lldb][ClangExpression] Add asm() label to all FunctionDecls we create from DWARF When resolving symbols during IR execution, lldb makes a last effort attempt to resolve external symbols from object files by approximate name matching. It currently uses `CPlusPlusNameParser` to parse the demangled function name and arguments for the unresolved symbol and its candidates. However, this hand-rolled C++ parser doesn’t support ABI tags which, depending on the demangler, get demangled into `[abi:tag]`. This lack of parsing support causes lldb to never consider a candidate mangled function name that has ABI tags. The issue reproduces by calling an ABI-tagged template function from the expression evaluator. This is particularly problematic with the recent addition of ABI tags to numerous libcxx APIs. The issue stems from the fact that `clang::CodeGen` emits function function calls using the mangled name inferred from the `FunctionDecl` LLDB constructs from DWARF. Debug info often lacks information for us to construct a perfect FunctionDecl resulting in subtle mangled name inaccuracies. This patch side-steps the problem of inaccurate `FunctionDecl`s by attaching an `asm()` label to each `FunctionDecl` LLDB creates from DWARF. `clang::CodeGen` consults this label to get the mangled name as one of the first courses of action when emitting a function call. LLDB already does this for C++ member functions as of [675767a5910d2ec77ef8b51c78fe312cf9022896](https://reviews.llvm.org/D40283) **Testing** * Added API tests Differential Revision: https://reviews.llvm.org/D131974 Added: 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 Modified: lldb/packages/Python/lldbsuite/test/make/Makefile.rules lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp Removed: ################################################################################ diff --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules index 52b800b1eb36d..b065a43cb1934 100644 --- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules +++ b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules @@ -387,8 +387,7 @@ ifeq (1,$(USE_LIBSTDCPP)) 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. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 20eb49ddb45cc..fda68f289a397 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1248,6 +1248,20 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, lldbassert(function_decl); if (function_decl) { + // Attach an asm(<mangled_name>) label to the FunctionDecl. + // This ensures that clang::CodeGen emits function calls + // using symbols that are mangled according to the DW_AT_linkage_name. + // If we didn't do this, the external symbols wouldn't exactly + // match the mangled name LLDB knows about and the IRExecutionUnit + // would have to fall back to searching object files for + // approximately matching function names. The motivating + // example is generating calls to ABI-tagged template functions. + // This is done separately for member functions in + // AddMethodToCXXRecordType. + if (attrs.mangled_name && attrs.storage == clang::SC_Extern) + function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( + m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false)); + LinkDeclContextToDIE(function_decl, die); if (!function_param_decls.empty()) { diff --git a/lldb/test/API/lang/cpp/abi_tag_lookup/Makefile b/lldb/test/API/lang/cpp/abi_tag_lookup/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/lang/cpp/abi_tag_lookup/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py b/lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py new file mode 100644 index 0000000000000..1a1b8692f430d --- /dev/null +++ b/lldb/test/API/lang/cpp/abi_tag_lookup/TestAbiTagLookup.py @@ -0,0 +1,52 @@ +""" +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") + self.expect_expr("withAbiTag(0, 0)", 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") + + self.expect_expr("v1::withImplicitTag(Tagged{.mem = 6})", result_type="int", result_value="6") + self.expect_expr("withImplicitTag(Tagged{.mem = 6})", result_type="int", result_value="6") diff --git a/lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp b/lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp new file mode 100644 index 0000000000000..4c1ff688df0cd --- /dev/null +++ b/lldb/test/API/lang/cpp/abi_tag_lookup/main.cpp @@ -0,0 +1,71 @@ +#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; +} + +[[gnu::abi_tag("Baz")]] int withAbiTag(const int &, const int &) { 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; +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits