Skip to content

Commit eeee46d

Browse files
committed
[LLDB] Support importing modules from llvmcas:// URLs
This patch creates a wrapper LLDB Swft module loader that owns both an ESML (explicit Swift module loader) and a CAS explicit module loader, dispatches module discovery calls to both, and tries to find each module in the CAS first, before trying the ESML. rdar://166576110
1 parent 7309a6a commit eeee46d

File tree

12 files changed

+432
-133
lines changed

12 files changed

+432
-133
lines changed

lldb/include/lldb/Core/ModuleList.h

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333
#include <cstddef>
3434
#include <cstdint>
3535

36+
namespace llvm {
37+
namespace cas {
38+
class CASConfiguration;
39+
class ObjectStore;
40+
class ActionCache;
41+
} // namespace cas
42+
} // namespace llvm
43+
3644
namespace lldb_private {
3745
class ConstString;
3846
class FileSpecList;
@@ -106,6 +114,7 @@ class ModuleListProperties : public Properties {
106114
// START CAS
107115
/// Get CASPath set via properties.
108116
FileSpec GetCASOnDiskPath() const;
117+
bool SetCASOnDiskPath(const FileSpec &);
109118

110119
/// Get CASPluginPath set via properties.
111120
FileSpec GetCASPluginPath() const;
@@ -538,10 +547,14 @@ class ModuleList {
538547

539548
// START CAS
540549

541-
/// Get CAS configuration using global module properties or from candidate
542-
/// search path.
543-
static std::optional<llvm::cas::CASConfiguration>
544-
GetCASConfiguration(FileSpec CandidateConfigSearchPath);
550+
struct CAS {
551+
std::shared_ptr<llvm::cas::CASConfiguration> configuration;
552+
std::shared_ptr<llvm::cas::ObjectStore> object_store;
553+
std::shared_ptr<llvm::cas::ActionCache> action_cache;
554+
};
555+
/// Search for a CAS configuration file near this module. This
556+
/// operation does a lot of file system stat calls.
557+
static llvm::Expected<CAS> GetOrCreateCAS(const lldb::ModuleSP &module_sp);
545558

546559
/// Gets the shared module from CAS. It works the same as `GetSharedModule`
547560
/// but the lookup is done inside the CAS.
@@ -550,11 +563,9 @@ class ModuleList {
550563
/// true if module is successfully loaded, false if module is not found
551564
/// in the CAS, error if there are any errors happened during the loading
552565
/// process.
553-
static llvm::Expected<bool> GetSharedModuleFromCAS(ConstString module_name,
554-
llvm::StringRef cas_id,
555-
FileSpec cu_path,
556-
ModuleSpec &module_spec,
557-
lldb::ModuleSP &module_sp);
566+
static llvm::Expected<bool>
567+
GetSharedModuleFromCAS(llvm::StringRef cas_id, const lldb::ModuleSP &nearby,
568+
ModuleSpec &module_spec, lldb::ModuleSP &module_sp);
558569
// END CAS
559570

560571
static bool RemoveSharedModule(lldb::ModuleSP &module_sp);

lldb/source/Core/ModuleList.cpp

Lines changed: 102 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "lldb/Interpreter/Property.h"
1818
#include "lldb/Symbol/ObjectFile.h"
1919
#include "lldb/Symbol/SymbolContext.h"
20+
#include "lldb/Symbol/SymbolFile.h"
2021
#include "lldb/Symbol/TypeList.h"
2122
#include "lldb/Symbol/VariableList.h"
2223
#include "lldb/Utility/ArchSpec.h"
@@ -28,6 +29,7 @@
2829
#include "lldb/Utility/UUID.h"
2930
#include "lldb/lldb-defines.h"
3031
#include "llvm/ADT/ScopeExit.h"
32+
#include "llvm/Support/Error.h"
3133
#include "llvm/Support/FileUtilities.h"
3234

3335
#if defined(_WIN32)
@@ -304,6 +306,11 @@ FileSpec ModuleListProperties::GetCASOnDiskPath() const {
304306
return GetPropertyAtIndexAs<FileSpec>(idx, {});
305307
}
306308

309+
bool ModuleListProperties::SetCASOnDiskPath(const FileSpec &path) {
310+
const uint32_t idx = ePropertyCASOnDiskPath;
311+
return SetPropertyAtIndex(idx, path);
312+
}
313+
307314
FileSpec ModuleListProperties::GetCASPluginPath() const {
308315
const uint32_t idx = ePropertyCASPluginPath;
309316
return GetPropertyAtIndexAs<FileSpec>(idx, {});
@@ -1299,7 +1306,8 @@ class SharedModuleList {
12991306
struct SharedModuleListInfo {
13001307
SharedModuleList module_list;
13011308
ModuleListProperties module_list_properties;
1302-
std::shared_ptr<llvm::cas::ObjectStore> cas_object_store;
1309+
// TODO: This should be an LRU cache of multiple CAS.
1310+
ModuleList::CAS cas = {};
13031311
std::mutex shared_lock;
13041312
};
13051313
}
@@ -1322,8 +1330,8 @@ static SharedModuleList &GetSharedModuleList() {
13221330
return GetSharedModuleListInfo().module_list;
13231331
}
13241332

1325-
std::optional<llvm::cas::CASConfiguration>
1326-
ModuleList::GetCASConfiguration(FileSpec CandidateConfigSearchPath) {
1333+
static std::optional<llvm::cas::CASConfiguration>
1334+
GetCASConfiguration(FileSpec CandidateConfigSearchPath) {
13271335
// Config CAS from properties.
13281336
llvm::cas::CASConfiguration cas_config;
13291337
cas_config.CASPath =
@@ -1344,25 +1352,6 @@ ModuleList::GetCASConfiguration(FileSpec CandidateConfigSearchPath) {
13441352
return std::nullopt;
13451353
}
13461354

1347-
static llvm::Expected<std::shared_ptr<llvm::cas::ObjectStore>>
1348-
GetOrCreateCASStorage(FileSpec CandidateConfigSearchPath) {
1349-
auto &shared_module_list = GetSharedModuleListInfo();
1350-
if (shared_module_list.cas_object_store)
1351-
return shared_module_list.cas_object_store;
1352-
1353-
auto config = ModuleList::GetCASConfiguration(CandidateConfigSearchPath);
1354-
if (!config)
1355-
return nullptr;
1356-
1357-
auto cas = config->createDatabases();
1358-
if (!cas)
1359-
return cas.takeError();
1360-
1361-
std::scoped_lock<std::mutex> lock(shared_module_list.shared_lock);
1362-
shared_module_list.cas_object_store = std::move(cas->first);
1363-
return shared_module_list.cas_object_store;
1364-
}
1365-
13661355
ModuleListProperties &ModuleList::GetGlobalModuleListProperties() {
13671356
return GetSharedModuleListInfo().module_list_properties;
13681357
}
@@ -1634,19 +1623,18 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
16341623
return error;
16351624
}
16361625

1637-
static llvm::Expected<bool> loadModuleFromCAS(ConstString module_name,
1638-
llvm::StringRef cas_id,
1639-
FileSpec cu_path,
1640-
ModuleSpec &module_spec) {
1641-
auto maybe_cas = GetOrCreateCASStorage(cu_path);
1626+
static llvm::Expected<bool> loadModuleFromCASImpl(llvm::StringRef cas_id,
1627+
const lldb::ModuleSP &nearby,
1628+
ModuleSpec &module_spec) {
1629+
auto maybe_cas = ModuleList::GetOrCreateCAS(nearby);
16421630
if (!maybe_cas)
16431631
return maybe_cas.takeError();
16441632

1645-
auto cas = std::move(*maybe_cas);
1633+
auto cas = std::move(maybe_cas->object_store);
16461634
if (!cas) {
16471635
LLDB_LOG(GetLog(LLDBLog::Modules),
16481636
"skip loading module '{0}' from CAS: CAS is not available",
1649-
module_name);
1637+
cas_id);
16501638
return false;
16511639
}
16521640

@@ -1670,15 +1658,96 @@ static llvm::Expected<bool> loadModuleFromCAS(ConstString module_name,
16701658
loaded.GetArchitecture() = module_spec.GetArchitecture();
16711659
module_spec = loaded;
16721660

1673-
LLDB_LOG(GetLog(LLDBLog::Modules), "loading module '{0}' using CASID '{1}'",
1674-
module_name, cas_id);
1661+
LLDB_LOG(GetLog(LLDBLog::Modules), "loading module using CASID '{0}'",
1662+
cas_id);
16751663
return true;
16761664
}
16771665

1666+
/// Load the module referenced by \c cas_id from a CAS located
1667+
/// near \c nearby.
1668+
static llvm::Expected<bool> loadModuleFromCAS(llvm::StringRef cas_id,
1669+
const lldb::ModuleSP &nearby,
1670+
ModuleSpec &module_spec) {
1671+
static llvm::StringMap<bool> g_cache;
1672+
static std::recursive_mutex g_cache_lock;
1673+
std::scoped_lock<std::recursive_mutex> lock(g_cache_lock);
1674+
auto cached = g_cache.find(cas_id);
1675+
if (cached != g_cache.end())
1676+
return cached->second;
1677+
auto result = loadModuleFromCASImpl(cas_id, nearby, module_spec);
1678+
// Errors are only returned the first time.
1679+
g_cache.insert({cas_id, result ? *result : false});
1680+
return result;
1681+
}
1682+
1683+
llvm::Expected<ModuleList::CAS>
1684+
ModuleList::GetOrCreateCAS(const ModuleSP &module_sp) {
1685+
if (!module_sp)
1686+
return llvm::createStringError("no lldb::Module available");
1687+
1688+
auto &shared_module_list = GetSharedModuleListInfo();
1689+
std::scoped_lock<std::mutex> lock(shared_module_list.shared_lock);
1690+
if (shared_module_list.cas.object_store)
1691+
return shared_module_list.cas;
1692+
1693+
std::set<FileSpec> unique_paths;
1694+
auto insert_module_path = [&](const ModuleSP &m) -> IterationAction {
1695+
if (m) {
1696+
FileSpec path = m->GetFileSpec();
1697+
path.ClearFilename();
1698+
unique_paths.insert(path);
1699+
}
1700+
return IterationAction::Continue;
1701+
};
1702+
insert_module_path(module_sp);
1703+
1704+
std::optional<llvm::cas::CASConfiguration> cas_config;
1705+
for (auto &path : unique_paths)
1706+
cas_config = GetCASConfiguration(path);
1707+
if (!cas_config) {
1708+
unique_paths.clear();
1709+
insert_module_path(module_sp);
1710+
if (SymbolFile *sf = module_sp->GetSymbolFile()) {
1711+
sf->GetDebugInfoModules().ForEach(insert_module_path);
1712+
for (auto &path : unique_paths)
1713+
if ((cas_config = GetCASConfiguration(path)))
1714+
break;
1715+
}
1716+
}
1717+
if (!cas_config &&
1718+
!ModuleList::GetGlobalModuleListProperties().GetCASOnDiskPath())
1719+
for (auto &path : unique_paths) {
1720+
llvm::StringRef parent = path.GetDirectory().GetStringRef();
1721+
while (!parent.empty() &&
1722+
llvm::sys::path::filename(parent) != "DerivedData")
1723+
parent = llvm::sys::path::parent_path(parent);
1724+
if (parent.empty())
1725+
continue;
1726+
llvm::SmallString<256> cas_path(parent);
1727+
llvm::sys::path::append(cas_path, "CompilationCache.noindex", "builtin");
1728+
FileSpec fs = FileSpec(cas_path);
1729+
ModuleList::GetGlobalModuleListProperties().SetCASOnDiskPath(fs);
1730+
cas_config = GetCASConfiguration(fs);
1731+
if (cas_config)
1732+
break;
1733+
}
1734+
1735+
if (!cas_config)
1736+
return llvm::createStringError("no CAS available");
1737+
auto cas = cas_config->createDatabases();
1738+
if (!cas)
1739+
return cas.takeError();
1740+
1741+
shared_module_list.cas = {
1742+
std::make_shared<llvm::cas::CASConfiguration>(*cas_config),
1743+
std::move(cas->first), std::move(cas->second)};
1744+
return shared_module_list.cas;
1745+
}
1746+
16781747
llvm::Expected<bool> ModuleList::GetSharedModuleFromCAS(
1679-
ConstString module_name, llvm::StringRef cas_id, FileSpec cu_path,
1748+
llvm::StringRef cas_id, const lldb::ModuleSP &nearby,
16801749
ModuleSpec &module_spec, lldb::ModuleSP &module_sp) {
1681-
auto loaded = loadModuleFromCAS(module_name, cas_id, cu_path, module_spec);
1750+
auto loaded = loadModuleFromCAS(cas_id, nearby, module_spec);
16821751
if (!loaded)
16831752
return loaded.takeError();
16841753

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,21 +2006,25 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
20062006

20072007
dwo_module_spec.GetArchitecture() =
20082008
m_objfile_sp->GetModule()->GetArchitecture();
2009+
dwo_module_spec.GetFileSpec().SetFile(dwo_path, FileSpec::Style::native);
20092010

2010-
// Try load from CAS, if loaded, continue to next one.
2011-
auto loaded = ModuleList::GetSharedModuleFromCAS(
2012-
const_name, dwo_path, GetObjectFile()->GetFileSpec(), dwo_module_spec,
2013-
module_sp);
2014-
if (!loaded)
2015-
GetObjectFile()->GetModule()->ReportWarning(
2016-
"Failed to load module '{0}' from CAS: {1}", const_name,
2017-
toString(loaded.takeError()));
2018-
2019-
// succeed, loaded next module.
2020-
if (*loaded)
2021-
continue;
2011+
// BEGIN CAS
2012+
llvm::StringRef url(dwo_path);
2013+
if (url.starts_with("llvmcas://")) {
2014+
LLDB_LOG(GetLog(LLDBLog::Symbols|LLDBLog::Modules),
2015+
"Loading module '{0}' from CAS at {1}...", const_name, url);
2016+
auto loaded = ModuleList::GetSharedModuleFromCAS(
2017+
url, GetObjectFile()->GetModule(), dwo_module_spec, module_sp);
2018+
if (!loaded)
2019+
GetObjectFile()->GetModule()->ReportWarning(
2020+
"Failed to load module '{0}' from CAS: {1}", const_name,
2021+
toString(loaded.takeError()));
2022+
else if (*loaded)
2023+
// Succeed, load next module.
2024+
continue;
2025+
}
2026+
// END CAS
20222027

2023-
dwo_module_spec.GetFileSpec().SetFile(dwo_path, FileSpec::Style::native);
20242028
if (dwo_module_spec.GetFileSpec().IsRelative()) {
20252029
const char *comp_dir =
20262030
die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr);

lldb/source/Plugins/TypeSystem/Swift/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_lldb_library(lldbPluginTypeSystemSwift PLUGIN
2+
LLDBExplicitModuleLoader.cpp
23
SwiftDWARFImporterForClangTypes.cpp
34
TypeSystemSwift.cpp
45
TypeSystemSwiftTypeRef.cpp

0 commit comments

Comments
 (0)