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" 10*0eae32dcSDimitry 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 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 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 42e8d8bef9SDimitry Andric Lua::~Lua() { 43e8d8bef9SDimitry Andric assert(m_lua_state); 44e8d8bef9SDimitry Andric lua_close(m_lua_state); 45e8d8bef9SDimitry Andric } 46e8d8bef9SDimitry Andric 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 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> 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); 85*0eae32dcSDimitry Andric StructuredDataImpl extra_args_impl(std::move(extra_args_sp)); 86e8d8bef9SDimitry Andric return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, 87e8d8bef9SDimitry Andric bp_loc_sp, extra_args_impl); 88e8d8bef9SDimitry Andric } 89e8d8bef9SDimitry Andric 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> 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); 112fe6060f1SDimitry Andric return LLDBSwigLuaWatchpointCallbackFunction(m_lua_state, stop_frame_sp, 113fe6060f1SDimitry Andric wp_sp); 114fe6060f1SDimitry Andric } 115fe6060f1SDimitry Andric 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 133480093f4SDimitry Andric llvm::Error Lua::LoadModule(llvm::StringRef filename) { 134480093f4SDimitry Andric 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 140480093f4SDimitry Andric ConstString module_extension = file.GetFileNameExtension(); 141480093f4SDimitry Andric if (module_extension != ".lua") { 142480093f4SDimitry Andric return llvm::make_error<llvm::StringError>("invalid extension", 143480093f4SDimitry Andric llvm::inconvertibleErrorCode()); 144480093f4SDimitry Andric } 145480093f4SDimitry Andric 146480093f4SDimitry Andric int error = luaL_loadfile(m_lua_state, filename.data()) || 147480093f4SDimitry Andric lua_pcall(m_lua_state, 0, 1, 0); 148e8d8bef9SDimitry Andric if (error != LUA_OK) { 149480093f4SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>( 150480093f4SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 151480093f4SDimitry Andric llvm::inconvertibleErrorCode()); 152480093f4SDimitry Andric // Pop error message from the stack. 153480093f4SDimitry Andric lua_pop(m_lua_state, 1); 154480093f4SDimitry Andric return e; 155480093f4SDimitry Andric } 156480093f4SDimitry Andric 157480093f4SDimitry Andric ConstString module_name = file.GetFileNameStrippingExtension(); 158480093f4SDimitry Andric lua_setglobal(m_lua_state, module_name.GetCString()); 159480093f4SDimitry Andric return llvm::Error::success(); 160480093f4SDimitry Andric } 1615ffd83dbSDimitry Andric 1625ffd83dbSDimitry Andric llvm::Error Lua::ChangeIO(FILE *out, FILE *err) { 1635ffd83dbSDimitry Andric assert(out != nullptr); 1645ffd83dbSDimitry Andric assert(err != nullptr); 1655ffd83dbSDimitry Andric 1665ffd83dbSDimitry Andric lua_getglobal(m_lua_state, "io"); 1675ffd83dbSDimitry Andric 1685ffd83dbSDimitry Andric lua_getfield(m_lua_state, -1, "stdout"); 1695ffd83dbSDimitry Andric if (luaL_Stream *s = static_cast<luaL_Stream *>( 1705ffd83dbSDimitry Andric luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 1715ffd83dbSDimitry Andric s->f = out; 1725ffd83dbSDimitry Andric lua_pop(m_lua_state, 1); 1735ffd83dbSDimitry Andric } else { 1745ffd83dbSDimitry Andric lua_pop(m_lua_state, 2); 1755ffd83dbSDimitry Andric return llvm::make_error<llvm::StringError>("could not get stdout", 1765ffd83dbSDimitry Andric llvm::inconvertibleErrorCode()); 1775ffd83dbSDimitry Andric } 1785ffd83dbSDimitry Andric 1795ffd83dbSDimitry Andric lua_getfield(m_lua_state, -1, "stderr"); 1805ffd83dbSDimitry Andric if (luaL_Stream *s = static_cast<luaL_Stream *>( 1815ffd83dbSDimitry Andric luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 1825ffd83dbSDimitry Andric s->f = out; 1835ffd83dbSDimitry Andric lua_pop(m_lua_state, 1); 1845ffd83dbSDimitry Andric } else { 1855ffd83dbSDimitry Andric lua_pop(m_lua_state, 2); 1865ffd83dbSDimitry Andric return llvm::make_error<llvm::StringError>("could not get stderr", 1875ffd83dbSDimitry Andric llvm::inconvertibleErrorCode()); 1885ffd83dbSDimitry Andric } 1895ffd83dbSDimitry Andric 1905ffd83dbSDimitry Andric lua_pop(m_lua_state, 1); 1915ffd83dbSDimitry Andric return llvm::Error::success(); 1925ffd83dbSDimitry Andric } 193