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" 12e8d8bef9SDimitry 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 18e8d8bef9SDimitry Andric #pragma clang diagnostic push 19e8d8bef9SDimitry Andric #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" 20e8d8bef9SDimitry Andric 21e8d8bef9SDimitry Andric // Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has 22e8d8bef9SDimitry Andric // C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is 23e8d8bef9SDimitry Andric // incompatible with C 24e8d8bef9SDimitry Andric #if _MSC_VER 25e8d8bef9SDimitry Andric #pragma warning (push) 26e8d8bef9SDimitry Andric #pragma warning (disable : 4190) 27e8d8bef9SDimitry Andric #endif 28e8d8bef9SDimitry Andric 29e8d8bef9SDimitry Andric extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction( 30e8d8bef9SDimitry Andric lua_State *L, lldb::StackFrameSP stop_frame_sp, 31e8d8bef9SDimitry Andric lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl); 32e8d8bef9SDimitry Andric 33*fe6060f1SDimitry Andric extern "C" llvm::Expected<bool> LLDBSwigLuaWatchpointCallbackFunction( 34*fe6060f1SDimitry Andric lua_State *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp); 35*fe6060f1SDimitry Andric 36e8d8bef9SDimitry Andric #if _MSC_VER 37e8d8bef9SDimitry Andric #pragma warning (pop) 38e8d8bef9SDimitry Andric #endif 39e8d8bef9SDimitry Andric 40e8d8bef9SDimitry Andric #pragma clang diagnostic pop 41e8d8bef9SDimitry Andric 42e8d8bef9SDimitry Andric static int lldb_print(lua_State *L) { 43e8d8bef9SDimitry Andric int n = lua_gettop(L); 44e8d8bef9SDimitry Andric lua_getglobal(L, "io"); 45e8d8bef9SDimitry Andric lua_getfield(L, -1, "stdout"); 46e8d8bef9SDimitry Andric lua_getfield(L, -1, "write"); 47e8d8bef9SDimitry Andric for (int i = 1; i <= n; i++) { 48e8d8bef9SDimitry Andric lua_pushvalue(L, -1); // write() 49e8d8bef9SDimitry Andric lua_pushvalue(L, -3); // io.stdout 50e8d8bef9SDimitry Andric luaL_tolstring(L, i, nullptr); 51e8d8bef9SDimitry Andric lua_pushstring(L, i != n ? "\t" : "\n"); 52e8d8bef9SDimitry Andric lua_call(L, 3, 0); 53e8d8bef9SDimitry Andric } 54e8d8bef9SDimitry Andric return 0; 55e8d8bef9SDimitry Andric } 56e8d8bef9SDimitry Andric 57e8d8bef9SDimitry Andric Lua::Lua() : m_lua_state(luaL_newstate()) { 58e8d8bef9SDimitry Andric assert(m_lua_state); 59e8d8bef9SDimitry Andric luaL_openlibs(m_lua_state); 60e8d8bef9SDimitry Andric luaopen_lldb(m_lua_state); 61e8d8bef9SDimitry Andric lua_pushcfunction(m_lua_state, lldb_print); 62e8d8bef9SDimitry Andric lua_setglobal(m_lua_state, "print"); 63e8d8bef9SDimitry Andric } 64e8d8bef9SDimitry Andric 65e8d8bef9SDimitry Andric Lua::~Lua() { 66e8d8bef9SDimitry Andric assert(m_lua_state); 67e8d8bef9SDimitry Andric lua_close(m_lua_state); 68e8d8bef9SDimitry Andric } 69e8d8bef9SDimitry Andric 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); 74e8d8bef9SDimitry 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 85e8d8bef9SDimitry Andric llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) { 86e8d8bef9SDimitry Andric lua_pushlightuserdata(m_lua_state, baton); 87e8d8bef9SDimitry Andric const char *fmt_str = "return function(frame, bp_loc, ...) {0} end"; 88e8d8bef9SDimitry Andric std::string func_str = llvm::formatv(fmt_str, body).str(); 89e8d8bef9SDimitry Andric if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 90e8d8bef9SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>( 91e8d8bef9SDimitry Andric llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 92e8d8bef9SDimitry Andric llvm::inconvertibleErrorCode()); 93e8d8bef9SDimitry Andric // Pop error message from the stack. 94e8d8bef9SDimitry Andric lua_pop(m_lua_state, 2); 95e8d8bef9SDimitry Andric return e; 96e8d8bef9SDimitry Andric } 97e8d8bef9SDimitry Andric lua_settable(m_lua_state, LUA_REGISTRYINDEX); 98e8d8bef9SDimitry Andric return llvm::Error::success(); 99e8d8bef9SDimitry Andric } 100e8d8bef9SDimitry Andric 101e8d8bef9SDimitry Andric llvm::Expected<bool> 102e8d8bef9SDimitry Andric Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 103e8d8bef9SDimitry Andric lldb::BreakpointLocationSP bp_loc_sp, 104e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 105e8d8bef9SDimitry Andric 106e8d8bef9SDimitry Andric lua_pushlightuserdata(m_lua_state, baton); 107e8d8bef9SDimitry Andric lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 108e8d8bef9SDimitry Andric auto *extra_args_impl = [&]() -> StructuredDataImpl * { 109e8d8bef9SDimitry Andric if (extra_args_sp == nullptr) 110e8d8bef9SDimitry Andric return nullptr; 111e8d8bef9SDimitry Andric auto *extra_args_impl = new StructuredDataImpl(); 112e8d8bef9SDimitry Andric extra_args_impl->SetObjectSP(extra_args_sp); 113e8d8bef9SDimitry Andric return extra_args_impl; 114e8d8bef9SDimitry Andric }(); 115e8d8bef9SDimitry Andric return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, 116e8d8bef9SDimitry Andric bp_loc_sp, extra_args_impl); 117e8d8bef9SDimitry Andric } 118e8d8bef9SDimitry Andric 119*fe6060f1SDimitry Andric llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) { 120*fe6060f1SDimitry Andric lua_pushlightuserdata(m_lua_state, baton); 121*fe6060f1SDimitry Andric const char *fmt_str = "return function(frame, wp, ...) {0} end"; 122*fe6060f1SDimitry Andric std::string func_str = llvm::formatv(fmt_str, body).str(); 123*fe6060f1SDimitry Andric if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 124*fe6060f1SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>( 125*fe6060f1SDimitry Andric llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 126*fe6060f1SDimitry Andric llvm::inconvertibleErrorCode()); 127*fe6060f1SDimitry Andric // Pop error message from the stack. 128*fe6060f1SDimitry Andric lua_pop(m_lua_state, 2); 129*fe6060f1SDimitry Andric return e; 130*fe6060f1SDimitry Andric } 131*fe6060f1SDimitry Andric lua_settable(m_lua_state, LUA_REGISTRYINDEX); 132*fe6060f1SDimitry Andric return llvm::Error::success(); 133*fe6060f1SDimitry Andric } 134*fe6060f1SDimitry Andric 135*fe6060f1SDimitry Andric llvm::Expected<bool> 136*fe6060f1SDimitry Andric Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 137*fe6060f1SDimitry Andric lldb::WatchpointSP wp_sp) { 138*fe6060f1SDimitry Andric 139*fe6060f1SDimitry Andric lua_pushlightuserdata(m_lua_state, baton); 140*fe6060f1SDimitry Andric lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 141*fe6060f1SDimitry Andric return LLDBSwigLuaWatchpointCallbackFunction(m_lua_state, stop_frame_sp, 142*fe6060f1SDimitry Andric wp_sp); 143*fe6060f1SDimitry Andric } 144*fe6060f1SDimitry Andric 145e8d8bef9SDimitry Andric llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) { 146e8d8bef9SDimitry Andric int error = 147e8d8bef9SDimitry Andric luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer"); 148e8d8bef9SDimitry Andric if (error == LUA_OK) { 149e8d8bef9SDimitry Andric // Pop buffer 150e8d8bef9SDimitry Andric lua_pop(m_lua_state, 1); 151e8d8bef9SDimitry Andric return llvm::Error::success(); 152e8d8bef9SDimitry Andric } 153e8d8bef9SDimitry Andric 154e8d8bef9SDimitry Andric llvm::Error e = llvm::make_error<llvm::StringError>( 155e8d8bef9SDimitry Andric llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 156e8d8bef9SDimitry Andric llvm::inconvertibleErrorCode()); 157e8d8bef9SDimitry Andric // Pop error message from the stack. 158e8d8bef9SDimitry Andric lua_pop(m_lua_state, 1); 159e8d8bef9SDimitry Andric return e; 160e8d8bef9SDimitry Andric } 161e8d8bef9SDimitry Andric 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); 177e8d8bef9SDimitry 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 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