-
Notifications
You must be signed in to change notification settings - Fork 344
Support debugging Swift dylibs that were loaded after SwiftASTContext #3311
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1949,7 +1949,7 @@ static lldb::ModuleSP GetUnitTestModule(lldb_private::ModuleList &modules) { | |
/// Scan a newly added lldb::Module fdor Swift modules and report any errors in | ||
/// its module SwiftASTContext to Target. | ||
static void | ||
ProcessModule(ModuleSP &&module_sp, std::string m_description, | ||
ProcessModule(ModuleSP module_sp, std::string m_description, | ||
bool use_all_compiler_flags, Target &target, | ||
std::vector<std::string> &module_search_paths, | ||
std::vector<std::pair<std::string, bool>> &framework_search_paths, | ||
|
@@ -5069,6 +5069,37 @@ void SwiftASTContext::PrintDiagnostics(DiagnosticManager &diagnostic_manager, | |
|
||
void SwiftASTContext::ModulesDidLoad(ModuleList &module_list) { | ||
ClearModuleDependentCaches(); | ||
|
||
// Scan the new modules for Swift contents and try to import it if | ||
// safe, otherwise poison this context. | ||
TargetSP target_sp = GetTarget().lock(); | ||
if (!target_sp) | ||
return; | ||
|
||
bool use_all_compiler_flags = target_sp->GetUseAllCompilerFlags(); | ||
unsigned num_images = module_list.GetSize(); | ||
for (size_t mi = 0; mi != num_images; ++mi) { | ||
std::vector<std::string> module_search_paths; | ||
std::vector<std::pair<std::string, bool>> framework_search_paths; | ||
std::vector<std::string> extra_clang_args; | ||
lldb::ModuleSP module_sp = module_list.GetModuleAtIndex(mi); | ||
ProcessModule(module_sp, m_description, use_all_compiler_flags, *target_sp, | ||
module_search_paths, framework_search_paths, | ||
extra_clang_args); | ||
// If the use-all-compiler-flags setting is enabled, the expression | ||
// context is supposed to merge all search paths form all dylibs. | ||
if (use_all_compiler_flags && !extra_clang_args.empty()) { | ||
adrian-prantl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// We cannot reconfigure ClangImporter after its creation. | ||
// Instead poison the SwiftASTContext so it gets recreated. | ||
m_fatal_errors.SetErrorStringWithFormat( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be worth adding an API on SwiftASTContext (ClearClangImporter or something) to do this? I worry that having a fatal error pending on the context could get you into trouble if some other subsystem checks for errors but isn't prepared to reconstitute the context. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only way to clear clangimporter is to create a new Swift compiler instance (= a new SwiftASTContext). The recreation is transparently handled by Target's GetScratchContext function. |
||
"New Swift image added: %s", | ||
module_sp->GetFileSpec().GetPath().c_str()); | ||
} | ||
|
||
// Scan the dylib for .swiftast sections. | ||
std::vector<std::string> module_names; | ||
RegisterSectionModules(*module_sp, module_names); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to be done for all modules? Or would it be already done for most modules? |
||
} | ||
} | ||
|
||
void SwiftASTContext::ClearModuleDependentCaches() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# This Makefile recursively calls itself, hence the ?=. | ||
EXE ?= a.out | ||
C_SOURCES ?= loader.c | ||
all: dylib $(EXE) | ||
|
||
include Makefile.rules | ||
|
||
.PHONY: dylib | ||
dylib: | ||
$(MAKE) MAKE_DSYM=$(MAKE_DSYM) CC=$(CC) SWIFTC=$(SWIFTC) \ | ||
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \ | ||
VPATH=$(SRCDIR) -I $(SRCDIR) \ | ||
-f $(SRCDIR)/Makefile \ | ||
DYLIB_FILENAME=dylib.dylib \ | ||
DYLIB_SWIFT_SOURCES=dylib.swift \ | ||
DYLIB_NAME=dylib \ | ||
DYLIB_ONLY=YES \ | ||
C_SOURCES= \ | ||
LD_EXTRAS="-lSwiftCore -Xlinker -exported_symbol -Xlinker _f" \ | ||
dylib.dylib | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from lldbsuite.test.lldbtest import * | ||
from lldbsuite.test.decorators import * | ||
import lldbsuite.test.lldbutil as lldbutil | ||
|
||
class TestSwiftLateDylib(TestBase): | ||
|
||
mydir = TestBase.compute_mydir(__file__) | ||
|
||
@skipUnlessDarwin | ||
@swiftTest | ||
@skipIfDarwinEmbedded | ||
def test(self): | ||
"""Test that a late loaded Swift dylib is debuggable""" | ||
self.build() | ||
target, process, _, _ = lldbutil.run_to_name_breakpoint(self, "main") | ||
# Initialize SwiftASTContext before loading the dylib. | ||
self.expect("expr -l Swift -- 0") | ||
bkpt = target.BreakpointCreateByLocation(lldb.SBFileSpec('dylib.swift'), 7) | ||
lldbutil.continue_to_breakpoint(process, bkpt) | ||
self.expect("v x", substrs=['Hello from the Dylib']) | ||
self.expect("expr x", substrs=['Hello from the Dylib']) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
struct FromDylib { | ||
let msg = "Hello from the Dylib!" | ||
} | ||
|
||
@_silgen_name("f") public func f() { | ||
let x = FromDylib() | ||
print(x) // line 7 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#include <dlfcn.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <libgen.h> | ||
|
||
int main(int argc, const char **argv) { | ||
char *dylib_name = strcat(dirname(argv[0]),"/dylib.dylib"); | ||
void *dylib = dlopen(dylib_name, RTLD_NOW); | ||
void (*f)() = dlsym(dylib, "f"); | ||
f(); | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
struct FromClang { | ||
int x; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# This Makefile recursively calls itself, hence the ?=. | ||
EXE ?= a.out | ||
C_SOURCES ?= loader.c | ||
all: dylib $(EXE) | ||
|
||
include Makefile.rules | ||
|
||
.PHONY: dylib | ||
dylib: | ||
$(MAKE) MAKE_DSYM=$(MAKE_DSYM) CC=$(CC) SWIFTC=$(SWIFTC) \ | ||
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \ | ||
VPATH=$(SRCDIR) -I $(SRCDIR) \ | ||
-f $(SRCDIR)/Makefile \ | ||
DYLIB_FILENAME=dylib.dylib \ | ||
DYLIB_SWIFT_SOURCES=dylib.swift \ | ||
DYLIB_NAME=dylib \ | ||
DYLIB_ONLY=YES \ | ||
SWIFTFLAGS_EXTRAS="-Xcc -I$(SRCDIR)" \ | ||
C_SOURCES= \ | ||
LD_EXTRAS="-lSwiftCore -Xlinker -exported_symbol -Xlinker _f" \ | ||
dylib.dylib | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from lldbsuite.test.lldbtest import * | ||
from lldbsuite.test.decorators import * | ||
import lldbsuite.test.lldbutil as lldbutil | ||
|
||
class TestSwiftLateDylibClangDeps(TestBase): | ||
|
||
mydir = TestBase.compute_mydir(__file__) | ||
|
||
@skipUnlessDarwin | ||
@swiftTest | ||
@skipIfDarwinEmbedded | ||
def test(self): | ||
"""Test that a late loaded Swift dylib with Clang dependencies is debuggable""" | ||
self.build() | ||
target, process, _, _ = lldbutil.run_to_name_breakpoint(self, "main") | ||
# Initialize SwiftASTContext before loading the dylib. | ||
self.expect("expr -l Swift -- 0") | ||
bkpt = target.BreakpointCreateByLocation(lldb.SBFileSpec('dylib.swift'), 5) | ||
lldbutil.continue_to_breakpoint(process, bkpt) | ||
self.expect("v x", substrs=['42']) | ||
self.expect("expr x", substrs=['42']) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import ClangMod | ||
|
||
@_silgen_name("f") public func f() { | ||
let x = FromClang(x: 42) | ||
print(x) // line 5 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#include <dlfcn.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <libgen.h> | ||
|
||
int main(int argc, const char **argv) { | ||
char *dylib_name = strcat(dirname(argv[0]),"/dylib.dylib"); | ||
void *dylib = dlopen(dylib_name, RTLD_NOW); | ||
void (*f)() = dlsym(dylib, "f"); | ||
f(); | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module ClangMod { | ||
header "ClangMod.h" | ||
} |
Uh oh!
There was an error while loading. Please reload this page.