aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ScriptInterpreter
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
commitb60736ec1405bb0a8dd40989f67ef4c93da068ab (patch)
tree5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /lldb/source/Plugins/ScriptInterpreter
parentcfca06d7963fa0909f90483b42a6d7d194d01e08 (diff)
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp105
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h21
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp161
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h43
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp4
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp331
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h16
7 files changed, 526 insertions, 155 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
index acd6128d84c5..f14e2732f6eb 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
@@ -9,16 +9,66 @@
#include "Lua.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Utility/FileSpec.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
using namespace lldb_private;
using namespace lldb;
+#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> LLDBSwigLuaBreakpointCallbackFunction(
+ lua_State *L, lldb::StackFrameSP stop_frame_sp,
+ lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl);
+
+#if _MSC_VER
+#pragma warning (pop)
+#endif
+
+#pragma clang diagnostic pop
+
+static int lldb_print(lua_State *L) {
+ int n = lua_gettop(L);
+ lua_getglobal(L, "io");
+ lua_getfield(L, -1, "stdout");
+ lua_getfield(L, -1, "write");
+ for (int i = 1; i <= n; i++) {
+ lua_pushvalue(L, -1); // write()
+ lua_pushvalue(L, -3); // io.stdout
+ luaL_tolstring(L, i, nullptr);
+ lua_pushstring(L, i != n ? "\t" : "\n");
+ lua_call(L, 3, 0);
+ }
+ return 0;
+}
+
+Lua::Lua() : m_lua_state(luaL_newstate()) {
+ assert(m_lua_state);
+ luaL_openlibs(m_lua_state);
+ luaopen_lldb(m_lua_state);
+ lua_pushcfunction(m_lua_state, lldb_print);
+ lua_setglobal(m_lua_state, "print");
+}
+
+Lua::~Lua() {
+ assert(m_lua_state);
+ lua_close(m_lua_state);
+}
+
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)
+ if (error == LUA_OK)
return llvm::Error::success();
llvm::Error e = llvm::make_error<llvm::StringError>(
@@ -29,6 +79,57 @@ llvm::Error Lua::Run(llvm::StringRef buffer) {
return e;
}
+llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) {
+ lua_pushlightuserdata(m_lua_state, baton);
+ const char *fmt_str = "return function(frame, bp_loc, ...) {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::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
+ lldb::BreakpointLocationSP bp_loc_sp,
+ StructuredData::ObjectSP extra_args_sp) {
+
+ lua_pushlightuserdata(m_lua_state, baton);
+ lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
+ auto *extra_args_impl = [&]() -> StructuredDataImpl * {
+ if (extra_args_sp == nullptr)
+ return nullptr;
+ auto *extra_args_impl = new StructuredDataImpl();
+ extra_args_impl->SetObjectSP(extra_args_sp);
+ return extra_args_impl;
+ }();
+ return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp,
+ bp_loc_sp, extra_args_impl);
+}
+
+llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {
+ int error =
+ luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer");
+ if (error == LUA_OK) {
+ // Pop buffer
+ lua_pop(m_lua_state, 1);
+ 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)) {
@@ -44,7 +145,7 @@ llvm::Error Lua::LoadModule(llvm::StringRef filename) {
int error = luaL_loadfile(m_lua_state, filename.data()) ||
lua_pcall(m_lua_state, 0, 1, 0);
- if (error) {
+ if (error != LUA_OK) {
llvm::Error e = llvm::make_error<llvm::StringError>(
llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
llvm::inconvertibleErrorCode());
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
index 300115aac8a7..873440f0aab3 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
@@ -9,6 +9,9 @@
#ifndef liblldb_Lua_h_
#define liblldb_Lua_h_
+#include "lldb/API/SBBreakpointLocation.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
@@ -25,19 +28,17 @@ 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);
- }
+ Lua();
+ ~Lua();
llvm::Error Run(llvm::StringRef buffer);
+ llvm::Error RegisterBreakpointCallback(void *baton, const char *body);
+ llvm::Expected<bool>
+ CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
+ lldb::BreakpointLocationSP bp_loc_sp,
+ StructuredData::ObjectSP extra_args_sp);
llvm::Error LoadModule(llvm::StringRef filename);
+ llvm::Error CheckSyntax(llvm::StringRef buffer);
llvm::Error ChangeIO(FILE *out, FILE *err);
private:
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
index 8cbeac4563c3..920e334f51aa 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -8,29 +8,42 @@
#include "ScriptInterpreterLua.h"
#include "Lua.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/ExecutionContext.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StringList.h"
#include "lldb/Utility/Timer.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatAdapters.h"
+#include <memory>
+#include <vector>
using namespace lldb;
using namespace lldb_private;
LLDB_PLUGIN_DEFINE(ScriptInterpreterLua)
+enum ActiveIOHandler {
+ eIOHandlerNone,
+ eIOHandlerBreakpoint,
+ eIOHandlerWatchpoint
+};
+
class IOHandlerLuaInterpreter : public IOHandlerDelegate,
public IOHandlerEditline {
public:
IOHandlerLuaInterpreter(Debugger &debugger,
- ScriptInterpreterLua &script_interpreter)
+ ScriptInterpreterLua &script_interpreter,
+ ActiveIOHandler active_io_handler = eIOHandlerNone)
: IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua",
">>> ", "..> ", true, debugger.GetUseColor(), 0,
*this, nullptr),
- m_script_interpreter(script_interpreter) {
+ m_script_interpreter(script_interpreter),
+ m_active_io_handler(active_io_handler) {
llvm::cantFail(m_script_interpreter.GetLua().ChangeIO(
debugger.GetOutputFile().GetStream(),
debugger.GetErrorFile().GetStream()));
@@ -41,20 +54,79 @@ public:
llvm::cantFail(m_script_interpreter.LeaveSession());
}
- void IOHandlerInputComplete(IOHandler &io_handler,
- std::string &data) override {
- if (llvm::StringRef(data).rtrim() == "quit") {
- io_handler.SetIsDone(true);
+ void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
+ const char *instructions = nullptr;
+ switch (m_active_io_handler) {
+ case eIOHandlerNone:
+ case eIOHandlerWatchpoint:
+ break;
+ case eIOHandlerBreakpoint:
+ 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, bp_loc, ...) end\n";
+ SetPrompt(llvm::StringRef("..> "));
+ break;
+ }
+ if (instructions == nullptr)
return;
+ if (interactive)
+ *io_handler.GetOutputStreamFileSP() << instructions;
+ }
+
+ bool IOHandlerIsInputComplete(IOHandler &io_handler,
+ StringList &lines) override {
+ size_t last = lines.GetSize() - 1;
+ if (IsQuitCommand(lines.GetStringAtIndex(last))) {
+ if (m_active_io_handler == eIOHandlerBreakpoint)
+ lines.DeleteStringAtIndex(last);
+ return true;
}
+ StreamString str;
+ lines.Join("\n", str);
+ if (llvm::Error E =
+ m_script_interpreter.GetLua().CheckSyntax(str.GetString())) {
+ std::string error_str = toString(std::move(E));
+ // 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;
+ }
- if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) {
- *GetOutputStreamFileSP() << llvm::toString(std::move(error));
+ 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) {
+ Status error = m_script_interpreter.SetBreakpointCommandCallback(
+ bp_options, data.c_str());
+ if (error.Fail())
+ *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n';
+ }
+ io_handler.SetIsDone(true);
+ } break;
+ case eIOHandlerWatchpoint:
+ io_handler.SetIsDone(true);
+ break;
+ case eIOHandlerNone:
+ if (IsQuitCommand(data)) {
+ io_handler.SetIsDone(true);
+ return;
+ }
+ if (llvm::Error error = m_script_interpreter.GetLua().Run(data))
+ *io_handler.GetErrorStreamFileSP() << toString(std::move(error));
+ break;
}
}
private:
ScriptInterpreterLua &m_script_interpreter;
+ ActiveIOHandler m_active_io_handler;
+
+ bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; }
};
ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger)
@@ -107,8 +179,7 @@ bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command,
}
void ScriptInterpreterLua::ExecuteInterpreterLoop() {
- static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
- Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
+ LLDB_SCOPED_TIMER();
// 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
@@ -124,7 +195,7 @@ void ScriptInterpreterLua::ExecuteInterpreterLoop() {
bool ScriptInterpreterLua::LoadScriptingModule(
const char *filename, bool init_session, lldb_private::Status &error,
- StructuredData::ObjectSP *module_sp) {
+ StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) {
FileSystem::Instance().Collect(filename);
if (llvm::Error e = m_lua->LoadModule(filename)) {
@@ -174,6 +245,74 @@ llvm::Error ScriptInterpreterLua::LeaveSession() {
return m_lua->Run(str);
}
+bool ScriptInterpreterLua::BreakpointCallbackFunction(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_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());
+ BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id);
+ BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id));
+
+ Debugger &debugger = target->GetDebugger();
+ ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>(
+ debugger.GetScriptInterpreter(true, eScriptLanguageLua));
+ Lua &lua = lua_interpreter->GetLua();
+
+ CommandDataLua *bp_option_data = static_cast<CommandDataLua *>(baton);
+ llvm::Expected<bool> BoolOrErr = lua.CallBreakpointCallback(
+ baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_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,
+ CommandReturnObject &result) {
+ IOHandlerSP io_handler_sp(
+ new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint));
+ io_handler_sp->SetUserData(&bp_options_vec);
+ m_debugger.RunIOHandlerAsync(io_handler_sp);
+}
+
+Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction(
+ 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();
+ return RegisterBreakpointCallback(bp_options, oneliner.c_str(),
+ extra_args_sp);
+}
+
+Status ScriptInterpreterLua::SetBreakpointCommandCallback(
+ 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,
+ StructuredData::ObjectSP extra_args_sp) {
+ Status error;
+ auto data_up = std::make_unique<CommandDataLua>(extra_args_sp);
+ error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text);
+ if (error.Fail())
+ return error;
+ auto baton_sp =
+ std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up));
+ bp_options->SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction,
+ baton_sp);
+ return error;
+}
+
lldb::ScriptInterpreterSP
ScriptInterpreterLua::CreateInstance(Debugger &debugger) {
return std::make_shared<ScriptInterpreterLua>(debugger);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
index bcc6ab24f6d0..1130ceee3c20 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h
@@ -9,12 +9,27 @@
#ifndef liblldb_ScriptInterpreterLua_h_
#define liblldb_ScriptInterpreterLua_h_
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-enumerations.h"
namespace lldb_private {
class Lua;
class ScriptInterpreterLua : public ScriptInterpreter {
public:
+ class CommandDataLua : public BreakpointOptions::CommandData {
+ public:
+ CommandDataLua() : BreakpointOptions::CommandData() {
+ interpreter = lldb::eScriptLanguageLua;
+ }
+ CommandDataLua(StructuredData::ObjectSP extra_args_sp)
+ : BreakpointOptions::CommandData(), m_extra_args_sp(extra_args_sp) {
+ interpreter = lldb::eScriptLanguageLua;
+ }
+ StructuredData::ObjectSP m_extra_args_sp;
+ };
+
ScriptInterpreterLua(Debugger &debugger);
~ScriptInterpreterLua() override;
@@ -25,10 +40,10 @@ public:
void ExecuteInterpreterLoop() override;
- bool
- LoadScriptingModule(const char *filename, bool init_session,
- lldb_private::Status &error,
- StructuredData::ObjectSP *module_sp = nullptr) override;
+ bool LoadScriptingModule(const char *filename, bool init_session,
+ lldb_private::Status &error,
+ StructuredData::ObjectSP *module_sp = nullptr,
+ FileSpec extra_search_dir = {}) override;
// Static Functions
static void Initialize();
@@ -41,6 +56,11 @@ public:
static const char *GetPluginDescriptionStatic();
+ static bool BreakpointCallbackFunction(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
// PluginInterface protocol
lldb_private::ConstString GetPluginName() override;
@@ -51,9 +71,24 @@ public:
llvm::Error EnterSession(lldb::user_id_t debugger_id);
llvm::Error LeaveSession();
+ void CollectDataForBreakpointCommandCallback(
+ std::vector<BreakpointOptions *> &bp_options_vec,
+ CommandReturnObject &result) override;
+
+ Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
+ const char *command_body_text) override;
+
+ Status SetBreakpointCommandCallbackFunction(
+ 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,
+ const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp);
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index 6f040fdef09b..7c49502f1b57 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -451,7 +451,11 @@ Expected<llvm::StringRef> PythonString::AsUTF8() const {
size_t PythonString::GetSize() const {
if (IsValid()) {
#if PY_MAJOR_VERSION >= 3
+#if PY_MINOR_VERSION >= 3
+ return PyUnicode_GetLength(m_py_obj);
+#else
return PyUnicode_GetSize(m_py_obj);
+#endif
#else
return PyString_Size(m_py_obj);
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 9f56b4fa60a5..6b53bd3a2edc 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/Config.h"
+#include "lldb/lldb-enumerations.h"
#if LLDB_ENABLE_PYTHON
@@ -32,6 +33,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Utility/ReproducerInstrumentation.h"
#include "lldb/Utility/Timer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -127,6 +129,16 @@ extern "C" unsigned int
LLDBSwigPythonCallBreakpointResolver(void *implementor, const char *method_name,
lldb_private::SymbolContext *sym_ctx);
+extern "C" void *LLDBSwigPythonCreateScriptedStopHook(
+ TargetSP target_sp, const char *python_class_name,
+ const char *session_dictionary_name, lldb_private::StructuredDataImpl *args,
+ lldb_private::Status &error);
+
+extern "C" bool
+LLDBSwigPythonStopHookCallHandleStop(void *implementor,
+ lldb::ExecutionContextRefSP exc_ctx,
+ lldb::StreamSP stream);
+
extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor,
uint32_t max);
@@ -204,6 +216,12 @@ extern "C" void *
LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting,
const lldb::TargetSP &target_sp);
+static ScriptInterpreterPythonImpl *GetPythonInterpreter(Debugger &debugger) {
+ ScriptInterpreter *script_interpreter =
+ debugger.GetScriptInterpreter(true, lldb::eScriptLanguagePython);
+ return static_cast<ScriptInterpreterPythonImpl *>(script_interpreter);
+}
+
static bool g_initialized = false;
namespace {
@@ -420,6 +438,7 @@ ScriptInterpreterPythonImpl::Locker::Locker(
: ScriptInterpreterLocker(),
m_teardown_session((on_leave & TearDownSession) == TearDownSession),
m_python_interpreter(py_interpreter) {
+ repro::Recorder::PrivateThread();
DoAcquireLock();
if ((on_entry & InitSession) == InitSession) {
if (!DoInitSession(on_entry, in, out, err)) {
@@ -982,8 +1001,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
}
void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() {
- static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
- Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
+ LLDB_SCOPED_TIMER();
Debugger &debugger = m_debugger;
@@ -1815,11 +1833,10 @@ StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan(
return {};
Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger();
- ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter();
ScriptInterpreterPythonImpl *python_interpreter =
- static_cast<ScriptInterpreterPythonImpl *>(script_interpreter);
+ GetPythonInterpreter(debugger);
- if (!script_interpreter)
+ if (!python_interpreter)
return {};
void *ret_val;
@@ -1919,11 +1936,10 @@ ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver(
return StructuredData::GenericSP();
Debugger &debugger = bkpt_sp->GetTarget().GetDebugger();
- ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter();
ScriptInterpreterPythonImpl *python_interpreter =
- static_cast<ScriptInterpreterPythonImpl *>(script_interpreter);
+ GetPythonInterpreter(debugger);
- if (!script_interpreter)
+ if (!python_interpreter)
return StructuredData::GenericSP();
void *ret_val;
@@ -1979,6 +1995,59 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth(
return lldb::eSearchDepthModule;
}
+StructuredData::GenericSP ScriptInterpreterPythonImpl::CreateScriptedStopHook(
+ TargetSP target_sp, const char *class_name, StructuredDataImpl *args_data,
+ Status &error) {
+
+ if (!target_sp) {
+ error.SetErrorString("No target for scripted stop-hook.");
+ return StructuredData::GenericSP();
+ }
+
+ if (class_name == nullptr || class_name[0] == '\0') {
+ error.SetErrorString("No class name for scripted stop-hook.");
+ return StructuredData::GenericSP();
+ }
+
+ ScriptInterpreterPythonImpl *python_interpreter =
+ GetPythonInterpreter(m_debugger);
+
+ if (!python_interpreter) {
+ error.SetErrorString("No script interpreter for scripted stop-hook.");
+ return StructuredData::GenericSP();
+ }
+
+ void *ret_val;
+
+ {
+ Locker py_lock(this,
+ Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+
+ ret_val = LLDBSwigPythonCreateScriptedStopHook(
+ target_sp, class_name, python_interpreter->m_dictionary_name.c_str(),
+ args_data, error);
+ }
+
+ return StructuredData::GenericSP(new StructuredPythonObject(ret_val));
+}
+
+bool ScriptInterpreterPythonImpl::ScriptedStopHookHandleStop(
+ StructuredData::GenericSP implementor_sp, ExecutionContext &exc_ctx,
+ lldb::StreamSP stream_sp) {
+ assert(implementor_sp &&
+ "can't call a stop hook with an invalid implementor");
+ assert(stream_sp && "can't call a stop hook with an invalid stream");
+
+ Locker py_lock(this,
+ Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+
+ lldb::ExecutionContextRefSP exc_ctx_ref_sp(new ExecutionContextRef(exc_ctx));
+
+ bool ret_val = LLDBSwigPythonStopHookCallHandleStop(
+ implementor_sp->GetValue(), exc_ctx_ref_sp, stream_sp);
+ return ret_val;
+}
+
StructuredData::ObjectSP
ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec,
lldb_private::Status &error) {
@@ -2039,11 +2108,10 @@ ScriptInterpreterPythonImpl::CreateSyntheticScriptedProvider(
return StructuredData::ObjectSP();
Debugger &debugger = target->GetDebugger();
- ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter();
ScriptInterpreterPythonImpl *python_interpreter =
- (ScriptInterpreterPythonImpl *)script_interpreter;
+ GetPythonInterpreter(debugger);
- if (!script_interpreter)
+ if (!python_interpreter)
return StructuredData::ObjectSP();
void *ret_val = nullptr;
@@ -2151,8 +2219,7 @@ bool ScriptInterpreterPythonImpl::GetScriptedSummary(
StructuredData::ObjectSP &callee_wrapper_sp,
const TypeSummaryOptions &options, std::string &retval) {
- static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
- Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
+ LLDB_SCOPED_TIMER();
if (!valobj.get()) {
retval.assign("<no object>");
@@ -2210,11 +2277,10 @@ bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction(
return true;
Debugger &debugger = target->GetDebugger();
- ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter();
ScriptInterpreterPythonImpl *python_interpreter =
- (ScriptInterpreterPythonImpl *)script_interpreter;
+ GetPythonInterpreter(debugger);
- if (!script_interpreter)
+ if (!python_interpreter)
return true;
if (python_function_name && python_function_name[0]) {
@@ -2276,11 +2342,10 @@ bool ScriptInterpreterPythonImpl::WatchpointCallbackFunction(
return true;
Debugger &debugger = target->GetDebugger();
- ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter();
ScriptInterpreterPythonImpl *python_interpreter =
- (ScriptInterpreterPythonImpl *)script_interpreter;
+ GetPythonInterpreter(debugger);
- if (!script_interpreter)
+ if (!python_interpreter)
return true;
if (python_function_name && python_function_name[0]) {
@@ -2669,7 +2734,10 @@ 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) {
+ StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) {
+ namespace fs = llvm::sys::fs;
+ namespace path = llvm::sys::path;
+
if (!pathname || !pathname[0]) {
error.SetErrorString("invalid pathname");
return false;
@@ -2677,24 +2745,55 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this();
- {
- FileSpec target_file(pathname);
- FileSystem::Instance().Resolve(target_file);
- FileSystem::Instance().Collect(target_file);
- std::string basename(target_file.GetFilename().GetCString());
+ // Before executing Python code, lock the GIL.
+ Locker py_lock(this,
+ Locker::AcquireLock |
+ (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN,
+ Locker::FreeAcquiredLock |
+ (init_session ? Locker::TearDownSession : 0));
+
+ auto ExtendSysPath = [this](std::string directory) -> llvm::Error {
+ if (directory.empty()) {
+ return llvm::make_error<llvm::StringError>(
+ "invalid directory name", llvm::inconvertibleErrorCode());
+ }
+ replace_all(directory, "\\", "\\\\");
+ replace_all(directory, "'", "\\'");
+
+ // Make sure that Python has "directory" in the search path.
StreamString command_stream;
+ command_stream.Printf("if not (sys.path.__contains__('%s')):\n "
+ "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();
+ if (!syspath_retval) {
+ return llvm::make_error<llvm::StringError>(
+ "Python sys.path handling failed", llvm::inconvertibleErrorCode());
+ }
+
+ return llvm::Error::success();
+ };
+
+ std::string module_name(pathname);
+
+ if (extra_search_dir) {
+ if (llvm::Error e = ExtendSysPath(extra_search_dir.GetPath())) {
+ error = std::move(e);
+ return false;
+ }
+ } else {
+ FileSpec module_file(pathname);
+ FileSystem::Instance().Resolve(module_file);
+ FileSystem::Instance().Collect(module_file);
- // Before executing Python code, lock the GIL.
- Locker py_lock(this,
- Locker::AcquireLock |
- (init_session ? Locker::InitSession : 0) |
- Locker::NoSTDIN,
- Locker::FreeAcquiredLock |
- (init_session ? Locker::TearDownSession : 0));
- namespace fs = llvm::sys::fs;
fs::file_status st;
- std::error_code ec = status(target_file.GetPath(), st);
+ std::error_code ec = status(module_file.GetPath(), st);
if (ec || st.type() == fs::file_type::status_error ||
st.type() == fs::file_type::type_unknown ||
@@ -2705,113 +2804,98 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule(
error.SetErrorString("invalid pathname");
return false;
}
- basename = pathname; // not a filename, probably a package of some sort,
- // let it go through
+ // Not a filename, probably a package of some sort, let it go through.
} else if (is_directory(st) || is_regular_file(st)) {
- if (target_file.GetDirectory().IsEmpty()) {
+ if (module_file.GetDirectory().IsEmpty()) {
error.SetErrorString("invalid directory name");
return false;
}
-
- std::string directory = target_file.GetDirectory().GetCString();
- replace_all(directory, "\\", "\\\\");
- replace_all(directory, "'", "\\'");
-
- // now make sure that Python has "directory" in the search path
- StreamString command_stream;
- command_stream.Printf("if not (sys.path.__contains__('%s')):\n "
- "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();
- if (!syspath_retval) {
- error.SetErrorString("Python sys.path handling failed");
+ if (llvm::Error e =
+ ExtendSysPath(module_file.GetDirectory().GetCString())) {
+ error = std::move(e);
return false;
}
-
- // strip .py or .pyc extension
- ConstString extension = target_file.GetFileNameExtension();
- if (extension) {
- if (llvm::StringRef(extension.GetCString()) == ".py")
- basename.resize(basename.length() - 3);
- else if (llvm::StringRef(extension.GetCString()) == ".pyc")
- basename.resize(basename.length() - 4);
- }
+ module_name = module_file.GetFilename().GetCString();
} else {
error.SetErrorString("no known way to import this module specification");
return false;
}
+ }
- // check if the module is already import-ed
- command_stream.Clear();
- command_stream.Printf("sys.modules.__contains__('%s')", basename.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)", basename.c_str());
- bool was_imported_locally = GetSessionDictionary()
- .GetItemForKey(PythonString(basename))
- .IsAllocated();
+ // Strip .py or .pyc extension
+ llvm::StringRef extension = llvm::sys::path::extension(module_name);
+ if (!extension.empty()) {
+ if (extension == ".py")
+ module_name.resize(module_name.length() - 3);
+ else if (extension == ".pyc")
+ module_name.resize(module_name.length() - 4);
+ }
- bool was_imported = (was_imported_globally || was_imported_locally);
+ // check if the module is already import-ed
+ 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();
- // now actually do the import
- command_stream.Clear();
+ bool was_imported = (was_imported_globally || was_imported_locally);
- if (was_imported) {
- if (!was_imported_locally)
- command_stream.Printf("import %s ; reload_module(%s)", basename.c_str(),
- basename.c_str());
- else
- command_stream.Printf("reload_module(%s)", basename.c_str());
- } else
- command_stream.Printf("import %s", basename.c_str());
+ // now actually do the import
+ command_stream.Clear();
- error = ExecuteMultipleLines(command_stream.GetData(),
- ScriptInterpreter::ExecuteScriptOptions()
- .SetEnableIO(false)
- .SetSetLLDBGlobals(false));
- if (error.Fail())
- return false;
+ if (was_imported) {
+ if (!was_imported_locally)
+ command_stream.Printf("import %s ; reload_module(%s)",
+ module_name.c_str(), module_name.c_str());
+ else
+ command_stream.Printf("reload_module(%s)", module_name.c_str());
+ } else
+ command_stream.Printf("import %s", module_name.c_str());
- // if we are here, everything worked
- // call __lldb_init_module(debugger,dict)
- if (!LLDBSwigPythonCallModuleInit(basename.c_str(),
- m_dictionary_name.c_str(), debugger_sp)) {
- error.SetErrorString("calling __lldb_init_module failed");
- return false;
- }
+ error = ExecuteMultipleLines(command_stream.GetData(),
+ ScriptInterpreter::ExecuteScriptOptions()
+ .SetEnableIO(false)
+ .SetSetLLDBGlobals(false));
+ if (error.Fail())
+ return false;
- if (module_sp) {
- // everything went just great, now set the module object
- command_stream.Clear();
- command_stream.Printf("%s", basename.c_str());
- void *module_pyobj = nullptr;
- if (ExecuteOneLineWithReturn(
- command_stream.GetData(),
- ScriptInterpreter::eScriptReturnTypeOpaqueObject,
- &module_pyobj) &&
- module_pyobj)
- *module_sp = std::make_shared<StructuredPythonObject>(module_pyobj);
- }
+ // if we are here, everything worked
+ // call __lldb_init_module(debugger,dict)
+ if (!LLDBSwigPythonCallModuleInit(module_name.c_str(),
+ m_dictionary_name.c_str(), debugger_sp)) {
+ error.SetErrorString("calling __lldb_init_module failed");
+ return false;
+ }
- return true;
+ if (module_sp) {
+ // everything went just great, now set the module object
+ command_stream.Clear();
+ command_stream.Printf("%s", module_name.c_str());
+ void *module_pyobj = nullptr;
+ if (ExecuteOneLineWithReturn(
+ command_stream.GetData(),
+ ScriptInterpreter::eScriptReturnTypeOpaqueObject, &module_pyobj) &&
+ module_pyobj)
+ *module_sp = std::make_shared<StructuredPythonObject>(module_pyobj);
}
+
+ return true;
}
bool ScriptInterpreterPythonImpl::IsReservedWord(const char *word) {
@@ -3154,8 +3238,7 @@ void ScriptInterpreterPythonImpl::InitializePrivate() {
g_initialized = true;
- static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
- Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
+ LLDB_SCOPED_TIMER();
// RAII-based initialization which correctly handles multiple-initialization,
// version- specific differences among Python 2 and Python 3, and saving and
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index 22b2c8152eac..45dad4217005 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -106,6 +106,14 @@ public:
StructuredData::GenericSP implementor_sp) override;
StructuredData::GenericSP
+ CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name,
+ StructuredDataImpl *args_data, Status &error) override;
+
+ bool ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp,
+ ExecutionContext &exc_ctx,
+ lldb::StreamSP stream_sp) override;
+
+ StructuredData::GenericSP
CreateFrameRecognizer(const char *class_name) override;
lldb::ValueObjectListSP
@@ -223,10 +231,10 @@ public:
bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value,
std::string &output, Status &error) override;
- bool
- LoadScriptingModule(const char *filename, bool init_session,
- lldb_private::Status &error,
- StructuredData::ObjectSP *module_sp = nullptr) override;
+ bool LoadScriptingModule(const char *filename, bool init_session,
+ lldb_private::Status &error,
+ StructuredData::ObjectSP *module_sp = nullptr,
+ FileSpec extra_search_dir = {}) override;
bool IsReservedWord(const char *word) override;