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 29532e4203SPedro Tammela extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction( 30532e4203SPedro Tammela lua_State *L, lldb::StackFrameSP stop_frame_sp, 31532e4203SPedro Tammela lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl); 32a0d7406aSPedro Tammela 33*e81ba283SSiger Yang extern "C" llvm::Expected<bool> LLDBSwigLuaWatchpointCallbackFunction( 34*e81ba283SSiger Yang lua_State *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp); 35*e81ba283SSiger Yang 36a0d7406aSPedro Tammela #if _MSC_VER 37a0d7406aSPedro Tammela #pragma warning (pop) 38a0d7406aSPedro Tammela #endif 39a0d7406aSPedro Tammela 40a0d7406aSPedro Tammela #pragma clang diagnostic pop 41a0d7406aSPedro Tammela 42ca175710SPedro Tammela static int lldb_print(lua_State *L) { 43ca175710SPedro Tammela int n = lua_gettop(L); 44ca175710SPedro Tammela lua_getglobal(L, "io"); 45ca175710SPedro Tammela lua_getfield(L, -1, "stdout"); 46ca175710SPedro Tammela lua_getfield(L, -1, "write"); 47ca175710SPedro Tammela for (int i = 1; i <= n; i++) { 48ca175710SPedro Tammela lua_pushvalue(L, -1); // write() 49ca175710SPedro Tammela lua_pushvalue(L, -3); // io.stdout 50ca175710SPedro Tammela luaL_tolstring(L, i, nullptr); 51ca175710SPedro Tammela lua_pushstring(L, i != n ? "\t" : "\n"); 52ca175710SPedro Tammela lua_call(L, 3, 0); 53ca175710SPedro Tammela } 54ca175710SPedro Tammela return 0; 55ca175710SPedro Tammela } 56ca175710SPedro Tammela 57ca175710SPedro Tammela Lua::Lua() : m_lua_state(luaL_newstate()) { 58ca175710SPedro Tammela assert(m_lua_state); 59ca175710SPedro Tammela luaL_openlibs(m_lua_state); 60ca175710SPedro Tammela luaopen_lldb(m_lua_state); 61ca175710SPedro Tammela lua_pushcfunction(m_lua_state, lldb_print); 62ca175710SPedro Tammela lua_setglobal(m_lua_state, "print"); 63ca175710SPedro Tammela } 64ca175710SPedro Tammela 65ca175710SPedro Tammela Lua::~Lua() { 66ca175710SPedro Tammela assert(m_lua_state); 67ca175710SPedro Tammela lua_close(m_lua_state); 68ca175710SPedro Tammela } 69ca175710SPedro Tammela 7028613242SJonas Devlieghere llvm::Error Lua::Run(llvm::StringRef buffer) { 7128613242SJonas Devlieghere int error = 7228613242SJonas Devlieghere luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") || 7328613242SJonas Devlieghere lua_pcall(m_lua_state, 0, 0, 0); 744b9fa3b7SPedro Tammela if (error == LUA_OK) 7528613242SJonas Devlieghere return llvm::Error::success(); 7628613242SJonas Devlieghere 7728613242SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 7828613242SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 7928613242SJonas Devlieghere llvm::inconvertibleErrorCode()); 8028613242SJonas Devlieghere // Pop error message from the stack. 8128613242SJonas Devlieghere lua_pop(m_lua_state, 1); 8228613242SJonas Devlieghere return e; 8328613242SJonas Devlieghere } 84572b9f46SJonas Devlieghere 85a0d7406aSPedro Tammela llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) { 86a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 87a0d7406aSPedro Tammela const char *fmt_str = "return function(frame, bp_loc, ...) {0} end"; 88a0d7406aSPedro Tammela std::string func_str = llvm::formatv(fmt_str, body).str(); 89a0d7406aSPedro Tammela if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 90a0d7406aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 91280ae107SPedro Tammela llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 92a0d7406aSPedro Tammela llvm::inconvertibleErrorCode()); 93a0d7406aSPedro Tammela // Pop error message from the stack. 94a0d7406aSPedro Tammela lua_pop(m_lua_state, 2); 95a0d7406aSPedro Tammela return e; 96a0d7406aSPedro Tammela } 97a0d7406aSPedro Tammela lua_settable(m_lua_state, LUA_REGISTRYINDEX); 98a0d7406aSPedro Tammela return llvm::Error::success(); 99a0d7406aSPedro Tammela } 100a0d7406aSPedro Tammela 101a0d7406aSPedro Tammela llvm::Expected<bool> 102a0d7406aSPedro Tammela Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 103532e4203SPedro Tammela lldb::BreakpointLocationSP bp_loc_sp, 104532e4203SPedro Tammela StructuredData::ObjectSP extra_args_sp) { 105532e4203SPedro Tammela 106a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 107a0d7406aSPedro Tammela lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 108532e4203SPedro Tammela auto *extra_args_impl = [&]() -> StructuredDataImpl * { 109532e4203SPedro Tammela if (extra_args_sp == nullptr) 110532e4203SPedro Tammela return nullptr; 111532e4203SPedro Tammela auto *extra_args_impl = new StructuredDataImpl(); 112532e4203SPedro Tammela extra_args_impl->SetObjectSP(extra_args_sp); 113532e4203SPedro Tammela return extra_args_impl; 114532e4203SPedro Tammela }(); 115a0d7406aSPedro Tammela return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, 116532e4203SPedro Tammela bp_loc_sp, extra_args_impl); 117a0d7406aSPedro Tammela } 118a0d7406aSPedro Tammela 119*e81ba283SSiger Yang llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) { 120*e81ba283SSiger Yang lua_pushlightuserdata(m_lua_state, baton); 121*e81ba283SSiger Yang const char *fmt_str = "return function(frame, wp, ...) {0} end"; 122*e81ba283SSiger Yang std::string func_str = llvm::formatv(fmt_str, body).str(); 123*e81ba283SSiger Yang if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 124*e81ba283SSiger Yang llvm::Error e = llvm::make_error<llvm::StringError>( 125*e81ba283SSiger Yang llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 126*e81ba283SSiger Yang llvm::inconvertibleErrorCode()); 127*e81ba283SSiger Yang // Pop error message from the stack. 128*e81ba283SSiger Yang lua_pop(m_lua_state, 2); 129*e81ba283SSiger Yang return e; 130*e81ba283SSiger Yang } 131*e81ba283SSiger Yang lua_settable(m_lua_state, LUA_REGISTRYINDEX); 132*e81ba283SSiger Yang return llvm::Error::success(); 133*e81ba283SSiger Yang } 134*e81ba283SSiger Yang 135*e81ba283SSiger Yang llvm::Expected<bool> 136*e81ba283SSiger Yang Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 137*e81ba283SSiger Yang lldb::WatchpointSP wp_sp) { 138*e81ba283SSiger Yang 139*e81ba283SSiger Yang lua_pushlightuserdata(m_lua_state, baton); 140*e81ba283SSiger Yang lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 141*e81ba283SSiger Yang return LLDBSwigLuaWatchpointCallbackFunction(m_lua_state, stop_frame_sp, 142*e81ba283SSiger Yang wp_sp); 143*e81ba283SSiger Yang } 144*e81ba283SSiger Yang 145d853bd7aSPedro Tammela llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) { 146d853bd7aSPedro Tammela int error = 147d853bd7aSPedro Tammela luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer"); 148d853bd7aSPedro Tammela if (error == LUA_OK) { 149d853bd7aSPedro Tammela // Pop buffer 150d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 151d853bd7aSPedro Tammela return llvm::Error::success(); 152d853bd7aSPedro Tammela } 153d853bd7aSPedro Tammela 154d853bd7aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 155d853bd7aSPedro Tammela llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 156d853bd7aSPedro Tammela llvm::inconvertibleErrorCode()); 157d853bd7aSPedro Tammela // Pop error message from the stack. 158d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 159d853bd7aSPedro Tammela return e; 160d853bd7aSPedro Tammela } 161d853bd7aSPedro Tammela 162572b9f46SJonas Devlieghere llvm::Error Lua::LoadModule(llvm::StringRef filename) { 163572b9f46SJonas Devlieghere FileSpec file(filename); 164572b9f46SJonas Devlieghere if (!FileSystem::Instance().Exists(file)) { 165572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid path", 166572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 167572b9f46SJonas Devlieghere } 168572b9f46SJonas Devlieghere 169572b9f46SJonas Devlieghere ConstString module_extension = file.GetFileNameExtension(); 170572b9f46SJonas Devlieghere if (module_extension != ".lua") { 171572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid extension", 172572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 173572b9f46SJonas Devlieghere } 174572b9f46SJonas Devlieghere 175572b9f46SJonas Devlieghere int error = luaL_loadfile(m_lua_state, filename.data()) || 176572b9f46SJonas Devlieghere lua_pcall(m_lua_state, 0, 1, 0); 1774b9fa3b7SPedro Tammela if (error != LUA_OK) { 178572b9f46SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 179572b9f46SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 180572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 181572b9f46SJonas Devlieghere // Pop error message from the stack. 182572b9f46SJonas Devlieghere lua_pop(m_lua_state, 1); 183572b9f46SJonas Devlieghere return e; 184572b9f46SJonas Devlieghere } 185572b9f46SJonas Devlieghere 186572b9f46SJonas Devlieghere ConstString module_name = file.GetFileNameStrippingExtension(); 187572b9f46SJonas Devlieghere lua_setglobal(m_lua_state, module_name.GetCString()); 188572b9f46SJonas Devlieghere return llvm::Error::success(); 189572b9f46SJonas Devlieghere } 190fa1b4a96SJonas Devlieghere 191fa1b4a96SJonas Devlieghere llvm::Error Lua::ChangeIO(FILE *out, FILE *err) { 192fa1b4a96SJonas Devlieghere assert(out != nullptr); 193fa1b4a96SJonas Devlieghere assert(err != nullptr); 194fa1b4a96SJonas Devlieghere 195fa1b4a96SJonas Devlieghere lua_getglobal(m_lua_state, "io"); 196fa1b4a96SJonas Devlieghere 197fa1b4a96SJonas Devlieghere lua_getfield(m_lua_state, -1, "stdout"); 198fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 199fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 200fa1b4a96SJonas Devlieghere s->f = out; 201fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 202fa1b4a96SJonas Devlieghere } else { 203fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 204fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stdout", 205fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 206fa1b4a96SJonas Devlieghere } 207fa1b4a96SJonas Devlieghere 208be494adbSJonas Devlieghere lua_getfield(m_lua_state, -1, "stderr"); 209fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 210fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 211fa1b4a96SJonas Devlieghere s->f = out; 212fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 213fa1b4a96SJonas Devlieghere } else { 214fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 215fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stderr", 216fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 217fa1b4a96SJonas Devlieghere } 218fa1b4a96SJonas Devlieghere 219fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 220fa1b4a96SJonas Devlieghere return llvm::Error::success(); 221fa1b4a96SJonas Devlieghere } 222