aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Core/Debugger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core/Debugger.cpp')
-rw-r--r--lldb/source/Core/Debugger.cpp89
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;