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: 61fe6060f1SDimitry Andric break; 62e8d8bef9SDimitry Andric case eIOHandlerWatchpoint: 63fe6060f1SDimitry Andric instructions = "Enter your Lua command(s). Type 'quit' to end.\n" 64fe6060f1SDimitry Andric "The commands are compiled as the body of the following " 65fe6060f1SDimitry Andric "Lua function\n" 66fe6060f1SDimitry Andric "function (frame, wp) end\n"; 67fe6060f1SDimitry 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))) { 87fe6060f1SDimitry Andric if (m_active_io_handler == eIOHandlerBreakpoint || 88fe6060f1SDimitry 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 } 100fe6060f1SDimitry Andric // The breakpoint and watchpoint handler only exits with a explicit 'quit' 101fe6060f1SDimitry Andric return m_active_io_handler != eIOHandlerBreakpoint && 102fe6060f1SDimitry 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: { 109fe6060f1SDimitry Andric auto *bp_options_vec = 110fe6060f1SDimitry Andric static_cast<std::vector<std::reference_wrapper<BreakpointOptions>> *>( 111e8d8bef9SDimitry Andric io_handler.GetUserData()); 112fe6060f1SDimitry 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; 120fe6060f1SDimitry Andric case eIOHandlerWatchpoint: { 121fe6060f1SDimitry Andric auto *wp_options = 122fe6060f1SDimitry Andric static_cast<WatchpointOptions *>(io_handler.GetUserData()); 123fe6060f1SDimitry Andric m_script_interpreter.SetWatchpointCommandCallback(wp_options, 124fe6060f1SDimitry Andric data.c_str()); 125e8d8bef9SDimitry Andric io_handler.SetIsDone(true); 126fe6060f1SDimitry 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 149fe6060f1SDimitry Andric ScriptInterpreterLua::~ScriptInterpreterLua() = default; 150480093f4SDimitry Andric 151*349cc55cSDimitry Andric StructuredData::DictionarySP ScriptInterpreterLua::GetInterpreterInfo() { 152*349cc55cSDimitry Andric auto info = std::make_shared<StructuredData::Dictionary>(); 153*349cc55cSDimitry Andric info->AddStringItem("language", "lua"); 154*349cc55cSDimitry Andric return info; 155*349cc55cSDimitry Andric } 156*349cc55cSDimitry Andric 157480093f4SDimitry Andric bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, 158480093f4SDimitry Andric CommandReturnObject *result, 159480093f4SDimitry Andric const ExecuteScriptOptions &options) { 1605ffd83dbSDimitry Andric if (command.empty()) { 1615ffd83dbSDimitry Andric if (result) 1625ffd83dbSDimitry Andric result->AppendError("empty command passed to lua\n"); 1635ffd83dbSDimitry Andric return false; 1645ffd83dbSDimitry Andric } 1655ffd83dbSDimitry Andric 1665ffd83dbSDimitry Andric llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 1675ffd83dbSDimitry Andric io_redirect_or_error = ScriptInterpreterIORedirect::Create( 1685ffd83dbSDimitry Andric options.GetEnableIO(), m_debugger, result); 1695ffd83dbSDimitry Andric if (!io_redirect_or_error) { 1705ffd83dbSDimitry Andric if (result) 1715ffd83dbSDimitry Andric result->AppendErrorWithFormatv( 1725ffd83dbSDimitry Andric "failed to redirect I/O: {0}\n", 1735ffd83dbSDimitry Andric llvm::fmt_consume(io_redirect_or_error.takeError())); 1745ffd83dbSDimitry Andric else 1755ffd83dbSDimitry Andric llvm::consumeError(io_redirect_or_error.takeError()); 1765ffd83dbSDimitry Andric return false; 1775ffd83dbSDimitry Andric } 1785ffd83dbSDimitry Andric 1795ffd83dbSDimitry Andric ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; 1805ffd83dbSDimitry Andric 1815ffd83dbSDimitry Andric if (llvm::Error e = 1825ffd83dbSDimitry Andric m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(), 1835ffd83dbSDimitry Andric io_redirect.GetErrorFile()->GetStream())) { 1845ffd83dbSDimitry Andric result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n", 1855ffd83dbSDimitry Andric llvm::toString(std::move(e))); 1865ffd83dbSDimitry Andric return false; 1875ffd83dbSDimitry Andric } 1885ffd83dbSDimitry Andric 189480093f4SDimitry Andric if (llvm::Error e = m_lua->Run(command)) { 190480093f4SDimitry Andric result->AppendErrorWithFormatv( 191480093f4SDimitry Andric "lua failed attempting to evaluate '{0}': {1}\n", command, 192480093f4SDimitry Andric llvm::toString(std::move(e))); 193480093f4SDimitry Andric return false; 194480093f4SDimitry Andric } 1955ffd83dbSDimitry Andric 1965ffd83dbSDimitry Andric io_redirect.Flush(); 197480093f4SDimitry Andric return true; 198480093f4SDimitry Andric } 199480093f4SDimitry Andric 200480093f4SDimitry Andric void ScriptInterpreterLua::ExecuteInterpreterLoop() { 201e8d8bef9SDimitry Andric LLDB_SCOPED_TIMER(); 202480093f4SDimitry Andric 203480093f4SDimitry Andric // At the moment, the only time the debugger does not have an input file 204480093f4SDimitry Andric // handle is when this is called directly from lua, in which case it is 205480093f4SDimitry Andric // both dangerous and unnecessary (not to mention confusing) to try to embed 206480093f4SDimitry Andric // a running interpreter loop inside the already running lua interpreter 207480093f4SDimitry Andric // loop, so we won't do it. 2085ffd83dbSDimitry Andric if (!m_debugger.GetInputFile().IsValid()) 209480093f4SDimitry Andric return; 210480093f4SDimitry Andric 2115ffd83dbSDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this)); 2125ffd83dbSDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 213480093f4SDimitry Andric } 214480093f4SDimitry Andric 215480093f4SDimitry Andric bool ScriptInterpreterLua::LoadScriptingModule( 216fe6060f1SDimitry Andric const char *filename, const LoadScriptOptions &options, 217fe6060f1SDimitry Andric lldb_private::Status &error, StructuredData::ObjectSP *module_sp, 218fe6060f1SDimitry Andric FileSpec extra_search_dir) { 219480093f4SDimitry Andric 2205ffd83dbSDimitry Andric FileSystem::Instance().Collect(filename); 221480093f4SDimitry Andric if (llvm::Error e = m_lua->LoadModule(filename)) { 222480093f4SDimitry Andric error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n", 223480093f4SDimitry Andric filename, llvm::toString(std::move(e))); 224480093f4SDimitry Andric return false; 225480093f4SDimitry Andric } 226480093f4SDimitry Andric return true; 227480093f4SDimitry Andric } 228480093f4SDimitry Andric 229480093f4SDimitry Andric void ScriptInterpreterLua::Initialize() { 230480093f4SDimitry Andric static llvm::once_flag g_once_flag; 231480093f4SDimitry Andric 232480093f4SDimitry Andric llvm::call_once(g_once_flag, []() { 233480093f4SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 234480093f4SDimitry Andric GetPluginDescriptionStatic(), 235480093f4SDimitry Andric lldb::eScriptLanguageLua, CreateInstance); 236480093f4SDimitry Andric }); 237480093f4SDimitry Andric } 238480093f4SDimitry Andric 239480093f4SDimitry Andric void ScriptInterpreterLua::Terminate() {} 240480093f4SDimitry Andric 241480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) { 242480093f4SDimitry Andric if (m_session_is_active) 243480093f4SDimitry Andric return llvm::Error::success(); 244480093f4SDimitry Andric 245480093f4SDimitry Andric const char *fmt_str = 246480093f4SDimitry Andric "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); " 247480093f4SDimitry Andric "lldb.target = lldb.debugger:GetSelectedTarget(); " 248480093f4SDimitry Andric "lldb.process = lldb.target:GetProcess(); " 249480093f4SDimitry Andric "lldb.thread = lldb.process:GetSelectedThread(); " 250480093f4SDimitry Andric "lldb.frame = lldb.thread:GetSelectedFrame()"; 251480093f4SDimitry Andric return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str()); 252480093f4SDimitry Andric } 253480093f4SDimitry Andric 254480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::LeaveSession() { 255480093f4SDimitry Andric if (!m_session_is_active) 256480093f4SDimitry Andric return llvm::Error::success(); 257480093f4SDimitry Andric 258480093f4SDimitry Andric m_session_is_active = false; 259480093f4SDimitry Andric 260480093f4SDimitry Andric llvm::StringRef str = "lldb.debugger = nil; " 261480093f4SDimitry Andric "lldb.target = nil; " 262480093f4SDimitry Andric "lldb.process = nil; " 263480093f4SDimitry Andric "lldb.thread = nil; " 264480093f4SDimitry Andric "lldb.frame = nil"; 265480093f4SDimitry Andric return m_lua->Run(str); 266480093f4SDimitry Andric } 267480093f4SDimitry Andric 268e8d8bef9SDimitry Andric bool ScriptInterpreterLua::BreakpointCallbackFunction( 269e8d8bef9SDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t break_id, 270e8d8bef9SDimitry Andric user_id_t break_loc_id) { 271e8d8bef9SDimitry Andric assert(context); 272e8d8bef9SDimitry Andric 273e8d8bef9SDimitry Andric ExecutionContext exe_ctx(context->exe_ctx_ref); 274e8d8bef9SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 275e8d8bef9SDimitry Andric if (target == nullptr) 276e8d8bef9SDimitry Andric return true; 277e8d8bef9SDimitry Andric 278e8d8bef9SDimitry Andric StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 279e8d8bef9SDimitry Andric BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); 280e8d8bef9SDimitry Andric BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id)); 281e8d8bef9SDimitry Andric 282e8d8bef9SDimitry Andric Debugger &debugger = target->GetDebugger(); 283e8d8bef9SDimitry Andric ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 284e8d8bef9SDimitry Andric debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 285e8d8bef9SDimitry Andric Lua &lua = lua_interpreter->GetLua(); 286e8d8bef9SDimitry Andric 287e8d8bef9SDimitry Andric CommandDataLua *bp_option_data = static_cast<CommandDataLua *>(baton); 288e8d8bef9SDimitry Andric llvm::Expected<bool> BoolOrErr = lua.CallBreakpointCallback( 289e8d8bef9SDimitry Andric baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp); 290e8d8bef9SDimitry Andric if (llvm::Error E = BoolOrErr.takeError()) { 291e8d8bef9SDimitry Andric debugger.GetErrorStream() << toString(std::move(E)); 292e8d8bef9SDimitry Andric return true; 293e8d8bef9SDimitry Andric } 294e8d8bef9SDimitry Andric 295e8d8bef9SDimitry Andric return *BoolOrErr; 296e8d8bef9SDimitry Andric } 297e8d8bef9SDimitry Andric 298fe6060f1SDimitry Andric bool ScriptInterpreterLua::WatchpointCallbackFunction( 299fe6060f1SDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t watch_id) { 300fe6060f1SDimitry Andric assert(context); 301fe6060f1SDimitry Andric 302fe6060f1SDimitry Andric ExecutionContext exe_ctx(context->exe_ctx_ref); 303fe6060f1SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 304fe6060f1SDimitry Andric if (target == nullptr) 305fe6060f1SDimitry Andric return true; 306fe6060f1SDimitry Andric 307fe6060f1SDimitry Andric StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 308fe6060f1SDimitry Andric WatchpointSP wp_sp = target->GetWatchpointList().FindByID(watch_id); 309fe6060f1SDimitry Andric 310fe6060f1SDimitry Andric Debugger &debugger = target->GetDebugger(); 311fe6060f1SDimitry Andric ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 312fe6060f1SDimitry Andric debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 313fe6060f1SDimitry Andric Lua &lua = lua_interpreter->GetLua(); 314fe6060f1SDimitry Andric 315fe6060f1SDimitry Andric llvm::Expected<bool> BoolOrErr = 316fe6060f1SDimitry Andric lua.CallWatchpointCallback(baton, stop_frame_sp, wp_sp); 317fe6060f1SDimitry Andric if (llvm::Error E = BoolOrErr.takeError()) { 318fe6060f1SDimitry Andric debugger.GetErrorStream() << toString(std::move(E)); 319fe6060f1SDimitry Andric return true; 320fe6060f1SDimitry Andric } 321fe6060f1SDimitry Andric 322fe6060f1SDimitry Andric return *BoolOrErr; 323fe6060f1SDimitry Andric } 324fe6060f1SDimitry Andric 325e8d8bef9SDimitry Andric void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback( 326fe6060f1SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 327e8d8bef9SDimitry Andric CommandReturnObject &result) { 328e8d8bef9SDimitry Andric IOHandlerSP io_handler_sp( 329e8d8bef9SDimitry Andric new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint)); 330e8d8bef9SDimitry Andric io_handler_sp->SetUserData(&bp_options_vec); 331e8d8bef9SDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 332e8d8bef9SDimitry Andric } 333e8d8bef9SDimitry Andric 334fe6060f1SDimitry Andric void ScriptInterpreterLua::CollectDataForWatchpointCommandCallback( 335fe6060f1SDimitry Andric WatchpointOptions *wp_options, CommandReturnObject &result) { 336fe6060f1SDimitry Andric IOHandlerSP io_handler_sp( 337fe6060f1SDimitry Andric new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerWatchpoint)); 338fe6060f1SDimitry Andric io_handler_sp->SetUserData(wp_options); 339fe6060f1SDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 340fe6060f1SDimitry Andric } 341fe6060f1SDimitry Andric 342e8d8bef9SDimitry Andric Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction( 343fe6060f1SDimitry Andric BreakpointOptions &bp_options, const char *function_name, 344e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 345e8d8bef9SDimitry Andric const char *fmt_str = "return {0}(frame, bp_loc, ...)"; 346e8d8bef9SDimitry Andric std::string oneliner = llvm::formatv(fmt_str, function_name).str(); 347e8d8bef9SDimitry Andric return RegisterBreakpointCallback(bp_options, oneliner.c_str(), 348e8d8bef9SDimitry Andric extra_args_sp); 349e8d8bef9SDimitry Andric } 350e8d8bef9SDimitry Andric 351e8d8bef9SDimitry Andric Status ScriptInterpreterLua::SetBreakpointCommandCallback( 352fe6060f1SDimitry Andric BreakpointOptions &bp_options, const char *command_body_text) { 353e8d8bef9SDimitry Andric return RegisterBreakpointCallback(bp_options, command_body_text, {}); 354e8d8bef9SDimitry Andric } 355e8d8bef9SDimitry Andric 356e8d8bef9SDimitry Andric Status ScriptInterpreterLua::RegisterBreakpointCallback( 357fe6060f1SDimitry Andric BreakpointOptions &bp_options, const char *command_body_text, 358e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 359e8d8bef9SDimitry Andric Status error; 360e8d8bef9SDimitry Andric auto data_up = std::make_unique<CommandDataLua>(extra_args_sp); 361e8d8bef9SDimitry Andric error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text); 362e8d8bef9SDimitry Andric if (error.Fail()) 363e8d8bef9SDimitry Andric return error; 364e8d8bef9SDimitry Andric auto baton_sp = 365e8d8bef9SDimitry Andric std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up)); 366fe6060f1SDimitry Andric bp_options.SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction, 367fe6060f1SDimitry Andric baton_sp); 368fe6060f1SDimitry Andric return error; 369fe6060f1SDimitry Andric } 370fe6060f1SDimitry Andric 371fe6060f1SDimitry Andric void ScriptInterpreterLua::SetWatchpointCommandCallback( 372fe6060f1SDimitry Andric WatchpointOptions *wp_options, const char *command_body_text) { 373fe6060f1SDimitry Andric RegisterWatchpointCallback(wp_options, command_body_text, {}); 374fe6060f1SDimitry Andric } 375fe6060f1SDimitry Andric 376fe6060f1SDimitry Andric Status ScriptInterpreterLua::RegisterWatchpointCallback( 377fe6060f1SDimitry Andric WatchpointOptions *wp_options, const char *command_body_text, 378fe6060f1SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 379fe6060f1SDimitry Andric Status error; 380fe6060f1SDimitry Andric auto data_up = std::make_unique<WatchpointOptions::CommandData>(); 381fe6060f1SDimitry Andric error = m_lua->RegisterWatchpointCallback(data_up.get(), command_body_text); 382fe6060f1SDimitry Andric if (error.Fail()) 383fe6060f1SDimitry Andric return error; 384fe6060f1SDimitry Andric auto baton_sp = 385fe6060f1SDimitry Andric std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up)); 386fe6060f1SDimitry Andric wp_options->SetCallback(ScriptInterpreterLua::WatchpointCallbackFunction, 387e8d8bef9SDimitry Andric baton_sp); 388e8d8bef9SDimitry Andric return error; 389e8d8bef9SDimitry Andric } 390e8d8bef9SDimitry Andric 391480093f4SDimitry Andric lldb::ScriptInterpreterSP 392480093f4SDimitry Andric ScriptInterpreterLua::CreateInstance(Debugger &debugger) { 393480093f4SDimitry Andric return std::make_shared<ScriptInterpreterLua>(debugger); 394480093f4SDimitry Andric } 395480093f4SDimitry Andric 396*349cc55cSDimitry Andric llvm::StringRef ScriptInterpreterLua::GetPluginDescriptionStatic() { 397480093f4SDimitry Andric return "Lua script interpreter"; 398480093f4SDimitry Andric } 399480093f4SDimitry Andric 400480093f4SDimitry Andric Lua &ScriptInterpreterLua::GetLua() { return *m_lua; } 401