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