From 17eecb2799db527984f10a73aefb7bd1bf7bd6a9 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 6 Oct 2021 13:00:42 -0700 Subject: [PATCH 1/5] Use llvm::VersionTuple to store DWARF producer info (NFC) This has the nice side-effect that it can actually store the quadruple version numbers that Apple's tools are using nowadays. rdar://82982162 Differential Revision: https://reviews.llvm.org/D111200 (cherry picked from commit 14aa3f3703b54854dcd5aa270f68515388420e6f) Conflicts: lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp --- .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 58 +++++-------------- .../Plugins/SymbolFile/DWARF/DWARFUnit.h | 12 +--- .../SymbolFile/DWARF/DWARFUnitTest.cpp | 39 +++++++++++++ 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 824e43872269b..a1ddc40f09886 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -609,52 +609,38 @@ bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() { } bool DWARFUnit::Supports_unnamed_objc_bitfields() { - if (GetProducer() == eProducerClang) { - const uint32_t major_version = GetProducerVersionMajor(); - return major_version > 425 || - (major_version == 425 && GetProducerVersionUpdate() >= 13); - } - return true; // Assume all other compilers didn't have incorrect ObjC bitfield - // info + if (GetProducer() == eProducerClang) + return GetProducerVersion() >= llvm::VersionTuple(425, 0, 13); + // Assume all other compilers didn't have incorrect ObjC bitfield info. + return true; } void DWARFUnit::ParseProducerInfo() { - m_producer_version_major = UINT32_MAX; - m_producer_version_minor = UINT32_MAX; - m_producer_version_update = UINT32_MAX; - const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); if (die) { - const char *producer_cstr = die->GetAttributeValueAsString(this, DW_AT_producer, nullptr); - if (producer_cstr) { + llvm::StringRef producer(producer_cstr); + if (!producer.empty()) { RegularExpression llvm_gcc_regex( llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " "Inc\\. build [0-9]+\\) \\(LLVM build " "[\\.0-9]+\\)$")); - if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { + if (llvm_gcc_regex.Execute(producer)) { m_producer = eProducerLLVMGCC; - } else if (strstr(producer_cstr, "clang")) { + } else if (producer.contains("clang")) { static RegularExpression g_clang_version_regex( - llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); + llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); llvm::SmallVector matches; - if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), - &matches)) { - m_producer_version_major = - StringConvert::ToUInt32(matches[1].str().c_str(), UINT32_MAX, 10); - m_producer_version_minor = - StringConvert::ToUInt32(matches[2].str().c_str(), UINT32_MAX, 10); - m_producer_version_update = - StringConvert::ToUInt32(matches[3].str().c_str(), UINT32_MAX, 10); - } + if (g_clang_version_regex.Execute(producer, &matches)) + m_producer_version.tryParse(matches[1]); m_producer = eProducerClang; - } else if (strstr(producer_cstr, "GNU")) + } else if (producer.contains("GNU")) m_producer = eProducerGCC; } } if (m_producer == eProducerInvalid) - m_producer = eProcucerOther; + m_producer = eProducerOther; } DWARFProducer DWARFUnit::GetProducer() { @@ -663,22 +649,10 @@ DWARFProducer DWARFUnit::GetProducer() { return m_producer; } -uint32_t DWARFUnit::GetProducerVersionMajor() { - if (m_producer_version_major == 0) - ParseProducerInfo(); - return m_producer_version_major; -} - -uint32_t DWARFUnit::GetProducerVersionMinor() { - if (m_producer_version_minor == 0) - ParseProducerInfo(); - return m_producer_version_minor; -} - -uint32_t DWARFUnit::GetProducerVersionUpdate() { - if (m_producer_version_update == 0) +llvm::VersionTuple DWARFUnit::GetProducerVersion() { + if (m_producer_version.empty()) ParseProducerInfo(); - return m_producer_version_update; + return m_producer_version; } uint64_t DWARFUnit::GetDWARFLanguageType() { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index da79a6aaf64e5..59bf28f637844 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -29,7 +29,7 @@ enum DWARFProducer { eProducerClang, eProducerGCC, eProducerLLVMGCC, - eProcucerOther + eProducerOther }; /// Base class describing the header of any kind of "unit." Some information @@ -194,11 +194,7 @@ class DWARFUnit : public lldb_private::UserID { DWARFProducer GetProducer(); - uint32_t GetProducerVersionMajor(); - - uint32_t GetProducerVersionMinor(); - - uint32_t GetProducerVersionUpdate(); + llvm::VersionTuple GetProducerVersion(); uint64_t GetDWARFLanguageType(); @@ -308,9 +304,7 @@ class DWARFUnit : public lldb_private::UserID { std::unique_ptr m_func_aranges_up; dw_addr_t m_base_addr = 0; DWARFProducer m_producer = eProducerInvalid; - uint32_t m_producer_version_major = 0; - uint32_t m_producer_version_minor = 0; - uint32_t m_producer_version_update = 0; + llvm::VersionTuple m_producer_version; llvm::Optional m_language_type; lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; llvm::Optional m_comp_dir; diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp index f5cfd1e61120b..5b36f22aea1b9 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp @@ -84,3 +84,42 @@ TEST(DWARFUnitTest, MissingSentinel) { EXPECT_EQ(die_first->GetFirstChild(), nullptr); EXPECT_EQ(die_first->GetSibling(), nullptr); } + +TEST(DWARFUnitTest, Producer) { + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_str: + - 'Apple clang version 13.0.0 (clang-1300.0.29.3)' + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_strp + - Attribute: DW_AT_language + Form: DW_FORM_data2 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x1 + Values: + - Value: 0x0 + - Value: 0xC + - AbbrCode: 0x0 +)"; + + YAMLModuleTester t(yamldata); + DWARFUnit *unit = t.GetDwarfUnit(); + ASSERT_TRUE((bool)unit); + EXPECT_EQ(unit->GetProducer(), eProducerClang); + EXPECT_EQ(unit->GetProducerVersion(), llvm::VersionTuple(1300, 0, 29, 3)); +} From 6ce519ec9f967742f91a209f40bcf7b4e076da1a Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 6 Oct 2021 14:30:02 -0700 Subject: [PATCH 2/5] Simplify control flow (NFC) (cherry picked from commit 2edb9058ea635f950f67bf7cb52f76588d362dfc) --- .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index a1ddc40f09886..f981dd4b6ce11 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -616,31 +616,31 @@ bool DWARFUnit::Supports_unnamed_objc_bitfields() { } void DWARFUnit::ParseProducerInfo() { + m_producer = eProducerOther; const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); - if (die) { - const char *producer_cstr = - die->GetAttributeValueAsString(this, DW_AT_producer, nullptr); - llvm::StringRef producer(producer_cstr); - if (!producer.empty()) { - RegularExpression llvm_gcc_regex( - llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " - "Inc\\. build [0-9]+\\) \\(LLVM build " - "[\\.0-9]+\\)$")); - if (llvm_gcc_regex.Execute(producer)) { - m_producer = eProducerLLVMGCC; - } else if (producer.contains("clang")) { - static RegularExpression g_clang_version_regex( - llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); - llvm::SmallVector matches; - if (g_clang_version_regex.Execute(producer, &matches)) - m_producer_version.tryParse(matches[1]); - m_producer = eProducerClang; - } else if (producer.contains("GNU")) - m_producer = eProducerGCC; - } - } - if (m_producer == eProducerInvalid) - m_producer = eProducerOther; + if (!die) + return; + + llvm::StringRef producer( + die->GetAttributeValueAsString(this, DW_AT_producer, nullptr)); + if (producer.empty()) + return; + + static RegularExpression llvm_gcc_regex( + llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " + "Inc\\. build [0-9]+\\) \\(LLVM build " + "[\\.0-9]+\\)$")); + if (llvm_gcc_regex.Execute(producer)) { + m_producer = eProducerLLVMGCC; + } else if (producer.contains("clang")) { + static RegularExpression g_clang_version_regex( + llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); + llvm::SmallVector matches; + if (g_clang_version_regex.Execute(producer, &matches)) + m_producer_version.tryParse(matches[1]); + m_producer = eProducerClang; + } else if (producer.contains("GNU")) + m_producer = eProducerGCC; } DWARFProducer DWARFUnit::GetProducer() { From 8d10843a2c794bdee0bdf6b14e97bc192306be30 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 6 Oct 2021 14:44:32 -0700 Subject: [PATCH 3/5] Add a unit test for llvm-gcc producer strings and cleanup code. (NFC) (cherry picked from commit 8c5f3348af38843b5f0ca13e82cc285af4e3582d) --- .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 17 ++++---- .../SymbolFile/DWARF/DWARFUnitTest.cpp | 40 +++++++++++++++++-- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index f981dd4b6ce11..2243787f9c714 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -626,16 +626,17 @@ void DWARFUnit::ParseProducerInfo() { if (producer.empty()) return; - static RegularExpression llvm_gcc_regex( - llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " - "Inc\\. build [0-9]+\\) \\(LLVM build " - "[\\.0-9]+\\)$")); - if (llvm_gcc_regex.Execute(producer)) { + static RegularExpression g_llvm_gcc_regex( + llvm::StringRef(R"(4\.[012]\.[01] )" + R"(\(Based on Apple Inc\. build [0-9]+\) )" + R"(\(LLVM build [\.0-9]+\)$)")); + static RegularExpression g_clang_version_regex( + llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); + + if (g_llvm_gcc_regex.Execute(producer)) { m_producer = eProducerLLVMGCC; } else if (producer.contains("clang")) { - static RegularExpression g_clang_version_regex( - llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); - llvm::SmallVector matches; + llvm::SmallVector matches; if (g_clang_version_regex.Execute(producer, &matches)) m_producer_version.tryParse(matches[1]); m_producer = eProducerClang; diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp index 5b36f22aea1b9..85e3ae3cd8a5f 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp @@ -85,7 +85,7 @@ TEST(DWARFUnitTest, MissingSentinel) { EXPECT_EQ(die_first->GetSibling(), nullptr); } -TEST(DWARFUnitTest, Producer) { +TEST(DWARFUnitTest, ClangProducer) { const char *yamldata = R"( --- !ELF FileHeader: @@ -104,8 +104,6 @@ TEST(DWARFUnitTest, Producer) { Attributes: - Attribute: DW_AT_producer Form: DW_FORM_strp - - Attribute: DW_AT_language - Form: DW_FORM_data2 debug_info: - Version: 4 AddrSize: 8 @@ -113,7 +111,6 @@ TEST(DWARFUnitTest, Producer) { - AbbrCode: 0x1 Values: - Value: 0x0 - - Value: 0xC - AbbrCode: 0x0 )"; @@ -123,3 +120,38 @@ TEST(DWARFUnitTest, Producer) { EXPECT_EQ(unit->GetProducer(), eProducerClang); EXPECT_EQ(unit->GetProducerVersion(), llvm::VersionTuple(1300, 0, 29, 3)); } + +TEST(DWARFUnitTest, LLVMGCCProducer) { + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_str: + - 'i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)' + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_strp + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x1 + Values: + - Value: 0x0 + - AbbrCode: 0x0 +)"; + + YAMLModuleTester t(yamldata); + DWARFUnit *unit = t.GetDwarfUnit(); + ASSERT_TRUE((bool)unit); + EXPECT_EQ(unit->GetProducer(), eProducerLLVMGCC); +} From d0e1226bafdbeabfe92c881cd281bb57e808d326 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 6 Oct 2021 15:04:36 -0700 Subject: [PATCH 4/5] Recognize the Swift compiler in DW_AT_producer This patch adds support for Swift compiler producer strings to DWARFUnit. Differential Revision: https://reviews.llvm.org/D111278 (cherry picked from commit aab7afeec1fb771c8ae044257d44f6362d72c732) --- .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 18 ++++++---- .../Plugins/SymbolFile/DWARF/DWARFUnit.h | 1 + .../SymbolFile/DWARF/DWARFUnitTest.cpp | 36 +++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 2243787f9c714..fdc5e1c1efd2f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -626,22 +626,28 @@ void DWARFUnit::ParseProducerInfo() { if (producer.empty()) return; + static RegularExpression g_swiftlang_version_regex( + llvm::StringRef(R"(swiftlang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); + static RegularExpression g_clang_version_regex( + llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); static RegularExpression g_llvm_gcc_regex( llvm::StringRef(R"(4\.[012]\.[01] )" R"(\(Based on Apple Inc\. build [0-9]+\) )" R"(\(LLVM build [\.0-9]+\)$)")); - static RegularExpression g_clang_version_regex( - llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))")); - if (g_llvm_gcc_regex.Execute(producer)) { - m_producer = eProducerLLVMGCC; + llvm::SmallVector matches; + if (g_swiftlang_version_regex.Execute(producer, &matches)) { + m_producer_version.tryParse(matches[1]); + m_producer = eProducerSwift; } else if (producer.contains("clang")) { - llvm::SmallVector matches; if (g_clang_version_regex.Execute(producer, &matches)) m_producer_version.tryParse(matches[1]); m_producer = eProducerClang; - } else if (producer.contains("GNU")) + } else if (producer.contains("GNU")) { m_producer = eProducerGCC; + } else if (g_llvm_gcc_regex.Execute(producer)) { + m_producer = eProducerLLVMGCC; + } } DWARFProducer DWARFUnit::GetProducer() { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 59bf28f637844..315c77a78f110 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -29,6 +29,7 @@ enum DWARFProducer { eProducerClang, eProducerGCC, eProducerLLVMGCC, + eProducerSwift, eProducerOther }; diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp index 85e3ae3cd8a5f..123acb6ea8e3f 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp @@ -155,3 +155,39 @@ TEST(DWARFUnitTest, LLVMGCCProducer) { ASSERT_TRUE((bool)unit); EXPECT_EQ(unit->GetProducer(), eProducerLLVMGCC); } + +TEST(DWARFUnitTest, SwiftProducer) { + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_str: + - 'Apple Swift version 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1)' + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_strp + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x1 + Values: + - Value: 0x0 + - AbbrCode: 0x0 +)"; + + YAMLModuleTester t(yamldata); + DWARFUnit *unit = t.GetDwarfUnit(); + ASSERT_TRUE((bool)unit); + EXPECT_EQ(unit->GetProducer(), eProducerSwift); + EXPECT_EQ(unit->GetProducerVersion(), llvm::VersionTuple(1300, 0, 31, 1)); +} From 639b9f6357e7346b3eab0c2ce8eccfebd3e8cb6d Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 6 Oct 2021 18:45:15 -0700 Subject: [PATCH 5/5] Implement a warning that detects Swift compile units that were compiled with a different Swift compiler than the one that is embedded in LLDB. rdar://82982242 --- lldb/include/lldb/Symbol/SymbolFile.h | 3 ++ lldb/include/lldb/Target/Process.h | 12 +++++- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 10 +++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 2 + .../DWARF/SymbolFileDWARFDebugMap.cpp | 9 +++++ .../DWARF/SymbolFileDWARFDebugMap.h | 2 + lldb/source/Target/Process.cpp | 32 ++++++++++++++++ lldb/source/Target/TargetProperties.td | 3 ++ lldb/source/Target/Thread.cpp | 9 ++++- lldb/test/Shell/Swift/ToolchainMismatch.test | 38 +++++++++++++++++++ 10 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 lldb/test/Shell/Swift/ToolchainMismatch.test diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 9901c2c57557b..5501410aa49c1 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -131,6 +131,9 @@ class SymbolFile : public PluginInterface { Symtab *GetSymtab(); + virtual llvm::VersionTuple GetProducerVersion(CompileUnit &comp_unit) { + return {}; + } virtual lldb::LanguageType ParseLanguage(CompileUnit &comp_unit) = 0; /// Return the Xcode SDK comp_unit was compiled against. virtual XcodeSDK ParseXcodeSDK(CompileUnit &comp_unit) { return {}; } diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index a6a5d6abf9001..c06467a1ceb37 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -93,6 +93,9 @@ class ProcessProperties : public Properties { void SetDetachKeepsStopped(bool keep_stopped); bool GetWarningsOptimization() const; bool GetWarningsUnsupportedLanguage() const; +#ifdef LLDB_ENABLE_SWIFT + bool GetWarningsToolchainMismatch() const; +#endif bool GetStopOnExec() const; std::chrono::seconds GetUtilityExpressionTimeout() const; std::chrono::seconds GetInterruptTimeout() const; @@ -372,7 +375,8 @@ class Process : public std::enable_shared_from_this, enum Warnings { eWarningsOptimization = 1, eWarningsUnsupportedLanguage = 2, - eWarningsSwiftImport + eWarningsSwiftImport, + eWarningsToolchainMismatch }; typedef Range LoadRange; @@ -1311,6 +1315,7 @@ class Process : public std::enable_shared_from_this, /// pre-computed. void PrintWarningOptimization(const SymbolContext &sc); +#ifdef LLDB_ENABLE_SWIFT /// Prints a async warning message to the user one time per Process /// for a Module whose Swift AST sections couldn't be loaded because /// they aren't buildable on the current machine. @@ -1320,6 +1325,11 @@ class Process : public std::enable_shared_from_this, void PrintWarningCantLoadSwiftModule(const Module &module, std::string details); + /// Print a user-visible warning about Swift CUs compiled with a + /// different Swift compiler than the one embedded in LLDB. + void PrintWarningToolchainMismatch(const SymbolContext &sc); +#endif + /// Print a user-visible warning about a function written in a /// language that this version of LLDB doesn't support. /// diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index af6cf08dab100..18be95eaf6ec0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -804,6 +804,16 @@ bool SymbolFileDWARF::FixupAddress(Address &addr) { // This is a normal DWARF file, no address fixups need to happen return true; } + +llvm::VersionTuple SymbolFileDWARF::GetProducerVersion(CompileUnit &comp_unit) { + std::lock_guard guard(GetModuleMutex()); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); + if (dwarf_cu) + return dwarf_cu->GetProducerVersion(); + else + return {}; +} + lldb::LanguageType SymbolFileDWARF::ParseLanguage(CompileUnit &comp_unit) { std::lock_guard guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 424656899e13f..0fb507fbeb595 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -108,6 +108,8 @@ class SymbolFileDWARF : public lldb_private::SymbolFile, void InitializeObject() override; // Compile Unit function calls + llvm::VersionTuple + GetProducerVersion(lldb_private::CompileUnit &comp_unit) override; lldb::LanguageType ParseLanguage(lldb_private::CompileUnit &comp_unit) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 492c282c685d8..1ecc871bb27e2 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -623,6 +623,15 @@ size_t SymbolFileDWARFDebugMap::GetCompUnitInfosForModule( return cu_infos.size(); } +llvm::VersionTuple +SymbolFileDWARFDebugMap::GetProducerVersion(CompileUnit &comp_unit) { + std::lock_guard guard(GetModuleMutex()); + SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); + if (oso_dwarf) + return oso_dwarf->GetProducerVersion(comp_unit); + return {}; +} + lldb::LanguageType SymbolFileDWARFDebugMap::ParseLanguage(CompileUnit &comp_unit) { std::lock_guard guard(GetModuleMutex()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 2f9b5086699c2..b2d564043655b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -56,6 +56,8 @@ class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile { void InitializeObject() override; // Compile Unit function calls + llvm::VersionTuple + GetProducerVersion(lldb_private::CompileUnit &comp_unit) override; lldb::LanguageType ParseLanguage(lldb_private::CompileUnit &comp_unit) override; lldb_private::XcodeSDK diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index fc02b21e7cbc4..06ddb998cb9b0 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -38,6 +38,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/AssertFrameRecognizer.h" #include "lldb/Target/DynamicLoader.h" @@ -71,6 +72,10 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#ifdef LLDB_ENABLE_SWIFT +#include "swift/Basic/Version.h" +#endif + using namespace lldb; using namespace lldb_private; using namespace std::chrono; @@ -285,6 +290,14 @@ bool ProcessProperties::GetWarningsUnsupportedLanguage() const { nullptr, idx, g_process_properties[idx].default_uint_value != 0); } +#ifdef LLDB_ENABLE_SWIFT +bool ProcessProperties::GetWarningsToolchainMismatch() const { + const uint32_t idx = ePropertyWarningToolchainMismatch; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_process_properties[idx].default_uint_value != 0); +} +#endif + bool ProcessProperties::GetStopOnExec() const { const uint32_t idx = ePropertyStopOnExec; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -5869,6 +5882,7 @@ void Process::PrintWarningOptimization(const SymbolContext &sc) { } } +#ifdef LLDB_ENABLE_SWIFT void Process::PrintWarningCantLoadSwiftModule(const Module &module, std::string details) { PrintWarning(Process::Warnings::eWarningsSwiftImport, (void *)&module, @@ -5876,6 +5890,24 @@ void Process::PrintWarningCantLoadSwiftModule(const Module &module, module.GetFileSpec().GetCString(), details.c_str()); } +void Process::PrintWarningToolchainMismatch(const SymbolContext &sc) { + if (!GetWarningsToolchainMismatch()) + return; + if (!sc.module_sp || !sc.comp_unit) + return; + if (sc.GetLanguage() != eLanguageTypeSwift) + return; + if (SymbolFile *sym_file = sc.module_sp->GetSymbolFile()) + if (sym_file->GetProducerVersion(*sc.comp_unit) != + swift::version::Version::getCurrentCompilerVersion()) + PrintWarning(Process::Warnings::eWarningsToolchainMismatch, + sc.module_sp.get(), + "%s was compiled with a Swift compiler from a different " + "toolchain. Swift expression evaluation may not work.\n", + sc.module_sp->GetFileSpec().GetFilename().GetCString()); +} +#endif + void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) { if (!GetWarningsUnsupportedLanguage()) return; diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index f238bdfc84d4f..92353e220a10b 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -241,6 +241,9 @@ let Definition = "process" in { def WarningUnsupportedLanguage: Property<"unsupported-language-warnings", "Boolean">, DefaultTrue, Desc<"If true, warn when stopped in code that is written in a source language that LLDB does not support.">; + def WarningToolchainMismatch: Property<"toolchain-mismatch-warnings", "Boolean">, + DefaultTrue, + Desc<"If true, warn when stopped in code that was compiled by a Swift compiler different from the one embedded in LLDB.">; def StopOnExec: Property<"stop-on-exec", "Boolean">, Global, DefaultTrue, diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 8e1aac73bf293..955eab775b7d3 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -322,11 +322,18 @@ void Thread::FrameSelectedCallback(StackFrame *frame) { if (frame->HasDebugInformation() && (GetProcess()->GetWarningsOptimization() || - GetProcess()->GetWarningsUnsupportedLanguage())) { + GetProcess()->GetWarningsUnsupportedLanguage() +#ifdef LLDB_ENABLE_SWIFT + || GetProcess()->GetWarningsToolchainMismatch()) +#endif + ) { SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextModule); GetProcess()->PrintWarningOptimization(sc); GetProcess()->PrintWarningUnsupportedLanguage(sc); +#ifdef LLDB_ENABLE_SWIFT + GetProcess()->PrintWarningToolchainMismatch(sc); +#endif } SymbolContext msc = frame->GetSymbolContext(eSymbolContextModule); if (msc.module_sp) diff --git a/lldb/test/Shell/Swift/ToolchainMismatch.test b/lldb/test/Shell/Swift/ToolchainMismatch.test new file mode 100644 index 0000000000000..59d5b50d8f0a0 --- /dev/null +++ b/lldb/test/Shell/Swift/ToolchainMismatch.test @@ -0,0 +1,38 @@ +# REQUIRES: swift + +# Tests that a warning is printed when stopped in a Swift frame +# compiled by a different Swift compiler than the one embedded in LLDB. + +# RUN: rm -rf %t && mkdir %t && cd %t +# RUN: %target-swiftc -g \ +# RUN: -module-cache-path %t/cache %S/Inputs/main.swift \ +# RUN: -module-name main -o %t/a.ll -emit-ir +# RUN: sed -i -e 's/producer: "[^"]*Swift [^"]*"/producer: "Future Swift (swiftlang-9999.8.7.6)"/g' %t/a.ll +# RUN: %clang_host -c %t/a.ll -o %t/a.o +# RUN: llvm-dwarfdump -r 0 %t/a.o | grep -q swiftlang-9999 +# RUN: %target-swiftc \ +# RUN: -module-cache-path %t/cache \ +# RUN: %t/a.o -o %t/a.out +# RUN: %lldb %t/a.out -s %s 2>&1 | FileCheck %s + +# Sanity check: Swift +# RUN: %target-swiftc -g \ +# RUN: -module-cache-path %t/cache %S/Inputs/main.swift \ +# RUN: -module-name main -o %t/good.out +# RUN: %lldb %t/good.out -s %s 2>&1 | FileCheck %s --check-prefix=SANITY + +# Sanity check: Clang +# RUN: %clang_host -g \ +# RUN: %S/../Driver/Inputs/hello.cpp \ +# RUN: -o %t/clang.out +# RUN: %lldb %t/clang.out -s %s 2>&1 | FileCheck %s --check-prefix=SANITY + +b main +run +quit + +# The {{ }} avoids accidentally matching the input script! +# CHECK: {{a\.out}} was compiled with a Swift compiler from a different toolchain. +# CHECK: stop reason{{ = }}breakpoint +# SANITY-NOT: {{a\.out}} was compiled with a Swift compiler from a different toolchain. +# SANITY: stop reason{{ = }}breakpoint