1480093f4SDimitry Andric //===-- Lua.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 "Lua.h"
100eae32dcSDimitry Andric #include "SWIGLuaBridge.h"
11480093f4SDimitry Andric #include "lldb/Host/FileSystem.h"
12480093f4SDimitry Andric #include "lldb/Utility/FileSpec.h"
13e8d8bef9SDimitry Andric #include "llvm/Support/Error.h"
14480093f4SDimitry Andric #include "llvm/Support/FormatVariadic.h"
15480093f4SDimitry Andric
16480093f4SDimitry Andric using namespace lldb_private;
17480093f4SDimitry Andric using namespace lldb;
18480093f4SDimitry Andric
lldb_print(lua_State * L)19e8d8bef9SDimitry Andric static int lldb_print(lua_State *L) {
20e8d8bef9SDimitry Andric int n = lua_gettop(L);
21e8d8bef9SDimitry Andric lua_getglobal(L, "io");
22e8d8bef9SDimitry Andric lua_getfield(L, -1, "stdout");
23e8d8bef9SDimitry Andric lua_getfield(L, -1, "write");
24e8d8bef9SDimitry Andric for (int i = 1; i <= n; i++) {
25e8d8bef9SDimitry Andric lua_pushvalue(L, -1); // write()
26e8d8bef9SDimitry Andric lua_pushvalue(L, -3); // io.stdout
27e8d8bef9SDimitry Andric luaL_tolstring(L, i, nullptr);
28e8d8bef9SDimitry Andric lua_pushstring(L, i != n ? "\t" : "\n");
29e8d8bef9SDimitry Andric lua_call(L, 3, 0);
30e8d8bef9SDimitry Andric }
31e8d8bef9SDimitry Andric return 0;
32e8d8bef9SDimitry Andric }
33e8d8bef9SDimitry Andric
Lua()34e8d8bef9SDimitry Andric Lua::Lua() : m_lua_state(luaL_newstate()) {
35e8d8bef9SDimitry Andric assert(m_lua_state);
36e8d8bef9SDimitry Andric luaL_openlibs(m_lua_state);
37e8d8bef9SDimitry Andric luaopen_lldb(m_lua_state);
38e8d8bef9SDimitry Andric lua_pushcfunction(m_lua_state, lldb_print);
39e8d8bef9SDimitry Andric lua_setglobal(m_lua_state, "print");
40e8d8bef9SDimitry Andric }
41e8d8bef9SDimitry Andric
~Lua()42e8d8bef9SDimitry Andric Lua::~Lua() {
43e8d8bef9SDimitry Andric assert(m_lua_state);
44e8d8bef9SDimitry Andric lua_close(m_lua_state);
45e8d8bef9SDimitry Andric }
46e8d8bef9SDimitry Andric
Run(llvm::StringRef buffer)47480093f4SDimitry Andric llvm::Error Lua::Run(llvm::StringRef buffer) {
48480093f4SDimitry Andric int error =
49480093f4SDimitry Andric luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||
50480093f4SDimitry Andric lua_pcall(m_lua_state, 0, 0, 0);
51e8d8bef9SDimitry Andric if (error == LUA_OK)
52480093f4SDimitry Andric return llvm::Error::success();
53480093f4SDimitry Andric
54480093f4SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
55480093f4SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
56480093f4SDimitry Andric llvm::inconvertibleErrorCode());
57480093f4SDimitry Andric // Pop error message from the stack.
58480093f4SDimitry Andric lua_pop(m_lua_state, 1);
59480093f4SDimitry Andric return e;
60480093f4SDimitry Andric }
61480093f4SDimitry Andric
RegisterBreakpointCallback(void * baton,const char * body)62e8d8bef9SDimitry Andric llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) {
63e8d8bef9SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
64e8d8bef9SDimitry Andric const char *fmt_str = "return function(frame, bp_loc, ...) {0} end";
65e8d8bef9SDimitry Andric std::string func_str = llvm::formatv(fmt_str, body).str();
66e8d8bef9SDimitry Andric if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {
67e8d8bef9SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
68e8d8bef9SDimitry Andric llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),
69e8d8bef9SDimitry Andric llvm::inconvertibleErrorCode());
70e8d8bef9SDimitry Andric // Pop error message from the stack.
71e8d8bef9SDimitry Andric lua_pop(m_lua_state, 2);
72e8d8bef9SDimitry Andric return e;
73e8d8bef9SDimitry Andric }
74e8d8bef9SDimitry Andric lua_settable(m_lua_state, LUA_REGISTRYINDEX);
75e8d8bef9SDimitry Andric return llvm::Error::success();
76e8d8bef9SDimitry Andric }
77e8d8bef9SDimitry Andric
78e8d8bef9SDimitry Andric llvm::Expected<bool>
CallBreakpointCallback(void * baton,lldb::StackFrameSP stop_frame_sp,lldb::BreakpointLocationSP bp_loc_sp,StructuredData::ObjectSP extra_args_sp)79e8d8bef9SDimitry Andric Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
80e8d8bef9SDimitry Andric lldb::BreakpointLocationSP bp_loc_sp,
81e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) {
82e8d8bef9SDimitry Andric
83e8d8bef9SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
84e8d8bef9SDimitry Andric lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
850eae32dcSDimitry Andric StructuredDataImpl extra_args_impl(std::move(extra_args_sp));
86*06c3fb27SDimitry Andric return lua::SWIGBridge::LLDBSwigLuaBreakpointCallbackFunction(
87*06c3fb27SDimitry Andric m_lua_state, stop_frame_sp, bp_loc_sp, extra_args_impl);
88e8d8bef9SDimitry Andric }
89e8d8bef9SDimitry Andric
RegisterWatchpointCallback(void * baton,const char * body)90fe6060f1SDimitry Andric llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) {
91fe6060f1SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
92fe6060f1SDimitry Andric const char *fmt_str = "return function(frame, wp, ...) {0} end";
93fe6060f1SDimitry Andric std::string func_str = llvm::formatv(fmt_str, body).str();
94fe6060f1SDimitry Andric if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {
95fe6060f1SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
96fe6060f1SDimitry Andric llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),
97fe6060f1SDimitry Andric llvm::inconvertibleErrorCode());
98fe6060f1SDimitry Andric // Pop error message from the stack.
99fe6060f1SDimitry Andric lua_pop(m_lua_state, 2);
100fe6060f1SDimitry Andric return e;
101fe6060f1SDimitry Andric }
102fe6060f1SDimitry Andric lua_settable(m_lua_state, LUA_REGISTRYINDEX);
103fe6060f1SDimitry Andric return llvm::Error::success();
104fe6060f1SDimitry Andric }
105fe6060f1SDimitry Andric
106fe6060f1SDimitry Andric llvm::Expected<bool>
CallWatchpointCallback(void * baton,lldb::StackFrameSP stop_frame_sp,lldb::WatchpointSP wp_sp)107fe6060f1SDimitry Andric Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
108fe6060f1SDimitry Andric lldb::WatchpointSP wp_sp) {
109fe6060f1SDimitry Andric
110fe6060f1SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
111fe6060f1SDimitry Andric lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
112*06c3fb27SDimitry Andric return lua::SWIGBridge::LLDBSwigLuaWatchpointCallbackFunction(
113*06c3fb27SDimitry Andric m_lua_state, stop_frame_sp, wp_sp);
114fe6060f1SDimitry Andric }
115fe6060f1SDimitry Andric
CheckSyntax(llvm::StringRef buffer)116e8d8bef9SDimitry Andric llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {
117e8d8bef9SDimitry Andric int error =
118e8d8bef9SDimitry Andric luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer");
119e8d8bef9SDimitry Andric if (error == LUA_OK) {
120e8d8bef9SDimitry Andric // Pop buffer
121e8d8bef9SDimitry Andric lua_pop(m_lua_state, 1);
122e8d8bef9SDimitry Andric return llvm::Error::success();
123e8d8bef9SDimitry Andric }
124e8d8bef9SDimitry Andric
125e8d8bef9SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
126e8d8bef9SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
127e8d8bef9SDimitry Andric llvm::inconvertibleErrorCode());
128e8d8bef9SDimitry Andric // Pop error message from the stack.
129e8d8bef9SDimitry Andric lua_pop(m_lua_state, 1);
130e8d8bef9SDimitry Andric return e;
131e8d8bef9SDimitry Andric }
132e8d8bef9SDimitry Andric
LoadModule(llvm::StringRef filename)133480093f4SDimitry Andric llvm::Error Lua::LoadModule(llvm::StringRef filename) {
134*06c3fb27SDimitry Andric const FileSpec file(filename);
135480093f4SDimitry Andric if (!FileSystem::Instance().Exists(file)) {
136480093f4SDimitry Andric return llvm::make_error<llvm::StringError>("invalid path",
137480093f4SDimitry Andric llvm::inconvertibleErrorCode());
138480093f4SDimitry Andric }
139480093f4SDimitry Andric
140*06c3fb27SDimitry Andric if (file.GetFileNameExtension() != ".lua") {
141480093f4SDimitry Andric return llvm::make_error<llvm::StringError>("invalid extension",
142480093f4SDimitry Andric llvm::inconvertibleErrorCode());
143480093f4SDimitry Andric }
144480093f4SDimitry Andric
145480093f4SDimitry Andric int error = luaL_loadfile(m_lua_state, filename.data()) ||
146480093f4SDimitry Andric lua_pcall(m_lua_state, 0, 1, 0);
147e8d8bef9SDimitry Andric if (error != LUA_OK) {
148480093f4SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
149480093f4SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
150480093f4SDimitry Andric llvm::inconvertibleErrorCode());
151480093f4SDimitry Andric // Pop error message from the stack.
152480093f4SDimitry Andric lua_pop(m_lua_state, 1);
153480093f4SDimitry Andric return e;
154480093f4SDimitry Andric }
155480093f4SDimitry Andric
156480093f4SDimitry Andric ConstString module_name = file.GetFileNameStrippingExtension();
157480093f4SDimitry Andric lua_setglobal(m_lua_state, module_name.GetCString());
158480093f4SDimitry Andric return llvm::Error::success();
159480093f4SDimitry Andric }
1605ffd83dbSDimitry Andric
ChangeIO(FILE * out,FILE * err)1615ffd83dbSDimitry Andric llvm::Error Lua::ChangeIO(FILE *out, FILE *err) {
1625ffd83dbSDimitry Andric assert(out != nullptr);
1635ffd83dbSDimitry Andric assert(err != nullptr);
1645ffd83dbSDimitry Andric
1655ffd83dbSDimitry Andric lua_getglobal(m_lua_state, "io");
1665ffd83dbSDimitry Andric
1675ffd83dbSDimitry Andric lua_getfield(m_lua_state, -1, "stdout");
1685ffd83dbSDimitry Andric if (luaL_Stream *s = static_cast<luaL_Stream *>(
1695ffd83dbSDimitry Andric luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
1705ffd83dbSDimitry Andric s->f = out;
1715ffd83dbSDimitry Andric lua_pop(m_lua_state, 1);
1725ffd83dbSDimitry Andric } else {
1735ffd83dbSDimitry Andric lua_pop(m_lua_state, 2);
1745ffd83dbSDimitry Andric return llvm::make_error<llvm::StringError>("could not get stdout",
1755ffd83dbSDimitry Andric llvm::inconvertibleErrorCode());
1765ffd83dbSDimitry Andric }
1775ffd83dbSDimitry Andric
1785ffd83dbSDimitry Andric lua_getfield(m_lua_state, -1, "stderr");
1795ffd83dbSDimitry Andric if (luaL_Stream *s = static_cast<luaL_Stream *>(
1805ffd83dbSDimitry Andric luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
1815ffd83dbSDimitry Andric s->f = out;
1825ffd83dbSDimitry Andric lua_pop(m_lua_state, 1);
1835ffd83dbSDimitry Andric } else {
1845ffd83dbSDimitry Andric lua_pop(m_lua_state, 2);
1855ffd83dbSDimitry Andric return llvm::make_error<llvm::StringError>("could not get stderr",
1865ffd83dbSDimitry Andric llvm::inconvertibleErrorCode());
1875ffd83dbSDimitry Andric }
1885ffd83dbSDimitry Andric
1895ffd83dbSDimitry Andric lua_pop(m_lua_state, 1);
1905ffd83dbSDimitry Andric return llvm::Error::success();
1915ffd83dbSDimitry Andric }
192