summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ScriptInterpreter
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /lldb/source/Plugins/ScriptInterpreter
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp32
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp56
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h2
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp4
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h6
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp95
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h30
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp230
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h2
10 files changed, 256 insertions, 202 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
index ecee8cc674f81..acd6128d84c5a 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
@@ -57,3 +57,35 @@ llvm::Error Lua::LoadModule(llvm::StringRef filename) {
lua_setglobal(m_lua_state, module_name.GetCString());
return llvm::Error::success();
}
+
+llvm::Error Lua::ChangeIO(FILE *out, FILE *err) {
+ assert(out != nullptr);
+ assert(err != nullptr);
+
+ lua_getglobal(m_lua_state, "io");
+
+ lua_getfield(m_lua_state, -1, "stdout");
+ if (luaL_Stream *s = static_cast<luaL_Stream *>(
+ luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
+ s->f = out;
+ lua_pop(m_lua_state, 1);
+ } else {
+ lua_pop(m_lua_state, 2);
+ return llvm::make_error<llvm::StringError>("could not get stdout",
+ llvm::inconvertibleErrorCode());
+ }
+
+ lua_getfield(m_lua_state, -1, "stderr");
+ if (luaL_Stream *s = static_cast<luaL_Stream *>(
+ luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
+ s->f = out;
+ lua_pop(m_lua_state, 1);
+ } else {
+ lua_pop(m_lua_state, 2);
+ return llvm::make_error<llvm::StringError>("could not get stderr",
+ llvm::inconvertibleErrorCode());
+ }
+
+ lua_pop(m_lua_state, 1);
+ return llvm::Error::success();
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
index f2984a925dfe1..300115aac8a7d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
@@ -38,6 +38,7 @@ public:
llvm::Error Run(llvm::StringRef buffer);
llvm::Error LoadModule(llvm::StringRef filename);
+ llvm::Error ChangeIO(FILE *out, FILE *err);
private:
lua_State *m_lua_state;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
index 701d68d1ec084..8cbeac4563c30 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -1,4 +1,4 @@
-//===-- ScriptInterpreterLua.cpp --------------------------------*- C++ -*-===//
+//===-- ScriptInterpreterLua.cpp ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -15,10 +15,13 @@
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StringList.h"
#include "lldb/Utility/Timer.h"
+#include "llvm/Support/FormatAdapters.h"
using namespace lldb;
using namespace lldb_private;
+LLDB_PLUGIN_DEFINE(ScriptInterpreterLua)
+
class IOHandlerLuaInterpreter : public IOHandlerDelegate,
public IOHandlerEditline {
public:
@@ -28,15 +31,23 @@ public:
">>> ", "..> ", true, debugger.GetUseColor(), 0,
*this, nullptr),
m_script_interpreter(script_interpreter) {
+ llvm::cantFail(m_script_interpreter.GetLua().ChangeIO(
+ debugger.GetOutputFile().GetStream(),
+ debugger.GetErrorFile().GetStream()));
llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID()));
}
- ~IOHandlerLuaInterpreter() {
+ ~IOHandlerLuaInterpreter() override {
llvm::cantFail(m_script_interpreter.LeaveSession());
}
void IOHandlerInputComplete(IOHandler &io_handler,
std::string &data) override {
+ if (llvm::StringRef(data).rtrim() == "quit") {
+ io_handler.SetIsDone(true);
+ return;
+ }
+
if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) {
*GetOutputStreamFileSP() << llvm::toString(std::move(error));
}
@@ -55,12 +66,43 @@ ScriptInterpreterLua::~ScriptInterpreterLua() {}
bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command,
CommandReturnObject *result,
const ExecuteScriptOptions &options) {
+ if (command.empty()) {
+ if (result)
+ result->AppendError("empty command passed to lua\n");
+ return false;
+ }
+
+ llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
+ io_redirect_or_error = ScriptInterpreterIORedirect::Create(
+ options.GetEnableIO(), m_debugger, result);
+ if (!io_redirect_or_error) {
+ if (result)
+ result->AppendErrorWithFormatv(
+ "failed to redirect I/O: {0}\n",
+ llvm::fmt_consume(io_redirect_or_error.takeError()));
+ else
+ llvm::consumeError(io_redirect_or_error.takeError());
+ return false;
+ }
+
+ ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error;
+
+ if (llvm::Error e =
+ m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(),
+ io_redirect.GetErrorFile()->GetStream())) {
+ result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n",
+ llvm::toString(std::move(e)));
+ return false;
+ }
+
if (llvm::Error e = m_lua->Run(command)) {
result->AppendErrorWithFormatv(
"lua failed attempting to evaluate '{0}': {1}\n", command,
llvm::toString(std::move(e)));
return false;
}
+
+ io_redirect.Flush();
return true;
}
@@ -68,25 +110,23 @@ void ScriptInterpreterLua::ExecuteInterpreterLoop() {
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
- Debugger &debugger = m_debugger;
-
// At the moment, the only time the debugger does not have an input file
// handle is when this is called directly from lua, in which case it is
// both dangerous and unnecessary (not to mention confusing) to try to embed
// a running interpreter loop inside the already running lua interpreter
// loop, so we won't do it.
-
- if (!debugger.GetInputFile().IsValid())
+ if (!m_debugger.GetInputFile().IsValid())
return;
- IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(debugger, *this));
- debugger.PushIOHandler(io_handler_sp);
+ IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this));
+ m_debugger.RunIOHandlerAsync(io_handler_sp);
}
bool ScriptInterpreterLua::LoadScriptingModule(
const char *filename, bool init_session, lldb_private::Status &error,
StructuredData::ObjectSP *module_sp) {
+ FileSystem::Instance().Collect(filename);
if (llvm::Error e = m_lua->LoadModule(filename)) {
error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n",
filename, llvm::toString(std::move(e)));
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
index 4e922151385b6..bcc6ab24f6d0b 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
@@ -25,7 +25,7 @@ public:
void ExecuteInterpreterLoop() override;
- virtual bool
+ bool
LoadScriptingModule(const char *filename, bool init_session,
lldb_private::Status &error,
StructuredData::ObjectSP *module_sp = nullptr) override;
diff --git a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
index 3517f831970dd..d9c32cc132d4c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
@@ -1,4 +1,4 @@
-//===-- ScriptInterpreterNone.cpp -------------------------------*- C++ -*-===//
+//===-- ScriptInterpreterNone.cpp -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -20,6 +20,8 @@
using namespace lldb;
using namespace lldb_private;
+LLDB_PLUGIN_DEFINE(ScriptInterpreterNone)
+
ScriptInterpreterNone::ScriptInterpreterNone(Debugger &debugger)
: ScriptInterpreter(debugger, eScriptLanguageNone) {}
diff --git a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h
index 242065cc23e86..c438b6315c5d9 100644
--- a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h
+++ b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_ScriptInterpreterNone_h_
-#define liblldb_ScriptInterpreterNone_h_
+#ifndef LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_NONE_SCRIPTINTERPRETERNONE_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_NONE_SCRIPTINTERPRETERNONE_H
#include "lldb/Interpreter/ScriptInterpreter.h"
@@ -44,4 +44,4 @@ public:
} // namespace lldb_private
-#endif // liblldb_ScriptInterpreterNone_h_
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTINTERPRETER_NONE_SCRIPTINTERPRETERNONE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index e5a67653e3341..6f040fdef09b8 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -1,4 +1,4 @@
-//===-- PythonDataObjects.cpp -----------------------------------*- C++ -*-===//
+//===-- PythonDataObjects.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -44,7 +44,15 @@ template <>
Expected<long long> python::As<long long>(Expected<PythonObject> &&obj) {
if (!obj)
return obj.takeError();
- return obj.get().AsLongLong();
+ return obj->AsLongLong();
+}
+
+template <>
+Expected<unsigned long long>
+python::As<unsigned long long>(Expected<PythonObject> &&obj) {
+ if (!obj)
+ return obj.takeError();
+ return obj->AsUnsignedLongLong();
}
template <>
@@ -58,7 +66,56 @@ Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) {
auto utf8 = str.AsUTF8();
if (!utf8)
return utf8.takeError();
- return utf8.get();
+ return std::string(utf8.get());
+}
+
+Expected<long long> PythonObject::AsLongLong() const {
+ if (!m_py_obj)
+ return nullDeref();
+#if PY_MAJOR_VERSION < 3
+ if (!PyLong_Check(m_py_obj)) {
+ PythonInteger i(PyRefType::Borrowed, m_py_obj);
+ return i.AsLongLong();
+ }
+#endif
+ assert(!PyErr_Occurred());
+ long long r = PyLong_AsLongLong(m_py_obj);
+ if (PyErr_Occurred())
+ return exception();
+ return r;
+}
+
+Expected<long long> PythonObject::AsUnsignedLongLong() const {
+ if (!m_py_obj)
+ return nullDeref();
+#if PY_MAJOR_VERSION < 3
+ if (!PyLong_Check(m_py_obj)) {
+ PythonInteger i(PyRefType::Borrowed, m_py_obj);
+ return i.AsUnsignedLongLong();
+ }
+#endif
+ assert(!PyErr_Occurred());
+ long long r = PyLong_AsUnsignedLongLong(m_py_obj);
+ if (PyErr_Occurred())
+ return exception();
+ return r;
+}
+
+// wraps on overflow, instead of raising an error.
+Expected<unsigned long long> PythonObject::AsModuloUnsignedLongLong() const {
+ if (!m_py_obj)
+ return nullDeref();
+#if PY_MAJOR_VERSION < 3
+ if (!PyLong_Check(m_py_obj)) {
+ PythonInteger i(PyRefType::Borrowed, m_py_obj);
+ return i.AsModuloUnsignedLongLong();
+ }
+#endif
+ assert(!PyErr_Occurred());
+ unsigned long long r = PyLong_AsUnsignedLongLongMask(m_py_obj);
+ if (PyErr_Occurred())
+ return exception();
+ return r;
}
void StructuredPythonObject::Serialize(llvm::json::OStream &s) const {
@@ -463,32 +520,22 @@ void PythonInteger::Convert(PyRefType &type, PyObject *&py_obj) {
#endif
}
-int64_t PythonInteger::GetInteger() const {
- if (m_py_obj) {
- assert(PyLong_Check(m_py_obj) &&
- "PythonInteger::GetInteger has a PyObject that isn't a PyLong");
-
- int overflow = 0;
- int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow);
- if (overflow != 0) {
- // We got an integer that overflows, like 18446744072853913392L we can't
- // use PyLong_AsLongLong() as it will return 0xffffffffffffffff. If we
- // use the unsigned long long it will work as expected.
- const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj);
- result = static_cast<int64_t>(uval);
- }
- return result;
- }
- return UINT64_MAX;
-}
-
void PythonInteger::SetInteger(int64_t value) {
*this = Take<PythonInteger>(PyLong_FromLongLong(value));
}
StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
StructuredData::IntegerSP result(new StructuredData::Integer);
- result->SetValue(GetInteger());
+ // FIXME this is really not ideal. Errors are silently converted to 0
+ // and overflows are silently wrapped. But we'd need larger changes
+ // to StructuredData to fix it, so that's how it is for now.
+ llvm::Expected<unsigned long long> value = AsModuloUnsignedLongLong();
+ if (!value) {
+ llvm::consumeError(value.takeError());
+ result->SetValue(0);
+ } else {
+ result->SetValue(value.get());
+ }
return result;
}
@@ -1044,7 +1091,7 @@ std::string PythonException::ReadBacktrace() const {
if (!backtrace) {
std::string message =
std::string(toCString()) + "\n" +
- "Traceback unavailble, an error occurred while reading it:\n";
+ "Traceback unavailable, an error occurred while reading it:\n";
return (message + llvm::toString(backtrace.takeError()));
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
index b75045b239a8c..22f6c67eb7a5d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -36,7 +36,7 @@
// can never fail to assert instead, such as the creation of
// PythonString from a string literal.
//
-// * Elimintate Reset(), and make all non-default constructors private.
+// * Eliminate Reset(), and make all non-default constructors private.
// Python objects should be created with Retain<> or Take<>, and they
// should be assigned with operator=
//
@@ -90,7 +90,9 @@ public:
void Serialize(llvm::json::OStream &s) const override;
private:
- DISALLOW_COPY_AND_ASSIGN(StructuredPythonObject);
+ StructuredPythonObject(const StructuredPythonObject &) = delete;
+ const StructuredPythonObject &
+ operator=(const StructuredPythonObject &) = delete;
};
enum class PyObjectType {
@@ -319,7 +321,6 @@ public:
StructuredData::ObjectSP CreateStructuredObject() const;
-public:
template <typename... T>
llvm::Expected<PythonObject> CallMethod(const char *name,
const T &... t) const {
@@ -360,15 +361,12 @@ public:
return !!r;
}
- llvm::Expected<long long> AsLongLong() {
- if (!m_py_obj)
- return nullDeref();
- assert(!PyErr_Occurred());
- long long r = PyLong_AsLongLong(m_py_obj);
- if (PyErr_Occurred())
- return exception();
- return r;
- }
+ llvm::Expected<long long> AsLongLong() const;
+
+ llvm::Expected<long long> AsUnsignedLongLong() const;
+
+ // wraps on overflow, instead of raising an error.
+ llvm::Expected<unsigned long long> AsModuloUnsignedLongLong() const;
llvm::Expected<bool> IsInstance(const PythonObject &cls) {
if (!m_py_obj || !cls.IsValid())
@@ -400,6 +398,10 @@ template <>
llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj);
template <>
+llvm::Expected<unsigned long long>
+As<unsigned long long>(llvm::Expected<PythonObject> &&obj);
+
+template <>
llvm::Expected<std::string> As<std::string>(llvm::Expected<PythonObject> &&obj);
@@ -491,8 +493,6 @@ public:
static bool Check(PyObject *py_obj);
static void Convert(PyRefType &type, PyObject *&py_obj);
- int64_t GetInteger() const;
-
void SetInteger(int64_t value);
StructuredData::IntegerSP CreateStructuredInteger() const;
@@ -595,7 +595,7 @@ public:
// safe, returns invalid on error;
static PythonModule ImportModule(llvm::StringRef name) {
- std::string s = name;
+ std::string s = std::string(name);
auto mod = Import(s.c_str());
if (!mod) {
llvm::consumeError(mod.takeError());
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 06e0d5bfa63f4..9f56b4fa60a50 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -1,4 +1,4 @@
-//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===//
+//===-- ScriptInterpreterPython.cpp ---------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -16,7 +16,6 @@
#include "PythonDataObjects.h"
#include "PythonReadline.h"
#include "ScriptInterpreterPythonImpl.h"
-
#include "lldb/API/SBFrame.h"
#include "lldb/API/SBValue.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@@ -26,7 +25,6 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
-#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Pipe.h"
@@ -35,13 +33,9 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Utility/Timer.h"
-
-#if defined(_WIN32)
-#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
-#endif
-
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatAdapters.h"
@@ -56,6 +50,8 @@ using namespace lldb_private;
using namespace lldb_private::python;
using llvm::Expected;
+LLDB_PLUGIN_DEFINE(ScriptInterpreterPython)
+
// Defined in the SWIG source file
#if PY_MAJOR_VERSION >= 3
extern "C" PyObject *PyInit__lldb(void);
@@ -222,10 +218,6 @@ struct InitializePythonRAII {
public:
InitializePythonRAII()
: m_gil_state(PyGILState_UNLOCKED), m_was_already_initialized(false) {
- // Python will muck with STDIN terminal state, so save off any current TTY
- // settings so we can restore them.
- m_stdin_tty_state.Save(STDIN_FILENO, false);
-
InitializePythonHome();
#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
@@ -269,20 +261,40 @@ public:
// We initialized the threads in this function, just unlock the GIL.
PyEval_SaveThread();
}
-
- m_stdin_tty_state.Restore();
}
private:
void InitializePythonHome() {
-#if defined(LLDB_PYTHON_HOME)
+#if LLDB_EMBED_PYTHON_HOME
#if PY_MAJOR_VERSION >= 3
- size_t size = 0;
- static wchar_t *g_python_home = Py_DecodeLocale(LLDB_PYTHON_HOME, &size);
+ typedef wchar_t* str_type;
#else
- static char g_python_home[] = LLDB_PYTHON_HOME;
+ typedef char* str_type;
#endif
- Py_SetPythonHome(g_python_home);
+ static str_type g_python_home = []() -> str_type {
+ const char *lldb_python_home = LLDB_PYTHON_HOME;
+ const char *absolute_python_home = nullptr;
+ llvm::SmallString<64> path;
+ if (llvm::sys::path::is_absolute(lldb_python_home)) {
+ absolute_python_home = lldb_python_home;
+ } else {
+ FileSpec spec = HostInfo::GetShlibDir();
+ if (!spec)
+ return nullptr;
+ spec.GetPath(path);
+ llvm::sys::path::append(path, lldb_python_home);
+ absolute_python_home = path.c_str();
+ }
+#if PY_MAJOR_VERSION >= 3
+ size_t size = 0;
+ return Py_DecodeLocale(absolute_python_home, &size);
+#else
+ return strdup(absolute_python_home);
+#endif
+ }();
+ if (g_python_home != nullptr) {
+ Py_SetPythonHome(g_python_home);
+ }
#else
#if defined(__APPLE__) && PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 7
// For Darwin, the only Python version supported is the one shipped in the
@@ -471,7 +483,7 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger)
m_run_one_line_str_global(),
m_dictionary_name(m_debugger.GetInstanceName().AsCString()),
m_active_io_handler(eIOHandlerNone), m_session_is_active(false),
- m_pty_slave_is_open(false), m_valid_session(true), m_lock_count(0),
+ m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0),
m_command_thread_state(nullptr) {
InitializePrivate();
@@ -853,7 +865,7 @@ static std::string GenerateUniqueName(const char *base_name_wanted,
else
sstr.Printf("%s_%p", base_name_wanted, name_token);
- return sstr.GetString();
+ return std::string(sstr.GetString());
}
bool ScriptInterpreterPythonImpl::GetEmbeddedInterpreterModuleObjects() {
@@ -877,15 +889,6 @@ bool ScriptInterpreterPythonImpl::GetEmbeddedInterpreterModuleObjects() {
return m_run_one_line_function.IsValid();
}
-static void ReadThreadBytesReceived(void *baton, const void *src,
- size_t src_len) {
- if (src && src_len) {
- Stream *strm = (Stream *)baton;
- strm->Write(src, src_len);
- strm->Flush();
- }
-}
-
bool ScriptInterpreterPythonImpl::ExecuteOneLine(
llvm::StringRef command, CommandReturnObject *result,
const ExecuteScriptOptions &options) {
@@ -901,77 +904,21 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
// another string to pass to PyRun_SimpleString messes up the escaping. So
// we use the following more complicated method to pass the command string
// directly down to Python.
- Debugger &debugger = m_debugger;
-
- FileSP input_file_sp;
- StreamFileSP output_file_sp;
- StreamFileSP error_file_sp;
- Communication output_comm(
- "lldb.ScriptInterpreterPythonImpl.ExecuteOneLine.comm");
- bool join_read_thread = false;
- if (options.GetEnableIO()) {
- if (result) {
- input_file_sp = debugger.GetInputFileSP();
- // Set output to a temporary file so we can forward the results on to
- // the result object
-
- Pipe pipe;
- Status pipe_result = pipe.CreateNew(false);
- if (pipe_result.Success()) {
-#if defined(_WIN32)
- lldb::file_t read_file = pipe.GetReadNativeHandle();
- pipe.ReleaseReadFileDescriptor();
- std::unique_ptr<ConnectionGenericFile> conn_up(
- new ConnectionGenericFile(read_file, true));
-#else
- std::unique_ptr<ConnectionFileDescriptor> conn_up(
- new ConnectionFileDescriptor(pipe.ReleaseReadFileDescriptor(),
- true));
-#endif
- if (conn_up->IsConnected()) {
- output_comm.SetConnection(conn_up.release());
- output_comm.SetReadThreadBytesReceivedCallback(
- ReadThreadBytesReceived, &result->GetOutputStream());
- output_comm.StartReadThread();
- join_read_thread = true;
- FILE *outfile_handle =
- fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
- output_file_sp = std::make_shared<StreamFile>(outfile_handle, true);
- error_file_sp = output_file_sp;
- if (outfile_handle)
- ::setbuf(outfile_handle, nullptr);
-
- result->SetImmediateOutputFile(
- debugger.GetOutputStream().GetFileSP());
- result->SetImmediateErrorFile(
- debugger.GetErrorStream().GetFileSP());
- }
- }
- }
- if (!input_file_sp || !output_file_sp || !error_file_sp)
- debugger.AdoptTopIOHandlerFilesIfInvalid(input_file_sp, output_file_sp,
- error_file_sp);
- } else {
- auto nullin = FileSystem::Instance().Open(
- FileSpec(FileSystem::DEV_NULL),
- File::eOpenOptionRead);
- auto nullout = FileSystem::Instance().Open(
- FileSpec(FileSystem::DEV_NULL),
- File::eOpenOptionWrite);
- if (!nullin) {
- result->AppendErrorWithFormatv("failed to open /dev/null: {0}\n",
- llvm::fmt_consume(nullin.takeError()));
- return false;
- }
- if (!nullout) {
- result->AppendErrorWithFormatv("failed to open /dev/null: {0}\n",
- llvm::fmt_consume(nullout.takeError()));
- return false;
- }
- input_file_sp = std::move(nullin.get());
- error_file_sp = output_file_sp = std::make_shared<StreamFile>(std::move(nullout.get()));
+ llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
+ io_redirect_or_error = ScriptInterpreterIORedirect::Create(
+ options.GetEnableIO(), m_debugger, result);
+ if (!io_redirect_or_error) {
+ if (result)
+ result->AppendErrorWithFormatv(
+ "failed to redirect I/O: {0}\n",
+ llvm::fmt_consume(io_redirect_or_error.takeError()));
+ else
+ llvm::consumeError(io_redirect_or_error.takeError());
+ return false;
}
+ ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error;
+
bool success = false;
{
// WARNING! It's imperative that this RAII scope be as tight as
@@ -987,8 +934,9 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
Locker::AcquireLock | Locker::InitSession |
(options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) |
((result && result->GetInteractive()) ? 0 : Locker::NoSTDIN),
- Locker::FreeAcquiredLock | Locker::TearDownSession, input_file_sp,
- output_file_sp->GetFileSP(), error_file_sp->GetFileSP());
+ Locker::FreeAcquiredLock | Locker::TearDownSession,
+ io_redirect.GetInputFile(), io_redirect.GetOutputFile(),
+ io_redirect.GetErrorFile());
// Find the correct script interpreter dictionary in the main module.
PythonDictionary &session_dict = GetSessionDictionary();
@@ -1014,21 +962,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
}
}
- // Flush our output and error file handles
- output_file_sp->Flush();
- error_file_sp->Flush();
- }
-
- if (join_read_thread) {
- // Close the write end of the pipe since we are done with our one line
- // script. This should cause the read thread that output_comm is using to
- // exit
- output_file_sp->GetFile().Close();
- // The close above should cause this thread to exit when it gets to the
- // end of file, so let it get all its data
- output_comm.JoinReadThread();
- // Now we can close the read end of the pipe
- output_comm.Disconnect();
+ io_redirect.Flush();
}
if (success)
@@ -1064,7 +998,7 @@ void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() {
IOHandlerSP io_handler_sp(new IOHandlerPythonInterpreter(debugger, this));
if (io_handler_sp) {
- debugger.PushIOHandler(io_handler_sp);
+ debugger.RunIOHandlerAsync(io_handler_sp);
}
}
@@ -1343,8 +1277,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
bp_options->SetCallback(
ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp);
return error;
- } else
- return error;
+ }
+ return error;
}
// Set a Python one-liner as the callback for the watchpoint.
@@ -1970,8 +1904,7 @@ lldb::StateType ScriptInterpreterPythonImpl::ScriptedThreadPlanGetRunState(
}
if (should_step)
return lldb::eStateStepping;
- else
- return lldb::eStateRunning;
+ return lldb::eStateRunning;
}
StructuredData::GenericSP
@@ -2043,8 +1976,7 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth(
if (depth_as_int <= lldb::kLastSearchDepthKind)
return (lldb::SearchDepth)depth_as_int;
- else
- return lldb::eSearchDepthModule;
+ return lldb::eSearchDepthModule;
}
StructuredData::ObjectSP
@@ -2748,6 +2680,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
{
FileSpec target_file(pathname);
FileSystem::Instance().Resolve(target_file);
+ FileSystem::Instance().Collect(target_file);
std::string basename(target_file.GetFilename().GetCString());
StreamString command_stream;
@@ -3010,39 +2943,42 @@ bool ScriptInterpreterPythonImpl::RunScriptBasedCommand(
return ret_val;
}
-// in Python, a special attribute __doc__ contains the docstring for an object
-// (function, method, class, ...) if any is defined Otherwise, the attribute's
-// value is None
+/// In Python, a special attribute __doc__ contains the docstring for an object
+/// (function, method, class, ...) if any is defined Otherwise, the attribute's
+/// value is None.
bool ScriptInterpreterPythonImpl::GetDocumentationForItem(const char *item,
std::string &dest) {
dest.clear();
+
if (!item || !*item)
return false;
+
std::string command(item);
command += ".__doc__";
- char *result_ptr = nullptr; // Python is going to point this to valid data if
- // ExecuteOneLineWithReturn returns successfully
+ // Python is going to point this to valid data if ExecuteOneLineWithReturn
+ // returns successfully.
+ char *result_ptr = nullptr;
if (ExecuteOneLineWithReturn(
- command.c_str(), ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
+ command, ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
&result_ptr,
ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false))) {
if (result_ptr)
dest.assign(result_ptr);
return true;
- } else {
- StreamString str_stream;
- str_stream.Printf(
- "Function %s was not found. Containing module might be missing.", item);
- dest = str_stream.GetString();
- return false;
}
+
+ StreamString str_stream;
+ str_stream << "Function " << item
+ << " was not found. Containing module might be missing.";
+ dest = std::string(str_stream.GetString());
+
+ return false;
}
bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject(
StructuredData::GenericSP cmd_obj_sp, std::string &dest) {
- bool got_string = false;
dest.clear();
Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
@@ -3076,12 +3012,12 @@ bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject(
if (PyErr_Occurred())
PyErr_Clear();
- // right now we know this function exists and is callable..
+ // Right now we know this function exists and is callable.
PythonObject py_return(
PyRefType::Owned,
PyObject_CallMethod(implementor.get(), callee_name, nullptr));
- // if it fails, print the error but otherwise go on
+ // If it fails, print the error but otherwise go on.
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
@@ -3091,9 +3027,10 @@ bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject(
PythonString py_string(PyRefType::Borrowed, py_return.get());
llvm::StringRef return_data(py_string.GetString());
dest.assign(return_data.data(), return_data.size());
- got_string = true;
+ return true;
}
- return got_string;
+
+ return false;
}
uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject(
@@ -3131,20 +3068,15 @@ uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject(
if (PyErr_Occurred())
PyErr_Clear();
- // right now we know this function exists and is callable..
- PythonObject py_return(
- PyRefType::Owned,
- PyObject_CallMethod(implementor.get(), callee_name, nullptr));
+ long long py_return = unwrapOrSetPythonException(
+ As<long long>(implementor.CallMethod(callee_name)));
// if it fails, print the error but otherwise go on
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
- }
-
- if (py_return.IsAllocated() && PythonInteger::Check(py_return.get())) {
- PythonInteger int_value(PyRefType::Borrowed, py_return.get());
- result = int_value.GetInteger();
+ } else {
+ result = py_return;
}
return result;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index 1fa198b07e54e..22b2c8152eac0 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -395,7 +395,7 @@ public:
std::string m_dictionary_name;
ActiveIOHandler m_active_io_handler;
bool m_session_is_active;
- bool m_pty_slave_is_open;
+ bool m_pty_secondary_is_open;
bool m_valid_session;
uint32_t m_lock_count;
PyThreadState *m_command_thread_state;