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" 10*a52af6d3SPavel Labath #include "SWIGLuaBridge.h" 11572b9f46SJonas Devlieghere #include "lldb/Host/FileSystem.h" 12572b9f46SJonas Devlieghere #include "lldb/Utility/FileSpec.h" 13a0d7406aSPedro Tammela #include "llvm/Support/Error.h" 1428613242SJonas Devlieghere #include "llvm/Support/FormatVariadic.h" 1528613242SJonas Devlieghere 1628613242SJonas Devlieghere using namespace lldb_private; 1745c971f7SJonas Devlieghere using namespace lldb; 1828613242SJonas Devlieghere 19ca175710SPedro Tammela static int lldb_print(lua_State *L) { 20ca175710SPedro Tammela int n = lua_gettop(L); 21ca175710SPedro Tammela lua_getglobal(L, "io"); 22ca175710SPedro Tammela lua_getfield(L, -1, "stdout"); 23ca175710SPedro Tammela lua_getfield(L, -1, "write"); 24ca175710SPedro Tammela for (int i = 1; i <= n; i++) { 25ca175710SPedro Tammela lua_pushvalue(L, -1); // write() 26ca175710SPedro Tammela lua_pushvalue(L, -3); // io.stdout 27ca175710SPedro Tammela luaL_tolstring(L, i, nullptr); 28ca175710SPedro Tammela lua_pushstring(L, i != n ? "\t" : "\n"); 29ca175710SPedro Tammela lua_call(L, 3, 0); 30ca175710SPedro Tammela } 31ca175710SPedro Tammela return 0; 32ca175710SPedro Tammela } 33ca175710SPedro Tammela 34ca175710SPedro Tammela Lua::Lua() : m_lua_state(luaL_newstate()) { 35ca175710SPedro Tammela assert(m_lua_state); 36ca175710SPedro Tammela luaL_openlibs(m_lua_state); 37ca175710SPedro Tammela luaopen_lldb(m_lua_state); 38ca175710SPedro Tammela lua_pushcfunction(m_lua_state, lldb_print); 39ca175710SPedro Tammela lua_setglobal(m_lua_state, "print"); 40ca175710SPedro Tammela } 41ca175710SPedro Tammela 42ca175710SPedro Tammela Lua::~Lua() { 43ca175710SPedro Tammela assert(m_lua_state); 44ca175710SPedro Tammela lua_close(m_lua_state); 45ca175710SPedro Tammela } 46ca175710SPedro Tammela 4728613242SJonas Devlieghere llvm::Error Lua::Run(llvm::StringRef buffer) { 4828613242SJonas Devlieghere int error = 4928613242SJonas Devlieghere luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") || 5028613242SJonas Devlieghere lua_pcall(m_lua_state, 0, 0, 0); 514b9fa3b7SPedro Tammela if (error == LUA_OK) 5228613242SJonas Devlieghere return llvm::Error::success(); 5328613242SJonas Devlieghere 5428613242SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 5528613242SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 5628613242SJonas Devlieghere llvm::inconvertibleErrorCode()); 5728613242SJonas Devlieghere // Pop error message from the stack. 5828613242SJonas Devlieghere lua_pop(m_lua_state, 1); 5928613242SJonas Devlieghere return e; 6028613242SJonas Devlieghere } 61572b9f46SJonas Devlieghere 62a0d7406aSPedro Tammela llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) { 63a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 64a0d7406aSPedro Tammela const char *fmt_str = "return function(frame, bp_loc, ...) {0} end"; 65a0d7406aSPedro Tammela std::string func_str = llvm::formatv(fmt_str, body).str(); 66a0d7406aSPedro Tammela if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 67a0d7406aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 68280ae107SPedro Tammela llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 69a0d7406aSPedro Tammela llvm::inconvertibleErrorCode()); 70a0d7406aSPedro Tammela // Pop error message from the stack. 71a0d7406aSPedro Tammela lua_pop(m_lua_state, 2); 72a0d7406aSPedro Tammela return e; 73a0d7406aSPedro Tammela } 74a0d7406aSPedro Tammela lua_settable(m_lua_state, LUA_REGISTRYINDEX); 75a0d7406aSPedro Tammela return llvm::Error::success(); 76a0d7406aSPedro Tammela } 77a0d7406aSPedro Tammela 78a0d7406aSPedro Tammela llvm::Expected<bool> 79a0d7406aSPedro Tammela Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 80532e4203SPedro Tammela lldb::BreakpointLocationSP bp_loc_sp, 81532e4203SPedro Tammela StructuredData::ObjectSP extra_args_sp) { 82532e4203SPedro Tammela 83a0d7406aSPedro Tammela lua_pushlightuserdata(m_lua_state, baton); 84a0d7406aSPedro Tammela lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 85532e4203SPedro Tammela auto *extra_args_impl = [&]() -> StructuredDataImpl * { 86532e4203SPedro Tammela if (extra_args_sp == nullptr) 87532e4203SPedro Tammela return nullptr; 88532e4203SPedro Tammela auto *extra_args_impl = new StructuredDataImpl(); 89532e4203SPedro Tammela extra_args_impl->SetObjectSP(extra_args_sp); 90532e4203SPedro Tammela return extra_args_impl; 91532e4203SPedro Tammela }(); 92a0d7406aSPedro Tammela return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, 93532e4203SPedro Tammela bp_loc_sp, extra_args_impl); 94a0d7406aSPedro Tammela } 95a0d7406aSPedro Tammela 96e81ba283SSiger Yang llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) { 97e81ba283SSiger Yang lua_pushlightuserdata(m_lua_state, baton); 98e81ba283SSiger Yang const char *fmt_str = "return function(frame, wp, ...) {0} end"; 99e81ba283SSiger Yang std::string func_str = llvm::formatv(fmt_str, body).str(); 100e81ba283SSiger Yang if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { 101e81ba283SSiger Yang llvm::Error e = llvm::make_error<llvm::StringError>( 102e81ba283SSiger Yang llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), 103e81ba283SSiger Yang llvm::inconvertibleErrorCode()); 104e81ba283SSiger Yang // Pop error message from the stack. 105e81ba283SSiger Yang lua_pop(m_lua_state, 2); 106e81ba283SSiger Yang return e; 107e81ba283SSiger Yang } 108e81ba283SSiger Yang lua_settable(m_lua_state, LUA_REGISTRYINDEX); 109e81ba283SSiger Yang return llvm::Error::success(); 110e81ba283SSiger Yang } 111e81ba283SSiger Yang 112e81ba283SSiger Yang llvm::Expected<bool> 113e81ba283SSiger Yang Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, 114e81ba283SSiger Yang lldb::WatchpointSP wp_sp) { 115e81ba283SSiger Yang 116e81ba283SSiger Yang lua_pushlightuserdata(m_lua_state, baton); 117e81ba283SSiger Yang lua_gettable(m_lua_state, LUA_REGISTRYINDEX); 118e81ba283SSiger Yang return LLDBSwigLuaWatchpointCallbackFunction(m_lua_state, stop_frame_sp, 119e81ba283SSiger Yang wp_sp); 120e81ba283SSiger Yang } 121e81ba283SSiger Yang 122d853bd7aSPedro Tammela llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) { 123d853bd7aSPedro Tammela int error = 124d853bd7aSPedro Tammela luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer"); 125d853bd7aSPedro Tammela if (error == LUA_OK) { 126d853bd7aSPedro Tammela // Pop buffer 127d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 128d853bd7aSPedro Tammela return llvm::Error::success(); 129d853bd7aSPedro Tammela } 130d853bd7aSPedro Tammela 131d853bd7aSPedro Tammela llvm::Error e = llvm::make_error<llvm::StringError>( 132d853bd7aSPedro Tammela llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 133d853bd7aSPedro Tammela llvm::inconvertibleErrorCode()); 134d853bd7aSPedro Tammela // Pop error message from the stack. 135d853bd7aSPedro Tammela lua_pop(m_lua_state, 1); 136d853bd7aSPedro Tammela return e; 137d853bd7aSPedro Tammela } 138d853bd7aSPedro Tammela 139572b9f46SJonas Devlieghere llvm::Error Lua::LoadModule(llvm::StringRef filename) { 140572b9f46SJonas Devlieghere FileSpec file(filename); 141572b9f46SJonas Devlieghere if (!FileSystem::Instance().Exists(file)) { 142572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid path", 143572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 144572b9f46SJonas Devlieghere } 145572b9f46SJonas Devlieghere 146572b9f46SJonas Devlieghere ConstString module_extension = file.GetFileNameExtension(); 147572b9f46SJonas Devlieghere if (module_extension != ".lua") { 148572b9f46SJonas Devlieghere return llvm::make_error<llvm::StringError>("invalid extension", 149572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 150572b9f46SJonas Devlieghere } 151572b9f46SJonas Devlieghere 152572b9f46SJonas Devlieghere int error = luaL_loadfile(m_lua_state, filename.data()) || 153572b9f46SJonas Devlieghere lua_pcall(m_lua_state, 0, 1, 0); 1544b9fa3b7SPedro Tammela if (error != LUA_OK) { 155572b9f46SJonas Devlieghere llvm::Error e = llvm::make_error<llvm::StringError>( 156572b9f46SJonas Devlieghere llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), 157572b9f46SJonas Devlieghere llvm::inconvertibleErrorCode()); 158572b9f46SJonas Devlieghere // Pop error message from the stack. 159572b9f46SJonas Devlieghere lua_pop(m_lua_state, 1); 160572b9f46SJonas Devlieghere return e; 161572b9f46SJonas Devlieghere } 162572b9f46SJonas Devlieghere 163572b9f46SJonas Devlieghere ConstString module_name = file.GetFileNameStrippingExtension(); 164572b9f46SJonas Devlieghere lua_setglobal(m_lua_state, module_name.GetCString()); 165572b9f46SJonas Devlieghere return llvm::Error::success(); 166572b9f46SJonas Devlieghere } 167fa1b4a96SJonas Devlieghere 168fa1b4a96SJonas Devlieghere llvm::Error Lua::ChangeIO(FILE *out, FILE *err) { 169fa1b4a96SJonas Devlieghere assert(out != nullptr); 170fa1b4a96SJonas Devlieghere assert(err != nullptr); 171fa1b4a96SJonas Devlieghere 172fa1b4a96SJonas Devlieghere lua_getglobal(m_lua_state, "io"); 173fa1b4a96SJonas Devlieghere 174fa1b4a96SJonas Devlieghere lua_getfield(m_lua_state, -1, "stdout"); 175fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 176fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 177fa1b4a96SJonas Devlieghere s->f = out; 178fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 179fa1b4a96SJonas Devlieghere } else { 180fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 181fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stdout", 182fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 183fa1b4a96SJonas Devlieghere } 184fa1b4a96SJonas Devlieghere 185be494adbSJonas Devlieghere lua_getfield(m_lua_state, -1, "stderr"); 186fa1b4a96SJonas Devlieghere if (luaL_Stream *s = static_cast<luaL_Stream *>( 187fa1b4a96SJonas Devlieghere luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) { 188fa1b4a96SJonas Devlieghere s->f = out; 189fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 190fa1b4a96SJonas Devlieghere } else { 191fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 2); 192fa1b4a96SJonas Devlieghere return llvm::make_error<llvm::StringError>("could not get stderr", 193fa1b4a96SJonas Devlieghere llvm::inconvertibleErrorCode()); 194fa1b4a96SJonas Devlieghere } 195fa1b4a96SJonas Devlieghere 196fa1b4a96SJonas Devlieghere lua_pop(m_lua_state, 1); 197fa1b4a96SJonas Devlieghere return llvm::Error::success(); 198fa1b4a96SJonas Devlieghere } 199