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 fa346c5901e4d..01b54e3d17034 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; @@ -371,7 +374,8 @@ class Process : public std::enable_shared_from_this, enum Warnings { eWarningsOptimization = 1, eWarningsUnsupportedLanguage = 2, - eWarningsSwiftImport + eWarningsSwiftImport, + eWarningsToolchainMismatch }; typedef Range LoadRange; @@ -1329,6 +1333,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. @@ -1338,6 +1343,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 e5d9c6dcbe962..1f624d1d859a8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -854,6 +854,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 3f856f507c1b9..b8bbcbcf92dfb 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 fec687dd6e737..fa598d2dd5a0b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -621,6 +621,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 766eab887774d..3870b06047480 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 6f8c3e9d13943..fe02fe1728343 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; @@ -298,6 +303,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( @@ -5907,6 +5920,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, @@ -5914,6 +5928,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 31a063a598cd3..7af1980dce83a 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -238,6 +238,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 5c5001eed5273..5b6ebd6f0b499 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -321,11 +321,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