aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ScriptInterpreter
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp29
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h4
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp101
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h29
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp2
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp2
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h6
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp2
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp48
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h56
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp230
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h3
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h22
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp306
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h66
15 files changed, 777 insertions, 129 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
index f14e2732f6eb..e99b7b88379a 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
@@ -30,6 +30,9 @@ extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction(
lua_State *L, lldb::StackFrameSP stop_frame_sp,
lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl);
+extern "C" llvm::Expected<bool> LLDBSwigLuaWatchpointCallbackFunction(
+ lua_State *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp);
+
#if _MSC_VER
#pragma warning (pop)
#endif
@@ -113,6 +116,32 @@ Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
bp_loc_sp, extra_args_impl);
}
+llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) {
+ lua_pushlightuserdata(m_lua_state, baton);
+ const char *fmt_str = "return function(frame, wp, ...) {0} end";
+ std::string func_str = llvm::formatv(fmt_str, body).str();
+ if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {
+ llvm::Error e = llvm::make_error<llvm::StringError>(
+ llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),
+ llvm::inconvertibleErrorCode());
+ // Pop error message from the stack.
+ lua_pop(m_lua_state, 2);
+ return e;
+ }
+ lua_settable(m_lua_state, LUA_REGISTRYINDEX);
+ return llvm::Error::success();
+}
+
+llvm::Expected<bool>
+Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
+ lldb::WatchpointSP wp_sp) {
+
+ lua_pushlightuserdata(m_lua_state, baton);
+ lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
+ return LLDBSwigLuaWatchpointCallbackFunction(m_lua_state, stop_frame_sp,
+ wp_sp);
+}
+
llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {
int error =
luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer");
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
index 873440f0aab3..5daedf835b9b 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
@@ -37,6 +37,10 @@ public:
CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
lldb::BreakpointLocationSP bp_loc_sp,
StructuredData::ObjectSP extra_args_sp);
+ llvm::Error RegisterWatchpointCallback(void *baton, const char *body);
+ llvm::Expected<bool> CallWatchpointCallback(void *baton,
+ lldb::StackFrameSP stop_frame_sp,
+ lldb::WatchpointSP wp_sp);
llvm::Error LoadModule(llvm::StringRef filename);
llvm::Error CheckSyntax(llvm::StringRef buffer);
llvm::Error ChangeIO(FILE *out, FILE *err);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
index 920e334f51aa..ef46401c8b46 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -58,7 +58,13 @@ public:
const char *instructions = nullptr;
switch (m_active_io_handler) {
case eIOHandlerNone:
+ break;
case eIOHandlerWatchpoint:
+ instructions = "Enter your Lua command(s). Type 'quit' to end.\n"
+ "The commands are compiled as the body of the following "
+ "Lua function\n"
+ "function (frame, wp) end\n";
+ SetPrompt(llvm::StringRef("..> "));
break;
case eIOHandlerBreakpoint:
instructions = "Enter your Lua command(s). Type 'quit' to end.\n"
@@ -78,7 +84,8 @@ public:
StringList &lines) override {
size_t last = lines.GetSize() - 1;
if (IsQuitCommand(lines.GetStringAtIndex(last))) {
- if (m_active_io_handler == eIOHandlerBreakpoint)
+ if (m_active_io_handler == eIOHandlerBreakpoint ||
+ m_active_io_handler == eIOHandlerWatchpoint)
lines.DeleteStringAtIndex(last);
return true;
}
@@ -90,17 +97,19 @@ public:
// Lua always errors out to incomplete code with '<eof>'
return error_str.find("<eof>") == std::string::npos;
}
- // The breakpoint handler only exits with a explicit 'quit'
- return m_active_io_handler != eIOHandlerBreakpoint;
+ // The breakpoint and watchpoint handler only exits with a explicit 'quit'
+ return m_active_io_handler != eIOHandlerBreakpoint &&
+ m_active_io_handler != eIOHandlerWatchpoint;
}
void IOHandlerInputComplete(IOHandler &io_handler,
std::string &data) override {
switch (m_active_io_handler) {
case eIOHandlerBreakpoint: {
- auto *bp_options_vec = static_cast<std::vector<BreakpointOptions *> *>(
- io_handler.GetUserData());
- for (auto *bp_options : *bp_options_vec) {
+ auto *bp_options_vec =
+ static_cast<std::vector<std::reference_wrapper<BreakpointOptions>> *>(
+ io_handler.GetUserData());
+ for (BreakpointOptions &bp_options : *bp_options_vec) {
Status error = m_script_interpreter.SetBreakpointCommandCallback(
bp_options, data.c_str());
if (error.Fail())
@@ -108,9 +117,13 @@ public:
}
io_handler.SetIsDone(true);
} break;
- case eIOHandlerWatchpoint:
+ case eIOHandlerWatchpoint: {
+ auto *wp_options =
+ static_cast<WatchpointOptions *>(io_handler.GetUserData());
+ m_script_interpreter.SetWatchpointCommandCallback(wp_options,
+ data.c_str());
io_handler.SetIsDone(true);
- break;
+ } break;
case eIOHandlerNone:
if (IsQuitCommand(data)) {
io_handler.SetIsDone(true);
@@ -133,7 +146,7 @@ ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger)
: ScriptInterpreter(debugger, eScriptLanguageLua),
m_lua(std::make_unique<Lua>()) {}
-ScriptInterpreterLua::~ScriptInterpreterLua() {}
+ScriptInterpreterLua::~ScriptInterpreterLua() = default;
bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command,
CommandReturnObject *result,
@@ -194,8 +207,9 @@ void ScriptInterpreterLua::ExecuteInterpreterLoop() {
}
bool ScriptInterpreterLua::LoadScriptingModule(
- const char *filename, bool init_session, lldb_private::Status &error,
- StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) {
+ const char *filename, const LoadScriptOptions &options,
+ lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
+ FileSpec extra_search_dir) {
FileSystem::Instance().Collect(filename);
if (llvm::Error e = m_lua->LoadModule(filename)) {
@@ -275,8 +289,35 @@ bool ScriptInterpreterLua::BreakpointCallbackFunction(
return *BoolOrErr;
}
+bool ScriptInterpreterLua::WatchpointCallbackFunction(
+ void *baton, StoppointCallbackContext *context, user_id_t watch_id) {
+ assert(context);
+
+ ExecutionContext exe_ctx(context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target == nullptr)
+ return true;
+
+ StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP());
+ WatchpointSP wp_sp = target->GetWatchpointList().FindByID(watch_id);
+
+ Debugger &debugger = target->GetDebugger();
+ ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>(
+ debugger.GetScriptInterpreter(true, eScriptLanguageLua));
+ Lua &lua = lua_interpreter->GetLua();
+
+ llvm::Expected<bool> BoolOrErr =
+ lua.CallWatchpointCallback(baton, stop_frame_sp, wp_sp);
+ if (llvm::Error E = BoolOrErr.takeError()) {
+ debugger.GetErrorStream() << toString(std::move(E));
+ return true;
+ }
+
+ return *BoolOrErr;
+}
+
void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback(
- std::vector<BreakpointOptions *> &bp_options_vec,
+ std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
CommandReturnObject &result) {
IOHandlerSP io_handler_sp(
new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint));
@@ -284,8 +325,16 @@ void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback(
m_debugger.RunIOHandlerAsync(io_handler_sp);
}
+void ScriptInterpreterLua::CollectDataForWatchpointCommandCallback(
+ WatchpointOptions *wp_options, CommandReturnObject &result) {
+ IOHandlerSP io_handler_sp(
+ new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerWatchpoint));
+ io_handler_sp->SetUserData(wp_options);
+ m_debugger.RunIOHandlerAsync(io_handler_sp);
+}
+
Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction(
- BreakpointOptions *bp_options, const char *function_name,
+ BreakpointOptions &bp_options, const char *function_name,
StructuredData::ObjectSP extra_args_sp) {
const char *fmt_str = "return {0}(frame, bp_loc, ...)";
std::string oneliner = llvm::formatv(fmt_str, function_name).str();
@@ -294,12 +343,12 @@ Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction(
}
Status ScriptInterpreterLua::SetBreakpointCommandCallback(
- BreakpointOptions *bp_options, const char *command_body_text) {
+ BreakpointOptions &bp_options, const char *command_body_text) {
return RegisterBreakpointCallback(bp_options, command_body_text, {});
}
Status ScriptInterpreterLua::RegisterBreakpointCallback(
- BreakpointOptions *bp_options, const char *command_body_text,
+ BreakpointOptions &bp_options, const char *command_body_text,
StructuredData::ObjectSP extra_args_sp) {
Status error;
auto data_up = std::make_unique<CommandDataLua>(extra_args_sp);
@@ -308,7 +357,27 @@ Status ScriptInterpreterLua::RegisterBreakpointCallback(
return error;
auto baton_sp =
std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
- bp_options->SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction,
+ bp_options.SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction,
+ baton_sp);
+ return error;
+}
+
+void ScriptInterpreterLua::SetWatchpointCommandCallback(
+ WatchpointOptions *wp_options, const char *command_body_text) {
+ RegisterWatchpointCallback(wp_options, command_body_text, {});
+}
+
+Status ScriptInterpreterLua::RegisterWatchpointCallback(
+ WatchpointOptions *wp_options, const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp) {
+ Status error;
+ auto data_up = std::make_unique<WatchpointOptions::CommandData>();
+ error = m_lua->RegisterWatchpointCallback(data_up.get(), command_body_text);
+ if (error.Fail())
+ return error;
+ auto baton_sp =
+ std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up));
+ wp_options->SetCallback(ScriptInterpreterLua::WatchpointCallbackFunction,
baton_sp);
return error;
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
index 1130ceee3c20..808000b833ec 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
@@ -9,6 +9,9 @@
#ifndef liblldb_ScriptInterpreterLua_h_
#define liblldb_ScriptInterpreterLua_h_
+#include <vector>
+
+#include "lldb/Breakpoint/WatchpointOptions.h"
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Utility/Status.h"
@@ -40,7 +43,8 @@ public:
void ExecuteInterpreterLoop() override;
- bool LoadScriptingModule(const char *filename, bool init_session,
+ bool LoadScriptingModule(const char *filename,
+ const LoadScriptOptions &options,
lldb_private::Status &error,
StructuredData::ObjectSP *module_sp = nullptr,
FileSpec extra_search_dir = {}) override;
@@ -61,6 +65,10 @@ public:
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
+ static bool WatchpointCallbackFunction(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t watch_id);
+
// PluginInterface protocol
lldb_private::ConstString GetPluginName() override;
@@ -72,21 +80,32 @@ public:
llvm::Error LeaveSession();
void CollectDataForBreakpointCommandCallback(
- std::vector<BreakpointOptions *> &bp_options_vec,
+ std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
CommandReturnObject &result) override;
- Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
+ void
+ CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
+ CommandReturnObject &result) override;
+
+ Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
const char *command_body_text) override;
+ void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
+ const char *command_body_text) override;
+
Status SetBreakpointCommandCallbackFunction(
- BreakpointOptions *bp_options, const char *function_name,
+ BreakpointOptions &bp_options, const char *function_name,
StructuredData::ObjectSP extra_args_sp) override;
private:
std::unique_ptr<Lua> m_lua;
bool m_session_is_active = false;
- Status RegisterBreakpointCallback(BreakpointOptions *bp_options,
+ Status RegisterBreakpointCallback(BreakpointOptions &bp_options,
+ const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp);
+
+ Status RegisterWatchpointCallback(WatchpointOptions *wp_options,
const char *command_body_text,
StructuredData::ObjectSP extra_args_sp);
};
diff --git a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
index d9c32cc132d4..f8a385240bd9 100644
--- a/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
@@ -25,7 +25,7 @@ LLDB_PLUGIN_DEFINE(ScriptInterpreterNone)
ScriptInterpreterNone::ScriptInterpreterNone(Debugger &debugger)
: ScriptInterpreter(debugger, eScriptLanguageNone) {}
-ScriptInterpreterNone::~ScriptInterpreterNone() {}
+ScriptInterpreterNone::~ScriptInterpreterNone() = default;
bool ScriptInterpreterNone::ExecuteOneLine(llvm::StringRef command,
CommandReturnObject *,
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index 7c49502f1b57..f51d9b3a796c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -24,7 +24,7 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Errno.h"
-#include <stdio.h>
+#include <cstdio>
using namespace lldb_private;
using namespace lldb;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
index 22f6c67eb7a5..4577253227cd 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -229,7 +229,7 @@ struct PythonFormat<
class PythonObject {
public:
- PythonObject() : m_py_obj(nullptr) {}
+ PythonObject() = default;
PythonObject(PyRefType type, PyObject *py_obj) {
m_py_obj = py_obj;
@@ -378,7 +378,7 @@ public:
}
protected:
- PyObject *m_py_obj;
+ PyObject *m_py_obj = nullptr;
};
@@ -421,7 +421,7 @@ public:
Py_DECREF(py_obj);
}
- TypedPythonObject() {}
+ TypedPythonObject() = default;
};
class PythonBytes : public TypedPythonObject<PythonBytes> {
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
index 5f6429f5cd0e..95a3365ed983 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
@@ -2,7 +2,7 @@
#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
-#include <stdio.h>
+#include <cstdio>
#include <editline/readline.h>
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp
new file mode 100644
index 000000000000..7c7c5d73680a
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp
@@ -0,0 +1,48 @@
+//===-- SWIGPythonBridge.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 "lldb/Host/Config.h"
+#include "lldb/lldb-enumerations.h"
+
+#if LLDB_ENABLE_PYTHON
+
+// LLDB Python header must be included first
+#include "lldb-python.h"
+
+#include "SWIGPythonBridge.h"
+
+using namespace lldb;
+
+namespace lldb_private {
+
+template <typename T> const char *GetPythonValueFormatString(T t);
+template <> const char *GetPythonValueFormatString(char *) { return "s"; }
+template <> const char *GetPythonValueFormatString(char) { return "b"; }
+template <> const char *GetPythonValueFormatString(unsigned char) {
+ return "B";
+}
+template <> const char *GetPythonValueFormatString(short) { return "h"; }
+template <> const char *GetPythonValueFormatString(unsigned short) {
+ return "H";
+}
+template <> const char *GetPythonValueFormatString(int) { return "i"; }
+template <> const char *GetPythonValueFormatString(unsigned int) { return "I"; }
+template <> const char *GetPythonValueFormatString(long) { return "l"; }
+template <> const char *GetPythonValueFormatString(unsigned long) {
+ return "k";
+}
+template <> const char *GetPythonValueFormatString(long long) { return "L"; }
+template <> const char *GetPythonValueFormatString(unsigned long long) {
+ return "K";
+}
+template <> const char *GetPythonValueFormatString(float) { return "f"; }
+template <> const char *GetPythonValueFormatString(double) { return "d"; }
+
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
new file mode 100644
index 000000000000..1ef792bcf303
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -0,0 +1,56 @@
+//===-- ScriptInterpreterPython.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_SWIGPYTHONBRIDGE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SWIGPYTHONBRIDGE_H
+
+#include <string>
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+// GetPythonValueFormatString provides a system independent type safe way to
+// convert a variable's type into a python value format. Python value formats
+// are defined in terms of builtin C types and could change from system to as
+// the underlying typedef for uint* types, size_t, off_t and other values
+// change.
+
+template <typename T> const char *GetPythonValueFormatString(T t);
+template <> const char *GetPythonValueFormatString(char *);
+template <> const char *GetPythonValueFormatString(char);
+template <> const char *GetPythonValueFormatString(unsigned char);
+template <> const char *GetPythonValueFormatString(short);
+template <> const char *GetPythonValueFormatString(unsigned short);
+template <> const char *GetPythonValueFormatString(int);
+template <> const char *GetPythonValueFormatString(unsigned int);
+template <> const char *GetPythonValueFormatString(long);
+template <> const char *GetPythonValueFormatString(unsigned long);
+template <> const char *GetPythonValueFormatString(long long);
+template <> const char *GetPythonValueFormatString(unsigned long long);
+template <> const char *GetPythonValueFormatString(float t);
+template <> const char *GetPythonValueFormatString(double t);
+
+extern "C" void *LLDBSwigPythonCreateScriptedProcess(
+ const char *python_class_name, const char *session_dictionary_name,
+ const lldb::TargetSP &target_sp, StructuredDataImpl *args_impl,
+ std::string &error_string);
+
+extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data);
+extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data);
+extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data);
+
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SWIGPYTHONBRIDGE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 6b53bd3a2edc..7ad63722c31c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -16,7 +16,11 @@
#include "PythonDataObjects.h"
#include "PythonReadline.h"
+#include "SWIGPythonBridge.h"
#include "ScriptInterpreterPythonImpl.h"
+#include "ScriptedProcessPythonInterface.h"
+
+#include "lldb/API/SBError.h"
#include "lldb/API/SBFrame.h"
#include "lldb/API/SBValue.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@@ -41,10 +45,10 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatAdapters.h"
+#include <cstdio>
+#include <cstdlib>
#include <memory>
#include <mutex>
-#include <stdio.h>
-#include <stdlib.h>
#include <string>
using namespace lldb;
@@ -148,8 +152,6 @@ extern "C" void *LLDBSwigPython_GetChildAtIndex(void *implementor,
extern "C" int LLDBSwigPython_GetIndexOfChildWithName(void *implementor,
const char *child_name);
-extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data);
-
extern lldb::ValueObjectSP
LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data);
@@ -234,8 +236,7 @@ namespace {
// save off initial state at the beginning, and restore it at the end
struct InitializePythonRAII {
public:
- InitializePythonRAII()
- : m_gil_state(PyGILState_UNLOCKED), m_was_already_initialized(false) {
+ InitializePythonRAII() {
InitializePythonHome();
#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
@@ -355,8 +356,8 @@ private:
}
TerminalState m_stdin_tty_state;
- PyGILState_STATE m_gil_state;
- bool m_was_already_initialized;
+ PyGILState_STATE m_gil_state = PyGILState_UNLOCKED;
+ bool m_was_already_initialized = false;
};
} // namespace
@@ -410,6 +411,32 @@ FileSpec ScriptInterpreterPython::GetPythonDir() {
return g_spec;
}
+void ScriptInterpreterPython::SharedLibraryDirectoryHelper(
+ FileSpec &this_file) {
+ // When we're loaded from python, this_file will point to the file inside the
+ // python package directory. Replace it with the one in the lib directory.
+#ifdef _WIN32
+ // On windows, we need to manually back out of the python tree, and go into
+ // the bin directory. This is pretty much the inverse of what ComputePythonDir
+ // does.
+ if (this_file.GetFileNameExtension() == ConstString(".pyd")) {
+ this_file.RemoveLastPathComponent(); // _lldb.pyd or _lldb_d.pyd
+ this_file.RemoveLastPathComponent(); // lldb
+ llvm::StringRef libdir = LLDB_PYTHON_RELATIVE_LIBDIR;
+ for (auto it = llvm::sys::path::begin(libdir),
+ end = llvm::sys::path::end(libdir);
+ it != end; ++it)
+ this_file.RemoveLastPathComponent();
+ this_file.AppendPathComponent("bin");
+ this_file.AppendPathComponent("liblldb.dll");
+ }
+#else
+ // The python file is a symlink, so we can find the real library by resolving
+ // it. We can do this unconditionally.
+ FileSystem::Instance().ResolveSymbolicLink(this_file, this_file);
+#endif
+}
+
lldb_private::ConstString ScriptInterpreterPython::GetPluginNameStatic() {
static ConstString g_name("script-python");
return g_name;
@@ -506,6 +533,9 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger)
m_command_thread_state(nullptr) {
InitializePrivate();
+ m_scripted_process_interface_up =
+ std::make_unique<ScriptedProcessPythonInterface>(*this);
+
m_dictionary_name.append("_dict");
StreamString run_string;
run_string.Printf("%s = dict()", m_dictionary_name.c_str());
@@ -605,11 +635,10 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler,
case eIOHandlerNone:
break;
case eIOHandlerBreakpoint: {
- std::vector<BreakpointOptions *> *bp_options_vec =
- (std::vector<BreakpointOptions *> *)io_handler.GetUserData();
- for (auto bp_options : *bp_options_vec) {
- if (!bp_options)
- continue;
+ std::vector<std::reference_wrapper<BreakpointOptions>> *bp_options_vec =
+ (std::vector<std::reference_wrapper<BreakpointOptions>> *)
+ io_handler.GetUserData();
+ for (BreakpointOptions &bp_options : *bp_options_vec) {
auto data_up = std::make_unique<CommandDataPython>();
if (!data_up)
@@ -623,7 +652,7 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler,
.Success()) {
auto baton_sp = std::make_shared<BreakpointOptions::CommandBaton>(
std::move(data_up));
- bp_options->SetCallback(
+ bp_options.SetCallback(
ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp);
} else if (!batch_mode) {
StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
@@ -1048,11 +1077,24 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn(
llvm::StringRef in_string, ScriptInterpreter::ScriptReturnType return_type,
void *ret_value, const ExecuteScriptOptions &options) {
+ llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
+ io_redirect_or_error = ScriptInterpreterIORedirect::Create(
+ options.GetEnableIO(), m_debugger, /*result=*/nullptr);
+
+ if (!io_redirect_or_error) {
+ llvm::consumeError(io_redirect_or_error.takeError());
+ return false;
+ }
+
+ ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error;
+
Locker locker(this,
Locker::AcquireLock | Locker::InitSession |
(options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) |
Locker::NoSTDIN,
- Locker::FreeAcquiredLock | Locker::TearDownSession);
+ Locker::FreeAcquiredLock | Locker::TearDownSession,
+ io_redirect.GetInputFile(), io_redirect.GetOutputFile(),
+ io_redirect.GetErrorFile());
PythonModule &main_module = GetMainModule();
PythonDictionary globals = main_module.GetDictionary();
@@ -1161,11 +1203,22 @@ Status ScriptInterpreterPythonImpl::ExecuteMultipleLines(
if (in_string == nullptr)
return Status();
+ llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
+ io_redirect_or_error = ScriptInterpreterIORedirect::Create(
+ options.GetEnableIO(), m_debugger, /*result=*/nullptr);
+
+ if (!io_redirect_or_error)
+ return Status(io_redirect_or_error.takeError());
+
+ ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error;
+
Locker locker(this,
Locker::AcquireLock | Locker::InitSession |
(options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) |
Locker::NoSTDIN,
- Locker::FreeAcquiredLock | Locker::TearDownSession);
+ Locker::FreeAcquiredLock | Locker::TearDownSession,
+ io_redirect.GetInputFile(), io_redirect.GetOutputFile(),
+ io_redirect.GetErrorFile());
PythonModule &main_module = GetMainModule();
PythonDictionary globals = main_module.GetDictionary();
@@ -1196,7 +1249,7 @@ Status ScriptInterpreterPythonImpl::ExecuteMultipleLines(
}
void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback(
- std::vector<BreakpointOptions *> &bp_options_vec,
+ std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
CommandReturnObject &result) {
m_active_io_handler = eIOHandlerBreakpoint;
m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler(
@@ -1211,7 +1264,7 @@ void ScriptInterpreterPythonImpl::CollectDataForWatchpointCommandCallback(
}
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
- BreakpointOptions *bp_options, const char *function_name,
+ 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.
@@ -1253,7 +1306,7 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction(
}
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
- BreakpointOptions *bp_options,
+ BreakpointOptions &bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &cmd_data_up) {
Status error;
error = GenerateBreakpointCommandCallbackData(cmd_data_up->user_source,
@@ -1264,21 +1317,20 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
}
auto baton_sp =
std::make_shared<BreakpointOptions::CommandBaton>(std::move(cmd_data_up));
- bp_options->SetCallback(
+ bp_options.SetCallback(
ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp);
return error;
}
Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
- BreakpointOptions *bp_options, const char *command_body_text) {
+ BreakpointOptions &bp_options, const char *command_body_text) {
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) {
+ 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
@@ -1292,7 +1344,7 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback(
if (error.Success()) {
auto baton_sp =
std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
- bp_options->SetCallback(
+ bp_options.SetCallback(
ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp);
return error;
}
@@ -1330,7 +1382,7 @@ Status ScriptInterpreterPythonImpl::ExportFunctionDefinitionToInterpreter(
Status error = ExecuteMultipleLines(
function_def_string.c_str(),
- ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false));
+ ExecuteScriptOptions().SetEnableIO(false));
return error;
}
@@ -1678,35 +1730,6 @@ StructuredData::ArraySP ScriptInterpreterPythonImpl::OSPlugin_ThreadsInfo(
return StructuredData::ArraySP();
}
-// GetPythonValueFormatString provides a system independent type safe way to
-// convert a variable's type into a python value format. Python value formats
-// are defined in terms of builtin C types and could change from system to as
-// the underlying typedef for uint* types, size_t, off_t and other values
-// change.
-
-template <typename T> const char *GetPythonValueFormatString(T t);
-template <> const char *GetPythonValueFormatString(char *) { return "s"; }
-template <> const char *GetPythonValueFormatString(char) { return "b"; }
-template <> const char *GetPythonValueFormatString(unsigned char) {
- return "B";
-}
-template <> const char *GetPythonValueFormatString(short) { return "h"; }
-template <> const char *GetPythonValueFormatString(unsigned short) {
- return "H";
-}
-template <> const char *GetPythonValueFormatString(int) { return "i"; }
-template <> const char *GetPythonValueFormatString(unsigned int) { return "I"; }
-template <> const char *GetPythonValueFormatString(long) { return "l"; }
-template <> const char *GetPythonValueFormatString(unsigned long) {
- return "k";
-}
-template <> const char *GetPythonValueFormatString(long long) { return "L"; }
-template <> const char *GetPythonValueFormatString(unsigned long long) {
- return "K";
-}
-template <> const char *GetPythonValueFormatString(float t) { return "f"; }
-template <> const char *GetPythonValueFormatString(double t) { return "d"; }
-
StructuredData::StringSP
ScriptInterpreterPythonImpl::OSPlugin_RegisterContextData(
StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid) {
@@ -2058,7 +2081,10 @@ ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec,
StructuredData::ObjectSP module_sp;
- if (LoadScriptingModule(file_spec.GetPath().c_str(), true, error, &module_sp))
+ LoadScriptOptions load_script_options =
+ LoadScriptOptions().SetInitSession(true).SetSilent(false);
+ if (LoadScriptingModule(file_spec.GetPath().c_str(), load_script_options,
+ error, &module_sp))
return module_sp;
return StructuredData::ObjectSP();
@@ -2733,26 +2759,44 @@ uint64_t replace_all(std::string &str, const std::string &oldStr,
}
bool ScriptInterpreterPythonImpl::LoadScriptingModule(
- const char *pathname, bool init_session, lldb_private::Status &error,
- StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) {
+ const char *pathname, const LoadScriptOptions &options,
+ lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
+ FileSpec extra_search_dir) {
namespace fs = llvm::sys::fs;
namespace path = llvm::sys::path;
+ ExecuteScriptOptions exc_options = ExecuteScriptOptions()
+ .SetEnableIO(!options.GetSilent())
+ .SetSetLLDBGlobals(false);
+
if (!pathname || !pathname[0]) {
error.SetErrorString("invalid pathname");
return false;
}
+ llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
+ io_redirect_or_error = ScriptInterpreterIORedirect::Create(
+ exc_options.GetEnableIO(), m_debugger, /*result=*/nullptr);
+
+ if (!io_redirect_or_error) {
+ error = io_redirect_or_error.takeError();
+ return false;
+ }
+
+ ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error;
lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this();
// Before executing Python code, lock the GIL.
Locker py_lock(this,
Locker::AcquireLock |
- (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN,
+ (options.GetInitSession() ? Locker::InitSession : 0) |
+ Locker::NoSTDIN,
Locker::FreeAcquiredLock |
- (init_session ? Locker::TearDownSession : 0));
+ (options.GetInitSession() ? Locker::TearDownSession : 0),
+ io_redirect.GetInputFile(), io_redirect.GetOutputFile(),
+ io_redirect.GetErrorFile());
- auto ExtendSysPath = [this](std::string directory) -> llvm::Error {
+ auto ExtendSysPath = [&](std::string directory) -> llvm::Error {
if (directory.empty()) {
return llvm::make_error<llvm::StringError>(
"invalid directory name", llvm::inconvertibleErrorCode());
@@ -2767,11 +2811,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
"sys.path.insert(1,'%s');\n\n",
directory.c_str(), directory.c_str());
bool syspath_retval =
- ExecuteMultipleLines(command_stream.GetData(),
- ScriptInterpreter::ExecuteScriptOptions()
- .SetEnableIO(false)
- .SetSetLLDBGlobals(false))
- .Success();
+ ExecuteMultipleLines(command_stream.GetData(), exc_options).Success();
if (!syspath_retval) {
return llvm::make_error<llvm::StringError>(
"Python sys.path handling failed", llvm::inconvertibleErrorCode());
@@ -2781,6 +2821,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
};
std::string module_name(pathname);
+ bool possible_package = false;
if (extra_search_dir) {
if (llvm::Error e = ExtendSysPath(extra_search_dir.GetPath())) {
@@ -2805,6 +2846,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
return false;
}
// Not a filename, probably a package of some sort, let it go through.
+ possible_package = true;
} else if (is_directory(st) || is_regular_file(st)) {
if (module_file.GetDirectory().IsEmpty()) {
error.SetErrorString("invalid directory name");
@@ -2831,35 +2873,39 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
module_name.resize(module_name.length() - 4);
}
- // check if the module is already import-ed
+ if (!possible_package && module_name.find('.') != llvm::StringRef::npos) {
+ error.SetErrorStringWithFormat(
+ "Python does not allow dots in module names: %s", module_name.c_str());
+ return false;
+ }
+
+ if (module_name.find('-') != llvm::StringRef::npos) {
+ error.SetErrorStringWithFormat(
+ "Python discourages dashes in module names: %s", module_name.c_str());
+ return false;
+ }
+
+ // Check if the module is already imported.
StreamString command_stream;
command_stream.Clear();
command_stream.Printf("sys.modules.__contains__('%s')", module_name.c_str());
bool does_contain = false;
- // this call will succeed if the module was ever imported in any Debugger
- // in the lifetime of the process in which this LLDB framework is living
- bool was_imported_globally =
- (ExecuteOneLineWithReturn(
- command_stream.GetData(),
- ScriptInterpreterPythonImpl::eScriptReturnTypeBool, &does_contain,
- ScriptInterpreter::ExecuteScriptOptions()
- .SetEnableIO(false)
- .SetSetLLDBGlobals(false)) &&
- does_contain);
- // this call will fail if the module was not imported in this Debugger
- // before
- command_stream.Clear();
- command_stream.Printf("sys.getrefcount(%s)", module_name.c_str());
- bool was_imported_locally = GetSessionDictionary()
- .GetItemForKey(PythonString(module_name))
- .IsAllocated();
-
- bool was_imported = (was_imported_globally || was_imported_locally);
+ // This call will succeed if the module was ever imported in any Debugger in
+ // the lifetime of the process in which this LLDB framework is living.
+ const bool does_contain_executed = ExecuteOneLineWithReturn(
+ command_stream.GetData(),
+ ScriptInterpreterPythonImpl::eScriptReturnTypeBool, &does_contain, exc_options);
+
+ const bool was_imported_globally = does_contain_executed && does_contain;
+ const bool was_imported_locally =
+ GetSessionDictionary()
+ .GetItemForKey(PythonString(module_name))
+ .IsAllocated();
// now actually do the import
command_stream.Clear();
- if (was_imported) {
+ if (was_imported_globally || was_imported_locally) {
if (!was_imported_locally)
command_stream.Printf("import %s ; reload_module(%s)",
module_name.c_str(), module_name.c_str());
@@ -2868,10 +2914,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
} else
command_stream.Printf("import %s", module_name.c_str());
- error = ExecuteMultipleLines(command_stream.GetData(),
- ScriptInterpreter::ExecuteScriptOptions()
- .SetEnableIO(false)
- .SetSetLLDBGlobals(false));
+ error = ExecuteMultipleLines(command_stream.GetData(), exc_options);
if (error.Fail())
return false;
@@ -2890,7 +2933,8 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
void *module_pyobj = nullptr;
if (ExecuteOneLineWithReturn(
command_stream.GetData(),
- ScriptInterpreter::eScriptReturnTypeOpaqueObject, &module_pyobj) &&
+ ScriptInterpreter::eScriptReturnTypeOpaqueObject, &module_pyobj,
+ exc_options) &&
module_pyobj)
*module_sp = std::make_shared<StructuredPythonObject>(module_pyobj);
}
@@ -3047,7 +3091,7 @@ bool ScriptInterpreterPythonImpl::GetDocumentationForItem(const char *item,
if (ExecuteOneLineWithReturn(
command, ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
&result_ptr,
- ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false))) {
+ ExecuteScriptOptions().SetEnableIO(false))) {
if (result_ptr)
dest.assign(result_ptr);
return true;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
index e59fedbd0971..b8b978118218 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -13,6 +13,8 @@
#if LLDB_ENABLE_PYTHON
+#include "ScriptedProcessPythonInterface.h"
+
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/StructuredDataImpl.h"
@@ -51,6 +53,7 @@ public:
static lldb_private::ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();
static FileSpec GetPythonDir();
+ static void SharedLibraryDirectoryHelper(FileSpec &this_file);
protected:
static void ComputePythonDirForApple(llvm::SmallVectorImpl<char> &path);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index 45dad4217005..d1b0b3fda1ef 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H
+
#include "lldb/Host/Config.h"
#if LLDB_ENABLE_PYTHON
@@ -231,7 +234,8 @@ public:
bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value,
std::string &output, Status &error) override;
- bool LoadScriptingModule(const char *filename, bool init_session,
+ bool LoadScriptingModule(const char *filename,
+ const LoadScriptOptions &options,
lldb_private::Status &error,
StructuredData::ObjectSP *module_sp = nullptr,
FileSpec extra_search_dir = {}) override;
@@ -241,7 +245,7 @@ public:
std::unique_ptr<ScriptInterpreterLocker> AcquireInterpreterLock() override;
void CollectDataForBreakpointCommandCallback(
- std::vector<BreakpointOptions *> &bp_options_vec,
+ std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
CommandReturnObject &result) override;
void
@@ -249,20 +253,19 @@ public:
CommandReturnObject &result) override;
/// Set the callback body text into the callback for the breakpoint.
- Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
+ Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
const char *callback_body) override;
Status SetBreakpointCommandCallbackFunction(
- BreakpointOptions *bp_options,
- const char *function_name,
+ BreakpointOptions &bp_options, const char *function_name,
StructuredData::ObjectSP extra_args_sp) override;
/// This one is for deserialization:
Status SetBreakpointCommandCallback(
- BreakpointOptions *bp_options,
+ BreakpointOptions &bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &data_up) override;
- Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
+ Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
const char *command_body_text,
StructuredData::ObjectSP extra_args_sp,
bool uses_extra_args);
@@ -416,7 +419,7 @@ public:
: IOHandler(debugger, IOHandler::Type::PythonInterpreter),
m_python(python) {}
- ~IOHandlerPythonInterpreter() override {}
+ ~IOHandlerPythonInterpreter() override = default;
ConstString GetControlSequence(char ch) override {
if (ch == 'd')
@@ -483,4 +486,5 @@ protected:
} // namespace lldb_private
-#endif
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
new file mode 100644
index 000000000000..ce262c930f8b
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
@@ -0,0 +1,306 @@
+//===-- ScriptedProcessPythonInterface.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 "lldb/Host/Config.h"
+#include "lldb/lldb-enumerations.h"
+
+#if LLDB_ENABLE_PYTHON
+
+// LLDB Python header must be included first
+#include "lldb-python.h"
+
+#include "SWIGPythonBridge.h"
+#include "ScriptInterpreterPythonImpl.h"
+#include "ScriptedProcessPythonInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject(
+ const llvm::StringRef class_name, lldb::TargetSP target_sp,
+ StructuredData::DictionarySP args_sp) {
+ if (class_name.empty())
+ return {};
+
+ std::string error_string;
+ StructuredDataImpl *args_impl = nullptr;
+ if (args_sp) {
+ args_impl = new StructuredDataImpl();
+ args_impl->SetObjectSP(args_sp);
+ }
+
+ void *ret_val;
+
+ {
+
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ ret_val = LLDBSwigPythonCreateScriptedProcess(
+ class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp,
+ args_impl, error_string);
+ }
+
+ m_object_instance_sp =
+ StructuredData::GenericSP(new StructuredPythonObject(ret_val));
+
+ return m_object_instance_sp;
+}
+
+Status ScriptedProcessPythonInterface::Launch() {
+ return GetStatusFromMethod("launch");
+}
+
+Status ScriptedProcessPythonInterface::Resume() {
+ return GetStatusFromMethod("resume");
+}
+
+bool ScriptedProcessPythonInterface::ShouldStop() {
+ llvm::Optional<unsigned long long> should_stop =
+ GetGenericInteger("should_stop");
+
+ if (!should_stop)
+ return false;
+
+ return static_cast<bool>(*should_stop);
+}
+
+Status ScriptedProcessPythonInterface::Stop() {
+ return GetStatusFromMethod("stop");
+}
+
+Status ScriptedProcessPythonInterface::GetStatusFromMethod(
+ llvm::StringRef method_name) {
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ if (!m_object_instance_sp)
+ return Status("Python object ill-formed.");
+
+ if (!m_object_instance_sp)
+ return Status("Cannot convert Python object to StructuredData::Generic.");
+ PythonObject implementor(PyRefType::Borrowed,
+ (PyObject *)m_object_instance_sp->GetValue());
+
+ if (!implementor.IsAllocated())
+ return Status("Python implementor not allocated.");
+
+ PythonObject pmeth(
+ PyRefType::Owned,
+ PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ if (!pmeth.IsAllocated())
+ return Status("Python method not allocated.");
+
+ if (PyCallable_Check(pmeth.get()) == 0) {
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ return Status("Python method not callable.");
+ }
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ PythonObject py_return(PyRefType::Owned,
+ PyObject_CallMethod(implementor.get(),
+ method_name.str().c_str(),
+ nullptr));
+
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyErr_Clear();
+ return Status("Python method could not be called.");
+ }
+
+ if (PyObject *py_ret_ptr = py_return.get()) {
+ lldb::SBError *sb_error =
+ (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr);
+
+ if (!sb_error)
+ return Status("Couldn't cast lldb::SBError to lldb::Status.");
+
+ Status status = m_interpreter.GetStatusFromSBError(*sb_error);
+
+ if (status.Fail())
+ return Status("error: %s", status.AsCString());
+
+ return status;
+ }
+
+ return Status("Returned object is null.");
+}
+
+llvm::Optional<unsigned long long>
+ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) {
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ if (!m_object_instance_sp)
+ return llvm::None;
+
+ if (!m_object_instance_sp)
+ return llvm::None;
+ PythonObject implementor(PyRefType::Borrowed,
+ (PyObject *)m_object_instance_sp->GetValue());
+
+ if (!implementor.IsAllocated())
+ return llvm::None;
+
+ PythonObject pmeth(
+ PyRefType::Owned,
+ PyObject_GetAttrString(implementor.get(), method_name.str().c_str()));
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ if (!pmeth.IsAllocated())
+ return llvm::None;
+
+ if (PyCallable_Check(pmeth.get()) == 0) {
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ return llvm::None;
+ }
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ PythonObject py_return(PyRefType::Owned,
+ PyObject_CallMethod(implementor.get(),
+ method_name.str().c_str(),
+ nullptr));
+
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ if (!py_return.get())
+ return llvm::None;
+
+ llvm::Expected<unsigned long long> size = py_return.AsUnsignedLongLong();
+ // FIXME: Handle error.
+ if (!size)
+ return llvm::None;
+
+ return *size;
+}
+
+lldb::MemoryRegionInfoSP
+ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress(
+ lldb::addr_t address) {
+ // TODO: Implement
+ return nullptr;
+}
+
+StructuredData::DictionarySP
+ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) {
+ // TODO: Implement
+ return nullptr;
+}
+
+StructuredData::DictionarySP
+ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) {
+ // TODO: Implement
+ return nullptr;
+}
+
+lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
+ lldb::addr_t address, size_t size, Status &error) {
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ auto error_with_message = [&error](llvm::StringRef message) {
+ error.SetErrorString(message);
+ return nullptr;
+ };
+
+ static char callee_name[] = "read_memory_at_address";
+ std::string param_format = GetPythonValueFormatString(address);
+ param_format += GetPythonValueFormatString(size);
+
+ if (!m_object_instance_sp)
+ return error_with_message("Python object ill-formed.");
+
+ if (!m_object_instance_sp)
+ return error_with_message("Python method not callable.");
+
+ PythonObject implementor(PyRefType::Borrowed,
+ (PyObject *)m_object_instance_sp->GetValue());
+
+ if (!implementor.IsAllocated())
+ return error_with_message("Python implementor not allocated.");
+
+ PythonObject pmeth(PyRefType::Owned,
+ PyObject_GetAttrString(implementor.get(), callee_name));
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ if (!pmeth.IsAllocated())
+ return error_with_message("Python method not allocated.");
+
+ if (PyCallable_Check(pmeth.get()) == 0) {
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ return error_with_message("Python method not callable.");
+ }
+
+ if (PyErr_Occurred())
+ PyErr_Clear();
+
+ PythonObject py_return(PyRefType::Owned,
+ PyObject_CallMethod(implementor.get(), callee_name,
+ param_format.c_str(), address,
+ size));
+
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyErr_Clear();
+ return error_with_message("Python method could not be called.");
+ }
+
+ if (PyObject *py_ret_ptr = py_return.get()) {
+ lldb::SBData *sb_data =
+ (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr);
+
+ if (!sb_data)
+ return error_with_message(
+ "Couldn't cast lldb::SBData to lldb::DataExtractor.");
+
+ return m_interpreter.GetDataExtractorFromSBData(*sb_data);
+ }
+
+ return error_with_message("Returned object is null.");
+}
+
+StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() {
+ // TODO: Implement
+ return nullptr;
+}
+
+lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() {
+ llvm::Optional<unsigned long long> pid = GetGenericInteger("get_process_id");
+ return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid;
+}
+
+bool ScriptedProcessPythonInterface::IsAlive() {
+ llvm::Optional<unsigned long long> is_alive = GetGenericInteger("is_alive");
+
+ if (!is_alive)
+ return false;
+
+ return static_cast<bool>(*is_alive);
+}
+
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
new file mode 100644
index 000000000000..30cb5a882af2
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
@@ -0,0 +1,66 @@
+//===-- ScriptedProcessPythonInterface.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_SCRIPTEDPROCESSPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "lldb/Interpreter/ScriptedProcessInterface.h"
+
+namespace lldb_private {
+class ScriptInterpreterPythonImpl;
+class ScriptedProcessPythonInterface : public ScriptedProcessInterface {
+public:
+ ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedProcessInterface(), m_interpreter(interpreter) {}
+
+ StructuredData::GenericSP
+ CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp,
+ StructuredData::DictionarySP args_sp) override;
+
+ Status Launch() override;
+
+ Status Resume() override;
+
+ bool ShouldStop() override;
+
+ Status Stop() override;
+
+ lldb::MemoryRegionInfoSP
+ GetMemoryRegionContainingAddress(lldb::addr_t address) override;
+
+ StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) override;
+
+ StructuredData::DictionarySP GetRegistersForThread(lldb::tid_t tid) override;
+
+ lldb::DataExtractorSP ReadMemoryAtAddress(lldb::addr_t address, size_t size,
+ Status &error) override;
+
+ StructuredData::DictionarySP GetLoadedImages() override;
+
+ lldb::pid_t GetProcessID() override;
+
+ bool IsAlive() override;
+
+protected:
+ llvm::Optional<unsigned long long>
+ GetGenericInteger(llvm::StringRef method_name);
+ Status GetStatusFromMethod(llvm::StringRef method_name);
+
+private:
+ // The lifetime is managed by the ScriptInterpreter
+ ScriptInterpreterPythonImpl &m_interpreter;
+ StructuredData::GenericSP m_object_instance_sp;
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSPYTHONINTERFACE_H