15ffd83dbSDimitry Andric //===-- ScriptInterpreterLua.cpp ------------------------------------------===// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric 9480093f4SDimitry Andric #include "ScriptInterpreterLua.h" 10480093f4SDimitry Andric #include "Lua.h" 11e8d8bef9SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h" 12480093f4SDimitry Andric #include "lldb/Core/Debugger.h" 13480093f4SDimitry Andric #include "lldb/Core/PluginManager.h" 14480093f4SDimitry Andric #include "lldb/Core/StreamFile.h" 15480093f4SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 16e8d8bef9SDimitry Andric #include "lldb/Target/ExecutionContext.h" 17480093f4SDimitry Andric #include "lldb/Utility/Stream.h" 18480093f4SDimitry Andric #include "lldb/Utility/StringList.h" 19480093f4SDimitry Andric #include "lldb/Utility/Timer.h" 20e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h" 215ffd83dbSDimitry Andric #include "llvm/Support/FormatAdapters.h" 22e8d8bef9SDimitry Andric #include <memory> 23e8d8bef9SDimitry Andric #include <vector> 24480093f4SDimitry Andric 25480093f4SDimitry Andric using namespace lldb; 26480093f4SDimitry Andric using namespace lldb_private; 27480093f4SDimitry Andric 285ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) 295ffd83dbSDimitry Andric 30e8d8bef9SDimitry Andric enum ActiveIOHandler { 31e8d8bef9SDimitry Andric eIOHandlerNone, 32e8d8bef9SDimitry Andric eIOHandlerBreakpoint, 33e8d8bef9SDimitry Andric eIOHandlerWatchpoint 34e8d8bef9SDimitry Andric }; 35e8d8bef9SDimitry Andric 36480093f4SDimitry Andric class IOHandlerLuaInterpreter : public IOHandlerDelegate, 37480093f4SDimitry Andric public IOHandlerEditline { 38480093f4SDimitry Andric public: 39480093f4SDimitry Andric IOHandlerLuaInterpreter(Debugger &debugger, 40e8d8bef9SDimitry Andric ScriptInterpreterLua &script_interpreter, 41e8d8bef9SDimitry Andric ActiveIOHandler active_io_handler = eIOHandlerNone) 42480093f4SDimitry Andric : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", 43480093f4SDimitry Andric ">>> ", "..> ", true, debugger.GetUseColor(), 0, 44480093f4SDimitry Andric *this, nullptr), 45e8d8bef9SDimitry Andric m_script_interpreter(script_interpreter), 46e8d8bef9SDimitry Andric m_active_io_handler(active_io_handler) { 475ffd83dbSDimitry Andric llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( 485ffd83dbSDimitry Andric debugger.GetOutputFile().GetStream(), 495ffd83dbSDimitry Andric debugger.GetErrorFile().GetStream())); 50480093f4SDimitry Andric llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); 51480093f4SDimitry Andric } 52480093f4SDimitry Andric 535ffd83dbSDimitry Andric ~IOHandlerLuaInterpreter() override { 54480093f4SDimitry Andric llvm::cantFail(m_script_interpreter.LeaveSession()); 55480093f4SDimitry Andric } 56480093f4SDimitry Andric 57e8d8bef9SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 58e8d8bef9SDimitry Andric const char *instructions = nullptr; 59e8d8bef9SDimitry Andric switch (m_active_io_handler) { 60e8d8bef9SDimitry Andric case eIOHandlerNone: 61*fe6060f1SDimitry Andric break; 62e8d8bef9SDimitry Andric case eIOHandlerWatchpoint: 63*fe6060f1SDimitry Andric instructions = "Enter your Lua command(s). Type 'quit' to end.\n" 64*fe6060f1SDimitry Andric "The commands are compiled as the body of the following " 65*fe6060f1SDimitry Andric "Lua function\n" 66*fe6060f1SDimitry Andric "function (frame, wp) end\n"; 67*fe6060f1SDimitry Andric SetPrompt(llvm::StringRef("..> ")); 68e8d8bef9SDimitry Andric break; 69e8d8bef9SDimitry Andric case eIOHandlerBreakpoint: 70e8d8bef9SDimitry Andric instructions = "Enter your Lua command(s). Type 'quit' to end.\n" 71e8d8bef9SDimitry Andric "The commands are compiled as the body of the following " 72e8d8bef9SDimitry Andric "Lua function\n" 73e8d8bef9SDimitry Andric "function (frame, bp_loc, ...) end\n"; 74e8d8bef9SDimitry Andric SetPrompt(llvm::StringRef("..> ")); 75e8d8bef9SDimitry Andric break; 76e8d8bef9SDimitry Andric } 77e8d8bef9SDimitry Andric if (instructions == nullptr) 78e8d8bef9SDimitry Andric return; 79e8d8bef9SDimitry Andric if (interactive) 80e8d8bef9SDimitry Andric *io_handler.GetOutputStreamFileSP() << instructions; 81e8d8bef9SDimitry Andric } 82e8d8bef9SDimitry Andric 83e8d8bef9SDimitry Andric bool IOHandlerIsInputComplete(IOHandler &io_handler, 84e8d8bef9SDimitry Andric StringList &lines) override { 85e8d8bef9SDimitry Andric size_t last = lines.GetSize() - 1; 86e8d8bef9SDimitry Andric if (IsQuitCommand(lines.GetStringAtIndex(last))) { 87*fe6060f1SDimitry Andric if (m_active_io_handler == eIOHandlerBreakpoint || 88*fe6060f1SDimitry Andric m_active_io_handler == eIOHandlerWatchpoint) 89e8d8bef9SDimitry Andric lines.DeleteStringAtIndex(last); 90e8d8bef9SDimitry Andric return true; 91e8d8bef9SDimitry Andric } 92e8d8bef9SDimitry Andric StreamString str; 93e8d8bef9SDimitry Andric lines.Join("\n", str); 94e8d8bef9SDimitry Andric if (llvm::Error E = 95e8d8bef9SDimitry Andric m_script_interpreter.GetLua().CheckSyntax(str.GetString())) { 96e8d8bef9SDimitry Andric std::string error_str = toString(std::move(E)); 97e8d8bef9SDimitry Andric // Lua always errors out to incomplete code with '<eof>' 98e8d8bef9SDimitry Andric return error_str.find("<eof>") == std::string::npos; 99e8d8bef9SDimitry Andric } 100*fe6060f1SDimitry Andric // The breakpoint and watchpoint handler only exits with a explicit 'quit' 101*fe6060f1SDimitry Andric return m_active_io_handler != eIOHandlerBreakpoint && 102*fe6060f1SDimitry Andric m_active_io_handler != eIOHandlerWatchpoint; 103e8d8bef9SDimitry Andric } 104e8d8bef9SDimitry Andric 105480093f4SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler, 106480093f4SDimitry Andric std::string &data) override { 107e8d8bef9SDimitry Andric switch (m_active_io_handler) { 108e8d8bef9SDimitry Andric case eIOHandlerBreakpoint: { 109*fe6060f1SDimitry Andric auto *bp_options_vec = 110*fe6060f1SDimitry Andric static_cast<std::vector<std::reference_wrapper<BreakpointOptions>> *>( 111e8d8bef9SDimitry Andric io_handler.GetUserData()); 112*fe6060f1SDimitry Andric for (BreakpointOptions &bp_options : *bp_options_vec) { 113e8d8bef9SDimitry Andric Status error = m_script_interpreter.SetBreakpointCommandCallback( 114e8d8bef9SDimitry Andric bp_options, data.c_str()); 115e8d8bef9SDimitry Andric if (error.Fail()) 116e8d8bef9SDimitry Andric *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n'; 117e8d8bef9SDimitry Andric } 118e8d8bef9SDimitry Andric io_handler.SetIsDone(true); 119e8d8bef9SDimitry Andric } break; 120*fe6060f1SDimitry Andric case eIOHandlerWatchpoint: { 121*fe6060f1SDimitry Andric auto *wp_options = 122*fe6060f1SDimitry Andric static_cast<WatchpointOptions *>(io_handler.GetUserData()); 123*fe6060f1SDimitry Andric m_script_interpreter.SetWatchpointCommandCallback(wp_options, 124*fe6060f1SDimitry Andric data.c_str()); 125e8d8bef9SDimitry Andric io_handler.SetIsDone(true); 126*fe6060f1SDimitry Andric } break; 127e8d8bef9SDimitry Andric case eIOHandlerNone: 128e8d8bef9SDimitry Andric if (IsQuitCommand(data)) { 1295ffd83dbSDimitry Andric io_handler.SetIsDone(true); 1305ffd83dbSDimitry Andric return; 1315ffd83dbSDimitry Andric } 132e8d8bef9SDimitry Andric if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) 133e8d8bef9SDimitry Andric *io_handler.GetErrorStreamFileSP() << toString(std::move(error)); 134e8d8bef9SDimitry Andric break; 135480093f4SDimitry Andric } 136480093f4SDimitry Andric } 137480093f4SDimitry Andric 138480093f4SDimitry Andric private: 139480093f4SDimitry Andric ScriptInterpreterLua &m_script_interpreter; 140e8d8bef9SDimitry Andric ActiveIOHandler m_active_io_handler; 141e8d8bef9SDimitry Andric 142e8d8bef9SDimitry Andric bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; } 143480093f4SDimitry Andric }; 144480093f4SDimitry Andric 145480093f4SDimitry Andric ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) 146480093f4SDimitry Andric : ScriptInterpreter(debugger, eScriptLanguageLua), 147480093f4SDimitry Andric m_lua(std::make_unique<Lua>()) {} 148480093f4SDimitry Andric 149*fe6060f1SDimitry Andric ScriptInterpreterLua::~ScriptInterpreterLua() = default; 150480093f4SDimitry Andric 151480093f4SDimitry Andric bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, 152480093f4SDimitry Andric CommandReturnObject *result, 153480093f4SDimitry Andric const ExecuteScriptOptions &options) { 1545ffd83dbSDimitry Andric if (command.empty()) { 1555ffd83dbSDimitry Andric if (result) 1565ffd83dbSDimitry Andric result->AppendError("empty command passed to lua\n"); 1575ffd83dbSDimitry Andric return false; 1585ffd83dbSDimitry Andric } 1595ffd83dbSDimitry Andric 1605ffd83dbSDimitry Andric llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 1615ffd83dbSDimitry Andric io_redirect_or_error = ScriptInterpreterIORedirect::Create( 1625ffd83dbSDimitry Andric options.GetEnableIO(), m_debugger, result); 1635ffd83dbSDimitry Andric if (!io_redirect_or_error) { 1645ffd83dbSDimitry Andric if (result) 1655ffd83dbSDimitry Andric result->AppendErrorWithFormatv( 1665ffd83dbSDimitry Andric "failed to redirect I/O: {0}\n", 1675ffd83dbSDimitry Andric llvm::fmt_consume(io_redirect_or_error.takeError())); 1685ffd83dbSDimitry Andric else 1695ffd83dbSDimitry Andric llvm::consumeError(io_redirect_or_error.takeError()); 1705ffd83dbSDimitry Andric return false; 1715ffd83dbSDimitry Andric } 1725ffd83dbSDimitry Andric 1735ffd83dbSDimitry Andric ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; 1745ffd83dbSDimitry Andric 1755ffd83dbSDimitry Andric if (llvm::Error e = 1765ffd83dbSDimitry Andric m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(), 1775ffd83dbSDimitry Andric io_redirect.GetErrorFile()->GetStream())) { 1785ffd83dbSDimitry Andric result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n", 1795ffd83dbSDimitry Andric llvm::toString(std::move(e))); 1805ffd83dbSDimitry Andric return false; 1815ffd83dbSDimitry Andric } 1825ffd83dbSDimitry Andric 183480093f4SDimitry Andric if (llvm::Error e = m_lua->Run(command)) { 184480093f4SDimitry Andric result->AppendErrorWithFormatv( 185480093f4SDimitry Andric "lua failed attempting to evaluate '{0}': {1}\n", command, 186480093f4SDimitry Andric llvm::toString(std::move(e))); 187480093f4SDimitry Andric return false; 188480093f4SDimitry Andric } 1895ffd83dbSDimitry Andric 1905ffd83dbSDimitry Andric io_redirect.Flush(); 191480093f4SDimitry Andric return true; 192480093f4SDimitry Andric } 193480093f4SDimitry Andric 194480093f4SDimitry Andric void ScriptInterpreterLua::ExecuteInterpreterLoop() { 195e8d8bef9SDimitry Andric LLDB_SCOPED_TIMER(); 196480093f4SDimitry Andric 197480093f4SDimitry Andric // At the moment, the only time the debugger does not have an input file 198480093f4SDimitry Andric // handle is when this is called directly from lua, in which case it is 199480093f4SDimitry Andric // both dangerous and unnecessary (not to mention confusing) to try to embed 200480093f4SDimitry Andric // a running interpreter loop inside the already running lua interpreter 201480093f4SDimitry Andric // loop, so we won't do it. 2025ffd83dbSDimitry Andric if (!m_debugger.GetInputFile().IsValid()) 203480093f4SDimitry Andric return; 204480093f4SDimitry Andric 2055ffd83dbSDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this)); 2065ffd83dbSDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 207480093f4SDimitry Andric } 208480093f4SDimitry Andric 209480093f4SDimitry Andric bool ScriptInterpreterLua::LoadScriptingModule( 210*fe6060f1SDimitry Andric const char *filename, const LoadScriptOptions &options, 211*fe6060f1SDimitry Andric lldb_private::Status &error, StructuredData::ObjectSP *module_sp, 212*fe6060f1SDimitry Andric FileSpec extra_search_dir) { 213480093f4SDimitry Andric 2145ffd83dbSDimitry Andric FileSystem::Instance().Collect(filename); 215480093f4SDimitry Andric if (llvm::Error e = m_lua->LoadModule(filename)) { 216480093f4SDimitry Andric error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n", 217480093f4SDimitry Andric filename, llvm::toString(std::move(e))); 218480093f4SDimitry Andric return false; 219480093f4SDimitry Andric } 220480093f4SDimitry Andric return true; 221480093f4SDimitry Andric } 222480093f4SDimitry Andric 223480093f4SDimitry Andric void ScriptInterpreterLua::Initialize() { 224480093f4SDimitry Andric static llvm::once_flag g_once_flag; 225480093f4SDimitry Andric 226480093f4SDimitry Andric llvm::call_once(g_once_flag, []() { 227480093f4SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 228480093f4SDimitry Andric GetPluginDescriptionStatic(), 229480093f4SDimitry Andric lldb::eScriptLanguageLua, CreateInstance); 230480093f4SDimitry Andric }); 231480093f4SDimitry Andric } 232480093f4SDimitry Andric 233480093f4SDimitry Andric void ScriptInterpreterLua::Terminate() {} 234480093f4SDimitry Andric 235480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) { 236480093f4SDimitry Andric if (m_session_is_active) 237480093f4SDimitry Andric return llvm::Error::success(); 238480093f4SDimitry Andric 239480093f4SDimitry Andric const char *fmt_str = 240480093f4SDimitry Andric "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); " 241480093f4SDimitry Andric "lldb.target = lldb.debugger:GetSelectedTarget(); " 242480093f4SDimitry Andric "lldb.process = lldb.target:GetProcess(); " 243480093f4SDimitry Andric "lldb.thread = lldb.process:GetSelectedThread(); " 244480093f4SDimitry Andric "lldb.frame = lldb.thread:GetSelectedFrame()"; 245480093f4SDimitry Andric return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str()); 246480093f4SDimitry Andric } 247480093f4SDimitry Andric 248480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::LeaveSession() { 249480093f4SDimitry Andric if (!m_session_is_active) 250480093f4SDimitry Andric return llvm::Error::success(); 251480093f4SDimitry Andric 252480093f4SDimitry Andric m_session_is_active = false; 253480093f4SDimitry Andric 254480093f4SDimitry Andric llvm::StringRef str = "lldb.debugger = nil; " 255480093f4SDimitry Andric "lldb.target = nil; " 256480093f4SDimitry Andric "lldb.process = nil; " 257480093f4SDimitry Andric "lldb.thread = nil; " 258480093f4SDimitry Andric "lldb.frame = nil"; 259480093f4SDimitry Andric return m_lua->Run(str); 260480093f4SDimitry Andric } 261480093f4SDimitry Andric 262e8d8bef9SDimitry Andric bool ScriptInterpreterLua::BreakpointCallbackFunction( 263e8d8bef9SDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t break_id, 264e8d8bef9SDimitry Andric user_id_t break_loc_id) { 265e8d8bef9SDimitry Andric assert(context); 266e8d8bef9SDimitry Andric 267e8d8bef9SDimitry Andric ExecutionContext exe_ctx(context->exe_ctx_ref); 268e8d8bef9SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 269e8d8bef9SDimitry Andric if (target == nullptr) 270e8d8bef9SDimitry Andric return true; 271e8d8bef9SDimitry Andric 272e8d8bef9SDimitry Andric StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 273e8d8bef9SDimitry Andric BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); 274e8d8bef9SDimitry Andric BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id)); 275e8d8bef9SDimitry Andric 276e8d8bef9SDimitry Andric Debugger &debugger = target->GetDebugger(); 277e8d8bef9SDimitry Andric ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 278e8d8bef9SDimitry Andric debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 279e8d8bef9SDimitry Andric Lua &lua = lua_interpreter->GetLua(); 280e8d8bef9SDimitry Andric 281e8d8bef9SDimitry Andric CommandDataLua *bp_option_data = static_cast<CommandDataLua *>(baton); 282e8d8bef9SDimitry Andric llvm::Expected<bool> BoolOrErr = lua.CallBreakpointCallback( 283e8d8bef9SDimitry Andric baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp); 284e8d8bef9SDimitry Andric if (llvm::Error E = BoolOrErr.takeError()) { 285e8d8bef9SDimitry Andric debugger.GetErrorStream() << toString(std::move(E)); 286e8d8bef9SDimitry Andric return true; 287e8d8bef9SDimitry Andric } 288e8d8bef9SDimitry Andric 289e8d8bef9SDimitry Andric return *BoolOrErr; 290e8d8bef9SDimitry Andric } 291e8d8bef9SDimitry Andric 292*fe6060f1SDimitry Andric bool ScriptInterpreterLua::WatchpointCallbackFunction( 293*fe6060f1SDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t watch_id) { 294*fe6060f1SDimitry Andric assert(context); 295*fe6060f1SDimitry Andric 296*fe6060f1SDimitry Andric ExecutionContext exe_ctx(context->exe_ctx_ref); 297*fe6060f1SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 298*fe6060f1SDimitry Andric if (target == nullptr) 299*fe6060f1SDimitry Andric return true; 300*fe6060f1SDimitry Andric 301*fe6060f1SDimitry Andric StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 302*fe6060f1SDimitry Andric WatchpointSP wp_sp = target->GetWatchpointList().FindByID(watch_id); 303*fe6060f1SDimitry Andric 304*fe6060f1SDimitry Andric Debugger &debugger = target->GetDebugger(); 305*fe6060f1SDimitry Andric ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 306*fe6060f1SDimitry Andric debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 307*fe6060f1SDimitry Andric Lua &lua = lua_interpreter->GetLua(); 308*fe6060f1SDimitry Andric 309*fe6060f1SDimitry Andric llvm::Expected<bool> BoolOrErr = 310*fe6060f1SDimitry Andric lua.CallWatchpointCallback(baton, stop_frame_sp, wp_sp); 311*fe6060f1SDimitry Andric if (llvm::Error E = BoolOrErr.takeError()) { 312*fe6060f1SDimitry Andric debugger.GetErrorStream() << toString(std::move(E)); 313*fe6060f1SDimitry Andric return true; 314*fe6060f1SDimitry Andric } 315*fe6060f1SDimitry Andric 316*fe6060f1SDimitry Andric return *BoolOrErr; 317*fe6060f1SDimitry Andric } 318*fe6060f1SDimitry Andric 319e8d8bef9SDimitry Andric void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback( 320*fe6060f1SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 321e8d8bef9SDimitry Andric CommandReturnObject &result) { 322e8d8bef9SDimitry Andric IOHandlerSP io_handler_sp( 323e8d8bef9SDimitry Andric new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint)); 324e8d8bef9SDimitry Andric io_handler_sp->SetUserData(&bp_options_vec); 325e8d8bef9SDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 326e8d8bef9SDimitry Andric } 327e8d8bef9SDimitry Andric 328*fe6060f1SDimitry Andric void ScriptInterpreterLua::CollectDataForWatchpointCommandCallback( 329*fe6060f1SDimitry Andric WatchpointOptions *wp_options, CommandReturnObject &result) { 330*fe6060f1SDimitry Andric IOHandlerSP io_handler_sp( 331*fe6060f1SDimitry Andric new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerWatchpoint)); 332*fe6060f1SDimitry Andric io_handler_sp->SetUserData(wp_options); 333*fe6060f1SDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 334*fe6060f1SDimitry Andric } 335*fe6060f1SDimitry Andric 336e8d8bef9SDimitry Andric Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction( 337*fe6060f1SDimitry Andric BreakpointOptions &bp_options, const char *function_name, 338e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 339e8d8bef9SDimitry Andric const char *fmt_str = "return {0}(frame, bp_loc, ...)"; 340e8d8bef9SDimitry Andric std::string oneliner = llvm::formatv(fmt_str, function_name).str(); 341e8d8bef9SDimitry Andric return RegisterBreakpointCallback(bp_options, oneliner.c_str(), 342e8d8bef9SDimitry Andric extra_args_sp); 343e8d8bef9SDimitry Andric } 344e8d8bef9SDimitry Andric 345e8d8bef9SDimitry Andric Status ScriptInterpreterLua::SetBreakpointCommandCallback( 346*fe6060f1SDimitry Andric BreakpointOptions &bp_options, const char *command_body_text) { 347e8d8bef9SDimitry Andric return RegisterBreakpointCallback(bp_options, command_body_text, {}); 348e8d8bef9SDimitry Andric } 349e8d8bef9SDimitry Andric 350e8d8bef9SDimitry Andric Status ScriptInterpreterLua::RegisterBreakpointCallback( 351*fe6060f1SDimitry Andric BreakpointOptions &bp_options, const char *command_body_text, 352e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 353e8d8bef9SDimitry Andric Status error; 354e8d8bef9SDimitry Andric auto data_up = std::make_unique<CommandDataLua>(extra_args_sp); 355e8d8bef9SDimitry Andric error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text); 356e8d8bef9SDimitry Andric if (error.Fail()) 357e8d8bef9SDimitry Andric return error; 358e8d8bef9SDimitry Andric auto baton_sp = 359e8d8bef9SDimitry Andric std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up)); 360*fe6060f1SDimitry Andric bp_options.SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction, 361*fe6060f1SDimitry Andric baton_sp); 362*fe6060f1SDimitry Andric return error; 363*fe6060f1SDimitry Andric } 364*fe6060f1SDimitry Andric 365*fe6060f1SDimitry Andric void ScriptInterpreterLua::SetWatchpointCommandCallback( 366*fe6060f1SDimitry Andric WatchpointOptions *wp_options, const char *command_body_text) { 367*fe6060f1SDimitry Andric RegisterWatchpointCallback(wp_options, command_body_text, {}); 368*fe6060f1SDimitry Andric } 369*fe6060f1SDimitry Andric 370*fe6060f1SDimitry Andric Status ScriptInterpreterLua::RegisterWatchpointCallback( 371*fe6060f1SDimitry Andric WatchpointOptions *wp_options, const char *command_body_text, 372*fe6060f1SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 373*fe6060f1SDimitry Andric Status error; 374*fe6060f1SDimitry Andric auto data_up = std::make_unique<WatchpointOptions::CommandData>(); 375*fe6060f1SDimitry Andric error = m_lua->RegisterWatchpointCallback(data_up.get(), command_body_text); 376*fe6060f1SDimitry Andric if (error.Fail()) 377*fe6060f1SDimitry Andric return error; 378*fe6060f1SDimitry Andric auto baton_sp = 379*fe6060f1SDimitry Andric std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up)); 380*fe6060f1SDimitry Andric wp_options->SetCallback(ScriptInterpreterLua::WatchpointCallbackFunction, 381e8d8bef9SDimitry Andric baton_sp); 382e8d8bef9SDimitry Andric return error; 383e8d8bef9SDimitry Andric } 384e8d8bef9SDimitry Andric 385480093f4SDimitry Andric lldb::ScriptInterpreterSP 386480093f4SDimitry Andric ScriptInterpreterLua::CreateInstance(Debugger &debugger) { 387480093f4SDimitry Andric return std::make_shared<ScriptInterpreterLua>(debugger); 388480093f4SDimitry Andric } 389480093f4SDimitry Andric 390480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginNameStatic() { 391480093f4SDimitry Andric static ConstString g_name("script-lua"); 392480093f4SDimitry Andric return g_name; 393480093f4SDimitry Andric } 394480093f4SDimitry Andric 395480093f4SDimitry Andric const char *ScriptInterpreterLua::GetPluginDescriptionStatic() { 396480093f4SDimitry Andric return "Lua script interpreter"; 397480093f4SDimitry Andric } 398480093f4SDimitry Andric 399480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginName() { 400480093f4SDimitry Andric return GetPluginNameStatic(); 401480093f4SDimitry Andric } 402480093f4SDimitry Andric 403480093f4SDimitry Andric uint32_t ScriptInterpreterLua::GetPluginVersion() { return 1; } 404480093f4SDimitry Andric 405480093f4SDimitry Andric Lua &ScriptInterpreterLua::GetLua() { return *m_lua; } 406