Skip to content

Commit 394f6cf

Browse files
committed
Support Swift macros in the expression evaluator.
This patch fixes a couple of bugs in the deserialization of Swift compiler plugin paths and makes sure that all shared library plugins are executed through an out-of-process plugin server. This is necessary to decouple LLDB from crashes in the plugins, and to ensure that the appropriate copy of libSwiftSyntax for the plugin is being used. Because the choice of swift-plugin-server is done via a heuristic, this patch also introduces a new target.experimental.swift-plugin-server-for-path setting that is a dictinary of plugin path prefix and swift-plugin-server binaries to override the choice. rdar://109854291
1 parent 0638570 commit 394f6cf

File tree

5 files changed

+217
-68
lines changed

5 files changed

+217
-68
lines changed

lldb/include/lldb/Target/Target.h

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

185185
EnableSwiftCxxInterop GetEnableSwiftCxxInterop() const;
186186

187+
Args GetSwiftPluginServerForPath() const;
188+
187189
bool GetSwiftAutoImportFrameworks() const;
188190

189191
bool GetEnableAutoImportClangModules() const;

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

Lines changed: 178 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,14 @@ static std::string GetPluginServer(llvm::StringRef plugin_library_path) {
10831083
return {};
10841084
}
10851085

1086+
static std::string GetPluginServerForSDK(llvm::StringRef sdk_path) {
1087+
XcodeSDK sdk(std::string(llvm::sys::path::filename(sdk_path)));
1088+
auto server_or_err = HostInfo::FindSDKTool(sdk, "swift-plugin-server");
1089+
if (!server_or_err)
1090+
return "";
1091+
return server_or_err->str();
1092+
}
1093+
10861094
/// Retrieve the serialized AST data blobs and initialize the compiler
10871095
/// invocation with the concatenated search paths from the blobs.
10881096
/// \returns true if an error was encountered.
@@ -1104,6 +1112,37 @@ static bool DeserializeAllCompilerFlags(swift::CompilerInvocation &invocation,
11041112
return false;
11051113

11061114
auto &search_path_options = invocation.getSearchPathOptions();
1115+
auto get_override_server = [&](llvm::StringRef plugin_path) -> std::string {
1116+
// If the user manually specified an override plugin server for a
1117+
// specific path prefix, return it.
1118+
Args plugin_servers =
1119+
Target::GetGlobalProperties().GetSwiftPluginServerForPath();
1120+
for (auto &arg: plugin_servers) {
1121+
auto key_value = arg.ref().split('=');
1122+
llvm::SmallString<0> ignore(plugin_path);
1123+
if (llvm::sys::path::replace_path_prefix(ignore, key_value.first, {}))
1124+
return key_value.second.str();
1125+
}
1126+
return {};
1127+
};
1128+
auto get_plugin_server = [&](llvm::StringRef plugin,
1129+
std::function<std::string(void)> fallback) {
1130+
// Search for a manual override first, then try fallback.
1131+
std::string server = get_override_server(plugin);
1132+
if (server.empty())
1133+
server = fallback();
1134+
if (server.empty()) {
1135+
HEALTH_LOG_PRINTF("Could not find swift-plugin-server for %s",
1136+
plugin.str().c_str());
1137+
return std::string();
1138+
}
1139+
if (!FileSystem::Instance().Exists(server)) {
1140+
HEALTH_LOG_PRINTF("Swift plugin server does not exist: %s",
1141+
server.c_str());
1142+
server.clear();
1143+
}
1144+
return server;
1145+
};
11071146

11081147
#define INIT_SEARCH_PATH_SET(TYPE, ACCESSOR, NAME, KEY) \
11091148
std::vector<TYPE> NAME; \
@@ -1204,54 +1243,73 @@ static bool DeserializeAllCompilerFlags(swift::CompilerInvocation &invocation,
12041243
// Rewrite them to go through an ABI-compatible swift-plugin-server.
12051244
if (known_plugin_search_paths.insert(path).second) {
12061245
if (known_external_plugin_search_paths.insert(path).second) {
1207-
std::string server = GetPluginServer(path);
1208-
if (server.empty()) {
1209-
HEALTH_LOG_PRINTF("Could not find swift-plugin-server for %s",
1210-
path.str().c_str());
1246+
std::string server = get_plugin_server(
1247+
path, [&]() { return GetPluginServer(path); });
1248+
if (server.empty())
12111249
continue;
1212-
}
12131250
if (exists(path))
12141251
external_plugin_search_paths.push_back({path.str(), server});
12151252
}
12161253
}
1217-
for (auto path :
1218-
extended_validation_info.getExternalPluginSearchPaths()) {
1219-
// Sandboxed system plugins shipping with some compiler.
1220-
// Keep the original plugin server path, it needs to be ABI
1221-
// compatible with the version of SwiftSyntax used by the plugin.
1222-
auto plugin_server = path.split('#');
1223-
llvm::StringRef plugin = plugin_server.first;
1224-
llvm::StringRef server = plugin_server.second;
1225-
if (known_external_plugin_search_paths.insert(plugin).second)
1226-
if (exists(plugin) && exists(server))
1227-
external_plugin_search_paths.push_back(
1228-
{plugin.str(), server.str()});
1229-
}
1254+
}
1255+
for (auto path :
1256+
extended_validation_info.getExternalPluginSearchPaths()) {
1257+
// Sandboxed system plugins shipping with some compiler.
1258+
// Keep the original plugin server path, it needs to be ABI
1259+
// compatible with the version of SwiftSyntax used by the plugin.
1260+
auto plugin_server = path.split('#');
1261+
llvm::StringRef plugin = plugin_server.first;
1262+
std::string server = get_plugin_server(
1263+
plugin, [&]() { return plugin_server.second.str(); });
1264+
if (server.empty())
1265+
continue;
1266+
if (known_external_plugin_search_paths.insert(plugin).second)
1267+
if (exists(plugin))
1268+
external_plugin_search_paths.push_back({plugin.str(), server});
1269+
}
12301270

1231-
for (auto path :
1232-
extended_validation_info.getCompilerPluginLibraryPaths()) {
1233-
// Compiler plugin libraries.
1234-
if (known_compiler_plugin_library_paths.insert(path).second)
1235-
if (exists(path))
1236-
compiler_plugin_library_paths.push_back(path.str());
1237-
}
1271+
for (auto dylib :
1272+
extended_validation_info.getCompilerPluginLibraryPaths()) {
1273+
// Compiler plugin libraries.
1274+
if (known_compiler_plugin_library_paths.insert(dylib).second)
1275+
if (exists(dylib)) {
1276+
// We never want to directly load any plugins, since a crash in
1277+
// the plugin would bring down LLDB. Here, we assume that the
1278+
// correct plugin server for a direct compiler plugin is the one
1279+
// from the SDK the compiler was building for. This is just a
1280+
// heuristic.
1281+
llvm::SmallString<0> dir(dylib);
1282+
llvm::sys::path::remove_filename(dir);
1283+
std::string server = get_plugin_server(dir, [&]() {
1284+
return GetPluginServerForSDK(invocation.getSDKPath());
1285+
});
1286+
if (server.empty())
1287+
continue;
12381288

1239-
for (auto path :
1240-
extended_validation_info.getCompilerPluginExecutablePaths()) {
1241-
// Compiler plugin executables.
1242-
auto plugin_modules = path.split('#');
1243-
llvm::StringRef plugin = plugin_modules.first;
1244-
llvm::StringRef modules_list = plugin_modules.second;
1245-
llvm::SmallVector<llvm::StringRef, 0> modules;
1246-
modules_list.split(modules, ",");
1247-
std::vector<std::string> modules_vec;
1248-
for (auto m : modules)
1249-
modules_vec.push_back(m.str());
1250-
if (known_compiler_plugin_executable_paths.insert(path).second)
1251-
if (exists(plugin))
1252-
compiler_plugin_executable_paths.push_back(
1253-
{plugin.str(), modules_vec});
1254-
}
1289+
// FIXME: The Swift compiler expects external plugins
1290+
// to be named libModuleName.[dylib|so|dll]. This
1291+
// means this our translation attempts only work for
1292+
// macro libraries following this convention. cf.
1293+
// PluginLoader::lookupExternalLibraryPluginByModuleName().
1294+
external_plugin_search_paths.push_back({dir.str().str(), server});
1295+
}
1296+
}
1297+
1298+
for (auto path :
1299+
extended_validation_info.getCompilerPluginExecutablePaths()) {
1300+
// Compiler plugin executables.
1301+
auto plugin_modules = path.split('#');
1302+
llvm::StringRef plugin = plugin_modules.first;
1303+
llvm::StringRef modules_list = plugin_modules.second;
1304+
llvm::SmallVector<llvm::StringRef, 0> modules;
1305+
modules_list.split(modules, ",");
1306+
std::vector<std::string> modules_vec;
1307+
for (auto m : modules)
1308+
modules_vec.push_back(m.str());
1309+
if (known_compiler_plugin_executable_paths.insert(path).second)
1310+
if (exists(plugin))
1311+
compiler_plugin_executable_paths.push_back(
1312+
{plugin.str(), modules_vec});
12551313
}
12561314
return true;
12571315
};
@@ -1884,6 +1942,10 @@ static void
18841942
ProcessModule(ModuleSP module_sp, std::string m_description,
18851943
bool discover_implicit_search_paths, bool use_all_compiler_flags,
18861944
Target &target, llvm::Triple triple,
1945+
std::vector<swift::ExternalPluginSearchPathAndServerPath>
1946+
&external_plugin_search_paths,
1947+
std::vector<swift::PluginExecutablePathAndModuleNames>
1948+
&compiler_plugin_executable_paths,
18871949
std::vector<std::string> &module_search_paths,
18881950
std::vector<std::pair<std::string, bool>> &framework_search_paths,
18891951
std::vector<std::string> &extra_clang_args) {
@@ -2002,7 +2064,15 @@ ProcessModule(ModuleSP module_sp, std::string m_description,
20022064
// collected here and surfaced.
20032065
}
20042066

2067+
// Copy the interesting deserialized flags to the out parameters.
20052068
const auto &opts = invocation.getSearchPathOptions();
2069+
external_plugin_search_paths.insert(external_plugin_search_paths.end(),
2070+
opts.ExternalPluginSearchPaths.begin(),
2071+
opts.ExternalPluginSearchPaths.end());
2072+
compiler_plugin_executable_paths.insert(
2073+
compiler_plugin_executable_paths.end(),
2074+
opts.getCompilerPluginExecutablePaths().begin(),
2075+
opts.getCompilerPluginExecutablePaths().end());
20062076
module_search_paths.insert(module_search_paths.end(),
20072077
opts.getImportSearchPaths().begin(),
20082078
opts.getImportSearchPaths().end());
@@ -2025,6 +2095,10 @@ lldb::TypeSystemSP SwiftASTContext::CreateInstance(
20252095

20262096
LLDB_SCOPED_TIMER();
20272097
std::string m_description = "SwiftASTContextForExpressions";
2098+
std::vector<swift::ExternalPluginSearchPathAndServerPath>
2099+
external_plugin_search_paths;
2100+
std::vector<swift::PluginExecutablePathAndModuleNames>
2101+
compiler_plugin_executable_paths;
20282102
std::vector<std::string> module_search_paths;
20292103
std::vector<std::pair<std::string, bool>> framework_search_paths;
20302104
TargetSP target_sp = typeref_typesystem.GetTargetWP().lock();
@@ -2198,8 +2272,9 @@ lldb::TypeSystemSP SwiftASTContext::CreateInstance(
21982272
std::vector<std::string> extra_clang_args;
21992273
ProcessModule(target.GetImages().GetModuleAtIndex(mi), m_description,
22002274
discover_implicit_search_paths, use_all_compiler_flags,
2201-
target, triple, module_search_paths, framework_search_paths,
2202-
extra_clang_args);
2275+
target, triple, external_plugin_search_paths,
2276+
compiler_plugin_executable_paths, module_search_paths,
2277+
framework_search_paths, extra_clang_args);
22032278
swift_ast_sp->AddExtraClangArgs(extra_clang_args);
22042279
}
22052280

@@ -2244,6 +2319,15 @@ lldb::TypeSystemSP SwiftASTContext::CreateInstance(
22442319
return {};
22452320
}
22462321

2322+
// Initialize the compiler plugin search paths.
2323+
auto &opts = swift_ast_sp->GetSearchPathOptions();
2324+
opts.ExternalPluginSearchPaths.insert(opts.ExternalPluginSearchPaths.end(),
2325+
external_plugin_search_paths.begin(),
2326+
external_plugin_search_paths.end());
2327+
assert(opts.getCompilerPluginExecutablePaths().empty());
2328+
opts.setCompilerPluginExecutablePaths(
2329+
std::move(compiler_plugin_executable_paths));
2330+
22472331
for (size_t mi = 0; mi != num_images; ++mi) {
22482332
std::vector<std::string> module_names;
22492333
auto module_sp = target.GetImages().GetModuleAtIndex(mi);
@@ -4854,16 +4938,23 @@ void SwiftASTContextForExpressions::ModulesDidLoad(ModuleList &module_list) {
48544938
bool use_all_compiler_flags = target_sp->GetUseAllCompilerFlags();
48554939
unsigned num_images = module_list.GetSize();
48564940
for (size_t mi = 0; mi != num_images; ++mi) {
4941+
std::vector<swift::ExternalPluginSearchPathAndServerPath>
4942+
external_plugin_search_paths;
4943+
std::vector<swift::PluginExecutablePathAndModuleNames>
4944+
compiler_plugin_executable_paths;
48574945
std::vector<std::string> module_search_paths;
48584946
std::vector<std::pair<std::string, bool>> framework_search_paths;
48594947
std::vector<std::string> extra_clang_args;
48604948
lldb::ModuleSP module_sp = module_list.GetModuleAtIndex(mi);
48614949
ProcessModule(module_sp, m_description, discover_implicit_search_paths,
48624950
use_all_compiler_flags, *target_sp, GetTriple(),
4863-
module_search_paths, framework_search_paths,
4864-
extra_clang_args);
4865-
// If the use-all-compiler-flags setting is enabled, the expression
4866-
// context is supposed to merge all search paths from all dylibs.
4951+
external_plugin_search_paths,
4952+
compiler_plugin_executable_paths, module_search_paths,
4953+
framework_search_paths, extra_clang_args);
4954+
// If the use-all-compiler-flags setting is enabled, the
4955+
// expression context is supposed to merge all search paths
4956+
// from all dylibs.
4957+
// TODO: Maybe we should also do this for compiler plugins?
48674958
if (use_all_compiler_flags && !extra_clang_args.empty()) {
48684959
// We cannot reconfigure ClangImporter after its creation.
48694960
// Instead poison the SwiftASTContext so it gets recreated.
@@ -4894,16 +4985,20 @@ void SwiftASTContext::LogConfiguration() {
48944985
HEALTH_LOG_PRINTF(" (no AST context)");
48954986
return;
48964987
}
4988+
HEALTH_LOG_PRINTF(" Swift/C++ interop : %s",
4989+
m_ast_context_ap->LangOpts.EnableCXXInterop ? "on" : "off");
4990+
HEALTH_LOG_PRINTF(" Swift/Objective-C interop : %s",
4991+
m_ast_context_ap->LangOpts.EnableObjCInterop ? "on" : "off");
48974992

4898-
HEALTH_LOG_PRINTF(" Architecture : %s",
4993+
HEALTH_LOG_PRINTF(" Architecture : %s",
48994994
m_ast_context_ap->LangOpts.Target.getTriple().c_str());
49004995
HEALTH_LOG_PRINTF(
4901-
" SDK path : %s",
4996+
" SDK path : %s",
49024997
m_ast_context_ap->SearchPathOpts.getSDKPath().str().c_str());
49034998
HEALTH_LOG_PRINTF(
4904-
" Runtime resource path : %s",
4999+
" Runtime resource path : %s",
49055000
m_ast_context_ap->SearchPathOpts.RuntimeResourcePath.c_str());
4906-
HEALTH_LOG_PRINTF(" Runtime library paths : (%llu items)",
5001+
HEALTH_LOG_PRINTF(" Runtime library paths : (%llu items)",
49075002
(unsigned long long)m_ast_context_ap->SearchPathOpts
49085003
.RuntimeLibraryPaths.size());
49095004

@@ -4912,7 +5007,7 @@ void SwiftASTContext::LogConfiguration() {
49125007
HEALTH_LOG_PRINTF(" %s", runtime_library_path.c_str());
49135008
}
49145009

4915-
HEALTH_LOG_PRINTF(" Runtime library import paths : (%llu items)",
5010+
HEALTH_LOG_PRINTF(" Runtime library import paths : (%llu items)",
49165011
(unsigned long long)m_ast_context_ap->SearchPathOpts
49175012
.getRuntimeLibraryImportPaths()
49185013
.size());
@@ -4922,7 +5017,7 @@ void SwiftASTContext::LogConfiguration() {
49225017
HEALTH_LOG_PRINTF(" %s", runtime_import_path.c_str());
49235018
}
49245019

4925-
HEALTH_LOG_PRINTF(" Framework search paths : (%llu items)",
5020+
HEALTH_LOG_PRINTF(" Framework search paths : (%llu items)",
49265021
(unsigned long long)m_ast_context_ap->SearchPathOpts
49275022
.getFrameworkSearchPaths()
49285023
.size());
@@ -4931,7 +5026,7 @@ void SwiftASTContext::LogConfiguration() {
49315026
HEALTH_LOG_PRINTF(" %s", framework_search_path.Path.c_str());
49325027
}
49335028

4934-
HEALTH_LOG_PRINTF(" Import search paths : (%llu items)",
5029+
HEALTH_LOG_PRINTF(" Import search paths : (%llu items)",
49355030
(unsigned long long)m_ast_context_ap->SearchPathOpts
49365031
.getImportSearchPaths()
49375032
.size());
@@ -4944,13 +5039,39 @@ void SwiftASTContext::LogConfiguration() {
49445039
GetClangImporterOptions();
49455040

49465041
HEALTH_LOG_PRINTF(
4947-
" Extra clang arguments : (%llu items)",
5042+
" Extra clang arguments : (%llu items)",
49485043
(unsigned long long)clang_importer_options.ExtraArgs.size());
49495044
for (std::string &extra_arg : clang_importer_options.ExtraArgs) {
49505045
HEALTH_LOG_PRINTF(" %s", extra_arg.c_str());
49515046
}
4952-
HEALTH_LOG_PRINTF(" Swift/C++ interop mode: %s",
4953-
m_ast_context_ap->LangOpts.EnableCXXInterop ? "on" : "off");
5047+
5048+
#define PRINT_PLUGIN_PATHS(ACCESSOR, NAME, TEMPLATE, ...) \
5049+
{ \
5050+
auto paths = m_ast_context_ap->SearchPathOpts.ACCESSOR; \
5051+
HEALTH_LOG_PRINTF(" %s: (%llu items)", NAME, \
5052+
(unsigned long long)paths.size()); \
5053+
for (auto &path : paths) { \
5054+
HEALTH_LOG_PRINTF(" " TEMPLATE, ##__VA_ARGS__); \
5055+
} \
5056+
}
5057+
PRINT_PLUGIN_PATHS(getCompilerPluginLibraryPaths(),
5058+
"Compiler Plugin Library Paths ",
5059+
"%s", path.c_str());
5060+
PRINT_PLUGIN_PATHS(getCompilerPluginExecutablePaths(),
5061+
"Compiler Plugin Executable Paths ", "%s: [%s]",
5062+
path.ExecutablePath.c_str(),
5063+
[](auto path_names) -> std::string {
5064+
std::string s;
5065+
llvm::raw_string_ostream os(s);
5066+
llvm::interleaveComma(path_names, os);
5067+
return os.str();
5068+
}(path.ModuleNames)
5069+
.c_str());
5070+
PRINT_PLUGIN_PATHS(PluginSearchPaths, "Plugin search paths ",
5071+
"%s", path.c_str());
5072+
PRINT_PLUGIN_PATHS(ExternalPluginSearchPaths,
5073+
"External plugin search paths ", "%s (server: %s)",
5074+
path.SearchPath.c_str(), path.ServerPath.c_str());
49545075
}
49555076

49565077
bool SwiftASTContext::HasTarget() {

lldb/source/Target/Target.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4654,6 +4654,16 @@ EnableSwiftCxxInterop TargetProperties::GetEnableSwiftCxxInterop() const {
46544654
return enable_interop;
46554655
}
46564656

4657+
Args TargetProperties::GetSwiftPluginServerForPath() const {
4658+
const uint32_t idx = ePropertySwiftPluginServerForPath;
4659+
4660+
llvm::StringMap<std::string> result;
4661+
Args property_plugin_server_path;
4662+
m_experimental_properties_up->GetValueProperties()->GetPropertyAtIndexAsArgs(
4663+
nullptr, idx, property_plugin_server_path);
4664+
return property_plugin_server_path;
4665+
}
4666+
46574667
bool TargetProperties::GetSwiftAutoImportFrameworks() const {
46584668
const uint32_t idx = ePropertySwiftAutoImportFrameworks;
46594669
return m_collection_sp->GetPropertyAtIndexAsBoolean(

lldb/source/Target/TargetProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ let Definition = "target_experimental" in {
2323
DefaultEnumValue<"eAutoDetectSwiftCxxInterop">,
2424
EnumValues<"OptionEnumValues(g_enable_swift_cxx_interop_values)">,
2525
Desc<"Passes the -enable-cxx-interop flag to the swift compiler.">;
26+
def SwiftPluginServerForPath: Property<"swift-plugin-server-for-path",
27+
"Dictionary">,
28+
ElementType<"String">,
29+
Desc<"A dictionary of plugin paths as keys and swift-plugin-server binaries as values">;
2630
}
2731

2832
let Definition = "target" in {

0 commit comments

Comments
 (0)