180814287SRaphael Isemann //===-- ScriptInterpreterLua.cpp ------------------------------------------===// 267de8962SJonas Devlieghere // 367de8962SJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 467de8962SJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information. 567de8962SJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 667de8962SJonas Devlieghere // 767de8962SJonas Devlieghere //===----------------------------------------------------------------------===// 867de8962SJonas Devlieghere 967de8962SJonas Devlieghere #include "ScriptInterpreterLua.h" 1028613242SJonas Devlieghere #include "Lua.h" 11a0d7406aSPedro Tammela #include "lldb/Breakpoint/StoppointCallbackContext.h" 1267de8962SJonas Devlieghere #include "lldb/Core/Debugger.h" 1367de8962SJonas Devlieghere #include "lldb/Core/PluginManager.h" 14f2d32ddcSAlex Langford #include "lldb/Host/StreamFile.h" 1528613242SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 16a0d7406aSPedro Tammela #include "lldb/Target/ExecutionContext.h" 1767de8962SJonas Devlieghere #include "lldb/Utility/Stream.h" 1867de8962SJonas Devlieghere #include "lldb/Utility/StringList.h" 1928613242SJonas Devlieghere #include "lldb/Utility/Timer.h" 20d853bd7aSPedro Tammela #include "llvm/ADT/StringRef.h" 21ed8184b7SJonas Devlieghere #include "llvm/Support/FormatAdapters.h" 22a0d7406aSPedro Tammela #include <memory> 23d853bd7aSPedro Tammela #include <vector> 2467de8962SJonas Devlieghere 2567de8962SJonas Devlieghere using namespace lldb; 2667de8962SJonas Devlieghere using namespace lldb_private; 2767de8962SJonas Devlieghere 28bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) 29fbb4d1e4SJonas Devlieghere 30d853bd7aSPedro Tammela enum ActiveIOHandler { 31d853bd7aSPedro Tammela eIOHandlerNone, 32d853bd7aSPedro Tammela eIOHandlerBreakpoint, 33d853bd7aSPedro Tammela eIOHandlerWatchpoint 34d853bd7aSPedro Tammela }; 35d853bd7aSPedro Tammela 3628613242SJonas Devlieghere class IOHandlerLuaInterpreter : public IOHandlerDelegate, 3728613242SJonas Devlieghere public IOHandlerEditline { 3828613242SJonas Devlieghere public: 394164be72SJonas Devlieghere IOHandlerLuaInterpreter(Debugger &debugger, 40d853bd7aSPedro Tammela ScriptInterpreterLua &script_interpreter, 41d853bd7aSPedro Tammela ActiveIOHandler active_io_handler = eIOHandlerNone) 4228613242SJonas Devlieghere : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", 4370599d70SJonas Devlieghere llvm::StringRef(">>> "), llvm::StringRef("..> "), 4470599d70SJonas Devlieghere true, debugger.GetUseColor(), 0, *this), 45d853bd7aSPedro Tammela m_script_interpreter(script_interpreter), 46d853bd7aSPedro Tammela m_active_io_handler(active_io_handler) { 47fa1b4a96SJonas Devlieghere llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( 48fa1b4a96SJonas Devlieghere debugger.GetOutputFile().GetStream(), 49fa1b4a96SJonas Devlieghere debugger.GetErrorFile().GetStream())); 5045c971f7SJonas Devlieghere llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); 5145c971f7SJonas Devlieghere } 5245c971f7SJonas Devlieghere 535ddd4fc5SJonas Devlieghere ~IOHandlerLuaInterpreter() override { 5445c971f7SJonas Devlieghere llvm::cantFail(m_script_interpreter.LeaveSession()); 5545c971f7SJonas Devlieghere } 5628613242SJonas Devlieghere 57d853bd7aSPedro Tammela void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 58d853bd7aSPedro Tammela const char *instructions = nullptr; 59d853bd7aSPedro Tammela switch (m_active_io_handler) { 60d853bd7aSPedro Tammela case eIOHandlerNone: 61e81ba283SSiger Yang break; 62d853bd7aSPedro Tammela case eIOHandlerWatchpoint: 63e81ba283SSiger Yang instructions = "Enter your Lua command(s). Type 'quit' to end.\n" 64e81ba283SSiger Yang "The commands are compiled as the body of the following " 65e81ba283SSiger Yang "Lua function\n" 66e81ba283SSiger Yang "function (frame, wp) end\n"; 67e81ba283SSiger Yang SetPrompt(llvm::StringRef("..> ")); 68d853bd7aSPedro Tammela break; 69d853bd7aSPedro Tammela case eIOHandlerBreakpoint: 70d853bd7aSPedro Tammela instructions = "Enter your Lua command(s). Type 'quit' to end.\n" 71d853bd7aSPedro Tammela "The commands are compiled as the body of the following " 72d853bd7aSPedro Tammela "Lua function\n" 73d853bd7aSPedro Tammela "function (frame, bp_loc, ...) end\n"; 74d853bd7aSPedro Tammela SetPrompt(llvm::StringRef("..> ")); 75d853bd7aSPedro Tammela break; 76d853bd7aSPedro Tammela } 77d853bd7aSPedro Tammela if (instructions == nullptr) 78d853bd7aSPedro Tammela return; 79d853bd7aSPedro Tammela if (interactive) 80d853bd7aSPedro Tammela *io_handler.GetOutputStreamFileSP() << instructions; 81d853bd7aSPedro Tammela } 82d853bd7aSPedro Tammela 83d853bd7aSPedro Tammela bool IOHandlerIsInputComplete(IOHandler &io_handler, 84d853bd7aSPedro Tammela StringList &lines) override { 85d853bd7aSPedro Tammela size_t last = lines.GetSize() - 1; 86d853bd7aSPedro Tammela if (IsQuitCommand(lines.GetStringAtIndex(last))) { 87e81ba283SSiger Yang if (m_active_io_handler == eIOHandlerBreakpoint || 88e81ba283SSiger Yang m_active_io_handler == eIOHandlerWatchpoint) 89d853bd7aSPedro Tammela lines.DeleteStringAtIndex(last); 90d853bd7aSPedro Tammela return true; 91d853bd7aSPedro Tammela } 92d853bd7aSPedro Tammela StreamString str; 93d853bd7aSPedro Tammela lines.Join("\n", str); 94d853bd7aSPedro Tammela if (llvm::Error E = 95d853bd7aSPedro Tammela m_script_interpreter.GetLua().CheckSyntax(str.GetString())) { 96d853bd7aSPedro Tammela std::string error_str = toString(std::move(E)); 97d853bd7aSPedro Tammela // Lua always errors out to incomplete code with '<eof>' 98d853bd7aSPedro Tammela return error_str.find("<eof>") == std::string::npos; 99d853bd7aSPedro Tammela } 100e81ba283SSiger Yang // The breakpoint and watchpoint handler only exits with a explicit 'quit' 101e81ba283SSiger Yang return m_active_io_handler != eIOHandlerBreakpoint && 102e81ba283SSiger Yang m_active_io_handler != eIOHandlerWatchpoint; 103d853bd7aSPedro Tammela } 104d853bd7aSPedro Tammela 10528613242SJonas Devlieghere void IOHandlerInputComplete(IOHandler &io_handler, 10628613242SJonas Devlieghere std::string &data) override { 107d853bd7aSPedro Tammela switch (m_active_io_handler) { 108d853bd7aSPedro Tammela case eIOHandlerBreakpoint: { 109cfb96d84SJim Ingham auto *bp_options_vec = 110cfb96d84SJim Ingham static_cast<std::vector<std::reference_wrapper<BreakpointOptions>> *>( 111d853bd7aSPedro Tammela io_handler.GetUserData()); 112cfb96d84SJim Ingham for (BreakpointOptions &bp_options : *bp_options_vec) { 113d853bd7aSPedro Tammela Status error = m_script_interpreter.SetBreakpointCommandCallback( 114ab81fc29SMed Ismail Bennani bp_options, data.c_str(), /*is_callback=*/false); 115d853bd7aSPedro Tammela if (error.Fail()) 116d853bd7aSPedro Tammela *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n'; 117d853bd7aSPedro Tammela } 118d853bd7aSPedro Tammela io_handler.SetIsDone(true); 119d853bd7aSPedro Tammela } break; 120e81ba283SSiger Yang case eIOHandlerWatchpoint: { 121e81ba283SSiger Yang auto *wp_options = 122e81ba283SSiger Yang static_cast<WatchpointOptions *>(io_handler.GetUserData()); 123e81ba283SSiger Yang m_script_interpreter.SetWatchpointCommandCallback(wp_options, 124ab81fc29SMed Ismail Bennani data.c_str(), 125ab81fc29SMed Ismail Bennani /*is_callback=*/false); 126d853bd7aSPedro Tammela io_handler.SetIsDone(true); 127e81ba283SSiger Yang } break; 128d853bd7aSPedro Tammela case eIOHandlerNone: 129d853bd7aSPedro Tammela if (IsQuitCommand(data)) { 1301728dec2SJonas Devlieghere io_handler.SetIsDone(true); 1311728dec2SJonas Devlieghere return; 1321728dec2SJonas Devlieghere } 133d853bd7aSPedro Tammela if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) 134d853bd7aSPedro Tammela *io_handler.GetErrorStreamFileSP() << toString(std::move(error)); 135d853bd7aSPedro Tammela break; 13628613242SJonas Devlieghere } 13728613242SJonas Devlieghere } 13828613242SJonas Devlieghere 13928613242SJonas Devlieghere private: 1404164be72SJonas Devlieghere ScriptInterpreterLua &m_script_interpreter; 141d853bd7aSPedro Tammela ActiveIOHandler m_active_io_handler; 142d853bd7aSPedro Tammela 143d853bd7aSPedro Tammela bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; } 14428613242SJonas Devlieghere }; 14528613242SJonas Devlieghere 14667de8962SJonas Devlieghere ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) 1474164be72SJonas Devlieghere : ScriptInterpreter(debugger, eScriptLanguageLua), 1484164be72SJonas Devlieghere m_lua(std::make_unique<Lua>()) {} 14967de8962SJonas Devlieghere 150fd2433e1SJonas Devlieghere ScriptInterpreterLua::~ScriptInterpreterLua() = default; 15167de8962SJonas Devlieghere 152bbef51ebSLawrence D'Anna StructuredData::DictionarySP ScriptInterpreterLua::GetInterpreterInfo() { 153bbef51ebSLawrence D'Anna auto info = std::make_shared<StructuredData::Dictionary>(); 154bbef51ebSLawrence D'Anna info->AddStringItem("language", "lua"); 155bbef51ebSLawrence D'Anna return info; 156bbef51ebSLawrence D'Anna } 157bbef51ebSLawrence D'Anna 15867de8962SJonas Devlieghere bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, 15928613242SJonas Devlieghere CommandReturnObject *result, 16028613242SJonas Devlieghere const ExecuteScriptOptions &options) { 161ed8184b7SJonas Devlieghere if (command.empty()) { 162ed8184b7SJonas Devlieghere if (result) 163ed8184b7SJonas Devlieghere result->AppendError("empty command passed to lua\n"); 164ed8184b7SJonas Devlieghere return false; 165ed8184b7SJonas Devlieghere } 166ed8184b7SJonas Devlieghere 167ed8184b7SJonas Devlieghere llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 168ed8184b7SJonas Devlieghere io_redirect_or_error = ScriptInterpreterIORedirect::Create( 169ed8184b7SJonas Devlieghere options.GetEnableIO(), m_debugger, result); 170ed8184b7SJonas Devlieghere if (!io_redirect_or_error) { 171ed8184b7SJonas Devlieghere if (result) 172ed8184b7SJonas Devlieghere result->AppendErrorWithFormatv( 173ed8184b7SJonas Devlieghere "failed to redirect I/O: {0}\n", 174ed8184b7SJonas Devlieghere llvm::fmt_consume(io_redirect_or_error.takeError())); 175ed8184b7SJonas Devlieghere else 176ed8184b7SJonas Devlieghere llvm::consumeError(io_redirect_or_error.takeError()); 177ed8184b7SJonas Devlieghere return false; 178ed8184b7SJonas Devlieghere } 179ed8184b7SJonas Devlieghere 180ed8184b7SJonas Devlieghere ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; 181ed8184b7SJonas Devlieghere 182ed8184b7SJonas Devlieghere if (llvm::Error e = 183ed8184b7SJonas Devlieghere m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(), 184ed8184b7SJonas Devlieghere io_redirect.GetErrorFile()->GetStream())) { 185ed8184b7SJonas Devlieghere result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n", 186ed8184b7SJonas Devlieghere llvm::toString(std::move(e))); 187ed8184b7SJonas Devlieghere return false; 188ed8184b7SJonas Devlieghere } 189ed8184b7SJonas Devlieghere 1904164be72SJonas Devlieghere if (llvm::Error e = m_lua->Run(command)) { 19128613242SJonas Devlieghere result->AppendErrorWithFormatv( 19228613242SJonas Devlieghere "lua failed attempting to evaluate '{0}': {1}\n", command, 19328613242SJonas Devlieghere llvm::toString(std::move(e))); 19467de8962SJonas Devlieghere return false; 19567de8962SJonas Devlieghere } 196ed8184b7SJonas Devlieghere 197ed8184b7SJonas Devlieghere io_redirect.Flush(); 19828613242SJonas Devlieghere return true; 19928613242SJonas Devlieghere } 20067de8962SJonas Devlieghere 20167de8962SJonas Devlieghere void ScriptInterpreterLua::ExecuteInterpreterLoop() { 2025c1c8443SJonas Devlieghere LLDB_SCOPED_TIMER(); 20328613242SJonas Devlieghere 20428613242SJonas Devlieghere // At the moment, the only time the debugger does not have an input file 20528613242SJonas Devlieghere // handle is when this is called directly from lua, in which case it is 20628613242SJonas Devlieghere // both dangerous and unnecessary (not to mention confusing) to try to embed 20728613242SJonas Devlieghere // a running interpreter loop inside the already running lua interpreter 20828613242SJonas Devlieghere // loop, so we won't do it. 2096e3faaebSJonas Devlieghere if (!m_debugger.GetInputFile().IsValid()) 21028613242SJonas Devlieghere return; 21128613242SJonas Devlieghere 2126e3faaebSJonas Devlieghere IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this)); 2136e3faaebSJonas Devlieghere m_debugger.RunIOHandlerAsync(io_handler_sp); 21467de8962SJonas Devlieghere } 21567de8962SJonas Devlieghere 216572b9f46SJonas Devlieghere bool ScriptInterpreterLua::LoadScriptingModule( 217f9517353SJonas Devlieghere const char *filename, const LoadScriptOptions &options, 218f9517353SJonas Devlieghere lldb_private::Status &error, StructuredData::ObjectSP *module_sp, 219f9517353SJonas Devlieghere FileSpec extra_search_dir) { 220572b9f46SJonas Devlieghere 221572b9f46SJonas Devlieghere if (llvm::Error e = m_lua->LoadModule(filename)) { 2220642cd76SAdrian Prantl error = Status::FromErrorStringWithFormatv( 2230642cd76SAdrian Prantl "lua failed to import '{0}': {1}\n", filename, 2240642cd76SAdrian Prantl llvm::toString(std::move(e))); 225572b9f46SJonas Devlieghere return false; 226572b9f46SJonas Devlieghere } 227572b9f46SJonas Devlieghere return true; 228572b9f46SJonas Devlieghere } 229572b9f46SJonas Devlieghere 23067de8962SJonas Devlieghere void ScriptInterpreterLua::Initialize() { 23167de8962SJonas Devlieghere static llvm::once_flag g_once_flag; 23267de8962SJonas Devlieghere 23367de8962SJonas Devlieghere llvm::call_once(g_once_flag, []() { 23467de8962SJonas Devlieghere PluginManager::RegisterPlugin(GetPluginNameStatic(), 23567de8962SJonas Devlieghere GetPluginDescriptionStatic(), 23667de8962SJonas Devlieghere lldb::eScriptLanguageLua, CreateInstance); 23767de8962SJonas Devlieghere }); 23867de8962SJonas Devlieghere } 23967de8962SJonas Devlieghere 24067de8962SJonas Devlieghere void ScriptInterpreterLua::Terminate() {} 24167de8962SJonas Devlieghere 24245c971f7SJonas Devlieghere llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) { 24345c971f7SJonas Devlieghere if (m_session_is_active) 24445c971f7SJonas Devlieghere return llvm::Error::success(); 24545c971f7SJonas Devlieghere 24645c971f7SJonas Devlieghere const char *fmt_str = 24745c971f7SJonas Devlieghere "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); " 24845c971f7SJonas Devlieghere "lldb.target = lldb.debugger:GetSelectedTarget(); " 24945c971f7SJonas Devlieghere "lldb.process = lldb.target:GetProcess(); " 25045c971f7SJonas Devlieghere "lldb.thread = lldb.process:GetSelectedThread(); " 25145c971f7SJonas Devlieghere "lldb.frame = lldb.thread:GetSelectedFrame()"; 25245c971f7SJonas Devlieghere return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str()); 25345c971f7SJonas Devlieghere } 25445c971f7SJonas Devlieghere 25545c971f7SJonas Devlieghere llvm::Error ScriptInterpreterLua::LeaveSession() { 25645c971f7SJonas Devlieghere if (!m_session_is_active) 25745c971f7SJonas Devlieghere return llvm::Error::success(); 25845c971f7SJonas Devlieghere 25945c971f7SJonas Devlieghere m_session_is_active = false; 26045c971f7SJonas Devlieghere 26145c971f7SJonas Devlieghere llvm::StringRef str = "lldb.debugger = nil; " 26245c971f7SJonas Devlieghere "lldb.target = nil; " 26345c971f7SJonas Devlieghere "lldb.process = nil; " 26445c971f7SJonas Devlieghere "lldb.thread = nil; " 26545c971f7SJonas Devlieghere "lldb.frame = nil"; 26645c971f7SJonas Devlieghere return m_lua->Run(str); 26745c971f7SJonas Devlieghere } 26845c971f7SJonas Devlieghere 269a0d7406aSPedro Tammela bool ScriptInterpreterLua::BreakpointCallbackFunction( 270a0d7406aSPedro Tammela void *baton, StoppointCallbackContext *context, user_id_t break_id, 271a0d7406aSPedro Tammela user_id_t break_loc_id) { 272a0d7406aSPedro Tammela assert(context); 273a0d7406aSPedro Tammela 274a0d7406aSPedro Tammela ExecutionContext exe_ctx(context->exe_ctx_ref); 275a0d7406aSPedro Tammela Target *target = exe_ctx.GetTargetPtr(); 276a0d7406aSPedro Tammela if (target == nullptr) 277a0d7406aSPedro Tammela return true; 278a0d7406aSPedro Tammela 279a0d7406aSPedro Tammela StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 280a0d7406aSPedro Tammela BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); 281a0d7406aSPedro Tammela BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id)); 282a0d7406aSPedro Tammela 283a0d7406aSPedro Tammela Debugger &debugger = target->GetDebugger(); 284a0d7406aSPedro Tammela ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 285a0d7406aSPedro Tammela debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 286a0d7406aSPedro Tammela Lua &lua = lua_interpreter->GetLua(); 287a0d7406aSPedro Tammela 288532e4203SPedro Tammela CommandDataLua *bp_option_data = static_cast<CommandDataLua *>(baton); 289532e4203SPedro Tammela llvm::Expected<bool> BoolOrErr = lua.CallBreakpointCallback( 290532e4203SPedro Tammela baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp); 291a0d7406aSPedro Tammela if (llvm::Error E = BoolOrErr.takeError()) { 292a0d7406aSPedro Tammela debugger.GetErrorStream() << toString(std::move(E)); 293a0d7406aSPedro Tammela return true; 294a0d7406aSPedro Tammela } 295a0d7406aSPedro Tammela 296a0d7406aSPedro Tammela return *BoolOrErr; 297a0d7406aSPedro Tammela } 298a0d7406aSPedro Tammela 299e81ba283SSiger Yang bool ScriptInterpreterLua::WatchpointCallbackFunction( 300e81ba283SSiger Yang void *baton, StoppointCallbackContext *context, user_id_t watch_id) { 301e81ba283SSiger Yang assert(context); 302e81ba283SSiger Yang 303e81ba283SSiger Yang ExecutionContext exe_ctx(context->exe_ctx_ref); 304e81ba283SSiger Yang Target *target = exe_ctx.GetTargetPtr(); 305e81ba283SSiger Yang if (target == nullptr) 306e81ba283SSiger Yang return true; 307e81ba283SSiger Yang 308e81ba283SSiger Yang StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 309e81ba283SSiger Yang WatchpointSP wp_sp = target->GetWatchpointList().FindByID(watch_id); 310e81ba283SSiger Yang 311e81ba283SSiger Yang Debugger &debugger = target->GetDebugger(); 312e81ba283SSiger Yang ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 313e81ba283SSiger Yang debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 314e81ba283SSiger Yang Lua &lua = lua_interpreter->GetLua(); 315e81ba283SSiger Yang 316e81ba283SSiger Yang llvm::Expected<bool> BoolOrErr = 317e81ba283SSiger Yang lua.CallWatchpointCallback(baton, stop_frame_sp, wp_sp); 318e81ba283SSiger Yang if (llvm::Error E = BoolOrErr.takeError()) { 319e81ba283SSiger Yang debugger.GetErrorStream() << toString(std::move(E)); 320e81ba283SSiger Yang return true; 321e81ba283SSiger Yang } 322e81ba283SSiger Yang 323e81ba283SSiger Yang return *BoolOrErr; 324e81ba283SSiger Yang } 325e81ba283SSiger Yang 326d853bd7aSPedro Tammela void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback( 327cfb96d84SJim Ingham std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 328d853bd7aSPedro Tammela CommandReturnObject &result) { 329d853bd7aSPedro Tammela IOHandlerSP io_handler_sp( 330d853bd7aSPedro Tammela new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint)); 331d853bd7aSPedro Tammela io_handler_sp->SetUserData(&bp_options_vec); 332d853bd7aSPedro Tammela m_debugger.RunIOHandlerAsync(io_handler_sp); 333d853bd7aSPedro Tammela } 334d853bd7aSPedro Tammela 335e81ba283SSiger Yang void ScriptInterpreterLua::CollectDataForWatchpointCommandCallback( 336e81ba283SSiger Yang WatchpointOptions *wp_options, CommandReturnObject &result) { 337e81ba283SSiger Yang IOHandlerSP io_handler_sp( 338e81ba283SSiger Yang new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerWatchpoint)); 339e81ba283SSiger Yang io_handler_sp->SetUserData(wp_options); 340e81ba283SSiger Yang m_debugger.RunIOHandlerAsync(io_handler_sp); 341e81ba283SSiger Yang } 342e81ba283SSiger Yang 343532e4203SPedro Tammela Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction( 344cfb96d84SJim Ingham BreakpointOptions &bp_options, const char *function_name, 345532e4203SPedro Tammela StructuredData::ObjectSP extra_args_sp) { 346532e4203SPedro Tammela const char *fmt_str = "return {0}(frame, bp_loc, ...)"; 347532e4203SPedro Tammela std::string oneliner = llvm::formatv(fmt_str, function_name).str(); 348532e4203SPedro Tammela return RegisterBreakpointCallback(bp_options, oneliner.c_str(), 349532e4203SPedro Tammela extra_args_sp); 350532e4203SPedro Tammela } 351532e4203SPedro Tammela 352a0d7406aSPedro Tammela Status ScriptInterpreterLua::SetBreakpointCommandCallback( 353ab81fc29SMed Ismail Bennani BreakpointOptions &bp_options, const char *command_body_text, 354ab81fc29SMed Ismail Bennani bool is_callback) { 355532e4203SPedro Tammela return RegisterBreakpointCallback(bp_options, command_body_text, {}); 356532e4203SPedro Tammela } 357532e4203SPedro Tammela 358532e4203SPedro Tammela Status ScriptInterpreterLua::RegisterBreakpointCallback( 359cfb96d84SJim Ingham BreakpointOptions &bp_options, const char *command_body_text, 360532e4203SPedro Tammela StructuredData::ObjectSP extra_args_sp) { 361532e4203SPedro Tammela auto data_up = std::make_unique<CommandDataLua>(extra_args_sp); 362*b9345707SJonas Devlieghere llvm::Error err = 363*b9345707SJonas Devlieghere m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text); 364*b9345707SJonas Devlieghere if (err) 365*b9345707SJonas Devlieghere return Status::FromError(std::move(err)); 366a0d7406aSPedro Tammela auto baton_sp = 367a0d7406aSPedro Tammela std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up)); 368cfb96d84SJim Ingham bp_options.SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction, 369a0d7406aSPedro Tammela baton_sp); 370*b9345707SJonas Devlieghere return {}; 371a0d7406aSPedro Tammela } 372a0d7406aSPedro Tammela 373e81ba283SSiger Yang void ScriptInterpreterLua::SetWatchpointCommandCallback( 374ab81fc29SMed Ismail Bennani WatchpointOptions *wp_options, const char *command_body_text, 375ab81fc29SMed Ismail Bennani bool is_callback) { 376e81ba283SSiger Yang RegisterWatchpointCallback(wp_options, command_body_text, {}); 377e81ba283SSiger Yang } 378e81ba283SSiger Yang 379e81ba283SSiger Yang Status ScriptInterpreterLua::RegisterWatchpointCallback( 380e81ba283SSiger Yang WatchpointOptions *wp_options, const char *command_body_text, 381e81ba283SSiger Yang StructuredData::ObjectSP extra_args_sp) { 382e81ba283SSiger Yang auto data_up = std::make_unique<WatchpointOptions::CommandData>(); 383*b9345707SJonas Devlieghere llvm::Error err = 384*b9345707SJonas Devlieghere m_lua->RegisterWatchpointCallback(data_up.get(), command_body_text); 385*b9345707SJonas Devlieghere if (err) 386*b9345707SJonas Devlieghere return Status::FromError(std::move(err)); 387e81ba283SSiger Yang auto baton_sp = 388e81ba283SSiger Yang std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up)); 389e81ba283SSiger Yang wp_options->SetCallback(ScriptInterpreterLua::WatchpointCallbackFunction, 390e81ba283SSiger Yang baton_sp); 391*b9345707SJonas Devlieghere return {}; 392e81ba283SSiger Yang } 393e81ba283SSiger Yang 39467de8962SJonas Devlieghere lldb::ScriptInterpreterSP 39567de8962SJonas Devlieghere ScriptInterpreterLua::CreateInstance(Debugger &debugger) { 39667de8962SJonas Devlieghere return std::make_shared<ScriptInterpreterLua>(debugger); 39767de8962SJonas Devlieghere } 39867de8962SJonas Devlieghere 3995f4980f0SPavel Labath llvm::StringRef ScriptInterpreterLua::GetPluginDescriptionStatic() { 40067de8962SJonas Devlieghere return "Lua script interpreter"; 40167de8962SJonas Devlieghere } 40267de8962SJonas Devlieghere 4034164be72SJonas Devlieghere Lua &ScriptInterpreterLua::GetLua() { return *m_lua; } 404