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" 11*a0d7406aSPedro Tammela #include "lldb/Breakpoint/StoppointCallbackContext.h" 1267de8962SJonas Devlieghere #include "lldb/Core/Debugger.h" 1367de8962SJonas Devlieghere #include "lldb/Core/PluginManager.h" 1467de8962SJonas Devlieghere #include "lldb/Core/StreamFile.h" 1528613242SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 16*a0d7406aSPedro 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" 20ed8184b7SJonas Devlieghere #include "llvm/Support/FormatAdapters.h" 21*a0d7406aSPedro Tammela #include <memory> 2267de8962SJonas Devlieghere 2367de8962SJonas Devlieghere using namespace lldb; 2467de8962SJonas Devlieghere using namespace lldb_private; 2567de8962SJonas Devlieghere 26bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) 27fbb4d1e4SJonas Devlieghere 2828613242SJonas Devlieghere class IOHandlerLuaInterpreter : public IOHandlerDelegate, 2928613242SJonas Devlieghere public IOHandlerEditline { 3028613242SJonas Devlieghere public: 314164be72SJonas Devlieghere IOHandlerLuaInterpreter(Debugger &debugger, 324164be72SJonas Devlieghere ScriptInterpreterLua &script_interpreter) 3328613242SJonas Devlieghere : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", 3428613242SJonas Devlieghere ">>> ", "..> ", true, debugger.GetUseColor(), 0, 3528613242SJonas Devlieghere *this, nullptr), 3645c971f7SJonas Devlieghere m_script_interpreter(script_interpreter) { 37fa1b4a96SJonas Devlieghere llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( 38fa1b4a96SJonas Devlieghere debugger.GetOutputFile().GetStream(), 39fa1b4a96SJonas Devlieghere debugger.GetErrorFile().GetStream())); 4045c971f7SJonas Devlieghere llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); 4145c971f7SJonas Devlieghere } 4245c971f7SJonas Devlieghere 435ddd4fc5SJonas Devlieghere ~IOHandlerLuaInterpreter() override { 4445c971f7SJonas Devlieghere llvm::cantFail(m_script_interpreter.LeaveSession()); 4545c971f7SJonas Devlieghere } 4628613242SJonas Devlieghere 4728613242SJonas Devlieghere void IOHandlerInputComplete(IOHandler &io_handler, 4828613242SJonas Devlieghere std::string &data) override { 491728dec2SJonas Devlieghere if (llvm::StringRef(data).rtrim() == "quit") { 501728dec2SJonas Devlieghere io_handler.SetIsDone(true); 511728dec2SJonas Devlieghere return; 521728dec2SJonas Devlieghere } 531728dec2SJonas Devlieghere 544164be72SJonas Devlieghere if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { 5528613242SJonas Devlieghere *GetOutputStreamFileSP() << llvm::toString(std::move(error)); 5628613242SJonas Devlieghere } 5728613242SJonas Devlieghere } 5828613242SJonas Devlieghere 5928613242SJonas Devlieghere private: 604164be72SJonas Devlieghere ScriptInterpreterLua &m_script_interpreter; 6128613242SJonas Devlieghere }; 6228613242SJonas Devlieghere 6367de8962SJonas Devlieghere ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) 644164be72SJonas Devlieghere : ScriptInterpreter(debugger, eScriptLanguageLua), 654164be72SJonas Devlieghere m_lua(std::make_unique<Lua>()) {} 6667de8962SJonas Devlieghere 6767de8962SJonas Devlieghere ScriptInterpreterLua::~ScriptInterpreterLua() {} 6867de8962SJonas Devlieghere 6967de8962SJonas Devlieghere bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, 7028613242SJonas Devlieghere CommandReturnObject *result, 7128613242SJonas Devlieghere const ExecuteScriptOptions &options) { 72ed8184b7SJonas Devlieghere if (command.empty()) { 73ed8184b7SJonas Devlieghere if (result) 74ed8184b7SJonas Devlieghere result->AppendError("empty command passed to lua\n"); 75ed8184b7SJonas Devlieghere return false; 76ed8184b7SJonas Devlieghere } 77ed8184b7SJonas Devlieghere 78ed8184b7SJonas Devlieghere llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 79ed8184b7SJonas Devlieghere io_redirect_or_error = ScriptInterpreterIORedirect::Create( 80ed8184b7SJonas Devlieghere options.GetEnableIO(), m_debugger, result); 81ed8184b7SJonas Devlieghere if (!io_redirect_or_error) { 82ed8184b7SJonas Devlieghere if (result) 83ed8184b7SJonas Devlieghere result->AppendErrorWithFormatv( 84ed8184b7SJonas Devlieghere "failed to redirect I/O: {0}\n", 85ed8184b7SJonas Devlieghere llvm::fmt_consume(io_redirect_or_error.takeError())); 86ed8184b7SJonas Devlieghere else 87ed8184b7SJonas Devlieghere llvm::consumeError(io_redirect_or_error.takeError()); 88ed8184b7SJonas Devlieghere return false; 89ed8184b7SJonas Devlieghere } 90ed8184b7SJonas Devlieghere 91ed8184b7SJonas Devlieghere ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; 92ed8184b7SJonas Devlieghere 93ed8184b7SJonas Devlieghere if (llvm::Error e = 94ed8184b7SJonas Devlieghere m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(), 95ed8184b7SJonas Devlieghere io_redirect.GetErrorFile()->GetStream())) { 96ed8184b7SJonas Devlieghere result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n", 97ed8184b7SJonas Devlieghere llvm::toString(std::move(e))); 98ed8184b7SJonas Devlieghere return false; 99ed8184b7SJonas Devlieghere } 100ed8184b7SJonas Devlieghere 1014164be72SJonas Devlieghere if (llvm::Error e = m_lua->Run(command)) { 10228613242SJonas Devlieghere result->AppendErrorWithFormatv( 10328613242SJonas Devlieghere "lua failed attempting to evaluate '{0}': {1}\n", command, 10428613242SJonas Devlieghere llvm::toString(std::move(e))); 10567de8962SJonas Devlieghere return false; 10667de8962SJonas Devlieghere } 107ed8184b7SJonas Devlieghere 108ed8184b7SJonas Devlieghere io_redirect.Flush(); 10928613242SJonas Devlieghere return true; 11028613242SJonas Devlieghere } 11167de8962SJonas Devlieghere 11267de8962SJonas Devlieghere void ScriptInterpreterLua::ExecuteInterpreterLoop() { 11328613242SJonas Devlieghere static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 11428613242SJonas Devlieghere Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); 11528613242SJonas Devlieghere 11628613242SJonas Devlieghere // At the moment, the only time the debugger does not have an input file 11728613242SJonas Devlieghere // handle is when this is called directly from lua, in which case it is 11828613242SJonas Devlieghere // both dangerous and unnecessary (not to mention confusing) to try to embed 11928613242SJonas Devlieghere // a running interpreter loop inside the already running lua interpreter 12028613242SJonas Devlieghere // loop, so we won't do it. 1216e3faaebSJonas Devlieghere if (!m_debugger.GetInputFile().IsValid()) 12228613242SJonas Devlieghere return; 12328613242SJonas Devlieghere 1246e3faaebSJonas Devlieghere IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this)); 1256e3faaebSJonas Devlieghere m_debugger.RunIOHandlerAsync(io_handler_sp); 12667de8962SJonas Devlieghere } 12767de8962SJonas Devlieghere 128572b9f46SJonas Devlieghere bool ScriptInterpreterLua::LoadScriptingModule( 129572b9f46SJonas Devlieghere const char *filename, bool init_session, lldb_private::Status &error, 13000bb397bSJonas Devlieghere StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) { 131572b9f46SJonas Devlieghere 1321f80e515SJonas Devlieghere FileSystem::Instance().Collect(filename); 133572b9f46SJonas Devlieghere if (llvm::Error e = m_lua->LoadModule(filename)) { 134572b9f46SJonas Devlieghere error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n", 135572b9f46SJonas Devlieghere filename, llvm::toString(std::move(e))); 136572b9f46SJonas Devlieghere return false; 137572b9f46SJonas Devlieghere } 138572b9f46SJonas Devlieghere return true; 139572b9f46SJonas Devlieghere } 140572b9f46SJonas Devlieghere 14167de8962SJonas Devlieghere void ScriptInterpreterLua::Initialize() { 14267de8962SJonas Devlieghere static llvm::once_flag g_once_flag; 14367de8962SJonas Devlieghere 14467de8962SJonas Devlieghere llvm::call_once(g_once_flag, []() { 14567de8962SJonas Devlieghere PluginManager::RegisterPlugin(GetPluginNameStatic(), 14667de8962SJonas Devlieghere GetPluginDescriptionStatic(), 14767de8962SJonas Devlieghere lldb::eScriptLanguageLua, CreateInstance); 14867de8962SJonas Devlieghere }); 14967de8962SJonas Devlieghere } 15067de8962SJonas Devlieghere 15167de8962SJonas Devlieghere void ScriptInterpreterLua::Terminate() {} 15267de8962SJonas Devlieghere 15345c971f7SJonas Devlieghere llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) { 15445c971f7SJonas Devlieghere if (m_session_is_active) 15545c971f7SJonas Devlieghere return llvm::Error::success(); 15645c971f7SJonas Devlieghere 15745c971f7SJonas Devlieghere const char *fmt_str = 15845c971f7SJonas Devlieghere "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); " 15945c971f7SJonas Devlieghere "lldb.target = lldb.debugger:GetSelectedTarget(); " 16045c971f7SJonas Devlieghere "lldb.process = lldb.target:GetProcess(); " 16145c971f7SJonas Devlieghere "lldb.thread = lldb.process:GetSelectedThread(); " 16245c971f7SJonas Devlieghere "lldb.frame = lldb.thread:GetSelectedFrame()"; 16345c971f7SJonas Devlieghere return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str()); 16445c971f7SJonas Devlieghere } 16545c971f7SJonas Devlieghere 16645c971f7SJonas Devlieghere llvm::Error ScriptInterpreterLua::LeaveSession() { 16745c971f7SJonas Devlieghere if (!m_session_is_active) 16845c971f7SJonas Devlieghere return llvm::Error::success(); 16945c971f7SJonas Devlieghere 17045c971f7SJonas Devlieghere m_session_is_active = false; 17145c971f7SJonas Devlieghere 17245c971f7SJonas Devlieghere llvm::StringRef str = "lldb.debugger = nil; " 17345c971f7SJonas Devlieghere "lldb.target = nil; " 17445c971f7SJonas Devlieghere "lldb.process = nil; " 17545c971f7SJonas Devlieghere "lldb.thread = nil; " 17645c971f7SJonas Devlieghere "lldb.frame = nil"; 17745c971f7SJonas Devlieghere return m_lua->Run(str); 17845c971f7SJonas Devlieghere } 17945c971f7SJonas Devlieghere 180*a0d7406aSPedro Tammela bool ScriptInterpreterLua::BreakpointCallbackFunction( 181*a0d7406aSPedro Tammela void *baton, StoppointCallbackContext *context, user_id_t break_id, 182*a0d7406aSPedro Tammela user_id_t break_loc_id) { 183*a0d7406aSPedro Tammela assert(context); 184*a0d7406aSPedro Tammela 185*a0d7406aSPedro Tammela ExecutionContext exe_ctx(context->exe_ctx_ref); 186*a0d7406aSPedro Tammela Target *target = exe_ctx.GetTargetPtr(); 187*a0d7406aSPedro Tammela if (target == nullptr) 188*a0d7406aSPedro Tammela return true; 189*a0d7406aSPedro Tammela 190*a0d7406aSPedro Tammela StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 191*a0d7406aSPedro Tammela BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); 192*a0d7406aSPedro Tammela BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id)); 193*a0d7406aSPedro Tammela 194*a0d7406aSPedro Tammela Debugger &debugger = target->GetDebugger(); 195*a0d7406aSPedro Tammela ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 196*a0d7406aSPedro Tammela debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 197*a0d7406aSPedro Tammela Lua &lua = lua_interpreter->GetLua(); 198*a0d7406aSPedro Tammela 199*a0d7406aSPedro Tammela llvm::Expected<bool> BoolOrErr = 200*a0d7406aSPedro Tammela lua.CallBreakpointCallback(baton, stop_frame_sp, bp_loc_sp); 201*a0d7406aSPedro Tammela if (llvm::Error E = BoolOrErr.takeError()) { 202*a0d7406aSPedro Tammela debugger.GetErrorStream() << toString(std::move(E)); 203*a0d7406aSPedro Tammela return true; 204*a0d7406aSPedro Tammela } 205*a0d7406aSPedro Tammela 206*a0d7406aSPedro Tammela return *BoolOrErr; 207*a0d7406aSPedro Tammela } 208*a0d7406aSPedro Tammela 209*a0d7406aSPedro Tammela Status ScriptInterpreterLua::SetBreakpointCommandCallback( 210*a0d7406aSPedro Tammela BreakpointOptions *bp_options, const char *command_body_text) { 211*a0d7406aSPedro Tammela Status error; 212*a0d7406aSPedro Tammela auto data_up = std::make_unique<CommandDataLua>(); 213*a0d7406aSPedro Tammela error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text); 214*a0d7406aSPedro Tammela if (error.Fail()) 215*a0d7406aSPedro Tammela return error; 216*a0d7406aSPedro Tammela auto baton_sp = 217*a0d7406aSPedro Tammela std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up)); 218*a0d7406aSPedro Tammela bp_options->SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction, 219*a0d7406aSPedro Tammela baton_sp); 220*a0d7406aSPedro Tammela return error; 221*a0d7406aSPedro Tammela } 222*a0d7406aSPedro Tammela 22367de8962SJonas Devlieghere lldb::ScriptInterpreterSP 22467de8962SJonas Devlieghere ScriptInterpreterLua::CreateInstance(Debugger &debugger) { 22567de8962SJonas Devlieghere return std::make_shared<ScriptInterpreterLua>(debugger); 22667de8962SJonas Devlieghere } 22767de8962SJonas Devlieghere 22867de8962SJonas Devlieghere lldb_private::ConstString ScriptInterpreterLua::GetPluginNameStatic() { 22967de8962SJonas Devlieghere static ConstString g_name("script-lua"); 23067de8962SJonas Devlieghere return g_name; 23167de8962SJonas Devlieghere } 23267de8962SJonas Devlieghere 23367de8962SJonas Devlieghere const char *ScriptInterpreterLua::GetPluginDescriptionStatic() { 23467de8962SJonas Devlieghere return "Lua script interpreter"; 23567de8962SJonas Devlieghere } 23667de8962SJonas Devlieghere 23767de8962SJonas Devlieghere lldb_private::ConstString ScriptInterpreterLua::GetPluginName() { 23867de8962SJonas Devlieghere return GetPluginNameStatic(); 23967de8962SJonas Devlieghere } 24067de8962SJonas Devlieghere 24167de8962SJonas Devlieghere uint32_t ScriptInterpreterLua::GetPluginVersion() { return 1; } 2424164be72SJonas Devlieghere 2434164be72SJonas Devlieghere Lua &ScriptInterpreterLua::GetLua() { return *m_lua; } 244