1*5ffd83dbSDimitry 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" 11480093f4SDimitry Andric #include "lldb/Core/Debugger.h" 12480093f4SDimitry Andric #include "lldb/Core/PluginManager.h" 13480093f4SDimitry Andric #include "lldb/Core/StreamFile.h" 14480093f4SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 15480093f4SDimitry Andric #include "lldb/Utility/Stream.h" 16480093f4SDimitry Andric #include "lldb/Utility/StringList.h" 17480093f4SDimitry Andric #include "lldb/Utility/Timer.h" 18*5ffd83dbSDimitry Andric #include "llvm/Support/FormatAdapters.h" 19480093f4SDimitry Andric 20480093f4SDimitry Andric using namespace lldb; 21480093f4SDimitry Andric using namespace lldb_private; 22480093f4SDimitry Andric 23*5ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) 24*5ffd83dbSDimitry Andric 25480093f4SDimitry Andric class IOHandlerLuaInterpreter : public IOHandlerDelegate, 26480093f4SDimitry Andric public IOHandlerEditline { 27480093f4SDimitry Andric public: 28480093f4SDimitry Andric IOHandlerLuaInterpreter(Debugger &debugger, 29480093f4SDimitry Andric ScriptInterpreterLua &script_interpreter) 30480093f4SDimitry Andric : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", 31480093f4SDimitry Andric ">>> ", "..> ", true, debugger.GetUseColor(), 0, 32480093f4SDimitry Andric *this, nullptr), 33480093f4SDimitry Andric m_script_interpreter(script_interpreter) { 34*5ffd83dbSDimitry Andric llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( 35*5ffd83dbSDimitry Andric debugger.GetOutputFile().GetStream(), 36*5ffd83dbSDimitry Andric debugger.GetErrorFile().GetStream())); 37480093f4SDimitry Andric llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); 38480093f4SDimitry Andric } 39480093f4SDimitry Andric 40*5ffd83dbSDimitry Andric ~IOHandlerLuaInterpreter() override { 41480093f4SDimitry Andric llvm::cantFail(m_script_interpreter.LeaveSession()); 42480093f4SDimitry Andric } 43480093f4SDimitry Andric 44480093f4SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler, 45480093f4SDimitry Andric std::string &data) override { 46*5ffd83dbSDimitry Andric if (llvm::StringRef(data).rtrim() == "quit") { 47*5ffd83dbSDimitry Andric io_handler.SetIsDone(true); 48*5ffd83dbSDimitry Andric return; 49*5ffd83dbSDimitry Andric } 50*5ffd83dbSDimitry Andric 51480093f4SDimitry Andric if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { 52480093f4SDimitry Andric *GetOutputStreamFileSP() << llvm::toString(std::move(error)); 53480093f4SDimitry Andric } 54480093f4SDimitry Andric } 55480093f4SDimitry Andric 56480093f4SDimitry Andric private: 57480093f4SDimitry Andric ScriptInterpreterLua &m_script_interpreter; 58480093f4SDimitry Andric }; 59480093f4SDimitry Andric 60480093f4SDimitry Andric ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) 61480093f4SDimitry Andric : ScriptInterpreter(debugger, eScriptLanguageLua), 62480093f4SDimitry Andric m_lua(std::make_unique<Lua>()) {} 63480093f4SDimitry Andric 64480093f4SDimitry Andric ScriptInterpreterLua::~ScriptInterpreterLua() {} 65480093f4SDimitry Andric 66480093f4SDimitry Andric bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, 67480093f4SDimitry Andric CommandReturnObject *result, 68480093f4SDimitry Andric const ExecuteScriptOptions &options) { 69*5ffd83dbSDimitry Andric if (command.empty()) { 70*5ffd83dbSDimitry Andric if (result) 71*5ffd83dbSDimitry Andric result->AppendError("empty command passed to lua\n"); 72*5ffd83dbSDimitry Andric return false; 73*5ffd83dbSDimitry Andric } 74*5ffd83dbSDimitry Andric 75*5ffd83dbSDimitry Andric llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 76*5ffd83dbSDimitry Andric io_redirect_or_error = ScriptInterpreterIORedirect::Create( 77*5ffd83dbSDimitry Andric options.GetEnableIO(), m_debugger, result); 78*5ffd83dbSDimitry Andric if (!io_redirect_or_error) { 79*5ffd83dbSDimitry Andric if (result) 80*5ffd83dbSDimitry Andric result->AppendErrorWithFormatv( 81*5ffd83dbSDimitry Andric "failed to redirect I/O: {0}\n", 82*5ffd83dbSDimitry Andric llvm::fmt_consume(io_redirect_or_error.takeError())); 83*5ffd83dbSDimitry Andric else 84*5ffd83dbSDimitry Andric llvm::consumeError(io_redirect_or_error.takeError()); 85*5ffd83dbSDimitry Andric return false; 86*5ffd83dbSDimitry Andric } 87*5ffd83dbSDimitry Andric 88*5ffd83dbSDimitry Andric ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; 89*5ffd83dbSDimitry Andric 90*5ffd83dbSDimitry Andric if (llvm::Error e = 91*5ffd83dbSDimitry Andric m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(), 92*5ffd83dbSDimitry Andric io_redirect.GetErrorFile()->GetStream())) { 93*5ffd83dbSDimitry Andric result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n", 94*5ffd83dbSDimitry Andric llvm::toString(std::move(e))); 95*5ffd83dbSDimitry Andric return false; 96*5ffd83dbSDimitry Andric } 97*5ffd83dbSDimitry Andric 98480093f4SDimitry Andric if (llvm::Error e = m_lua->Run(command)) { 99480093f4SDimitry Andric result->AppendErrorWithFormatv( 100480093f4SDimitry Andric "lua failed attempting to evaluate '{0}': {1}\n", command, 101480093f4SDimitry Andric llvm::toString(std::move(e))); 102480093f4SDimitry Andric return false; 103480093f4SDimitry Andric } 104*5ffd83dbSDimitry Andric 105*5ffd83dbSDimitry Andric io_redirect.Flush(); 106480093f4SDimitry Andric return true; 107480093f4SDimitry Andric } 108480093f4SDimitry Andric 109480093f4SDimitry Andric void ScriptInterpreterLua::ExecuteInterpreterLoop() { 110480093f4SDimitry Andric static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 111480093f4SDimitry Andric Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); 112480093f4SDimitry Andric 113480093f4SDimitry Andric // At the moment, the only time the debugger does not have an input file 114480093f4SDimitry Andric // handle is when this is called directly from lua, in which case it is 115480093f4SDimitry Andric // both dangerous and unnecessary (not to mention confusing) to try to embed 116480093f4SDimitry Andric // a running interpreter loop inside the already running lua interpreter 117480093f4SDimitry Andric // loop, so we won't do it. 118*5ffd83dbSDimitry Andric if (!m_debugger.GetInputFile().IsValid()) 119480093f4SDimitry Andric return; 120480093f4SDimitry Andric 121*5ffd83dbSDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this)); 122*5ffd83dbSDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 123480093f4SDimitry Andric } 124480093f4SDimitry Andric 125480093f4SDimitry Andric bool ScriptInterpreterLua::LoadScriptingModule( 126480093f4SDimitry Andric const char *filename, bool init_session, lldb_private::Status &error, 127480093f4SDimitry Andric StructuredData::ObjectSP *module_sp) { 128480093f4SDimitry Andric 129*5ffd83dbSDimitry Andric FileSystem::Instance().Collect(filename); 130480093f4SDimitry Andric if (llvm::Error e = m_lua->LoadModule(filename)) { 131480093f4SDimitry Andric error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n", 132480093f4SDimitry Andric filename, llvm::toString(std::move(e))); 133480093f4SDimitry Andric return false; 134480093f4SDimitry Andric } 135480093f4SDimitry Andric return true; 136480093f4SDimitry Andric } 137480093f4SDimitry Andric 138480093f4SDimitry Andric void ScriptInterpreterLua::Initialize() { 139480093f4SDimitry Andric static llvm::once_flag g_once_flag; 140480093f4SDimitry Andric 141480093f4SDimitry Andric llvm::call_once(g_once_flag, []() { 142480093f4SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 143480093f4SDimitry Andric GetPluginDescriptionStatic(), 144480093f4SDimitry Andric lldb::eScriptLanguageLua, CreateInstance); 145480093f4SDimitry Andric }); 146480093f4SDimitry Andric } 147480093f4SDimitry Andric 148480093f4SDimitry Andric void ScriptInterpreterLua::Terminate() {} 149480093f4SDimitry Andric 150480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) { 151480093f4SDimitry Andric if (m_session_is_active) 152480093f4SDimitry Andric return llvm::Error::success(); 153480093f4SDimitry Andric 154480093f4SDimitry Andric const char *fmt_str = 155480093f4SDimitry Andric "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); " 156480093f4SDimitry Andric "lldb.target = lldb.debugger:GetSelectedTarget(); " 157480093f4SDimitry Andric "lldb.process = lldb.target:GetProcess(); " 158480093f4SDimitry Andric "lldb.thread = lldb.process:GetSelectedThread(); " 159480093f4SDimitry Andric "lldb.frame = lldb.thread:GetSelectedFrame()"; 160480093f4SDimitry Andric return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str()); 161480093f4SDimitry Andric } 162480093f4SDimitry Andric 163480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::LeaveSession() { 164480093f4SDimitry Andric if (!m_session_is_active) 165480093f4SDimitry Andric return llvm::Error::success(); 166480093f4SDimitry Andric 167480093f4SDimitry Andric m_session_is_active = false; 168480093f4SDimitry Andric 169480093f4SDimitry Andric llvm::StringRef str = "lldb.debugger = nil; " 170480093f4SDimitry Andric "lldb.target = nil; " 171480093f4SDimitry Andric "lldb.process = nil; " 172480093f4SDimitry Andric "lldb.thread = nil; " 173480093f4SDimitry Andric "lldb.frame = nil"; 174480093f4SDimitry Andric return m_lua->Run(str); 175480093f4SDimitry Andric } 176480093f4SDimitry Andric 177480093f4SDimitry Andric lldb::ScriptInterpreterSP 178480093f4SDimitry Andric ScriptInterpreterLua::CreateInstance(Debugger &debugger) { 179480093f4SDimitry Andric return std::make_shared<ScriptInterpreterLua>(debugger); 180480093f4SDimitry Andric } 181480093f4SDimitry Andric 182480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginNameStatic() { 183480093f4SDimitry Andric static ConstString g_name("script-lua"); 184480093f4SDimitry Andric return g_name; 185480093f4SDimitry Andric } 186480093f4SDimitry Andric 187480093f4SDimitry Andric const char *ScriptInterpreterLua::GetPluginDescriptionStatic() { 188480093f4SDimitry Andric return "Lua script interpreter"; 189480093f4SDimitry Andric } 190480093f4SDimitry Andric 191480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginName() { 192480093f4SDimitry Andric return GetPluginNameStatic(); 193480093f4SDimitry Andric } 194480093f4SDimitry Andric 195480093f4SDimitry Andric uint32_t ScriptInterpreterLua::GetPluginVersion() { return 1; } 196480093f4SDimitry Andric 197480093f4SDimitry Andric Lua &ScriptInterpreterLua::GetLua() { return *m_lua; } 198