Skip to content

Commit d63debe

Browse files
committed
Experimental: Extend ClangImporter to import clang modules from DWARF
When debugging Objective-C or C++ code on Darwin, the debug info collected by dsymutil in the .dSYM bundle is entirely self-contained. It is possible to debug a program, set breakpoints and print variables even without having the complete original source code or a matching SDK available. With Swift, this is currently not the case. Even though .dSYM bundles contain the binary .swiftmodule for all Swift modules, any Clang modules that the Swift modules depend on, still need to be imported from source to even get basic LLDB functionality to work. If ClangImporter fails to import a Clang module, effectively the entire Swift module depending on it gets poisoned. This patch is addressing this issue by introducing a ModuleLoader that can ask queries about Clang Decls to LLDB, since LLDB knows how to reconstruct Clang decls from DWARF and clang -gmodules producxes full debug info for Clang modules that is embedded into the .dSYM budle. This initial version does not contain any advanced functionality at all, it merely produces an empty ModuleDecl. Intertestingly, even this is a considerable improvement over the status quo. LLDB can now print Swift-only variables in modules with failing Clang depenecies, and becuase of fallback mechanisms that were implemented earlier, it can even display the contents of pure Objective-C objects that are imported into Swift. C structs obviously don't work yet. rdar://problem/36032653
1 parent b3ca057 commit d63debe

File tree

29 files changed

+399
-13
lines changed

29 files changed

+399
-13
lines changed

include/swift/AST/Module.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ enum class FileUnitKind {
9494
SerializedAST,
9595
/// An imported Clang module.
9696
ClangModule,
97+
/// A Clang module imported from DWARF.
98+
DWARFModule
9799
};
98100

