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"
10480093f4SDimitry Andric #include "lldb/Host/FileSystem.h"
11480093f4SDimitry Andric #include "lldb/Utility/FileSpec.h"
12af732203SDimitry Andric #include "llvm/Support/Error.h"
13480093f4SDimitry Andric #include "llvm/Support/FormatVariadic.h"
14480093f4SDimitry Andric
15480093f4SDimitry Andric using namespace lldb_private;
16480093f4SDimitry Andric using namespace lldb;
17480093f4SDimitry Andric
18af732203SDimitry Andric #pragma clang diagnostic push
19af732203SDimitry Andric #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
20af732203SDimitry Andric
21af732203SDimitry Andric // Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has
22af732203SDimitry Andric // C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is
23af732203SDimitry Andric // incompatible with C
24af732203SDimitry Andric #if _MSC_VER
25af732203SDimitry Andric #pragma warning (push)
26af732203SDimitry Andric #pragma warning (disable : 4190)
27af732203SDimitry Andric #endif
28af732203SDimitry Andric
29af732203SDimitry Andric extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction(
30af732203SDimitry Andric lua_State *L, lldb::StackFrameSP stop_frame_sp,
31af732203SDimitry Andric lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl);
32af732203SDimitry Andric
33*5f7ddb14SDimitry Andric extern "C" llvm::Expected<bool> LLDBSwigLuaWatchpointCallbackFunction(
34*5f7ddb14SDimitry Andric lua_State *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp);
35*5f7ddb14SDimitry Andric
36af732203SDimitry Andric #if _MSC_VER
37af732203SDimitry Andric #pragma warning (pop)
38af732203SDimitry Andric #endif
39af732203SDimitry Andric
40af732203SDimitry Andric #pragma clang diagnostic pop
41af732203SDimitry Andric
lldb_print(lua_State * L)42af732203SDimitry Andric static int lldb_print(lua_State *L) {
43af732203SDimitry Andric int n = lua_gettop(L);
44af732203SDimitry Andric lua_getglobal(L, "io");
45af732203SDimitry Andric lua_getfield(L, -1, "stdout");
46af732203SDimitry Andric lua_getfield(L, -1, "write");
47af732203SDimitry Andric for (int i = 1; i <= n; i++) {
48af732203SDimitry Andric lua_pushvalue(L, -1); // write()
49af732203SDimitry Andric lua_pushvalue(L, -3); // io.stdout
50af732203SDimitry Andric luaL_tolstring(L, i, nullptr);
51af732203SDimitry Andric lua_pushstring(L, i != n ? "\t" : "\n");
52af732203SDimitry Andric lua_call(L, 3, 0);
53af732203SDimitry Andric }
54af732203SDimitry Andric return 0;
55af732203SDimitry Andric }
56af732203SDimitry Andric
Lua()57af732203SDimitry Andric Lua::Lua() : m_lua_state(luaL_newstate()) {
58af732203SDimitry Andric assert(m_lua_state);
59af732203SDimitry Andric luaL_openlibs(m_lua_state);
60af732203SDimitry Andric luaopen_lldb(m_lua_state);
61af732203SDimitry Andric lua_pushcfunction(m_lua_state, lldb_print);
62af732203SDimitry Andric lua_setglobal(m_lua_state, "print");
63af732203SDimitry Andric }
64af732203SDimitry Andric
~Lua()65af732203SDimitry Andric Lua::~Lua() {
66af732203SDimitry Andric assert(m_lua_state);
67af732203SDimitry Andric lua_close(m_lua_state);
68af732203SDimitry Andric }
69af732203SDimitry Andric
Run(llvm::StringRef buffer)70480093f4SDimitry Andric llvm::Error Lua::Run(llvm::StringRef buffer) {
71480093f4SDimitry Andric int error =
72480093f4SDimitry Andric luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||
73480093f4SDimitry Andric lua_pcall(m_lua_state, 0, 0, 0);
74af732203SDimitry Andric if (error == LUA_OK)
75480093f4SDimitry Andric return llvm::Error::success();
76480093f4SDimitry Andric
77480093f4SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
78480093f4SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
79480093f4SDimitry Andric llvm::inconvertibleErrorCode());
80480093f4SDimitry Andric // Pop error message from the stack.
81480093f4SDimitry Andric lua_pop(m_lua_state, 1);
82480093f4SDimitry Andric return e;
83480093f4SDimitry Andric }
84480093f4SDimitry Andric
RegisterBreakpointCallback(void * baton,const char * body)85af732203SDimitry Andric llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) {
86af732203SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
87af732203SDimitry Andric const char *fmt_str = "return function(frame, bp_loc, ...) {0} end";
88af732203SDimitry Andric std::string func_str = llvm::formatv(fmt_str, body).str();
89af732203SDimitry Andric if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {
90af732203SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
91af732203SDimitry Andric llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),
92af732203SDimitry Andric llvm::inconvertibleErrorCode());
93af732203SDimitry Andric // Pop error message from the stack.
94af732203SDimitry Andric lua_pop(m_lua_state, 2);
95af732203SDimitry Andric return e;
96af732203SDimitry Andric }
97af732203SDimitry Andric lua_settable(m_lua_state, LUA_REGISTRYINDEX);
98af732203SDimitry Andric return llvm::Error::success();
99af732203SDimitry Andric }
100af732203SDimitry Andric
101af732203SDimitry Andric llvm::Expected<bool>
CallBreakpointCallback(void * baton,lldb::StackFrameSP stop_frame_sp,lldb::BreakpointLocationSP bp_loc_sp,StructuredData::ObjectSP extra_args_sp)102af732203SDimitry Andric Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
103af732203SDimitry Andric lldb::BreakpointLocationSP bp_loc_sp,
104af732203SDimitry Andric StructuredData::ObjectSP extra_args_sp) {
105af732203SDimitry Andric
106af732203SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
107af732203SDimitry Andric lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
108af732203SDimitry Andric auto *extra_args_impl = [&]() -> StructuredDataImpl * {
109af732203SDimitry Andric if (extra_args_sp == nullptr)
110af732203SDimitry Andric return nullptr;
111af732203SDimitry Andric auto *extra_args_impl = new StructuredDataImpl();
112af732203SDimitry Andric extra_args_impl->SetObjectSP(extra_args_sp);
113af732203SDimitry Andric return extra_args_impl;
114af732203SDimitry Andric }();
115af732203SDimitry Andric return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp,
116af732203SDimitry Andric bp_loc_sp, extra_args_impl);
117af732203SDimitry Andric }
118af732203SDimitry Andric
RegisterWatchpointCallback(void * baton,const char * body)119*5f7ddb14SDimitry Andric llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) {
120*5f7ddb14SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
121*5f7ddb14SDimitry Andric const char *fmt_str = "return function(frame, wp, ...) {0} end";
122*5f7ddb14SDimitry Andric std::string func_str = llvm::formatv(fmt_str, body).str();
123*5f7ddb14SDimitry Andric if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {
124*5f7ddb14SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
125*5f7ddb14SDimitry Andric llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),
126*5f7ddb14SDimitry Andric llvm::inconvertibleErrorCode());
127*5f7ddb14SDimitry Andric // Pop error message from the stack.
128*5f7ddb14SDimitry Andric lua_pop(m_lua_state, 2);
129*5f7ddb14SDimitry Andric return e;
130*5f7ddb14SDimitry Andric }
131*5f7ddb14SDimitry Andric lua_settable(m_lua_state, LUA_REGISTRYINDEX);
132*5f7ddb14SDimitry Andric return llvm::Error::success();
133*5f7ddb14SDimitry Andric }
134*5f7ddb14SDimitry Andric
135*5f7ddb14SDimitry Andric llvm::Expected<bool>
CallWatchpointCallback(void * baton,lldb::StackFrameSP stop_frame_sp,lldb::WatchpointSP wp_sp)136*5f7ddb14SDimitry Andric Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
137*5f7ddb14SDimitry Andric lldb::WatchpointSP wp_sp) {
138*5f7ddb14SDimitry Andric
139*5f7ddb14SDimitry Andric lua_pushlightuserdata(m_lua_state, baton);
140*5f7ddb14SDimitry Andric lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
141*5f7ddb14SDimitry Andric return LLDBSwigLuaWatchpointCallbackFunction(m_lua_state, stop_frame_sp,
142*5f7ddb14SDimitry Andric wp_sp);
143*5f7ddb14SDimitry Andric }
144*5f7ddb14SDimitry Andric
CheckSyntax(llvm::StringRef buffer)145af732203SDimitry Andric llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {
146af732203SDimitry Andric int error =
147af732203SDimitry Andric luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer");
148af732203SDimitry Andric if (error == LUA_OK) {
149af732203SDimitry Andric // Pop buffer
150af732203SDimitry Andric lua_pop(m_lua_state, 1);
151af732203SDimitry Andric return llvm::Error::success();
152af732203SDimitry Andric }
153af732203SDimitry Andric
154af732203SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
155af732203SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
156af732203SDimitry Andric llvm::inconvertibleErrorCode());
157af732203SDimitry Andric // Pop error message from the stack.
158af732203SDimitry Andric lua_pop(m_lua_state, 1);
159af732203SDimitry Andric return e;
160af732203SDimitry Andric }
161af732203SDimitry Andric
LoadModule(llvm::StringRef filename)162480093f4SDimitry Andric llvm::Error Lua::LoadModule(llvm::StringRef filename) {
163480093f4SDimitry Andric FileSpec file(filename);
164480093f4SDimitry Andric if (!FileSystem::Instance().Exists(file)) {
165480093f4SDimitry Andric return llvm::make_error<llvm::StringError>("invalid path",
166480093f4SDimitry Andric llvm::inconvertibleErrorCode());
167480093f4SDimitry Andric }
168480093f4SDimitry Andric
169480093f4SDimitry Andric ConstString module_extension = file.GetFileNameExtension();
170480093f4SDimitry Andric if (module_extension != ".lua") {
171480093f4SDimitry Andric return llvm::make_error<llvm::StringError>("invalid extension",
172480093f4SDimitry Andric llvm::inconvertibleErrorCode());
173480093f4SDimitry Andric }
174480093f4SDimitry Andric
175480093f4SDimitry Andric int error = luaL_loadfile(m_lua_state, filename.data()) ||
176480093f4SDimitry Andric lua_pcall(m_lua_state, 0, 1, 0);
177af732203SDimitry Andric if (error != LUA_OK) {
178480093f4SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>(
179480093f4SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
180480093f4SDimitry Andric llvm::inconvertibleErrorCode());
181480093f4SDimitry Andric // Pop error message from the stack.
182480093f4SDimitry Andric lua_pop(m_lua_state, 1);
183480093f4SDimitry Andric return e;
184480093f4SDimitry Andric }
185480093f4SDimitry Andric
186480093f4SDimitry Andric ConstString module_name = file.GetFileNameStrippingExtension();
187480093f4SDimitry Andric lua_setglobal(m_lua_state, module_name.GetCString());
188480093f4SDimitry Andric return llvm::Error::success();
189480093f4SDimitry Andric }
1905ffd83dbSDimitry Andric
ChangeIO(FILE * out,FILE * err)1915ffd83dbSDimitry Andric llvm::Error Lua::ChangeIO(FILE *out, FILE *err) {
1925ffd83dbSDimitry Andric assert(out != nullptr);
1935ffd83dbSDimitry Andric assert(err != nullptr);
1945ffd83dbSDimitry Andric
1955ffd83dbSDimitry Andric lua_getglobal(m_lua_state, "io");
1965ffd83dbSDimitry Andric
1975ffd83dbSDimitry Andric lua_getfield(m_lua_state, -1, "stdout");
1985ffd83dbSDimitry Andric if (luaL_Stream *s = static_cast<luaL_Stream *>(
1995ffd83dbSDimitry Andric luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
2005ffd83dbSDimitry Andric s->f = out;
2015ffd83dbSDimitry Andric lua_pop(m_lua_state, 1);
2025ffd83dbSDimitry Andric } else {
2035ffd83dbSDimitry Andric lua_pop(m_lua_state, 2);
2045ffd83dbSDimitry Andric return llvm::make_error<llvm::StringError>("could not get stdout",
2055ffd83dbSDimitry Andric llvm::inconvertibleErrorCode());
2065ffd83dbSDimitry Andric }
2075ffd83dbSDimitry Andric
2085ffd83dbSDimitry Andric lua_getfield(m_lua_state, -1, "stderr");
2095ffd83dbSDimitry Andric if (luaL_Stream *s = static_cast<luaL_Stream *>(
2105ffd83dbSDimitry Andric luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
2115ffd83dbSDimitry Andric s->f = out;
2125ffd83dbSDimitry Andric lua_pop(m_lua_state, 1);
2135ffd83dbSDimitry Andric } else {
2145ffd83dbSDimitry Andric lua_pop(m_lua_state, 2);
2155ffd83dbSDimitry Andric return llvm::make_error<llvm::StringError>("could not get stderr",
2165ffd83dbSDimitry Andric llvm::inconvertibleErrorCode());
2175ffd83dbSDimitry Andric }
2185ffd83dbSDimitry Andric
2195ffd83dbSDimitry Andric lua_pop(m_lua_state, 1);
2205ffd83dbSDimitry Andric return llvm::Error::success();
2215ffd83dbSDimitry Andric }
222