diff options
author | Siger Yang <sigeryeung@gmail.com> | 2021-07-04 19:38:12 -0300 |
---|---|---|
committer | Pedro Tammela <pctammela@gmail.com> | 2021-07-07 14:51:02 -0300 |
commit | e81ba283131cf76ae62fa9b601a24d080578efaa (patch) | |
tree | 0939a8b3fcd96a847409c32bec8a59f8821e0c56 /lldb/source/Plugins/ScriptInterpreter/Lua | |
parent | 3ebfeb258698db82b7525cfaa1efd04db93d72ba (diff) | |
download | llvm-e81ba283131cf76ae62fa9b601a24d080578efaa.zip llvm-e81ba283131cf76ae62fa9b601a24d080578efaa.tar.gz llvm-e81ba283131cf76ae62fa9b601a24d080578efaa.tar.bz2 |
[lldb/lua] Add scripted watchpoints for Lua
Add support for Lua scripted watchpoints, with basic tests.
Differential Revision: https://reviews.llvm.org/D105034
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Lua')
4 files changed, 121 insertions, 5 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp index f14e273..e99b7b8 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 873440f..5daedf8 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 fe3dcb3..2105f4a 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,8 +97,9 @@ 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, @@ -109,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); @@ -276,6 +288,33 @@ 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<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, CommandReturnObject &result) { @@ -285,6 +324,14 @@ 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, StructuredData::ObjectSP extra_args_sp) { @@ -314,6 +361,26 @@ Status ScriptInterpreterLua::RegisterBreakpointCallback( 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; +} + 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 a6908d2..5eeac56 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h @@ -11,6 +11,7 @@ #include <vector> +#include "lldb/Breakpoint/WatchpointOptions.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Utility/Status.h" @@ -63,6 +64,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; @@ -77,9 +82,16 @@ public: std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, CommandReturnObject &result) override; + 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, StructuredData::ObjectSP extra_args_sp) override; @@ -91,6 +103,10 @@ private: 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); }; } // namespace lldb_private |