xref: /llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp (revision b93457073762bb347b6c7f39c23636dec036a815)
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