128613242SJonas Devlieghere //===-- Lua.cpp -----------------------------------------------------------===// 228613242SJonas Devlieghere // 328613242SJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 428613242SJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information. 528613242SJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 628613242SJonas Devlieghere // 728613242SJonas Devlieghere //===----------------------------------------------------------------------===// 828613242SJonas Devlieghere 928613242SJonas Devlieghere #include "Lua.h" 10572b9f46SJonas Devlieghere #include "lldb/Host/FileSystem.h" 11572b9f46SJonas Devlieghere #include "lldb/Utility/FileSpec.h" 12a0d7406aSPedro Tammela #include "llvm/Support/Error.h" 1328613242SJonas Devlieghere #include "llvm/Support/FormatVariadic.h" 1428613242SJonas Devlieghere 1528613242SJonas Devlieghere using namespace lldb_private; 1645c971f7SJonas Devlieghere using namespace lldb; 1728613242SJonas Devlieghere 18a0d7406aSPedro Tammela #pragma clang diagnostic push 19a0d7406aSPedro Tammela #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" 20a0d7406aSPedro Tammela 21a0d7406aSPedro Tammela // Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has 22a0d7406aSPedro Tammela // C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is 23a0d7406aSPedro Tammela // incompatible with C 24a0d7406aSPedro Tammela #if _MSC_VER 25a0d7406aSPedro Tammela #pragma warning (push) 26a0d7406aSPedro Tammela #pragma warning (disable : 4190) 27a0d7406aSPedro Tammela #endif 28a0d7406aSPedro Tammela 29*532e4203SPedro Tammela extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction( 30*532e4203SPedro Tammela lua_State *L, lldb::StackFrameSP stop_frame_sp, 31*532e4203SPedro Tammela lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl); 32a0d7406aSPedro Tammela 33a0d7406aSPedro Tammela #if _MSC_VER 34a0d7406aSPedro Tammela #pragma warning (pop) 35a0d7406aSPedro Tammela #endif 36a0d7406aSPedro Tammela 37a0d7406aSPedro Tammela #pragma clang diagnostic pop 38a0d7406aSPedro Tammela 39ca175710SPedro Tammela static int lldb_print(lua_State *L) { 40ca175710SPedro Tammela int n = lua_gettop(L); 41ca175710SPedro Tammela lua_getglobal(L, "io"); 42ca175710SPedro Tammela lua_getfield(L, -1, "stdout"); 43ca175710SPedro Tammela lua_getfield(L, -1, "write"); 44ca175710SPedro Tammela for (int i = 1; i <= n; i++) { 45ca175710SPedro Tammela lua_pushvalue(L, -1); // write() 46ca175710SPedro Tammela lua_pushvalue(L, -3); // io.stdout 47ca175710SPedro Tammela luaL_tolstring(L, i, nullptr); 48ca175710SPedro Tammela lua_pushstring(L, i != n ? "\t" : "\n"); 49ca175710SPedro Tammela lua_call(L, 3, 0); 50ca175710SPedro Tammela } 51ca175710SPedro Tammela return 0; 52ca175710SPedro Tammela } 53ca175710SPedro Tammela 54ca175710SPedro Tammela Lua::Lua() : m_lua_state(luaL_newstate()) { 55ca175710SPedro Tammela assert(m_lua_state); 56ca175710SPedro Tammela luaL_openlibs(m_lua_state); 57ca175710SPedro Tammela luaopen_lldb(m_lua_state); 58ca175710SPedro Tammela lua_pushcfunction(m_lua_state, lldb_print); 59ca175710SPedro Tammela lua_setglobal(m_lua_state, "print"); 60ca175710SPedro Tammela } 61ca175710SPedro Tammela 62ca175710SPedro Tammela Lua::~Lua() { 63ca175710SPedro Tammela assert(m_lua_state); 64ca175710SPedro Tammela lua_close(m_lua_state); 65ca175710SPedro Tammela } 66ca175710SPedro Tammela 6728613242SJonas Devlieghere llvm::Error Lua::Run(llvm::StringRef buffer) { 6828613242SJonas Devlieghere int error = 6928613242SJonas Devlieghere luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") || 7028613242SJonas Devlieghere lua_pcall(m_lua_state, 0, 0, 0); 714b9fa3b7SPedro Tammela if (error == LUA_OK) 7228613242SJonas Devlieghere return llvm::Error::success(); 7328613242SJonas Devlieghere 7428613242SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 7528613242SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 7628613242SJonas Devlieghere llvm::inconvertibleErrorCode()); 7728613242SJonas Devlieghere // Pop error message from the stack. 7828613242SJonas Devlieghere lua_pop(m_lua_state, 1); 7928613242SJonas Devlieghere return e; 8028613242SJonas Devlieghere } 81572b9f46SJonas Devlieghere 82a0d7406aSPedro Tammela llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) { 83a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 84a0d7406aSPedro Tammela const char *fmt_str = "return function(frame, bp_loc, ...) {0} end"; 85a0d7406aSPedro Tammela std::string func_str = llvm::formatv(fmt_str, body).str(); 86a0d7406aSPedro Tammela if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 87a0d7406aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 88280ae107SPedro Tammela llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 89a0d7406aSPedro Tammela llvm::inconvertibleErrorCode()); 90a0d7406aSPedro Tammela // Pop error message from the stack. 91a0d7406aSPedro Tammela lua_pop(m_lua_state, 2); 92a0d7406aSPedro Tammela return e; 93a0d7406aSPedro Tammela } 94a0d7406aSPedro Tammela lua_settable(m_lua_state, LUA_REGISTRYINDEX); 95a0d7406aSPedro Tammela return llvm::Error::success(); 96a0d7406aSPedro Tammela } 97a0d7406aSPedro Tammela 98a0d7406aSPedro Tammela llvm::Expected<bool> 99a0d7406aSPedro Tammela Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 100*532e4203SPedro Tammela lldb::BreakpointLocationSP bp_loc_sp, 101*532e4203SPedro Tammela StructuredData::ObjectSP extra_args_sp) { 102*532e4203SPedro Tammela 103a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 104a0d7406aSPedro Tammela lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 105*532e4203SPedro Tammela auto *extra_args_impl = [&]() -> StructuredDataImpl * { 106*532e4203SPedro Tammela if (extra_args_sp == nullptr) 107*532e4203SPedro Tammela return nullptr; 108*532e4203SPedro Tammela auto *extra_args_impl = new StructuredDataImpl(); 109*532e4203SPedro Tammela extra_args_impl->SetObjectSP(extra_args_sp); 110*532e4203SPedro Tammela return extra_args_impl; 111*532e4203SPedro Tammela }(); 112a0d7406aSPedro Tammela return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, 113*532e4203SPedro Tammela bp_loc_sp, extra_args_impl); 114a0d7406aSPedro Tammela } 115a0d7406aSPedro Tammela 116d853bd7aSPedro Tammela llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) { 117d853bd7aSPedro Tammela int error = 118d853bd7aSPedro Tammela luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer"); 119d853bd7aSPedro Tammela if (error == LUA_OK) { 120d853bd7aSPedro Tammela // Pop buffer 121d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 122d853bd7aSPedro Tammela return llvm::Error::success(); 123d853bd7aSPedro Tammela } 124d853bd7aSPedro Tammela 125d853bd7aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 126d853bd7aSPedro Tammela llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 127d853bd7aSPedro Tammela llvm::inconvertibleErrorCode()); 128d853bd7aSPedro Tammela // Pop error message from the stack. 129d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 130d853bd7aSPedro Tammela return e; 131d853bd7aSPedro Tammela } 132d853bd7aSPedro Tammela 133572b9f46SJonas Devlieghere llvm::Error Lua::LoadModule(llvm::StringRef filename) { 134572b9f46SJonas Devlieghere FileSpec file(filename); 135572b9f46SJonas Devlieghere if (!FileSystem::Instance().Exists(file)) { 136572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid path", 137572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 138572b9f46SJonas Devlieghere } 139572b9f46SJonas Devlieghere 140572b9f46SJonas Devlieghere ConstString module_extension = file.GetFileNameExtension(); 141572b9f46SJonas Devlieghere if (module_extension != ".lua") { 142572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid extension", 143572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 144572b9f46SJonas Devlieghere } 145572b9f46SJonas Devlieghere 146572b9f46SJonas Devlieghere int error = luaL_loadfile(m_lua_state, filename.data()) || 147572b9f46SJonas Devlieghere lua_pcall(m_lua_state, 0, 1, 0); 1484b9fa3b7SPedro Tammela if (error != LUA_OK) { 149572b9f46SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 150572b9f46SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 151572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 152572b9f46SJonas Devlieghere // Pop error message from the stack. 153572b9f46SJonas Devlieghere lua_pop(m_lua_state, 1); 154572b9f46SJonas Devlieghere return e; 155572b9f46SJonas Devlieghere } 156572b9f46SJonas Devlieghere 157572b9f46SJonas Devlieghere ConstString module_name = file.GetFileNameStrippingExtension(); 158572b9f46SJonas Devlieghere lua_setglobal(m_lua_state, module_name.GetCString()); 159572b9f46SJonas Devlieghere return llvm::Error::success(); 160572b9f46SJonas Devlieghere } 161fa1b4a96SJonas Devlieghere 162fa1b4a96SJonas Devlieghere llvm::Error Lua::ChangeIO(FILE *out, FILE *err) { 163fa1b4a96SJonas Devlieghere assert(out != nullptr); 164fa1b4a96SJonas Devlieghere assert(err != nullptr); 165fa1b4a96SJonas Devlieghere 166fa1b4a96SJonas Devlieghere lua_getglobal(m_lua_state, "io"); 167fa1b4a96SJonas Devlieghere 168fa1b4a96SJonas Devlieghere lua_getfield(m_lua_state, -1, "stdout"); 169fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 170fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 171fa1b4a96SJonas Devlieghere s->f = out; 172fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 173fa1b4a96SJonas Devlieghere } else { 174fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 175fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stdout", 176fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 177fa1b4a96SJonas Devlieghere } 178fa1b4a96SJonas Devlieghere 179be494adbSJonas Devlieghere lua_getfield(m_lua_state, -1, "stderr"); 180fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 181fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 182fa1b4a96SJonas Devlieghere s->f = out; 183fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 184fa1b4a96SJonas Devlieghere } else { 185fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 186fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stderr", 187fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 188fa1b4a96SJonas Devlieghere } 189fa1b4a96SJonas Devlieghere 190fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 191fa1b4a96SJonas Devlieghere return llvm::Error::success(); 192fa1b4a96SJonas Devlieghere } 193