diff options
Diffstat (limited to 'lldb/source/Core/Debugger.cpp')
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 32dcfb1ce17b..ae454fae3322 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -45,6 +45,7 @@ #include "lldb/Utility/Listener.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamCallback.h" @@ -75,6 +76,14 @@ #include <string> #include <system_error> +// Includes for pipe() +#if defined(_WIN32) +#include <fcntl.h> +#include <io.h> +#else +#include <unistd.h> +#endif + namespace lldb_private { class Address; } @@ -810,6 +819,86 @@ void Debugger::SetAsyncExecution(bool async_execution) { repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; } +static inline int OpenPipe(int fds[2], std::size_t size) { +#ifdef _WIN32 + return _pipe(fds, size, O_BINARY); +#else + (void)size; + return pipe(fds); +#endif +} + +Status Debugger::SetInputString(const char *data) { + Status result; + enum PIPES { READ, WRITE }; // Indexes for the read and write fds + int fds[2] = {-1, -1}; + + if (data == nullptr) { + result.SetErrorString("String data is null"); + return result; + } + + size_t size = strlen(data); + if (size == 0) { + result.SetErrorString("String data is empty"); + return result; + } + + if (OpenPipe(fds, size) != 0) { + result.SetErrorString( + "can't create pipe file descriptors for LLDB commands"); + return result; + } + + write(fds[WRITE], data, size); + // Close the write end of the pipe, so that the command interpreter will exit + // when it consumes all the data. + llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]); + + // Open the read file descriptor as a FILE * that we can return as an input + // handle. + FILE *commands_file = fdopen(fds[READ], "rb"); + if (commands_file == nullptr) { + result.SetErrorStringWithFormat("fdopen(%i, \"rb\") failed (errno = %i) " + "when trying to open LLDB commands pipe", + fds[READ], errno); + llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]); + return result; + } + + return SetInputFile( + (FileSP)std::make_shared<NativeFile>(commands_file, true)); +} + +Status Debugger::SetInputFile(FileSP file_sp) { + Status error; + repro::DataRecorder *recorder = nullptr; + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) + recorder = g->GetOrCreate<repro::CommandProvider>().GetNewRecorder(); + + static std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> loader = + repro::MultiLoader<repro::CommandProvider>::Create( + repro::Reproducer::Instance().GetLoader()); + if (loader) { + llvm::Optional<std::string> nextfile = loader->GetNextFile(); + FILE *fh = nextfile ? FileSystem::Instance().Fopen(nextfile->c_str(), "r") + : nullptr; + // FIXME Jonas Devlieghere: shouldn't this error be propagated out to the + // reproducer somehow if fh is NULL? + if (fh) { + file_sp = std::make_shared<NativeFile>(fh, true); + } + } + + if (!file_sp || !file_sp->IsValid()) { + error.SetErrorString("invalid file"); + return error; + } + + SetInputFile(file_sp, recorder); + return error; +} + void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) { assert(file_sp && file_sp->IsValid()); m_input_recorder = recorder; |