Index: lldb/include/lldb/API/SBDebugger.h =================================================================== --- lldb/include/lldb/API/SBDebugger.h +++ lldb/include/lldb/API/SBDebugger.h @@ -14,6 +14,10 @@ #include "lldb/API/SBDefines.h" #include "lldb/API/SBPlatform.h" +namespace lldb_private { +struct SystemInitializerOptions; +} + namespace lldb { class LLDB_API SBInputReader { @@ -31,6 +35,18 @@ bool IsActive() const; }; +class LLDB_API SBInitializationOptions { +public: + SBInitializationOptions(); + ~SBInitializationOptions(); + + void SetVFSOverlay(const char *overlay); + +private: + friend class lldb::SBDebugger; + std::unique_ptr m_opaque_up; +}; + class LLDB_API SBDebugger { public: FLAGS_ANONYMOUS_ENUM(){eBroadcastBitProgress = (1 << 0)}; @@ -84,6 +100,8 @@ static void Initialize(); static lldb::SBError InitializeWithErrorHandling(); + static lldb::SBError + InitializeWithErrorHandling(const SBInitializationOptions &options); static void Terminate(); Index: lldb/include/lldb/API/SBDefines.h =================================================================== --- lldb/include/lldb/API/SBDefines.h +++ lldb/include/lldb/API/SBDefines.h @@ -48,6 +48,7 @@ class LLDB_API SBFrame; class LLDB_API SBFunction; class LLDB_API SBHostOS; +class LLDB_API SBInitializationOptions; class LLDB_API SBInstruction; class LLDB_API SBInstructionList; class LLDB_API SBLanguageRuntime; Index: lldb/include/lldb/Initialization/SystemInitializerCommon.h =================================================================== --- lldb/include/lldb/Initialization/SystemInitializerCommon.h +++ lldb/include/lldb/Initialization/SystemInitializerCommon.h @@ -13,6 +13,12 @@ #include "lldb/Host/HostInfo.h" namespace lldb_private { +struct SystemInitializerOptions { + /// Overlay the virtual filesystem described by file over the real file + /// system. + FileSpec vfs_overlay; +}; + /// Initializes common lldb functionality. /// /// This class is responsible for initializing a subset of lldb @@ -23,7 +29,8 @@ /// the constructor. class SystemInitializerCommon : public SystemInitializer { public: - SystemInitializerCommon(HostInfo::SharedLibraryDirectoryHelper *helper); + SystemInitializerCommon(HostInfo::SharedLibraryDirectoryHelper *helper, + SystemInitializerOptions = {}); ~SystemInitializerCommon() override; llvm::Error Initialize() override; @@ -31,6 +38,7 @@ private: HostInfo::SharedLibraryDirectoryHelper *m_shlib_dir_helper; + SystemInitializerOptions m_options; }; } // namespace lldb_private Index: lldb/source/API/SBDebugger.cpp =================================================================== --- lldb/source/API/SBDebugger.cpp +++ lldb/source/API/SBDebugger.cpp @@ -127,6 +127,22 @@ return false; } +SBInitializationOptions::SBInitializationOptions() + : m_opaque_up(std::make_unique()) { + LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBInitializationOptions); +} + +SBInitializationOptions::~SBInitializationOptions() {} + +// We can't use an SBFileSpec as the argument, because that will try to use +// the FileSystem before it's initialized. +void SBInitializationOptions::SetVFSOverlay(const char *overlay) { + LLDB_RECORD_METHOD(void, SBInitializationOptions, SetVFSOverlay, + (const char *), overlay); + + m_opaque_up->vfs_overlay = FileSpec(overlay); +} + SBDebugger::SBDebugger() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBDebugger); } SBDebugger::SBDebugger(const lldb::DebuggerSP &debugger_sp) @@ -202,6 +218,21 @@ return LLDB_RECORD_RESULT(error); } +lldb::SBError SBDebugger::InitializeWithErrorHandling( + const SBInitializationOptions &options) { + LLDB_RECORD_STATIC_METHOD(lldb::SBError, SBDebugger, + InitializeWithErrorHandling, + (const lldb::SBInitializationOptions &), options); + + SBError error; + if (auto e = g_debugger_lifetime->Initialize( + std::make_unique(*options.m_opaque_up), + LoadPlugin)) { + error.SetError(Status(std::move(e))); + } + return LLDB_RECORD_RESULT(error); +} + void SBDebugger::Terminate() { LLDB_RECORD_STATIC_METHOD_NO_ARGS(void, SBDebugger, Terminate); @@ -844,16 +875,18 @@ // The version of CreateTarget that takes an ArchSpec won't accept an // empty ArchSpec, so when the arch hasn't been specified, we need to // call the target triple version. - error = m_opaque_sp->GetTargetList().CreateTarget(*m_opaque_sp, filename, - arch_cstr, eLoadDependentsYes, nullptr, target_sp); + error = m_opaque_sp->GetTargetList().CreateTarget( + *m_opaque_sp, filename, arch_cstr, eLoadDependentsYes, nullptr, + target_sp); } else { PlatformSP platform_sp = m_opaque_sp->GetPlatformList() .GetSelectedPlatform(); - ArchSpec arch = Platform::GetAugmentedArchSpec(platform_sp.get(), - arch_cstr); + ArchSpec arch = + Platform::GetAugmentedArchSpec(platform_sp.get(), arch_cstr); if (arch.IsValid()) - error = m_opaque_sp->GetTargetList().CreateTarget(*m_opaque_sp, filename, - arch, eLoadDependentsYes, platform_sp, target_sp); + error = m_opaque_sp->GetTargetList().CreateTarget( + *m_opaque_sp, filename, arch, eLoadDependentsYes, platform_sp, + target_sp); else error.SetErrorStringWithFormat("invalid arch_cstr: %s", arch_cstr); } @@ -1892,6 +1925,12 @@ LLDB_REGISTER_METHOD(lldb::SBCommandInterpreterRunResult, SBDebugger, RunCommandInterpreter, (const lldb::SBCommandInterpreterRunOptions &)); + LLDB_REGISTER_CONSTRUCTOR(SBInitializationOptions, ()); + LLDB_REGISTER_METHOD(void, SBInitializationOptions, SetVFSOverlay, + (const char *)); + LLDB_REGISTER_STATIC_METHOD(lldb::SBError, SBDebugger, + InitializeWithErrorHandling, + (const lldb::SBInitializationOptions &)); } } // namespace repro Index: lldb/source/API/SystemInitializerFull.h =================================================================== --- lldb/source/API/SystemInitializerFull.h +++ lldb/source/API/SystemInitializerFull.h @@ -20,7 +20,7 @@ /// internally by SBDebugger to initialize the system. class SystemInitializerFull : public SystemInitializerCommon { public: - SystemInitializerFull(); + SystemInitializerFull(SystemInitializerOptions options = {}); ~SystemInitializerFull() override; llvm::Error Initialize() override; Index: lldb/source/API/SystemInitializerFull.cpp =================================================================== --- lldb/source/API/SystemInitializerFull.cpp +++ lldb/source/API/SystemInitializerFull.cpp @@ -44,8 +44,8 @@ using namespace lldb_private; -SystemInitializerFull::SystemInitializerFull() - : SystemInitializerCommon(g_shlib_dir_helper) {} +SystemInitializerFull::SystemInitializerFull(SystemInitializerOptions options) + : SystemInitializerCommon(g_shlib_dir_helper, std::move(options)) {} SystemInitializerFull::~SystemInitializerFull() = default; llvm::Error SystemInitializerFull::Initialize() { Index: lldb/source/Initialization/SystemInitializerCommon.cpp =================================================================== --- lldb/source/Initialization/SystemInitializerCommon.cpp +++ lldb/source/Initialization/SystemInitializerCommon.cpp @@ -35,13 +35,14 @@ using namespace lldb_private::repro; SystemInitializerCommon::SystemInitializerCommon( - HostInfo::SharedLibraryDirectoryHelper *helper) - : m_shlib_dir_helper(helper) {} + HostInfo::SharedLibraryDirectoryHelper *helper, + SystemInitializerOptions options) + : m_shlib_dir_helper(helper), m_options(std::move(options)) {} SystemInitializerCommon::~SystemInitializerCommon() = default; /// Initialize the FileSystem based on the current reproducer mode. -static llvm::Error InitializeFileSystem() { +static llvm::Error InitializeFileSystem(FileSpec vfs_overlay) { auto &r = repro::Reproducer::Instance(); if (repro::Loader *loader = r.GetLoader()) { FileSpec vfs_mapping = loader->GetFile(); @@ -88,6 +89,12 @@ return llvm::Error::success(); } + if (vfs_overlay) { + if (llvm::Error e = FileSystem::Initialize(vfs_overlay)) + return e; + return llvm::Error::success(); + } + FileSystem::Initialize(); return llvm::Error::success(); } @@ -122,7 +129,7 @@ return e; } - if (auto e = InitializeFileSystem()) + if (auto e = InitializeFileSystem(m_options.vfs_overlay)) return e; Log::Initialize(); Index: lldb/test/Shell/Driver/Inputs/create_overlay.py =================================================================== --- /dev/null +++ lldb/test/Shell/Driver/Inputs/create_overlay.py @@ -0,0 +1,20 @@ +import sys + +_, virtual_path, real_path, overlay_path = sys.argv + +string = '''{ + "use-external-names": false, + "version": 0, + "roots": [ + { + "type": "file", + "name": "%s", + "external-contents": "%s" + } + ] +}''' % (virtual_path, real_path) + + +with open(overlay_path, 'w') as f: + f.write(string) + print(string) Index: lldb/test/Shell/Driver/TestOverlay.test =================================================================== --- /dev/null +++ lldb/test/Shell/Driver/TestOverlay.test @@ -0,0 +1,12 @@ +# REQUIRES: python + +# RUN: mkdir -p %t/foo +# RUN: %clang_host %p/Inputs/hello.c -g -o %t/foo/a.out + +# RUN: %python %p/Inputs/create_overlay.py %t/bar/a.out %t/foo/a.out %t.overlay + +# RUN: %lldb -vfs-overlay %t.overlay %t/bar/a.out 2>&1 | FileCheck %s +# CHECK-NOT: error: + +# RUN: %lldb %t/bar/a.out 2>&1 | FileCheck %s --check-prefix FAILURE +# FAILURE: unable to find executable Index: lldb/tools/driver/Driver.cpp =================================================================== --- lldb/tools/driver/Driver.cpp +++ lldb/tools/driver/Driver.cpp @@ -912,7 +912,10 @@ return *exit_code; } - SBError error = SBDebugger::InitializeWithErrorHandling(); + SBInitializationOptions options; + if (auto *arg = input_args.getLastArg(OPT_vfs_overlay)) + options.SetVFSOverlay(arg->getValue()); + SBError error = SBDebugger::InitializeWithErrorHandling(options); if (error.Fail()) { WithColor::error() << "initialization failed: " << error.GetCString() << '\n'; Index: lldb/tools/driver/Options.td =================================================================== --- lldb/tools/driver/Options.td +++ lldb/tools/driver/Options.td @@ -243,4 +243,8 @@ def generate_on_exit: F<"reproducer-generate-on-exit">, HelpText<"Generate reproducer on exit.">; +def vfs_overlay: Separate<["--", "-"], "vfs-overlay">, + MetaVarName<"">, + HelpText<"Overlay the virtual filesystem described by file over the real file system">; + def REM : R<["--"], "">;