Skip to content

Commit 6d98d1d

Browse files
committed
Avoid importing dynamic libraries and frameworks are already in the target.
The primary motivation behind this patch is to avoid the futile attempts of importing static frameworks in LLDB (which by design cannot work. While investiagting this I realized that the only situation where LLDB should automatically dlopen libraries is when a user expression conatins an import statement. All libraries that are discovered as dependencies of Swift modules found in the debug info must already be part of the target, so trying to import them is a waste of time and I/O. rdar://88974768 (cherry picked from commit ab85ab8) Conflicts: lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp
1 parent fc58b9c commit 6d98d1d

File tree

15 files changed

+251
-44
lines changed

15 files changed

+251
-44
lines changed

lldb/include/lldb/Target/Target.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ class TargetProperties : public Properties {
177177

178178
bool GetSwiftReadMetadataFromDSYM() const;
179179

180+
bool GetSwiftAutoImportFrameworks() const;
181+
180182
bool GetEnableAutoImportClangModules() const;
181183

182184
bool GetUseAllCompilerFlags() const;

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,8 +1278,7 @@ static llvm::Expected<ParsedExpression> ParseAndImport(
12781278
Status error;
12791279
SourceModule module_info;
12801280
module_info.path.emplace_back("Swift");
1281-
swift::ModuleDecl *module =
1282-
swift_ast_context.GetModule(module_info, error);
1281+
swift::ModuleDecl *module = swift_ast_context.GetModule(module_info, error);
12831282

12841283
if (error.Fail() || !module) {
12851284
LLDB_LOG(log, "couldn't load Swift Standard Library\n");

lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,8 +580,7 @@ void SwiftREPL::CompleteCode(const std::string &current_code,
580580
completion_module_info.path.push_back(ConstString("repl"));
581581
swift::ModuleDecl *repl_module = nullptr;
582582
if (m_completion_module_initialized)
583-
repl_module =
584-
swift_ast->GetModule(completion_module_info, error);
583+
repl_module = swift_ast->GetModule(completion_module_info, error);
585584
if (repl_module == nullptr) {
586585
swift::ImplicitImportInfo importInfo;
587586
importInfo.StdlibKind = swift::ImplicitStdlibKind::Stdlib;

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "swift/AST/SubstitutionMap.h"
3838
#include "swift/AST/Type.h"
3939
#include "swift/AST/Types.h"
40+
#include "swift/AST/ASTWalker.h"
4041
#include "swift/ASTSectionImporter/ASTSectionImporter.h"
4142
#include "swift/Basic/DiagnosticOptions.h"
4243
#include "swift/Basic/Dwarf.h"
@@ -3386,7 +3387,10 @@ void SwiftASTContext::CacheModule(swift::ModuleDecl *module) {
33863387
}
33873388

33883389
swift::ModuleDecl *SwiftASTContext::GetModule(const SourceModule &module,
3389-
Status &error) {
3390+
Status &error, bool *cached) {
3391+
if (cached)
3392+
*cached = false;
3393+
33903394
VALID_OR_RETURN(nullptr);
33913395
if (!module.path.size())
33923396
return nullptr;
@@ -3400,8 +3404,11 @@ swift::ModuleDecl *SwiftASTContext::GetModule(const SourceModule &module,
34003404
return nullptr;
34013405
}
34023406

3403-
if (swift::ModuleDecl *module_decl = GetCachedModule(module))
3407+
if (swift::ModuleDecl *module_decl = GetCachedModule(module)) {
3408+
if (cached)
3409+
*cached = true;
34043410
return module_decl;
3411+
}
34053412

34063413
LLDB_SCOPED_TIMER();
34073414
swift::ASTContext *ast = GetASTContext();
@@ -3535,27 +3542,33 @@ swift::ModuleDecl *SwiftASTContext::GetModule(const FileSpec &module_spec,
35353542
return NULL;
35363543
}
35373544

3538-
swift::ModuleDecl *
3539-
SwiftASTContext::FindAndLoadModule(const SourceModule &module, Process &process,
3540-
Status &error) {
3545+
template<typename ModuleT> swift::ModuleDecl *
3546+
SwiftASTContext::FindAndLoadModule(const ModuleT &module, Process &process,
3547+
bool import_dylib, Status &error) {
35413548
VALID_OR_RETURN(nullptr);
35423549

3543-
swift::ModuleDecl *swift_module = GetModule(module, error);
3550+
bool cached = false;
3551+
swift::ModuleDecl *swift_module = GetModule(module, error, &cached);
3552+
35443553
if (!swift_module)
35453554
return nullptr;
3546-
LoadModule(swift_module, process, error);
3547-
return swift_module;
3548-
}
35493555

3550-
swift::ModuleDecl *
3551-
SwiftASTContext::FindAndLoadModule(const FileSpec &module_spec,
3552-
Process &process, Status &error) {
3553-
VALID_OR_RETURN(nullptr);
3556+
// If import_dylib is true, this is an explicit "import Module"
3557+
// declaration in a user expression, and we should load the dylib
3558+
// even if we already cached an implicit import (which may not have
3559+
// loaded the dylib). If target.swift-auto-import-frameworks is
3560+
// set, all implicitly imported Swift modules' associated frameworks
3561+
// will be imported too.
3562+
TargetSP target_sp(GetTargetWP().lock());
3563+
if (target_sp)
3564+
import_dylib |= target_sp->GetSwiftAutoImportFrameworks();
3565+
3566+
if (cached && !import_dylib)
3567+
return swift_module;
3568+
3569+
if (import_dylib)
3570+
LoadModule(swift_module, process, error);
35543571

3555-
swift::ModuleDecl *swift_module = GetModule(module_spec, error);
3556-
if (!swift_module)
3557-
return nullptr;
3558-
LoadModule(swift_module, process, error);
35593572
return swift_module;
35603573
}
35613574

@@ -3623,6 +3636,13 @@ void SwiftASTContext::LoadModule(swift::ModuleDecl *swift_module,
36233636
// name are the same, and that we are contained in
36243637
// FileName.framework with no other intervening frameworks. We
36253638
// can get more restrictive if this gives false positives.
3639+
//
3640+
// If the framework exists on disk but it's a static framework
3641+
// (i.e., the binary inside is a static archive instead of a
3642+
// dylib) this cannot be detected. The dlopen call will fail,
3643+
// and dlerror does not contain enough information to
3644+
// unambiguously identify this case. So it will look as if the
3645+
// framework hasn't been found.
36263646
ConstString library_cstr(library_name);
36273647

36283648
std::string framework_name(library_name);
@@ -8130,6 +8150,7 @@ static void GetNameFromModule(swift::ModuleDecl *module, std::string &result) {
81308150
static swift::ModuleDecl *LoadOneModule(const SourceModule &module,
81318151
SwiftASTContext &swift_ast_context,
81328152
lldb::ProcessSP process_sp,
8153+
bool import_dylibs,
81338154
Status &error) {
81348155
LLDB_SCOPED_TIMER();
81358156
if (!module.path.size())
@@ -8148,8 +8169,8 @@ static swift::ModuleDecl *LoadOneModule(const SourceModule &module,
81488169
toplevel.GetStringRef() == imported_header_module->getName().str())
81498170
swift_module = imported_header_module;
81508171
else if (process_sp)
8151-
swift_module =
8152-
swift_ast_context.FindAndLoadModule(module, *process_sp.get(), error);
8172+
swift_module = swift_ast_context.FindAndLoadModule(
8173+
module, *process_sp.get(), import_dylibs, error);
81538174
else
81548175
swift_module = swift_ast_context.GetModule(module, error);
81558176

@@ -8224,8 +8245,8 @@ bool SwiftASTContext::GetImplicitImports(
82248245
// Otherwise, try reloading the ModuleDecl using the module name.
82258246
SourceModule module_info;
82268247
module_info.path.emplace_back(module_pair.first());
8227-
auto *module =
8228-
LoadOneModule(module_info, swift_ast_context, process_sp, error);
8248+
auto *module = LoadOneModule(module_info, swift_ast_context, process_sp,
8249+
/*import_dylibs=*/false, error);
82298250
if (!module)
82308251
return false;
82318252

@@ -8246,10 +8267,32 @@ bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context,
82468267
auto *persistent_expression_state =
82478268
sc.target_sp->GetSwiftPersistentExpressionState(exe_scope);
82488269

8270+
auto src_file_imports = source_file.getImports();
8271+
8272+
Progress progress(llvm::formatv("Caching Swift user imports from '{0}'",
8273+
source_file.getFilename().data()),
8274+
src_file_imports.size());
8275+
8276+
size_t completion = 0;
8277+
8278+
/// Find all explicit imports in the expression.
8279+
struct UserImportFinder : public swift::ASTWalker {
8280+
llvm::SmallDenseSet<swift::ModuleDecl*, 1> imports;
8281+
8282+
bool walkToDeclPre(swift::Decl *D) override {
8283+
if (auto *ID = llvm::dyn_cast<swift::ImportDecl>(D))
8284+
if (auto *M = ID->getModule())
8285+
imports.insert(M);
8286+
return true;
8287+
}
8288+
};
8289+
UserImportFinder import_finder;
8290+
source_file.walk(import_finder);
8291+
82498292
for (const auto &attributed_import : source_file.getImports()) {
8293+
progress.Increment(++completion);
82508294
swift::ModuleDecl *module = attributed_import.module.importedModule;
8251-
8252-
if (module) {
8295+
if (module && import_finder.imports.count(module)) {
82538296
std::string module_name;
82548297
GetNameFromModule(module, module_name);
82558298
if (!module_name.empty()) {
@@ -8259,7 +8302,8 @@ bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context,
82598302
LOG_PRINTF(GetLog(LLDBLog::Types | LLDBLog::Expressions),
82608303
"Performing auto import on found module: %s.\n",
82618304
module_name.c_str());
8262-
if (!LoadOneModule(module_info, swift_ast_context, process_sp, error))
8305+
if (!LoadOneModule(module_info, swift_ast_context, process_sp,
8306+
/*import_dylibs=*/true, error))
82638307
return false;
82648308

82658309
// How do we tell we are in REPL or playground mode?
@@ -8313,8 +8357,8 @@ bool SwiftASTContext::GetCompileUnitImportsImpl(
83138357
// Import the Swift standard library and its dependencies.
83148358
SourceModule swift_module;
83158359
swift_module.path.emplace_back("Swift");
8316-
auto *stdlib =
8317-
LoadOneModule(swift_module, *this, process_sp, error);
8360+
auto *stdlib = LoadOneModule(swift_module, *this, process_sp,
8361+
/*import_dylibs=*/true, error);
83188362
if (!stdlib)
83198363
return false;
83208364

@@ -8334,8 +8378,8 @@ bool SwiftASTContext::GetCompileUnitImportsImpl(
83348378
.Default(false))
83358379
continue;
83368380

8337-
auto *loaded_module =
8338-
LoadOneModule(module, *this, process_sp, error);
8381+
auto *loaded_module = LoadOneModule(module, *this, process_sp,
8382+
/*import_dylibs=*/false, error);
83398383
if (!loaded_module)
83408384
return false;
83418385

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -285,21 +285,19 @@ class SwiftASTContext : public TypeSystemSwift {
285285
// for all items in a swift::ASTContext have been setup to
286286
// allow for imports to happen correctly. Use with caution,
287287
// or use the GetModule() call that takes a FileSpec.
288-
swift::ModuleDecl *GetModule(const SourceModule &module, Status &error);
288+
swift::ModuleDecl *GetModule(const SourceModule &module, Status &error,
289+
bool *cached = nullptr);
289290

290291
swift::ModuleDecl *GetModule(const FileSpec &module_spec, Status &error);
291292

292293
void CacheModule(swift::ModuleDecl *module);
293294

294-
// Call this after the search paths are set up, it will find the module given
295-
// by module, load the module into the AST context, and also load any
296-
// "LinkLibraries" that the module requires.
297-
298-
swift::ModuleDecl *FindAndLoadModule(const SourceModule &module,
299-
Process &process, Status &error);
300-
301-
swift::ModuleDecl *FindAndLoadModule(const FileSpec &module_spec,
302-
Process &process, Status &error);
295+
/// Call this after the search paths are set up, it will find the module given
296+
/// by module, load the module into the AST context, and (if import_dylib is
297+
/// set) also load any "LinkLibraries" that the module requires.
298+
template <typename ModuleT>
299+
swift::ModuleDecl *FindAndLoadModule(const ModuleT &module, Process &process,
300+
bool import_dylib, Status &error);
303301

304302
void LoadModule(swift::ModuleDecl *swift_module, Process &process,
305303
Status &error);

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,8 +1321,9 @@ TypeSystemSwiftTypeRefForExpressions::TypeSystemSwiftTypeRefForExpressions(
13211321
void TypeSystemSwiftTypeRefForExpressions::PerformCompileUnitImports(
13221322
SymbolContext &sc) {
13231323
Status error;
1324-
// FIXME: this is uninitialized!
13251324
lldb::ProcessSP process_sp;
1325+
if (auto target_sp = sc.target_sp)
1326+
process_sp = target_sp->GetProcessSP();
13261327
if (m_swift_ast_context_initialized)
13271328
GetSwiftASTContext()->PerformCompileUnitImports(sc, process_sp, error);
13281329
else
@@ -1383,8 +1384,9 @@ TypeSystemSwiftTypeRefForExpressions::GetSwiftASTContext() const {
13831384

13841385
if (m_initial_symbol_context) {
13851386
Status error;
1386-
// FIXME: not initialized!
13871387
lldb::ProcessSP process_sp;
1388+
if (TargetSP target_sp = GetTargetWP().lock())
1389+
process_sp = target_sp->GetProcessSP();
13881390
m_swift_ast_context->PerformCompileUnitImports(*m_initial_symbol_context,
13891391
process_sp, error);
13901392
m_initial_symbol_context.reset();

lldb/source/Target/Target.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,6 +4261,7 @@ bool TargetProperties::GetSwiftCreateModuleContextsInParallel() const {
42614261
return true;
42624262
}
42634263

4264+
42644265
bool TargetProperties::GetSwiftReadMetadataFromFileCache() const {
42654266
const Property *exp_property = m_collection_sp->GetPropertyAtIndex(
42664267
nullptr, false, ePropertyExperimental);
@@ -4296,6 +4297,13 @@ bool TargetProperties::GetSwiftReadMetadataFromDSYM() const {
42964297

42974298
return true;
42984299
}
4300+
4301+
bool TargetProperties::GetSwiftAutoImportFrameworks() const {
4302+
const uint32_t idx = ePropertySwiftAutoImportFrameworks;
4303+
return m_collection_sp->GetPropertyAtIndexAsBoolean(
4304+
nullptr, idx, g_target_properties[idx].default_uint_value != 0);
4305+
}
4306+
42994307
ArchSpec TargetProperties::GetDefaultArchitecture() const {
43004308
OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch(
43014309
nullptr, ePropertyDefaultArch);

lldb/source/Target/TargetProperties.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ let Definition = "target" in {
190190
def SwiftExtraClangFlags: Property<"swift-extra-clang-flags", "String">,
191191
DefaultStringValue<"">,
192192
Desc<"Additional -Xcc flags to be passed to the Swift ClangImporter.">;
193+
def SwiftAutoImportFrameworks : Property<"swift-auto-import-frameworks", "Boolean">,
194+
DefaultFalse,
195+
Desc<"Automatically import all frameworks and dynamic libraries that are autolinked by Swift modules in the target.">;
193196
def UseAllCompilerFlags: Property<"use-all-compiler-flags", "Boolean">,
194197
DefaultTrue,
195198
Desc<"Try to use compiler flags for all modules when setting up the Swift expression parser, not just the main executable.">;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public typealias MyNumber = Int
2+
public class C {
3+
public init() { n = MyNumber(23) }
4+
let n : MyNumber
5+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
SWIFTFLAGS_EXTRAS = -F $(BUILDDIR)
4+
5+
all: Lazy.framework $(EXE)
6+
7+
include Makefile.rules
8+
9+
Lazy.framework: $(SRCDIR)/Lazy.swift
10+
$(MAKE) -f $(MAKEFILE_RULES) \
11+
DYLIB_NAME=Lazy \
12+
DYLIB_SWIFT_SOURCES=Lazy.swift \
13+
DYLIB_MODULENAME=Lazy \
14+
FRAMEWORK=Lazy
15+
rm -f $(BUILDDIR)/Lazy.swiftmodule $(BUILDDIR)/Lazy.swiftinterface
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
import lldbsuite.test.lldbtest as lldbtest
4+
import lldbsuite.test.lldbutil as lldbutil
5+
import os
6+
import unittest2
7+
8+
9+
class TestSwiftLazyFramework(lldbtest.TestBase):
10+
11+
NO_DEBUG_INFO_TESTCASE = True
12+
mydir = lldbtest.TestBase.compute_mydir(__file__)
13+
14+
@swiftTest
15+
@skipIf(oslist=no_match(["macosx"]))
16+
def test_system_framework(self):
17+
"""Test that a framework that is registered as autolinked in a Swift
18+
module used in the target, but not linked against the target is
19+
automatically loaded by LLDB."""
20+
self.build()
21+
self.expect("settings set target.swift-auto-import-frameworks true")
22+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
23+
self, 'break here', lldb.SBFileSpec('main.swift'))
24+
25+
# Verify that lazy is not linked in.
26+
self.runCmd("image list")
27+
output = self.res.GetOutput()
28+
self.assertIn("dyld", output)
29+
self.assertNotIn("Lazy.framework/Versions/A/Lazy", output)
30+
# FIXME: we should automatically retry the expression on dylib import.
31+
self.expect("expression -- 1", error=True)
32+
self.expect("expression -- C()", substrs=['23'])
33+
34+
# Verify that lazy has been dynamically loaded.
35+
self.expect("image list", substrs=["Lazy.framework/Versions/A/Lazy"])
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import Lazy
2+
let n = MyNumber(42)
3+
print("break here")
4+
print(n)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public struct D { public init() {} }

0 commit comments

Comments
 (0)