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 29a0d7406aSPedro Tammela extern "C" llvm::Expected<bool> 30a0d7406aSPedro Tammela LLDBSwigLuaBreakpointCallbackFunction(lua_State *L, 31a0d7406aSPedro Tammela lldb::StackFrameSP stop_frame_sp, 32a0d7406aSPedro Tammela lldb::BreakpointLocationSP bp_loc_sp); 33a0d7406aSPedro Tammela 34a0d7406aSPedro Tammela #if _MSC_VER 35a0d7406aSPedro Tammela #pragma warning (pop) 36a0d7406aSPedro Tammela #endif 37a0d7406aSPedro Tammela 38a0d7406aSPedro Tammela #pragma clang diagnostic pop 39a0d7406aSPedro Tammela 40ca175710SPedro Tammela static int lldb_print(lua_State *L) { 41ca175710SPedro Tammela int n = lua_gettop(L); 42ca175710SPedro Tammela lua_getglobal(L, "io"); 43ca175710SPedro Tammela lua_getfield(L, -1, "stdout"); 44ca175710SPedro Tammela lua_getfield(L, -1, "write"); 45ca175710SPedro Tammela for (int i = 1; i <= n; i++) { 46ca175710SPedro Tammela lua_pushvalue(L, -1); // write() 47ca175710SPedro Tammela lua_pushvalue(L, -3); // io.stdout 48ca175710SPedro Tammela luaL_tolstring(L, i, nullptr); 49ca175710SPedro Tammela lua_pushstring(L, i != n ? "\t" : "\n"); 50ca175710SPedro Tammela lua_call(L, 3, 0); 51ca175710SPedro Tammela } 52ca175710SPedro Tammela return 0; 53ca175710SPedro Tammela } 54ca175710SPedro Tammela 55ca175710SPedro Tammela Lua::Lua() : m_lua_state(luaL_newstate()) { 56ca175710SPedro Tammela assert(m_lua_state); 57ca175710SPedro Tammela luaL_openlibs(m_lua_state); 58ca175710SPedro Tammela luaopen_lldb(m_lua_state); 59ca175710SPedro Tammela lua_pushcfunction(m_lua_state, lldb_print); 60ca175710SPedro Tammela lua_setglobal(m_lua_state, "print"); 61ca175710SPedro Tammela } 62ca175710SPedro Tammela 63ca175710SPedro Tammela Lua::~Lua() { 64ca175710SPedro Tammela assert(m_lua_state); 65ca175710SPedro Tammela lua_close(m_lua_state); 66ca175710SPedro Tammela } 67ca175710SPedro Tammela 6828613242SJonas Devlieghere llvm::Error Lua::Run(llvm::StringRef buffer) { 6928613242SJonas Devlieghere int error = 7028613242SJonas Devlieghere luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") || 7128613242SJonas Devlieghere lua_pcall(m_lua_state, 0, 0, 0); 724b9fa3b7SPedro Tammela if (error == LUA_OK) 7328613242SJonas Devlieghere return llvm::Error::success(); 7428613242SJonas Devlieghere 7528613242SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 7628613242SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 7728613242SJonas Devlieghere llvm::inconvertibleErrorCode()); 7828613242SJonas Devlieghere // Pop error message from the stack. 7928613242SJonas Devlieghere lua_pop(m_lua_state, 1); 8028613242SJonas Devlieghere return e; 8128613242SJonas Devlieghere } 82572b9f46SJonas Devlieghere 83a0d7406aSPedro Tammela llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) { 84a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 85a0d7406aSPedro Tammela const char *fmt_str = "return function(frame, bp_loc, ...) {0} end"; 86a0d7406aSPedro Tammela std::string func_str = llvm::formatv(fmt_str, body).str(); 87a0d7406aSPedro Tammela if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 88a0d7406aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 89280ae107SPedro Tammela llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 90a0d7406aSPedro Tammela llvm::inconvertibleErrorCode()); 91a0d7406aSPedro Tammela // Pop error message from the stack. 92a0d7406aSPedro Tammela lua_pop(m_lua_state, 2); 93a0d7406aSPedro Tammela return e; 94a0d7406aSPedro Tammela } 95a0d7406aSPedro Tammela lua_settable(m_lua_state, LUA_REGISTRYINDEX); 96a0d7406aSPedro Tammela return llvm::Error::success(); 97a0d7406aSPedro Tammela } 98a0d7406aSPedro Tammela 99a0d7406aSPedro Tammela llvm::Expected<bool> 100a0d7406aSPedro Tammela Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 101a0d7406aSPedro Tammela lldb::BreakpointLocationSP bp_loc_sp) { 102a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 103a0d7406aSPedro Tammela lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 104a0d7406aSPedro Tammela return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, 105a0d7406aSPedro Tammela bp_loc_sp); 106a0d7406aSPedro Tammela } 107a0d7406aSPedro Tammela 108*d853bd7aSPedro Tammela llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) { 109*d853bd7aSPedro Tammela int error = 110*d853bd7aSPedro Tammela luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer"); 111*d853bd7aSPedro Tammela if (error == LUA_OK) { 112*d853bd7aSPedro Tammela // Pop buffer 113*d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 114*d853bd7aSPedro Tammela return llvm::Error::success(); 115*d853bd7aSPedro Tammela } 116*d853bd7aSPedro Tammela 117*d853bd7aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 118*d853bd7aSPedro Tammela llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 119*d853bd7aSPedro Tammela llvm::inconvertibleErrorCode()); 120*d853bd7aSPedro Tammela // Pop error message from the stack. 121*d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 122*d853bd7aSPedro Tammela return e; 123*d853bd7aSPedro Tammela } 124*d853bd7aSPedro Tammela 125572b9f46SJonas Devlieghere llvm::Error Lua::LoadModule(llvm::StringRef filename) { 126572b9f46SJonas Devlieghere FileSpec file(filename); 127572b9f46SJonas Devlieghere if (!FileSystem::Instance().Exists(file)) { 128572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid path", 129572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 130572b9f46SJonas Devlieghere } 131572b9f46SJonas Devlieghere 132572b9f46SJonas Devlieghere ConstString module_extension = file.GetFileNameExtension(); 133572b9f46SJonas Devlieghere if (module_extension != ".lua") { 134572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid extension", 135572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 136572b9f46SJonas Devlieghere } 137572b9f46SJonas Devlieghere 138572b9f46SJonas Devlieghere int error = luaL_loadfile(m_lua_state, filename.data()) || 139572b9f46SJonas Devlieghere lua_pcall(m_lua_state, 0, 1, 0); 1404b9fa3b7SPedro Tammela if (error != LUA_OK) { 141572b9f46SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 142572b9f46SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 143572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 144572b9f46SJonas Devlieghere // Pop error message from the stack. 145572b9f46SJonas Devlieghere lua_pop(m_lua_state, 1); 146572b9f46SJonas Devlieghere return e; 147572b9f46SJonas Devlieghere } 148572b9f46SJonas Devlieghere 149572b9f46SJonas Devlieghere ConstString module_name = file.GetFileNameStrippingExtension(); 150572b9f46SJonas Devlieghere lua_setglobal(m_lua_state, module_name.GetCString()); 151572b9f46SJonas Devlieghere return llvm::Error::success(); 152572b9f46SJonas Devlieghere } 153fa1b4a96SJonas Devlieghere 154fa1b4a96SJonas Devlieghere llvm::Error Lua::ChangeIO(FILE *out, FILE *err) { 155fa1b4a96SJonas Devlieghere assert(out != nullptr); 156fa1b4a96SJonas Devlieghere assert(err != nullptr); 157fa1b4a96SJonas Devlieghere 158fa1b4a96SJonas Devlieghere lua_getglobal(m_lua_state, "io"); 159fa1b4a96SJonas Devlieghere 160fa1b4a96SJonas Devlieghere lua_getfield(m_lua_state, -1, "stdout"); 161fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 162fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 163fa1b4a96SJonas Devlieghere s->f = out; 164fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 165fa1b4a96SJonas Devlieghere } else { 166fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 167fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stdout", 168fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 169fa1b4a96SJonas Devlieghere } 170fa1b4a96SJonas Devlieghere 171be494adbSJonas Devlieghere lua_getfield(m_lua_state, -1, "stderr"); 172fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 173fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 174fa1b4a96SJonas Devlieghere s->f = out; 175fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 176fa1b4a96SJonas Devlieghere } else { 177fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 178fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stderr", 179fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 180fa1b4a96SJonas Devlieghere } 181fa1b4a96SJonas Devlieghere 182fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 183fa1b4a96SJonas Devlieghere return llvm::Error::success(); 184fa1b4a96SJonas Devlieghere } 185