summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ScriptInterpreter
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
commit706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch)
tree4adf86a776049cbf7f69a1929c4babcbbef925eb /lldb/source/Plugins/ScriptInterpreter
parent7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff)
Notes
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp59
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h48
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp157
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h61
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp110
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h44
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp88
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h28
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp190
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h16
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h28
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h8
12 files changed, 690 insertions, 147 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
new file mode 100644
index 0000000000000..ecee8cc674f81
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
@@ -0,0 +1,59 @@
+//===-- Lua.cpp -----------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lua.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/FileSpec.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+llvm::Error Lua::Run(llvm::StringRef buffer) {
+ int error =
+ luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||
+ lua_pcall(m_lua_state, 0, 0, 0);
+ if (!error)
+ return llvm::Error::success();
+
+ llvm::Error e = llvm::make_error<llvm::StringError>(
+ llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
+ llvm::inconvertibleErrorCode());
+ // Pop error message from the stack.
+ lua_pop(m_lua_state, 1);
+ return e;
+}
+
+llvm::Error Lua::LoadModule(llvm::StringRef filename) {
+ FileSpec file(filename);
+ if (!FileSystem::Instance().Exists(file)) {
+ return llvm::make_error<llvm::StringError>("invalid path",
+ llvm::inconvertibleErrorCode());
+ }
+
+ ConstString module_extension = file.GetFileNameExtension();
+ if (module_extension != ".lua") {
+ return llvm::make_error<llvm::StringError>("invalid extension",
+ llvm::inconvertibleErrorCode());
+ }
+
+ int error = luaL_loadfile(m_lua_state, filename.data()) ||
+ lua_pcall(m_lua_state, 0, 1, 0);
+ if (error) {
+ llvm::Error e = llvm::make_error<llvm::StringError>(
+ llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
+ llvm::inconvertibleErrorCode());
+ // Pop error message from the stack.
+ lua_pop(m_lua_state, 1);
+ return e;
+ }
+
+ ConstString module_name = file.GetFileNameStrippingExtension();
+ lua_setglobal(m_lua_state, module_name.GetCString());
+ return llvm::Error::success();
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
new file mode 100644
index 0000000000000..f2984a925dfe1
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
@@ -0,0 +1,48 @@
+//===-- ScriptInterpreterLua.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Lua_h_
+#define liblldb_Lua_h_
+
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include "lua.hpp"
+
+#include <mutex>
+
+namespace lldb_private {
+
+extern "C" {
+int luaopen_lldb(lua_State *L);
+}
+
+class Lua {
+public:
+ Lua() : m_lua_state(luaL_newstate()) {
+ assert(m_lua_state);
+ luaL_openlibs(m_lua_state);
+ luaopen_lldb(m_lua_state);
+ }
+
+ ~Lua() {
+ assert(m_lua_state);
+ luaL_openlibs(m_lua_state);
+ }
+
+ llvm::Error Run(llvm::StringRef buffer);
+ llvm::Error LoadModule(llvm::StringRef filename);
+
+private:
+ lua_State *m_lua_state;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Lua_h_
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
new file mode 100644
index 0000000000000..701d68d1ec084
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -0,0 +1,157 @@
+//===-- ScriptInterpreterLua.cpp --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptInterpreterLua.h"
+#include "Lua.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/Utility/Timer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class IOHandlerLuaInterpreter : public IOHandlerDelegate,
+ public IOHandlerEditline {
+public:
+ IOHandlerLuaInterpreter(Debugger &debugger,
+ ScriptInterpreterLua &script_interpreter)
+ : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua",
+ ">>> ", "..> ", true, debugger.GetUseColor(), 0,
+ *this, nullptr),
+ m_script_interpreter(script_interpreter) {
+ llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID()));
+ }
+
+ ~IOHandlerLuaInterpreter() {
+ llvm::cantFail(m_script_interpreter.LeaveSession());
+ }
+
+ void IOHandlerInputComplete(IOHandler &io_handler,
+ std::string &data) override {
+ if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) {
+ *GetOutputStreamFileSP() << llvm::toString(std::move(error));
+ }
+ }
+
+private:
+ ScriptInterpreterLua &m_script_interpreter;
+};
+
+ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger)
+ : ScriptInterpreter(debugger, eScriptLanguageLua),
+ m_lua(std::make_unique<Lua>()) {}
+
+ScriptInterpreterLua::~ScriptInterpreterLua() {}
+
+bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command,
+ CommandReturnObject *result,
+ const ExecuteScriptOptions &options) {
+ 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;
+ }
+ return true;
+}
+
+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())
+ return;
+
+ IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(debugger, *this));
+ debugger.PushIOHandler(io_handler_sp);
+}
+
+bool ScriptInterpreterLua::LoadScriptingModule(
+ const char *filename, bool init_session, lldb_private::Status &error,
+ StructuredData::ObjectSP *module_sp) {
+
+ if (llvm::Error e = m_lua->LoadModule(filename)) {
+ error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n",
+ filename, llvm::toString(std::move(e)));
+ return false;
+ }
+ return true;
+}
+
+void ScriptInterpreterLua::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ lldb::eScriptLanguageLua, CreateInstance);
+ });
+}
+
+void ScriptInterpreterLua::Terminate() {}
+
+llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) {
+ if (m_session_is_active)
+ return llvm::Error::success();
+
+ const char *fmt_str =
+ "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); "
+ "lldb.target = lldb.debugger:GetSelectedTarget(); "
+ "lldb.process = lldb.target:GetProcess(); "
+ "lldb.thread = lldb.process:GetSelectedThread(); "
+ "lldb.frame = lldb.thread:GetSelectedFrame()";
+ return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str());
+}
+
+llvm::Error ScriptInterpreterLua::LeaveSession() {
+ if (!m_session_is_active)
+ return llvm::Error::success();
+
+ m_session_is_active = false;
+
+ llvm::StringRef str = "lldb.debugger = nil; "
+ "lldb.target = nil; "
+ "lldb.process = nil; "
+ "lldb.thread = nil; "
+ "lldb.frame = nil";
+ return m_lua->Run(str);
+}
+
+lldb::ScriptInterpreterSP
+ScriptInterpreterLua::CreateInstance(Debugger &debugger) {
+ return std::make_shared<ScriptInterpreterLua>(debugger);
+}
+
+lldb_private::ConstString ScriptInterpreterLua::GetPluginNameStatic() {
+ static ConstString g_name("script-lua");
+ return g_name;
+}
+
+const char *ScriptInterpreterLua::GetPluginDescriptionStatic() {
+ return "Lua script interpreter";
+}
+
+lldb_private::ConstString ScriptInterpreterLua::GetPluginName() {
+ return GetPluginNameStatic();
+}
+
+uint32_t ScriptInterpreterLua::GetPluginVersion() { return 1; }
+
+Lua &ScriptInterpreterLua::GetLua() { return *m_lua; }
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
new file mode 100644
index 0000000000000..4e922151385b6
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
@@ -0,0 +1,61 @@
+//===-- ScriptInterpreterLua.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ScriptInterpreterLua_h_
+#define liblldb_ScriptInterpreterLua_h_
+
+#include "lldb/Interpreter/ScriptInterpreter.h"
+
+namespace lldb_private {
+class Lua;
+class ScriptInterpreterLua : public ScriptInterpreter {
+public:
+ ScriptInterpreterLua(Debugger &debugger);
+
+ ~ScriptInterpreterLua() override;
+
+ bool ExecuteOneLine(
+ llvm::StringRef command, CommandReturnObject *result,
+ const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;
+
+ void ExecuteInterpreterLoop() override;
+
+ virtual bool
+ LoadScriptingModule(const char *filename, bool init_session,
+ lldb_private::Status &error,
+ StructuredData::ObjectSP *module_sp = nullptr) override;
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb::ScriptInterpreterSP CreateInstance(Debugger &debugger);
+
+ static lldb_private::ConstString GetPluginNameStatic();
+
+ static const char *GetPluginDescriptionStatic();
+
+ // PluginInterface protocol
+ lldb_private::ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override;
+
+ Lua &GetLua();
+
+ llvm::Error EnterSession(lldb::user_id_t debugger_id);
+ llvm::Error LeaveSession();
+
+private:
+ std::unique_ptr<Lua> m_lua;
+ bool m_session_is_active = false;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ScriptInterpreterLua_h_
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index 70d93424fdecb..e5a67653e3341 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -6,11 +6,9 @@
//
//===----------------------------------------------------------------------===//
-#ifdef LLDB_DISABLE_PYTHON
+#include "lldb/Host/Config.h"
-// Python is disabled in this build
-
-#else
+#if LLDB_ENABLE_PYTHON
#include "PythonDataObjects.h"
#include "ScriptInterpreterPython.h"
@@ -802,29 +800,11 @@ bool PythonCallable::Check(PyObject *py_obj) {
return PyCallable_Check(py_obj);
}
-PythonCallable::ArgInfo PythonCallable::GetNumInitArguments() const {
- auto arginfo = GetInitArgInfo();
- if (!arginfo) {
- llvm::consumeError(arginfo.takeError());
- return ArgInfo{};
- }
- return arginfo.get();
-}
-
-Expected<PythonCallable::ArgInfo> PythonCallable::GetInitArgInfo() const {
- if (!IsValid())
- return nullDeref();
- auto init = As<PythonCallable>(GetAttribute("__init__"));
- if (!init)
- return init.takeError();
- return init.get().GetArgInfo();
-}
-
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
static const char get_arg_info_script[] = R"(
from inspect import signature, Parameter, ismethod
from collections import namedtuple
-ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs', 'is_bound_method'])
+ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs'])
def main(f):
count = 0
varargs = False
@@ -840,7 +820,7 @@ def main(f):
pass
else:
raise Exception(f'unknown parameter kind: {kind}')
- return ArgInfo(count, varargs, ismethod(f))
+ return ArgInfo(count, varargs)
)";
#endif
@@ -856,21 +836,27 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {
Expected<PythonObject> pyarginfo = get_arg_info(*this);
if (!pyarginfo)
return pyarginfo.takeError();
- result.count = cantFail(As<long long>(pyarginfo.get().GetAttribute("count")));
- result.has_varargs =
+ long long count =
+ cantFail(As<long long>(pyarginfo.get().GetAttribute("count")));
+ bool has_varargs =
cantFail(As<bool>(pyarginfo.get().GetAttribute("has_varargs")));
- bool is_method =
- cantFail(As<bool>(pyarginfo.get().GetAttribute("is_bound_method")));
- result.max_positional_args =
- result.has_varargs ? ArgInfo::UNBOUNDED : result.count;
-
- // FIXME emulate old broken behavior
- if (is_method)
- result.count++;
+ result.max_positional_args = has_varargs ? ArgInfo::UNBOUNDED : count;
#else
+ PyObject *py_func_obj;
bool is_bound_method = false;
- PyObject *py_func_obj = m_py_obj;
+ bool is_class = false;
+
+ if (PyType_Check(m_py_obj) || PyClass_Check(m_py_obj)) {
+ auto init = GetAttribute("__init__");
+ if (!init)
+ return init.takeError();
+ py_func_obj = init.get().get();
+ is_class = true;
+ } else {
+ py_func_obj = m_py_obj;
+ }
+
if (PyMethod_Check(py_func_obj)) {
py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);
PythonObject im_self = GetAttributeValue("im_self");
@@ -899,11 +885,11 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {
if (!code)
return result;
- result.count = code->co_argcount;
- result.has_varargs = !!(code->co_flags & CO_VARARGS);
- result.max_positional_args = result.has_varargs
- ? ArgInfo::UNBOUNDED
- : (result.count - (int)is_bound_method);
+ auto count = code->co_argcount;
+ bool has_varargs = !!(code->co_flags & CO_VARARGS);
+ result.max_positional_args =
+ has_varargs ? ArgInfo::UNBOUNDED
+ : (count - (int)is_bound_method) - (int)is_class;
#endif
@@ -913,15 +899,6 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {
constexpr unsigned
PythonCallable::ArgInfo::UNBOUNDED; // FIXME delete after c++17
-PythonCallable::ArgInfo PythonCallable::GetNumArguments() const {
- auto arginfo = GetArgInfo();
- if (!arginfo) {
- llvm::consumeError(arginfo.takeError());
- return ArgInfo{};
- }
- return arginfo.get();
-}
-
PythonObject PythonCallable::operator()() {
return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr));
}
@@ -1385,11 +1362,13 @@ llvm::Expected<FileSP> PythonFile::ConvertToFile(bool borrowed) {
if (!options)
return options.takeError();
- // LLDB and python will not share I/O buffers. We should probably
- // flush the python buffers now.
- auto r = CallMethod("flush");
- if (!r)
- return r.takeError();
+ if (options.get() & File::eOpenOptionWrite) {
+ // LLDB and python will not share I/O buffers. We should probably
+ // flush the python buffers now.
+ auto r = CallMethod("flush");
+ if (!r)
+ return r.takeError();
+ }
FileSP file_sp;
if (borrowed) {
@@ -1498,14 +1477,23 @@ Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) {
PyObject *file_obj;
#if PY_MAJOR_VERSION >= 3
file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr,
- "ignore", nullptr, 0);
+ "ignore", nullptr, /*closefd=*/0);
#else
- // Read through the Python source, doesn't seem to modify these strings
- char *cmode = const_cast<char *>(mode);
- // We pass ::flush instead of ::fclose here so we borrow the FILE* --
- // the lldb_private::File still owns it.
- file_obj =
- PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, ::fflush);
+ // I'd like to pass ::fflush here if the file is writable, so that
+ // when the python side destructs the file object it will be flushed.
+ // However, this would be dangerous. It can cause fflush to be called
+ // after fclose if the python program keeps a reference to the file after
+ // the original lldb_private::File has been destructed.
+ //
+ // It's all well and good to ask a python program not to use a closed file
+ // but asking a python program to make sure objects get released in a
+ // particular order is not safe.
+ //
+ // The tradeoff here is that if a python 2 program wants to make sure this
+ // file gets flushed, they'll have to do it explicitly or wait untill the
+ // original lldb File itself gets flushed.
+ file_obj = PyFile_FromFile(file.GetStream(), py2_const_cast(""),
+ py2_const_cast(mode), [](FILE *) { return 0; });
#endif
if (!file_obj)
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
index 373d3212697d7..b75045b239a8c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -48,7 +48,9 @@
#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H
#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H
-#ifndef LLDB_DISABLE_PYTHON
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
// LLDB Python header must be included first
#include "lldb-python.h"
@@ -130,7 +132,7 @@ template <typename T> T Take(PyObject *obj) {
assert(!PyErr_Occurred());
T thing(PyRefType::Owned, obj);
assert(thing.IsValid());
- return std::move(thing);
+ return thing;
}
// Retain a reference you have borrowed, and turn it into
@@ -148,7 +150,7 @@ template <typename T> T Retain(PyObject *obj) {
assert(!PyErr_Occurred());
T thing(PyRefType::Borrowed, obj);
assert(thing.IsValid());
- return std::move(thing);
+ return thing;
}
// This class can be used like a utility function to convert from
@@ -189,6 +191,14 @@ inline llvm::Error keyError() {
"key not in dict");
}
+#if PY_MAJOR_VERSION < 3
+// The python 2 API declares some arguments as char* that should
+// be const char *, but it doesn't actually modify them.
+inline char *py2_const_cast(const char *s) { return const_cast<char *>(s); }
+#else
+inline const char *py2_const_cast(const char *s) { return s; }
+#endif
+
enum class PyInitialValue { Invalid, Empty };
template <typename T, typename Enable = void> struct PythonFormat;
@@ -309,16 +319,6 @@ public:
StructuredData::ObjectSP CreateStructuredObject() const;
-protected:
-
-#if PY_MAJOR_VERSION < 3
- // The python 2 API declares some arguments as char* that should
- // be const char *, but it doesn't actually modify them.
- static char *py2_const_cast(const char *s) { return const_cast<char *>(s); }
-#else
- static const char *py2_const_cast(const char *s) { return s; }
-#endif
-
public:
template <typename... T>
llvm::Expected<PythonObject> CallMethod(const char *name,
@@ -621,30 +621,12 @@ public:
* function and can accept an arbitrary number */
unsigned max_positional_args;
static constexpr unsigned UNBOUNDED = UINT_MAX; // FIXME c++17 inline
- /* the number of positional arguments, including optional ones,
- * and excluding varargs. If this is a bound method, then the
- * count will still include a +1 for self.
- *
- * FIXME. That's crazy. This should be replaced with
- * an accurate min and max for positional args.
- */
- int count;
- /* does the callable have positional varargs? */
- bool has_varargs : 1; // FIXME delete this
};
static bool Check(PyObject *py_obj);
llvm::Expected<ArgInfo> GetArgInfo() const;
- llvm::Expected<ArgInfo> GetInitArgInfo() const;
-
- ArgInfo GetNumArguments() const; // DEPRECATED
-
- // If the callable is a Py_Class, then find the number of arguments
- // of the __init__ method.
- ArgInfo GetNumInitArguments() const; // DEPRECATED
-
PythonObject operator()();
PythonObject operator()(std::initializer_list<PyObject *> args);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
new file mode 100644
index 0000000000000..5f6429f5cd0ec
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
@@ -0,0 +1,88 @@
+#include "PythonReadline.h"
+
+#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
+
+#include <stdio.h>
+
+#include <editline/readline.h>
+
+// Simple implementation of the Python readline module using libedit.
+// In the event that libedit is excluded from the build, this turns
+// back into a null implementation that blocks the module from pulling
+// in the GNU readline shared lib, which causes linkage confusion when
+// both readline and libedit's readline compatibility symbols collide.
+//
+// Currently it only installs a PyOS_ReadlineFunctionPointer, without
+// implementing any of the readline module methods. This is meant to
+// work around LLVM pr18841 to avoid seg faults in the stock Python
+// readline.so linked against GNU readline.
+//
+// Bug on the cpython side: https://bugs.python.org/issue38634
+
+PyDoc_STRVAR(moduleDocumentation,
+ "Simple readline module implementation based on libedit.");
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef readline_module = {
+ PyModuleDef_HEAD_INIT, // m_base
+ "lldb_editline", // m_name
+ moduleDocumentation, // m_doc
+ -1, // m_size
+ nullptr, // m_methods
+ nullptr, // m_reload
+ nullptr, // m_traverse
+ nullptr, // m_clear
+ nullptr, // m_free
+};
+#else
+static struct PyMethodDef moduleMethods[] = {{nullptr, nullptr, 0, nullptr}};
+#endif
+
+static char *
+#if PY_MAJOR_VERSION >= 3
+simple_readline(FILE *stdin, FILE *stdout, const char *prompt)
+#else
+simple_readline(FILE *stdin, FILE *stdout, char *prompt)
+#endif
+{
+ rl_instream = stdin;
+ rl_outstream = stdout;
+ char *line = readline(prompt);
+ if (!line) {
+#if PY_MAJOR_VERSION >= 3
+ char *ret = (char *)PyMem_RawMalloc(1);
+#else
+ char *ret = (char *)PyMem_Malloc(1);
+#endif
+ if (ret != NULL)
+ *ret = '\0';
+ return ret;
+ }
+ if (*line)
+ add_history(line);
+ int n = strlen(line);
+#if PY_MAJOR_VERSION >= 3
+ char *ret = (char *)PyMem_RawMalloc(n + 2);
+#else
+ char *ret = (char *)PyMem_Malloc(n + 2);
+#endif
+ if (ret) {
+ memcpy(ret, line, n);
+ free(line);
+ ret[n] = '\n';
+ ret[n + 1] = '\0';
+ }
+ return ret;
+}
+
+PyMODINIT_FUNC initlldb_readline(void) {
+ PyOS_ReadlineFunctionPointer = simple_readline;
+
+#if PY_MAJOR_VERSION >= 3
+ return PyModule_Create(&readline_module);
+#else
+ Py_InitModule4("readline", moduleMethods, moduleDocumentation,
+ static_cast<PyObject *>(NULL), PYTHON_API_VERSION);
+#endif
+}
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h
new file mode 100644
index 0000000000000..c75219eb1a4f9
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h
@@ -0,0 +1,28 @@
+//===-- PythonReadline.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_LIBEDIT && defined(__linux__)
+// NOTE: Since Python may define some pre-processor definitions which affect the
+// standard headers on some systems, you must include Python.h before any
+// standard headers are included.
+#include "Python.h"
+
+// no need to hack into Python's readline module if libedit isn't used.
+//
+#define LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE 1
+
+PyMODINIT_FUNC initlldb_readline(void);
+
+#endif
+
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 3eee52184142d..06e0d5bfa63f4 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -6,16 +6,15 @@
//
//===----------------------------------------------------------------------===//
-#ifdef LLDB_DISABLE_PYTHON
+#include "lldb/Host/Config.h"
-// Python is disabled in this build
-
-#else
+#if LLDB_ENABLE_PYTHON
// LLDB Python header must be included first
#include "lldb-python.h"
#include "PythonDataObjects.h"
+#include "PythonReadline.h"
#include "ScriptInterpreterPythonImpl.h"
#include "lldb/API/SBFrame.h"
@@ -72,10 +71,28 @@ extern "C" void init_lldb(void);
// These prototypes are the Pythonic implementations of the required callbacks.
// Although these are scripting-language specific, their definition depends on
// the public API.
-extern "C" bool LLDBSwigPythonBreakpointCallbackFunction(
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+
+// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has
+// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is
+// incompatible with C
+#if _MSC_VER
+#pragma warning (push)
+#pragma warning (disable : 4190)
+#endif
+
+extern "C" llvm::Expected<bool> LLDBSwigPythonBreakpointCallbackFunction(
const char *python_function_name, const char *session_dictionary_name,
const lldb::StackFrameSP &sb_frame,
- const lldb::BreakpointLocationSP &sb_bp_loc);
+ const lldb::BreakpointLocationSP &sb_bp_loc, StructuredDataImpl *args_impl);
+
+#if _MSC_VER
+#pragma warning (pop)
+#endif
+
+#pragma clang diagnostic pop
extern "C" bool LLDBSwigPythonWatchpointCallbackFunction(
const char *python_function_name, const char *session_dictionary_name,
@@ -211,6 +228,22 @@ public:
InitializePythonHome();
+#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
+ // Python's readline is incompatible with libedit being linked into lldb.
+ // Provide a patched version local to the embedded interpreter.
+ bool ReadlinePatched = false;
+ for (auto *p = PyImport_Inittab; p->name != NULL; p++) {
+ if (strcmp(p->name, "readline") == 0) {
+ p->initfunc = initlldb_readline;
+ break;
+ }
+ }
+ if (!ReadlinePatched) {
+ PyImport_AppendInittab("readline", initlldb_readline);
+ ReadlinePatched = true;
+ }
+#endif
+
// Register _lldb as a built-in module.
PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
@@ -552,8 +585,10 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler,
break;
data_up->user_source.SplitIntoLines(data);
+ StructuredData::ObjectSP empty_args_sp;
if (GenerateBreakpointCommandCallbackData(data_up->user_source,
- data_up->script_source)
+ data_up->script_source,
+ false)
.Success()) {
auto baton_sp = std::make_shared<BreakpointOptions::CommandBaton>(
std::move(data_up));
@@ -779,6 +814,32 @@ PythonDictionary &ScriptInterpreterPythonImpl::GetSysModuleDictionary() {
return m_sys_module_dict;
}
+llvm::Expected<unsigned>
+ScriptInterpreterPythonImpl::GetMaxPositionalArgumentsForCallable(
+ const llvm::StringRef &callable_name) {
+ if (callable_name.empty()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "called with empty callable name.");
+ }
+ Locker py_lock(this, Locker::AcquireLock |
+ Locker::InitSession |
+ Locker::NoSTDIN);
+ auto dict = PythonModule::MainModule()
+ .ResolveName<PythonDictionary>(m_dictionary_name);
+ auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(
+ callable_name, dict);
+ if (!pfunc.IsAllocated()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "can't find callable: %s", callable_name.str().c_str());
+ }
+ llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo();
+ if (!arg_info)
+ return arg_info.takeError();
+ return arg_info.get().max_positional_args;
+}
+
static std::string GenerateUniqueName(const char *base_name_wanted,
uint32_t &functions_counter,
const void *name_token = nullptr) {
@@ -1139,6 +1200,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn(
return true;
}
}
+ llvm_unreachable("Fully covered switch!");
}
Status ScriptInterpreterPythonImpl::ExecuteMultipleLines(
@@ -1186,24 +1248,56 @@ void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback(
CommandReturnObject &result) {
m_active_io_handler = eIOHandlerBreakpoint;
m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler(
- " ", *this, true, &bp_options_vec);
+ " ", *this, &bp_options_vec);
}
void ScriptInterpreterPythonImpl::CollectDataForWatchpointCommandCallback(
WatchpointOptions *wp_options, CommandReturnObject &result) {
m_active_io_handler = eIOHandlerWatchpoint;
m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler(
- " ", *this, true, wp_options);
+ " ", *this, wp_options);
}
-void ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
- BreakpointOptions *bp_options, const char *function_name) {
+Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options, const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) {
+ Status error;
// For now just cons up a oneliner that calls the provided function.
std::string oneliner("return ");
oneliner += function_name;
- oneliner += "(frame, bp_loc, internal_dict)";
- m_debugger.GetScriptInterpreter()->SetBreakpointCommandCallback(
- bp_options, oneliner.c_str());
+
+ llvm::Expected<unsigned> maybe_args =
+ GetMaxPositionalArgumentsForCallable(function_name);
+ if (!maybe_args) {
+ error.SetErrorStringWithFormat(
+ "could not get num args: %s",
+ llvm::toString(maybe_args.takeError()).c_str());
+ return error;
+ }
+ size_t max_args = *maybe_args;
+
+ bool uses_extra_args = false;
+ if (max_args >= 4) {
+ uses_extra_args = true;
+ oneliner += "(frame, bp_loc, extra_args, internal_dict)";
+ } else if (max_args >= 3) {
+ if (extra_args_sp) {
+ error.SetErrorString("cannot pass extra_args to a three argument callback"
+ );
+ return error;
+ }
+ uses_extra_args = false;
+ oneliner += "(frame, bp_loc, internal_dict)";
+ } else {
+ error.SetErrorStringWithFormat("expected 3 or 4 argument "
+ "function, %s can only take %zu",
+ function_name, max_args);
+ return error;
+ }
+
+ SetBreakpointCommandCallback(bp_options, oneliner.c_str(), extra_args_sp,
+ uses_extra_args);
+ return error;
}
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
@@ -1211,7 +1305,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
std::unique_ptr<BreakpointOptions::CommandData> &cmd_data_up) {
Status error;
error = GenerateBreakpointCommandCallbackData(cmd_data_up->user_source,
- cmd_data_up->script_source);
+ cmd_data_up->script_source,
+ false);
if (error.Fail()) {
return error;
}
@@ -1222,11 +1317,17 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
return error;
}
-// Set a Python one-liner as the callback for the breakpoint.
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
BreakpointOptions *bp_options, const char *command_body_text) {
- auto data_up = std::make_unique<CommandDataPython>();
+ return SetBreakpointCommandCallback(bp_options, command_body_text, {},false);
+}
+// Set a Python one-liner as the callback for the breakpoint.
+Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
+ BreakpointOptions *bp_options, const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp,
+ bool uses_extra_args) {
+ auto data_up = std::make_unique<CommandDataPython>(extra_args_sp);
// Split the command_body_text into lines, and pass that to
// GenerateBreakpointCommandCallbackData. That will wrap the body in an
// auto-generated function, and return the function name in script_source.
@@ -1234,7 +1335,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
data_up->user_source.SplitIntoLines(command_body_text);
Status error = GenerateBreakpointCommandCallbackData(data_up->user_source,
- data_up->script_source);
+ data_up->script_source,
+ uses_extra_args);
if (error.Success()) {
auto baton_sp =
std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
@@ -1771,8 +1873,7 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::OSPlugin_CreateThread(
StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan(
const char *class_name, StructuredDataImpl *args_data,
- std::string &error_str,
- lldb::ThreadPlanSP thread_plan_sp) {
+ std::string &error_str, lldb::ThreadPlanSP thread_plan_sp) {
if (class_name == nullptr || class_name[0] == '\0')
return StructuredData::ObjectSP();
@@ -1956,8 +2057,7 @@ ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec,
StructuredData::ObjectSP module_sp;
- if (LoadScriptingModule(file_spec.GetPath().c_str(), true, true, error,
- &module_sp))
+ if (LoadScriptingModule(file_spec.GetPath().c_str(), true, error, &module_sp))
return module_sp;
return StructuredData::ObjectSP();
@@ -2063,7 +2163,8 @@ bool ScriptInterpreterPythonImpl::GenerateTypeSynthClass(
}
Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData(
- StringList &user_input, std::string &output) {
+ StringList &user_input, std::string &output,
+ bool has_extra_args) {
static uint32_t num_created_functions = 0;
user_input.RemoveBlankLines();
StreamString sstr;
@@ -2075,8 +2176,12 @@ Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData(
std::string auto_generated_function_name(GenerateUniqueName(
"lldb_autogen_python_bp_callback_func_", num_created_functions));
- sstr.Printf("def %s (frame, bp_loc, internal_dict):",
- auto_generated_function_name.c_str());
+ if (has_extra_args)
+ sstr.Printf("def %s (frame, bp_loc, extra_args, internal_dict):",
+ auto_generated_function_name.c_str());
+ else
+ sstr.Printf("def %s (frame, bp_loc, internal_dict):",
+ auto_generated_function_name.c_str());
error = GenerateFunction(sstr.GetData(), user_input);
if (!error.Success())
@@ -2193,10 +2298,26 @@ bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction(
Locker py_lock(python_interpreter, Locker::AcquireLock |
Locker::InitSession |
Locker::NoSTDIN);
- ret_val = LLDBSwigPythonBreakpointCallbackFunction(
- python_function_name,
- python_interpreter->m_dictionary_name.c_str(), stop_frame_sp,
- bp_loc_sp);
+ Expected<bool> maybe_ret_val =
+ LLDBSwigPythonBreakpointCallbackFunction(
+ python_function_name,
+ python_interpreter->m_dictionary_name.c_str(), stop_frame_sp,
+ bp_loc_sp, bp_option_data->m_extra_args_up.get());
+
+ if (!maybe_ret_val) {
+
+ llvm::handleAllErrors(
+ maybe_ret_val.takeError(),
+ [&](PythonException &E) {
+ debugger.GetErrorStream() << E.ReadBacktrace();
+ },
+ [&](const llvm::ErrorInfoBase &E) {
+ debugger.GetErrorStream() << E.message();
+ });
+
+ } else {
+ ret_val = maybe_ret_val.get();
+ }
}
return ret_val;
}
@@ -2615,8 +2736,8 @@ uint64_t replace_all(std::string &str, const std::string &oldStr,
}
bool ScriptInterpreterPythonImpl::LoadScriptingModule(
- const char *pathname, bool can_reload, bool init_session,
- lldb_private::Status &error, StructuredData::ObjectSP *module_sp) {
+ const char *pathname, bool init_session, lldb_private::Status &error,
+ StructuredData::ObjectSP *module_sp) {
if (!pathname || !pathname[0]) {
error.SetErrorString("invalid pathname");
return false;
@@ -2716,11 +2837,6 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
bool was_imported = (was_imported_globally || was_imported_locally);
- if (was_imported && !can_reload) {
- error.SetErrorString("module already imported");
- return false;
- }
-
// now actually do the import
command_stream.Clear();
@@ -3171,4 +3287,4 @@ void ScriptInterpreterPythonImpl::AddToSysPath(AddLocation location,
//
// void ScriptInterpreterPythonImpl::Terminate() { Py_Finalize (); }
-#endif // LLDB_DISABLE_PYTHON
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
index 33ae308041b2e..e59fedbd0971f 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -9,14 +9,13 @@
#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H
#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H
-#ifdef LLDB_DISABLE_PYTHON
+#include "lldb/Host/Config.h"
-// Python is disabled in this build
-
-#else
+#if LLDB_ENABLE_PYTHON
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Core/IOHandler.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/lldb-private.h"
@@ -34,6 +33,13 @@ public:
CommandDataPython() : BreakpointOptions::CommandData() {
interpreter = lldb::eScriptLanguagePython;
}
+ CommandDataPython(StructuredData::ObjectSP extra_args_sp) :
+ BreakpointOptions::CommandData(),
+ m_extra_args_up(new StructuredDataImpl()) {
+ interpreter = lldb::eScriptLanguagePython;
+ m_extra_args_up->SetObjectSP(extra_args_sp);
+ }
+ lldb::StructuredDataImplUP m_extra_args_up;
};
ScriptInterpreterPython(Debugger &debugger)
@@ -52,5 +58,5 @@ protected:
};
} // namespace lldb_private
-#endif // LLDB_DISABLE_PYTHON
+#endif // LLDB_ENABLE_PYTHON
#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index 929567e579d8b..1fa198b07e54e 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -6,11 +6,9 @@
//
//===----------------------------------------------------------------------===//
-#ifdef LLDB_DISABLE_PYTHON
+#include "lldb/Host/Config.h"
-// Python is disabled in this build
-
-#else
+#if LLDB_ENABLE_PYTHON
#include "lldb-python.h"
@@ -179,8 +177,10 @@ public:
Status GenerateFunction(const char *signature,
const StringList &input) override;
- Status GenerateBreakpointCommandCallbackData(StringList &input,
- std::string &output) override;
+ Status GenerateBreakpointCommandCallbackData(
+ StringList &input,
+ std::string &output,
+ bool has_extra_args) override;
bool GenerateWatchpointCommandCallbackData(StringList &input,
std::string &output) override;
@@ -224,7 +224,7 @@ public:
std::string &output, Status &error) override;
bool
- LoadScriptingModule(const char *filename, bool can_reload, bool init_session,
+ LoadScriptingModule(const char *filename, bool init_session,
lldb_private::Status &error,
StructuredData::ObjectSP *module_sp = nullptr) override;
@@ -244,14 +244,21 @@ public:
Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
const char *callback_body) override;
- void SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options,
- const char *function_name) override;
+ Status SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options,
+ const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) override;
/// This one is for deserialization:
Status SetBreakpointCommandCallback(
BreakpointOptions *bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &data_up) override;
+ Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
+ const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp,
+ bool uses_extra_args);
+
/// Set a one-liner as the callback for the watchpoint.
void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
const char *oneliner) override;
@@ -369,6 +376,9 @@ public:
python::PythonDictionary &GetSysModuleDictionary();
+ llvm::Expected<unsigned> GetMaxPositionalArgumentsForCallable(
+ const llvm::StringRef &callable_name) override;
+
bool GetEmbeddedInterpreterModuleObjects();
bool SetStdHandle(lldb::FileSP file, const char *py_name,
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h b/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h
index 884514da99241..48f27b09b95c5 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h
@@ -9,12 +9,12 @@
#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H
#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H
+#include "lldb/Host/Config.h"
+
// Python.h needs to be included before any system headers in order to avoid
// redefinition of macros
-#ifdef LLDB_DISABLE_PYTHON
-// Python is disabled in this build
-#else
+#if LLDB_ENABLE_PYTHON
#include "llvm/Support/Compiler.h"
#if defined(_WIN32)
// If anyone #includes Host/PosixApi.h later, it will try to typedef pid_t. We
@@ -40,6 +40,6 @@
// Include python for non windows machines
#include <Python.h>
-#endif // LLDB_DISABLE_PYTHON
+#endif
#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H