Skip to content

Commit 1348ae3

Browse files
committed
Support debugging Swift dylibs that were loaded after SwiftASTContext was initialized.
This patch extends the ModulesDidLoad callback to register .swiftast sections in the new dylib and posons the context if necessary to force a reinitialization. rdar://81135636
1 parent ac211cc commit 1348ae3

File tree

11 files changed

+161
-1
lines changed

11 files changed

+161
-1
lines changed

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

+32-1
Original file line numberDiff line numberDiff line change
@@ -1949,7 +1949,7 @@ static lldb::ModuleSP GetUnitTestModule(lldb_private::ModuleList &modules) {
19491949
/// Scan a newly added lldb::Module fdor Swift modules and report any errors in
19501950
/// its module SwiftASTContext to Target.
19511951
static void
1952-
ProcessModule(ModuleSP &&module_sp, std::string m_description,
1952+
ProcessModule(ModuleSP module_sp, std::string m_description,
19531953
bool use_all_compiler_flags, Target &target,
19541954
std::vector<std::string> &module_search_paths,
19551955
std::vector<std::pair<std::string, bool>> &framework_search_paths,
@@ -5069,6 +5069,37 @@ void SwiftASTContext::PrintDiagnostics(DiagnosticManager &diagnostic_manager,
50695069

50705070
void SwiftASTContext::ModulesDidLoad(ModuleList &module_list) {
50715071
ClearModuleDependentCaches();
5072+
5073+
// Scan the new modules for Swift contents and try to import it if
5074+
// safe, otherwise poison this context.
5075+
TargetSP target_sp = GetTarget().lock();
5076+
if (!target_sp)
5077+
return;
5078+
5079+
bool use_all_compiler_flags = target_sp->GetUseAllCompilerFlags();
5080+
unsigned num_images = module_list.GetSize();
5081+
for (size_t mi = 0; mi != num_images; ++mi) {
5082+
std::vector<std::string> module_search_paths;
5083+
std::vector<std::pair<std::string, bool>> framework_search_paths;
5084+
std::vector<std::string> extra_clang_args;
5085+
lldb::ModuleSP module_sp = module_list.GetModuleAtIndex(mi);
5086+
ProcessModule(module_sp, m_description, use_all_compiler_flags, *target_sp,
5087+
module_search_paths, framework_search_paths,
5088+
extra_clang_args);
5089+
// If the use-all-compiler-flags setting is enabled, the expression
5090+
// context is supposed to merge all search paths form all dylibs.
5091+
if (use_all_compiler_flags && !extra_clang_args.empty()) {
5092+
// We cannot reconfigure ClangImporter after its creation.
5093+
// Instead poison the SwiftASTContext so it gets recreated.
5094+
m_fatal_errors.SetErrorStringWithFormat(
5095+
"New Swift image added: %s",
5096+
module_sp->GetFileSpec().GetPath().c_str());
5097+
}
5098+
5099+
// Scan the dylib for .swiftast sections.
5100+
std::vector<std::string> module_names;
5101+
RegisterSectionModules(*module_sp, module_names);
5102+
}
50725103
}
50735104

50745105
void SwiftASTContext::ClearModuleDependentCaches() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This Makefile recursively calls itself, hence the ?=.
2+
EXE ?= a.out
3+
C_SOURCES ?= loader.c
4+
all: dylib $(EXE)
5+
6+
include Makefile.rules
7+
8+
.PHONY: dylib
9+
dylib:
10+
$(MAKE) MAKE_DSYM=$(MAKE_DSYM) CC=$(CC) SWIFTC=$(SWIFTC) \
11+
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \
12+
VPATH=$(SRCDIR) -I $(SRCDIR) \
13+
-f $(SRCDIR)/Makefile \
14+
DYLIB_FILENAME=dylib.dylib \
15+
DYLIB_SWIFT_SOURCES=dylib.swift \
16+
DYLIB_NAME=dylib \
17+
DYLIB_ONLY=YES \
18+
C_SOURCES= \
19+
LD_EXTRAS="-lSwiftCore -Xlinker -exported_symbol -Xlinker _f" \
20+
dylib.dylib
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from lldbsuite.test.lldbtest import *
2+
from lldbsuite.test.decorators import *
3+
import lldbsuite.test.lldbutil as lldbutil
4+
5+
class TestSwiftLateDylib(TestBase):
6+
7+
mydir = TestBase.compute_mydir(__file__)
8+
9+
@skipUnlessDarwin
10+
@swiftTest
11+
@skipIfDarwinEmbedded
12+
def test(self):
13+
"""Test that a late loaded Swift dylib is debuggable"""
14+
self.build()
15+
target, process, _, _ = lldbutil.run_to_name_breakpoint(self, "main")
16+
# Initialize SwiftASTContext before loading the dylib.
17+
self.expect("expr -l Swift -- 0")
18+
bkpt = target.BreakpointCreateByLocation(lldb.SBFileSpec('dylib.swift'), 7)
19+
lldbutil.continue_to_breakpoint(process, bkpt)
20+
self.expect("v x", substrs=['Hello from the Dylib'])
21+
self.expect("expr x", substrs=['Hello from the Dylib'])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
struct FromDylib {
2+
let msg = "Hello from the Dylib!"
3+
}
4+
5+
@_silgen_name("f") public func f() {
6+
let x = FromDylib()
7+
print(x) // line 7
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <dlfcn.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
#include <libgen.h>
5+
6+
int main(int argc, const char **argv) {
7+
char *dylib_name = strcat(dirname(argv[0]),"/dylib.dylib");
8+
void *dylib = dlopen(dylib_name, RTLD_NOW);
9+
void (*f)() = dlsym(dylib, "f");
10+
f();
11+
return 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct FromClang {
2+
int x;
3+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# This Makefile recursively calls itself, hence the ?=.
2+
EXE ?= a.out
3+
C_SOURCES ?= loader.c
4+
all: dylib $(EXE)
5+
6+
include Makefile.rules
7+
8+
.PHONY: dylib
9+
dylib:
10+
$(MAKE) MAKE_DSYM=$(MAKE_DSYM) CC=$(CC) SWIFTC=$(SWIFTC) \
11+
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \
12+
VPATH=$(SRCDIR) -I $(SRCDIR) \
13+
-f $(SRCDIR)/Makefile \
14+
DYLIB_FILENAME=dylib.dylib \
15+
DYLIB_SWIFT_SOURCES=dylib.swift \
16+
DYLIB_NAME=dylib \
17+
DYLIB_ONLY=YES \
18+
SWIFTFLAGS_EXTRAS="-Xcc -I$(SRCDIR)" \
19+
C_SOURCES= \
20+
LD_EXTRAS="-lSwiftCore -Xlinker -exported_symbol -Xlinker _f" \
21+
dylib.dylib
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from lldbsuite.test.lldbtest import *
2+
from lldbsuite.test.decorators import *
3+
import lldbsuite.test.lldbutil as lldbutil
4+
5+
class TestSwiftLateDylibClangDeps(TestBase):
6+
7+
mydir = TestBase.compute_mydir(__file__)
8+
9+
@skipUnlessDarwin
10+
@swiftTest
11+
@skipIfDarwinEmbedded
12+
def test(self):
13+
"""Test that a late loaded Swift dylib with Clang dependencies is debuggable"""
14+
self.build()
15+
target, process, _, _ = lldbutil.run_to_name_breakpoint(self, "main")
16+
# Initialize SwiftASTContext before loading the dylib.
17+
self.expect("expr -l Swift -- 0")
18+
bkpt = target.BreakpointCreateByLocation(lldb.SBFileSpec('dylib.swift'), 5)
19+
lldbutil.continue_to_breakpoint(process, bkpt)
20+
self.expect("v x", substrs=['42'])
21+
self.expect("expr x", substrs=['42'])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import ClangMod
2+
3+
@_silgen_name("f") public func f() {
4+
let x = FromClang(x: 42)
5+
print(x) // line 5
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <dlfcn.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
#include <libgen.h>
5+
6+
int main(int argc, const char **argv) {
7+
char *dylib_name = strcat(dirname(argv[0]),"/dylib.dylib");
8+
void *dylib = dlopen(dylib_name, RTLD_NOW);
9+
void (*f)() = dlsym(dylib, "f");
10+
f();
11+
return 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module ClangMod {
2+
header "ClangMod.h"
3+
}

0 commit comments

Comments
 (0)