99101
enum class SourceFileKind {
@@ -1326,7 +1328,8 @@ class LoadedFile : public FileUnit {
13261328

13271329
static bool classof(const FileUnit *file) {
13281330
return file->getKind() == FileUnitKind::SerializedAST ||
1329-
file->getKind() == FileUnitKind::ClangModule;
1331+
file->getKind() == FileUnitKind::ClangModule ||
1332+
file->getKind() == FileUnitKind::DWARFModule;
13301333
}
13311334
static bool classof(const DeclContext *DC) {
13321335
return isa<FileUnit>(DC) && classof(cast<FileUnit>(DC));

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,12 @@ namespace swift {
9898
/// Support for alternate usage modes
9999
///
100100

101-
/// \brief Enable features useful for running in the debugger.
101+
/// Enable features useful for running in the debugger.
102102
bool DebuggerSupport = false;
103103

104+
/// Enable the DWARFImporter. Only used by lldb-moduleimport-test.
105+
bool EnableDWARFImporter = false;
106+
104107
/// Allows using identifiers with a leading dollar.
105108
bool EnableDollarIdentifiers = false;
106109

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//===--- DWARFImporter.h - Import Clang Modules -----------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// \file This file implements support for loading Clang modules that were
14+
// reconstructed from DWARF into Swift.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
#ifndef SWIFT_DWARF_IMPORTER_H
18+
#define SWIFT_DWARF_IMPORTER_H
19+
20+
#include "swift/AST/ClangModuleLoader.h"
21+
22+
namespace llvm {
23+
}
24+
25+
namespace clang {
26+
}
27+
28+
namespace swift {
29+
30+
/// Class that imports Clang modules into Swift, mapping directly
31+
/// from Clang ASTs over to Swift ASTs.
32+
class DWARFImporter final : public ClangModuleLoader {
33+
friend class ClangModuleUnit;
34+
35+
public:
36+
class Implementation;
37+
38+
private:
39+
Implementation &Impl;
40+
41+
DWARFImporter(ASTContext &ctx, const ClangImporterOptions &clangImporterOpts,
42+
DependencyTracker *tracker);
43+
44+
public:
45+
/// Create a new DWARF importer that can import a Clang Modules from DWARF
46+
/// into the given ASTContext.
47+
///
48+
/// \param ctx The ASTContext into which the module will be imported.
49+
/// The ASTContext's SearchPathOptions will be used for the DWARF importer.
50+
///
51+
/// \param importerOpts The options to use for the DWARF importer.
52+
///
53+
/// \param tracker The object tracking files this compilation depends on.
54+
///
55+
/// \returns a new DWARF module importer, or null (with a diagnostic) if
56+
/// an error occurred.
57+
static std::unique_ptr<DWARFImporter>
58+
create(ASTContext &ctx,
59+
const ClangImporterOptions &importerOpts,
60+
DependencyTracker *tracker = nullptr);
61+
62+
DWARFImporter(const DWARFImporter &) = delete;
63+
DWARFImporter(DWARFImporter &&) = delete;
64+
DWARFImporter &operator=(const DWARFImporter &) = delete;
65+
DWARFImporter &operator=(DWARFImporter &&) = delete;
66+
67+
~DWARFImporter();
68+
69+
/// Check whether the module with a given name can be imported without
70+
/// importing it.
71+
///
72+
/// Note that even if this check succeeds, errors may still occur if the
73+
/// module is loaded in full.
74+
bool canImportModule(std::pair<Identifier, SourceLoc> named) override;
75+
bool addSearchPath(StringRef newSearchPath, bool isFramework,
76+
bool isSystem) override;
77+
ModuleDecl *
78+
loadModule(SourceLoc importLoc,
79+
ArrayRef<std::pair<Identifier, SourceLoc>> path) override;
80+
bool
81+
isInOverlayModuleForImportedModule(const DeclContext *overlayDC,
82+
const DeclContext *importedDC) override;
83+
void loadExtensions(NominalTypeDecl *nominal,
84+
unsigned previousGeneration) override;
85+
void loadObjCMethods(
86+
ClassDecl *classDecl, ObjCSelector selector, bool isInstanceMethod,
87+
unsigned previousGeneration,
88+
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) override;
89+
ModuleDecl *getImportedHeaderModule() const override;
90+
void verifyAllModules() override;
91+
clang::ASTContext &getClangASTContext() const override;
92+
clang::Preprocessor &getClangPreprocessor() const override;
93+
clang::Sema &getClangSema() const override;
94+
const clang::CompilerInstance &getClangInstance() const override;
95+
96+
void printStatistics() const override;
97+
};
98+
99+
} // end namespace swift
100+
101+
#endif

lib/AST/ASTContext.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,7 @@ void ASTContext::addExternalDecl(Decl *decl) {
13801380
void ASTContext::addSynthesizedDecl(Decl *decl) {
13811381
auto *mod = cast<FileUnit>(decl->getDeclContext()->getModuleScopeContext());
13821382
if (mod->getKind() == FileUnitKind::ClangModule ||
1383+
mod->getKind() == FileUnitKind::DWARFModule ||
13831384
mod->getKind() == FileUnitKind::SerializedAST) {
13841385
ExternalDefinitions.insert(decl);
13851386
return;
@@ -1422,11 +1423,10 @@ void ASTContext::addSearchPath(StringRef searchPath, bool isFramework,
14221423

14231424
void ASTContext::addModuleLoader(std::unique_ptr<ModuleLoader> loader,
14241425
bool IsClang) {
1425-
if (IsClang) {
1426-
assert(!getImpl().TheClangModuleLoader && "Already have a Clang module loader");
1426+
if (IsClang && !getImpl().TheClangModuleLoader)
14271427
getImpl().TheClangModuleLoader =
1428-
static_cast<ClangModuleLoader *>(loader.get());
1429-
}
1428+
static_cast<ClangModuleLoader *>(loader.get());
1429+
14301430
getImpl().ModuleLoaders.push_back(std::move(loader));
14311431
}
14321432

lib/AST/ASTMangler.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,7 +1309,8 @@ ASTMangler::getSpecialManglingContext(const ValueDecl *decl) {
13091309
// Clang decls. Check getKind() directly to avoid a layering dependency.
13101310
// known-context ::= 'SC'
13111311
if (auto file = dyn_cast<FileUnit>(decl->getDeclContext())) {
1312-
if (file->getKind() == FileUnitKind::ClangModule) {
1312+
if (file->getKind() == FileUnitKind::ClangModule ||
1313+
file->getKind() == FileUnitKind::DWARFModule) {
13131314
if (decl->getClangDecl())
13141315
return ASTMangler::ObjCContext;
13151316
return ASTMangler::ClangImporterContext;
@@ -2273,7 +2274,8 @@ ASTMangler::appendProtocolConformance(const ProtocolConformance *conformance) {
22732274

22742275
bool needsModule = true;
22752276
if (auto *file = dyn_cast<FileUnit>(topLevelContext)) {
2276-
if (file->getKind() == FileUnitKind::ClangModule) {
2277+
if (file->getKind() == FileUnitKind::ClangModule ||
2278+
file->getKind() == FileUnitKind::DWARFModule) {
22772279
if (conformance->getProtocol()->hasClangNode())
22782280
appendOperator("So");
22792281
else

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3354,7 +3354,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
33543354

33553355
// Don't print qualifiers for imported types.
33563356
for (auto File : M->getFiles()) {
3357-
if (File->getKind() == FileUnitKind::ClangModule)
3357+
if (File->getKind() == FileUnitKind::ClangModule ||
3358+
File->getKind() == FileUnitKind::DWARFModule)
33583359
return false;
33593360
}
33603361

lib/AST/DeclContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ unsigned DeclContext::printContext(raw_ostream &OS, unsigned indent) const {
537537
break;
538538
case FileUnitKind::SerializedAST:
539539
case FileUnitKind::ClangModule:
540+
case FileUnitKind::DWARFModule:
540541
OS << " file=\"" << cast<LoadedFile>(this)->getFilename() << "\"";
541542
break;
542543
}

lib/AST/Module.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ lookupOperatorDeclForName(const FileUnit &File, SourceLoc Loc, Identifier Name,
876876
break;
877877
case FileUnitKind::SerializedAST:
878878
case FileUnitKind::ClangModule:
879+
case FileUnitKind::DWARFModule:
879880
return OperatorLookup<OP_DECL>::lookup(cast<LoadedFile>(File), Name);
880881
}
881882

lib/AST/ProtocolConformance.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,8 @@ void NominalTypeDecl::prepareConformanceTable() const {
12971297
// via the Clang importer, don't add any synthesized conformances.
12981298
auto *file = cast<FileUnit>(getModuleScopeContext());
12991299
if (file->getKind() != FileUnitKind::Source &&
1300-
file->getKind() != FileUnitKind::ClangModule) {
1300+
file->getKind() != FileUnitKind::ClangModule &&
1301+
file->getKind() != FileUnitKind::DWARFModule) {
13011302
return;
13021303
}
13031304

lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_subdirectory(Basic)
1919
add_subdirectory(ClangImporter)
2020
add_subdirectory(Demangling)
2121
add_subdirectory(Driver)
22+
add_subdirectory(DWARFImporter)
2223
add_subdirectory(Frontend)
2324
add_subdirectory(FrontendTool)
2425
add_subdirectory(Index)

lib/DWARFImporter/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
add_swift_host_library(swiftDWARFImporter STATIC
2+
DWARFImporter.cpp
3+
LINK_LIBRARIES
4+
swiftAST
5+
swiftParse
6+
)
7+
8+
#add_dependencies(swiftDWARFImporter )

0 commit comments

Comments
 (0)