xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
1*480093f4SDimitry Andric //===-- ScriptInterpreterLua.cpp --------------------------------*- C++ -*-===//
2*480093f4SDimitry Andric //
3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*480093f4SDimitry Andric //
7*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8*480093f4SDimitry Andric 
9*480093f4SDimitry Andric #include "ScriptInterpreterLua.h"
10*480093f4SDimitry Andric #include "Lua.h"
11*480093f4SDimitry Andric #include "lldb/Core/Debugger.h"
12*480093f4SDimitry Andric #include "lldb/Core/PluginManager.h"
13*480093f4SDimitry Andric #include "lldb/Core/StreamFile.h"
14*480093f4SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
15*480093f4SDimitry Andric #include "lldb/Utility/Stream.h"
16*480093f4SDimitry Andric #include "lldb/Utility/StringList.h"
17*480093f4SDimitry Andric #include "lldb/Utility/Timer.h"
18*480093f4SDimitry Andric 
19*480093f4SDimitry Andric using namespace lldb;
20*480093f4SDimitry Andric using namespace lldb_private;
21*480093f4SDimitry Andric 
22*480093f4SDimitry Andric class IOHandlerLuaInterpreter : public IOHandlerDelegate,
23*480093f4SDimitry Andric                                 public IOHandlerEditline {
24*480093f4SDimitry Andric public:
25*480093f4SDimitry Andric   IOHandlerLuaInterpreter(Debugger &debugger,
26*480093f4SDimitry Andric                           ScriptInterpreterLua &script_interpreter)
27*480093f4SDimitry Andric       : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua",
28*480093f4SDimitry Andric                           ">>> ", "..> ", true, debugger.GetUseColor(), 0,
29*480093f4SDimitry Andric                           *this, nullptr),
30*480093f4SDimitry Andric         m_script_interpreter(script_interpreter) {
31*480093f4SDimitry Andric     llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID()));
32*480093f4SDimitry Andric   }
33*480093f4SDimitry Andric 
34*480093f4SDimitry Andric   ~IOHandlerLuaInterpreter() {
35*480093f4SDimitry Andric     llvm::cantFail(m_script_interpreter.LeaveSession());
36*480093f4SDimitry Andric   }
37*480093f4SDimitry Andric 
38*480093f4SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
39*480093f4SDimitry Andric                               std::string &data) override {
40*480093f4SDimitry Andric     if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) {
41*480093f4SDimitry Andric       *GetOutputStreamFileSP() << llvm::toString(std::move(error));
42*480093f4SDimitry Andric     }
43*480093f4SDimitry Andric   }
44*480093f4SDimitry Andric 
45*480093f4SDimitry Andric private:
46*480093f4SDimitry Andric   ScriptInterpreterLua &m_script_interpreter;
47*480093f4SDimitry Andric };
48*480093f4SDimitry Andric 
49*480093f4SDimitry Andric ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger)
50*480093f4SDimitry Andric     : ScriptInterpreter(debugger, eScriptLanguageLua),
51*480093f4SDimitry Andric       m_lua(std::make_unique<Lua>()) {}
52*480093f4SDimitry Andric 
53*480093f4SDimitry Andric ScriptInterpreterLua::~ScriptInterpreterLua() {}
54*480093f4SDimitry Andric 
55*480093f4SDimitry Andric bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command,
56*480093f4SDimitry Andric                                           CommandReturnObject *result,
57*480093f4SDimitry Andric                                           const ExecuteScriptOptions &options) {
58*480093f4SDimitry Andric   if (llvm::Error e = m_lua->Run(command)) {
59*480093f4SDimitry Andric     result->AppendErrorWithFormatv(
60*480093f4SDimitry Andric         "lua failed attempting to evaluate '{0}': {1}\n", command,
61*480093f4SDimitry Andric         llvm::toString(std::move(e)));
62*480093f4SDimitry Andric     return false;
63*480093f4SDimitry Andric   }
64*480093f4SDimitry Andric   return true;
65*480093f4SDimitry Andric }
66*480093f4SDimitry Andric 
67*480093f4SDimitry Andric void ScriptInterpreterLua::ExecuteInterpreterLoop() {
68*480093f4SDimitry Andric   static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
69*480093f4SDimitry Andric   Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
70*480093f4SDimitry Andric 
71*480093f4SDimitry Andric   Debugger &debugger = m_debugger;
72*480093f4SDimitry Andric 
73*480093f4SDimitry Andric   // At the moment, the only time the debugger does not have an input file
74*480093f4SDimitry Andric   // handle is when this is called directly from lua, in which case it is
75*480093f4SDimitry Andric   // both dangerous and unnecessary (not to mention confusing) to try to embed
76*480093f4SDimitry Andric   // a running interpreter loop inside the already running lua interpreter
77*480093f4SDimitry Andric   // loop, so we won't do it.
78*480093f4SDimitry Andric 
79*480093f4SDimitry Andric   if (!debugger.GetInputFile().IsValid())
80*480093f4SDimitry Andric     return;
81*480093f4SDimitry Andric 
82*480093f4SDimitry Andric   IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(debugger, *this));
83*480093f4SDimitry Andric   debugger.PushIOHandler(io_handler_sp);
84*480093f4SDimitry Andric }
85*480093f4SDimitry Andric 
86*480093f4SDimitry Andric bool ScriptInterpreterLua::LoadScriptingModule(
87*480093f4SDimitry Andric     const char *filename, bool init_session, lldb_private::Status &error,
88*480093f4SDimitry Andric     StructuredData::ObjectSP *module_sp) {
89*480093f4SDimitry Andric 
90*480093f4SDimitry Andric   if (llvm::Error e = m_lua->LoadModule(filename)) {
91*480093f4SDimitry Andric     error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n",
92*480093f4SDimitry Andric                                     filename, llvm::toString(std::move(e)));
93*480093f4SDimitry Andric     return false;
94*480093f4SDimitry Andric   }
95*480093f4SDimitry Andric   return true;
96*480093f4SDimitry Andric }
97*480093f4SDimitry Andric 
98*480093f4SDimitry Andric void ScriptInterpreterLua::Initialize() {
99*480093f4SDimitry Andric   static llvm::once_flag g_once_flag;
100*480093f4SDimitry Andric 
101*480093f4SDimitry Andric   llvm::call_once(g_once_flag, []() {
102*480093f4SDimitry Andric     PluginManager::RegisterPlugin(GetPluginNameStatic(),
103*480093f4SDimitry Andric                                   GetPluginDescriptionStatic(),
104*480093f4SDimitry Andric                                   lldb::eScriptLanguageLua, CreateInstance);
105*480093f4SDimitry Andric   });
106*480093f4SDimitry Andric }
107*480093f4SDimitry Andric 
108*480093f4SDimitry Andric void ScriptInterpreterLua::Terminate() {}
109*480093f4SDimitry Andric 
110*480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) {
111*480093f4SDimitry Andric   if (m_session_is_active)
112*480093f4SDimitry Andric     return llvm::Error::success();
113*480093f4SDimitry Andric 
114*480093f4SDimitry Andric   const char *fmt_str =
115*480093f4SDimitry Andric       "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); "
116*480093f4SDimitry Andric       "lldb.target = lldb.debugger:GetSelectedTarget(); "
117*480093f4SDimitry Andric       "lldb.process = lldb.target:GetProcess(); "
118*480093f4SDimitry Andric       "lldb.thread = lldb.process:GetSelectedThread(); "
119*480093f4SDimitry Andric       "lldb.frame = lldb.thread:GetSelectedFrame()";
120*480093f4SDimitry Andric   return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str());
121*480093f4SDimitry Andric }
122*480093f4SDimitry Andric 
123*480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::LeaveSession() {
124*480093f4SDimitry Andric   if (!m_session_is_active)
125*480093f4SDimitry Andric     return llvm::Error::success();
126*480093f4SDimitry Andric 
127*480093f4SDimitry Andric   m_session_is_active = false;
128*480093f4SDimitry Andric 
129*480093f4SDimitry Andric   llvm::StringRef str = "lldb.debugger = nil; "
130*480093f4SDimitry Andric                         "lldb.target = nil; "
131*480093f4SDimitry Andric                         "lldb.process = nil; "
132*480093f4SDimitry Andric                         "lldb.thread = nil; "
133*480093f4SDimitry Andric                         "lldb.frame = nil";
134*480093f4SDimitry Andric   return m_lua->Run(str);
135*480093f4SDimitry Andric }
136*480093f4SDimitry Andric 
137*480093f4SDimitry Andric lldb::ScriptInterpreterSP
138*480093f4SDimitry Andric ScriptInterpreterLua::CreateInstance(Debugger &debugger) {
139*480093f4SDimitry Andric   return std::make_shared<ScriptInterpreterLua>(debugger);
140*480093f4SDimitry Andric }
141*480093f4SDimitry Andric 
142*480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginNameStatic() {
143*480093f4SDimitry Andric   static ConstString g_name("script-lua");
144*480093f4SDimitry Andric   return g_name;
145*480093f4SDimitry Andric }
146*480093f4SDimitry Andric 
147*480093f4SDimitry Andric const char *ScriptInterpreterLua::GetPluginDescriptionStatic() {
148*480093f4SDimitry Andric   return "Lua script interpreter";
149*480093f4SDimitry Andric }
150*480093f4SDimitry Andric 
151*480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginName() {
152*480093f4SDimitry Andric   return GetPluginNameStatic();
153*480093f4SDimitry Andric }
154*480093f4SDimitry Andric 
155*480093f4SDimitry Andric uint32_t ScriptInterpreterLua::GetPluginVersion() { return 1; }
156*480093f4SDimitry Andric 
157*480093f4SDimitry Andric Lua &ScriptInterpreterLua::GetLua() { return *m_lua; }
158