Skip to content

Commit 73af341

Browse files
committed
[lldb] Capture and load home directory from the reproducer.
When replaying the reproducer, lldb should source the .lldbinit file that was captured by the reproducer and not the one in the current home directory. This requires that we store the home directory as part of the reproducer. By returning the virtual home directory during replay, we ensure the correct virtual path gets constructed which the VFS can then find and remap to the correct file in the reproducer root. This patch adds a new HomeDirectoryProvider, similar to the existing WorkingDirectoryProvider. As the home directory is not part of the VFS, it is stored in LLDB's FileSystem instance.
1 parent c90ca0c commit 73af341

File tree

8 files changed

+94
-11
lines changed

8 files changed

+94
-11
lines changed

lldb/include/lldb/Host/FileSystem.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ class FileSystem {
3333

3434
FileSystem()
3535
: m_fs(llvm::vfs::getRealFileSystem()), m_collector(nullptr),
36-
m_mapped(false) {}
36+
m_home_directory(), m_mapped(false) {}
3737
FileSystem(std::shared_ptr<llvm::FileCollector> collector)
3838
: m_fs(llvm::vfs::getRealFileSystem()), m_collector(std::move(collector)),
39-
m_mapped(false) {}
39+
m_home_directory(), m_mapped(false) {}
4040
FileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
4141
bool mapped = false)
42-
: m_fs(std::move(fs)), m_collector(nullptr), m_mapped(mapped) {}
42+
: m_fs(std::move(fs)), m_collector(nullptr), m_home_directory(),
43+
m_mapped(mapped) {}
4344

4445
FileSystem(const FileSystem &fs) = delete;
4546
FileSystem &operator=(const FileSystem &fs) = delete;
@@ -193,10 +194,13 @@ class FileSystem {
193194
void Collect(const FileSpec &file_spec);
194195
void Collect(const llvm::Twine &file);
195196

197+
void SetHomeDirectory(std::string home_directory);
198+
196199
private:
197200
static llvm::Optional<FileSystem> &InstanceImpl();
198201
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> m_fs;
199202
std::shared_ptr<llvm::FileCollector> m_collector;
203+
std::string m_home_directory;
200204
bool m_mapped;
201205
};
202206
} // namespace lldb_private

lldb/include/lldb/Utility/Reproducer.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,25 @@ class WorkingDirectoryProvider
181181
static char ID;
182182
};
183183

184+
/// Provider for the home directory.
185+
///
186+
/// When the reproducer is kept, it writes the user's home directory to a file
187+
/// a file named home.txt in the reproducer root.
188+
class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
189+
public:
190+
HomeDirectoryProvider(const FileSpec &directory)
191+
: DirectoryProvider(directory) {
192+
llvm::SmallString<128> home_dir;
193+
llvm::sys::path::home_directory(home_dir);
194+
SetDirectory(std::string(home_dir));
195+
}
196+
struct Info {
197+
static const char *name;
198+
static const char *file;
199+
};
200+
static char ID;
201+
};
202+
184203
/// The recorder is a small object handed out by a provider to record data. It
185204
/// is commonly used in combination with a MultiProvider which is meant to
186205
/// record information for multiple instances of the same source of data.
@@ -495,6 +514,15 @@ template <typename T> class MultiLoader {
495514
unsigned m_index = 0;
496515
};
497516

517+
/// Helper to read directories written by the DirectoryProvider.
518+
template <typename T>
519+
llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
520+
llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
521+
if (!dir)
522+
return dir.takeError();
523+
return std::string(llvm::StringRef(*dir).rtrim());
524+
}
525+
498526
} // namespace repro
499527
} // namespace lldb_private
500528

lldb/source/Commands/CommandObjectReproducer.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum ReproducerProvider {
3131
eReproducerProviderProcessInfo,
3232
eReproducerProviderVersion,
3333
eReproducerProviderWorkingDirectory,
34+
eReproducerProviderHomeDirectory,
3435
eReproducerProviderNone
3536
};
3637

