xref: /src/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1706b4fc4SDimitry Andric //===-- Lua.cpp -----------------------------------------------------------===//
2706b4fc4SDimitry Andric //
3706b4fc4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4706b4fc4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5706b4fc4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6706b4fc4SDimitry Andric //
7706b4fc4SDimitry Andric //===----------------------------------------------------------------------===//
8706b4fc4SDimitry Andric 
9706b4fc4SDimitry Andric #include "Lua.h"
1077fc4c14SDimitry Andric #include "SWIGLuaBridge.h"
11706b4fc4SDimitry Andric #include "lldb/Host/FileSystem.h"
12706b4fc4SDimitry Andric #include "lldb/Utility/FileSpec.h"
13b60736ecSDimitry Andric #include "llvm/Support/Error.h"
14706b4fc4SDimitry Andric #include "llvm/Support/FormatVariadic.h"
15706b4fc4SDimitry Andric 
16706b4fc4SDimitry Andric using namespace lldb_private;
17706b4fc4SDimitry Andric using namespace lldb;
18706b4fc4SDimitry Andric 
lldb_print(lua_State * L)19b60736ecSDimitry Andric static int lldb_print(lua_State *L) {
20b60736ecSDimitry Andric   int n = lua_gettop(L);
21b60736ecSDimitry Andric   lua_getglobal(L, "io");
22b60736ecSDimitry Andric   lua_getfield(L, -1, "stdout");
23b60736ecSDimitry Andric   lua_getfield(L, -1, "write");
24b60736ecSDimitry Andric   for (int i = 1; i <= n; i++) {
25b60736ecSDimitry Andric     lua_pushvalue(L, -1); // write()
26b60736ecSDimitry Andric     lua_pushvalue(L, -3); // io.stdout
27b60736ecSDimitry Andric     luaL_tolstring(L, i, nullptr);
28b60736ecSDimitry Andric     lua_pushstring(L, i != n ? "\t" : "\n");
29b60736ecSDimitry Andric     lua_call(L, 3, 0);
30b60736ecSDimitry Andric   }
31b60736ecSDimitry Andric   return 0;
32b60736ecSDimitry Andric }
33b60736ecSDimitry Andric 
Lua()34b60736ecSDimitry Andric Lua::Lua() : m_lua_state(luaL_newstate()) {
35b60736ecSDimitry Andric   assert(m_lua_state);
36b60736ecSDimitry Andric   luaL_openlibs(m_lua_state);
37b60736ecSDimitry Andric   luaopen_lldb(m_lua_state);
38b60736ecSDimitry Andric   lua_pushcfunction(m_lua_state, lldb_print);
39b60736ecSDimitry Andric   lua_setglobal(m_lua_state, "print");
40b60736ecSDimitry Andric }
41b60736ecSDimitry Andric 
~Lua()42b60736ecSDimitry Andric Lua::~Lua() {
43b60736ecSDimitry Andric   assert(m_lua_state);
44b60736ecSDimitry Andric   lua_close(m_lua_state);
45b60736ecSDimitry Andric }
46b60736ecSDimitry Andric 
Run(llvm::StringRef buffer)47706b4fc4SDimitry Andric llvm::Error Lua::Run(llvm::StringRef buffer) {
48706b4fc4SDimitry Andric   int error =
49706b4fc4SDimitry Andric       luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||
50706b4fc4SDimitry Andric       lua_pcall(m_lua_state, 0, 0, 0);
51b60736ecSDimitry Andric   if (error == LUA_OK)
52706b4fc4SDimitry Andric     return llvm::Error::success();
53706b4fc4SDimitry Andric 
54706b4fc4SDimitry Andric   llvm::Error e = llvm::make_error<llvm::StringError>(
55706b4fc4SDimitry Andric       llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
56706b4fc4SDimitry Andric       llvm::inconvertibleErrorCode());
57706b4fc4SDimitry Andric   // Pop error message from the stack.
58706b4fc4SDimitry Andric   lua_pop(m_lua_state, 1);
59706b4fc4SDimitry Andric   return e;
60706b4fc4SDimitry Andric }
61706b4fc4SDimitry Andric 
RegisterBreakpointCallback(void * baton,const char * body)62b60736ecSDimitry Andric llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) {
63b60736ecSDimitry Andric   lua_pushlightuserdata(m_lua_state, baton);
64b60736ecSDimitry Andric   const char *fmt_str = "return function(frame, bp_loc, ...) {0} end";
65b60736ecSDimitry Andric   std::string func_str = llvm::formatv(fmt_str, body).str();
66b60736ecSDimitry Andric   if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {
67b60736ecSDimitry Andric     llvm::Error e = llvm::make_error<llvm::StringError>(
68b60736ecSDimitry Andric         llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),
69b60736ecSDimitry Andric         llvm::inconvertibleErrorCode());
70b60736ecSDimitry Andric     // Pop error message from the stack.
71b60736ecSDimitry Andric     lua_pop(m_lua_state, 2);
72b60736ecSDimitry Andric     return e;
73b60736ecSDimitry Andric   }
74b60736ecSDimitry Andric   lua_settable(m_lua_state, LUA_REGISTRYINDEX);
75b60736ecSDimitry Andric   return llvm::Error::success();
76b60736ecSDimitry Andric }
77b60736ecSDimitry Andric 
78b60736ecSDimitry Andric llvm::Expected<bool>
CallBreakpointCallback(void * baton,lldb::StackFrameSP stop_frame_sp,lldb::BreakpointLocationSP bp_loc_sp,StructuredData::ObjectSP extra_args_sp)79b60736ecSDimitry Andric Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
80b60736ecSDimitry Andric                             lldb::BreakpointLocationSP bp_loc_sp,
81b60736ecSDimitry Andric                             StructuredData::ObjectSP extra_args_sp) {
82b60736ecSDimitry Andric 
83b60736ecSDimitry Andric   lua_pushlightuserdata(m_lua_state, baton);
84b60736ecSDimitry Andric   lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
8577fc4c14SDimitry Andric   StructuredDataImpl extra_args_impl(std::move(extra_args_sp));
867fa27ce4SDimitry Andric   return lua::SWIGBridge::LLDBSwigLuaBreakpointCallbackFunction(
877fa27ce4SDimitry Andric       m_lua_state, stop_frame_sp, bp_loc_sp, extra_args_impl);
88b60736ecSDimitry Andric }
89b60736ecSDimitry Andric 
RegisterWatchpointCallback(void * baton,const char * body)90344a3780SDimitry Andric llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) {
91344a3780SDimitry Andric   lua_pushlightuserdata(m_lua_state, baton);
92344a3780SDimitry Andric   const char *fmt_str = "return function(frame, wp, ...) {0} end";
93344a3780SDimitry Andric   std::string func_str = llvm::formatv(fmt_str, body).str();
94344a3780SDimitry Andric   if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {
95344a3780SDimitry Andric     llvm::Error e = llvm::make_error<llvm::StringError>(
96344a3780SDimitry Andric         llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),
97344a3780SDimitry Andric         llvm::inconvertibleErrorCode());
98344a3780SDimitry Andric     // Pop error message from the stack.
99344a3780SDimitry Andric     lua_pop(m_lua_state, 2);
100344a3780SDimitry Andric     return e;
101344a3780SDimitry Andric   }
102344a3780SDimitry Andric   lua_settable(m_lua_state, LUA_REGISTRYINDEX);
103344a3780SDimitry Andric   return llvm::Error::success();
104344a3780SDimitry Andric }
105344a3780SDimitry Andric 
106344a3780SDimitry Andric llvm::Expected<bool>
CallWatchpointCallback(void * baton,lldb::StackFrameSP stop_frame_sp,lldb::WatchpointSP wp_sp)107344a3780SDimitry Andric Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
108344a3780SDimitry Andric                             lldb::WatchpointSP wp_sp) {
109344a3780SDimitry Andric 
110344a3780SDimitry Andric   lua_pushlightuserdata(m_lua_state, baton);
111344a3780SDimitry Andric   lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
1127fa27ce4SDimitry Andric   return lua::SWIGBridge::LLDBSwigLuaWatchpointCallbackFunction(
1137fa27ce4SDimitry Andric       m_lua_state, stop_frame_sp, wp_sp);
114344a3780SDimitry Andric }
115344a3780SDimitry Andric 
CheckSyntax(llvm::StringRef buffer)116b60736ecSDimitry Andric llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {
117b60736ecSDimitry Andric   int error =
118b60736ecSDimitry Andric       luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer");
119b60736ecSDimitry Andric   if (error == LUA_OK) {
120b60736ecSDimitry Andric     // Pop buffer
121b60736ecSDimitry Andric     lua_pop(m_lua_state, 1);
122b60736ecSDimitry Andric     return llvm::Error::success();
123b60736ecSDimitry Andric   }
124b60736ecSDimitry Andric 
125b60736ecSDimitry Andric   llvm::Error e = llvm::make_error<llvm::StringError>(
126b60736ecSDimitry Andric       llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
127b60736ecSDimitry Andric       llvm::inconvertibleErrorCode());
128b60736ecSDimitry Andric   // Pop error message from the stack.
129b60736ecSDimitry Andric   lua_pop(m_lua_state, 1);
130b60736ecSDimitry Andric   return e;
131b60736ecSDimitry Andric }
132b60736ecSDimitry Andric 
LoadModule(llvm::StringRef filename)133706b4fc4SDimitry Andric llvm::Error Lua::LoadModule(llvm::StringRef filename) {
1347fa27ce4SDimitry Andric   const FileSpec file(filename);
135706b4fc4SDimitry Andric   if (!FileSystem::Instance().Exists(file)) {
136706b4fc4SDimitry Andric     return llvm::make_error<llvm::StringError>("invalid path",
137706b4fc4SDimitry Andric                                                llvm::inconvertibleErrorCode());
138706b4fc4SDimitry Andric   }
139706b4fc4SDimitry Andric 
1407fa27ce4SDimitry Andric   if (file.GetFileNameExtension() != ".lua") {
141706b4fc4SDimitry Andric     return llvm::make_error<llvm::StringError>("invalid extension",
142706b4fc4SDimitry Andric                                                llvm::inconvertibleErrorCode());
143706b4fc4SDimitry Andric   }
144706b4fc4SDimitry Andric 
145706b4fc4SDimitry Andric   int error = luaL_loadfile(m_lua_state, filename.data()) ||
146706b4fc4SDimitry Andric               lua_pcall(m_lua_state, 0, 1, 0);
147b60736ecSDimitry Andric   if (error != LUA_OK) {
148706b4fc4SDimitry Andric     llvm::Error e = llvm::make_error<llvm::StringError>(
149706b4fc4SDimitry Andric         llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
150706b4fc4SDimitry Andric         llvm::inconvertibleErrorCode());
151706b4fc4SDimitry Andric     // Pop error message from the stack.
152706b4fc4SDimitry Andric     lua_pop(m_lua_state, 1);
153706b4fc4SDimitry Andric     return e;
154706b4fc4SDimitry Andric   }
155706b4fc4SDimitry Andric 
156706b4fc4SDimitry Andric   ConstString module_name = file.GetFileNameStrippingExtension();
157706b4fc4SDimitry Andric   lua_setglobal(m_lua_state, module_name.GetCString());
158706b4fc4SDimitry Andric   return llvm::Error::success();
159706b4fc4SDimitry Andric }
160cfca06d7SDimitry Andric 
ChangeIO(FILE * out,FILE * err)161cfca06d7SDimitry Andric llvm::Error Lua::ChangeIO(FILE *out, FILE *err) {
162cfca06d7SDimitry Andric   assert(out != nullptr);
163cfca06d7SDimitry Andric   assert(err != nullptr);
164cfca06d7SDimitry Andric 
165cfca06d7SDimitry Andric   lua_getglobal(m_lua_state, "io");
166cfca06d7SDimitry Andric 
167cfca06d7SDimitry Andric   lua_getfield(m_lua_state, -1, "stdout");
168cfca06d7SDimitry Andric   if (luaL_Stream *s = static_cast<luaL_Stream *>(
169cfca06d7SDimitry Andric           luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
170cfca06d7SDimitry Andric     s->f = out;
171cfca06d7SDimitry Andric     lua_pop(m_lua_state, 1);
172cfca06d7SDimitry Andric   } else {
173cfca06d7SDimitry Andric     lua_pop(m_lua_state, 2);
174cfca06d7SDimitry Andric     return llvm::make_error<llvm::StringError>("could not get stdout",
175cfca06d7SDimitry Andric                                                llvm::inconvertibleErrorCode());
176cfca06d7SDimitry Andric   }
177cfca06d7SDimitry Andric 
178cfca06d7SDimitry Andric   lua_getfield(m_lua_state, -1, "stderr");
179cfca06d7SDimitry Andric   if (luaL_Stream *s = static_cast<luaL_Stream *>(
180cfca06d7SDimitry Andric           luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
181cfca06d7SDimitry Andric     s->f = out;
182cfca06d7SDimitry Andric     lua_pop(m_lua_state, 1);
183cfca06d7SDimitry Andric   } else {
184cfca06d7SDimitry Andric     lua_pop(m_lua_state, 2);
185cfca06d7SDimitry Andric     return llvm::make_error<llvm::StringError>("could not get stderr",
186cfca06d7SDimitry Andric                                                llvm::inconvertibleErrorCode());
187cfca06d7SDimitry Andric   }
188cfca06d7SDimitry Andric 
189cfca06d7SDimitry Andric   lua_pop(m_lua_state, 1);
190cfca06d7SDimitry Andric   return llvm::Error::success();
191cfca06d7SDimitry Andric }
192