Skip to content

Implement a warning that detects Swift compile units that were compil… #3388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lldb/include/lldb/Symbol/SymbolFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}; }
Expand Down
12 changes: 11 additions & 1 deletion lldb/include/lldb/Target/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -371,7 +374,8 @@ class Process : public std::enable_shared_from_this<Process>,
enum Warnings {
eWarningsOptimization = 1,
eWarningsUnsupportedLanguage = 2,
eWarningsSwiftImport
eWarningsSwiftImport,
eWarningsToolchainMismatch
};

typedef Range<lldb::addr_t, lldb::addr_t> LoadRange;
Expand Down Expand Up @@ -1329,6 +1333,7 @@ class Process : public std::enable_shared_from_this<Process>,
/// 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.
Expand All @@ -1338,6 +1343,11 @@ class Process : public std::enable_shared_from_this<Process>,
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.
///
Expand Down
10 changes: 10 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::recursive_mutex> 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<std::recursive_mutex> guard(GetModuleMutex());
DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,15 @@ size_t SymbolFileDWARFDebugMap::GetCompUnitInfosForModule(
return cu_infos.size();
}

llvm::VersionTuple
SymbolFileDWARFDebugMap::GetProducerVersion(CompileUnit &comp_unit) {
std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> guard(GetModuleMutex());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -5907,13 +5920,32 @@ 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,
"%s: Cannot load Swift type information; %s\n",
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;
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Target/TargetProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion lldb/source/Target/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
38 changes: 38 additions & 0 deletions lldb/test/Shell/Swift/ToolchainMismatch.test
Original file line number Diff line number Diff line change
@@ -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