@@ -65,6 +66,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
6566
"cwd",
6667
"Working Directory",
6768
},
69+
{
70+
eReproducerProviderHomeDirectory,
71+
"home",
72+
"Home Directory",
73+
},
6874
{
6975
eReproducerProviderNone,
7076
"none",
@@ -433,7 +439,7 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
433439
}
434440
case eReproducerProviderWorkingDirectory: {
435441
Expected<std::string> cwd =
436-
loader->LoadBuffer<WorkingDirectoryProvider>();
442+
repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
437443
if (!cwd) {
438444
SetError(result, cwd.takeError());
439445
return false;
@@ -442,6 +448,17 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
442448
result.SetStatus(eReturnStatusSuccessFinishResult);
443449
return true;
444450
}
451+
case eReproducerProviderHomeDirectory: {
452+
Expected<std::string> home =
453+
repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
454+
if (!home) {
455+
SetError(result, home.takeError());
456+
return false;
457+
}
458+
result.AppendMessage(*home);
459+
result.SetStatus(eReturnStatusSuccessFinishResult);
460+
return true;
461+
}
445462
case eReproducerProviderCommands: {
446463
std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
447464
repro::MultiLoader<repro::CommandProvider>::Create(loader);

lldb/source/Host/common/FileSystem.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,10 @@ bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
361361
}
362362

363363
bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
364+
if (!m_home_directory.empty()) {
365+
path.assign(m_home_directory.begin(), m_home_directory.end());
366+
return true;
367+
}
364368
return llvm::sys::path::home_directory(path);
365369
}
366370

@@ -507,3 +511,7 @@ void FileSystem::Collect(const llvm::Twine &file) {
507511
else
508512
m_collector->addFile(file);
509513
}
514+
515+
void FileSystem::SetHomeDirectory(std::string home_directory) {
516+
m_home_directory = std::move(home_directory);
517+
}

lldb/source/Initialization/SystemInitializerCommon.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,24 @@ static llvm::Error InitializeFileSystem() {
5151
FileSystem::Initialize();
5252
}
5353

54-
llvm::Expected<std::string> cwd =
55-
loader->LoadBuffer<WorkingDirectoryProvider>();
56-
if (!cwd)
57-
return cwd.takeError();
58-
59-
llvm::StringRef working_dir = llvm::StringRef(*cwd).rtrim();
54+
// Set the current working directory form the reproducer.
55+
llvm::Expected<std::string> working_dir =
56+
repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
57+
if (!working_dir)
58+
return working_dir.takeError();
6059
if (std::error_code ec = FileSystem::Instance()
6160
.GetVirtualFileSystem()
62-
->setCurrentWorkingDirectory(working_dir)) {
61+
->setCurrentWorkingDirectory(*working_dir)) {
6362
return llvm::errorCodeToError(ec);
6463
}
6564

65+
// Set the home directory from the reproducer.
66+
llvm::Expected<std::string> home_dir =
67+
repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
68+
if (!home_dir)
69+
return home_dir.takeError();
70+
FileSystem::Instance().SetHomeDirectory(*home_dir);
71+
6672
return llvm::Error::success();
6773
}
6874

lldb/source/Utility/Reproducer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ static FileSpec MakeAbsolute(const FileSpec &file_spec) {
166166

167167
Generator::Generator(FileSpec root) : m_root(MakeAbsolute(std::move(root))) {
168168
GetOrCreate<repro::WorkingDirectoryProvider>();
169+
GetOrCreate<repro::HomeDirectoryProvider>();
169170
}
170171

171172
Generator::~Generator() {
@@ -306,6 +307,7 @@ char FileProvider::ID = 0;
306307
char ProviderBase::ID = 0;
307308
char VersionProvider::ID = 0;
308309
char WorkingDirectoryProvider::ID = 0;
310+
char HomeDirectoryProvider::ID = 0;
309311
const char *CommandProvider::Info::file = "command-interpreter.yaml";
310312
const char *CommandProvider::Info::name = "command-interpreter";
311313
const char *FileProvider::Info::file = "files.yaml";
@@ -314,3 +316,5 @@ const char *VersionProvider::Info::file = "version.txt";
314316
const char *VersionProvider::Info::name = "version";
315317
const char *WorkingDirectoryProvider::Info::file = "cwd.txt";
316318
const char *WorkingDirectoryProvider::Info::name = "cwd";
319+
const char *HomeDirectoryProvider::Info::file = "home.txt";
320+
const char *HomeDirectoryProvider::Info::name = "home";
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
reproducer status
2+
reproducer generate
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# RUN: echo "CHECK: %t.home" > %t.check
2+
3+
# RUN: rm -rf %t.repro
4+
# RUN: rm -rf %t.home
5+
# RUN: mkdir -p %t.repro
6+
# RUN: mkdir -p %t.home
7+
# RUN: echo "print 95000 + 126" > %t.home/.lldbinit
8+
# RUN: env HOME=%t.home %lldb-init -b -s %S/Inputs/HomeDir.in --capture --capture-path %t.repro | FileCheck %s
9+
10+
# RUN: cat %t.repro/home.txt | FileCheck %t.check
11+
# RUN: %lldb -b -o 'reproducer dump -p home -f %t.repro' | FileCheck %t.check
12+
13+
# RUN: %lldb --replay %t.repro | FileCheck %s
14+
# CHECK: 95126

0 commit comments

Comments
 (0)