Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
39642 views
//===-- Lua.cpp -----------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Lua.h"9#include "SWIGLuaBridge.h"10#include "lldb/Host/FileSystem.h"11#include "lldb/Utility/FileSpec.h"12#include "llvm/Support/Error.h"13#include "llvm/Support/FormatVariadic.h"1415using namespace lldb_private;16using namespace lldb;1718static int lldb_print(lua_State *L) {19int n = lua_gettop(L);20lua_getglobal(L, "io");21lua_getfield(L, -1, "stdout");22lua_getfield(L, -1, "write");23for (int i = 1; i <= n; i++) {24lua_pushvalue(L, -1); // write()25lua_pushvalue(L, -3); // io.stdout26luaL_tolstring(L, i, nullptr);27lua_pushstring(L, i != n ? "\t" : "\n");28lua_call(L, 3, 0);29}30return 0;31}3233Lua::Lua() : m_lua_state(luaL_newstate()) {34assert(m_lua_state);35luaL_openlibs(m_lua_state);36luaopen_lldb(m_lua_state);37lua_pushcfunction(m_lua_state, lldb_print);38lua_setglobal(m_lua_state, "print");39}4041Lua::~Lua() {42assert(m_lua_state);43lua_close(m_lua_state);44}4546llvm::Error Lua::Run(llvm::StringRef buffer) {47int error =48luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||49lua_pcall(m_lua_state, 0, 0, 0);50if (error == LUA_OK)51return llvm::Error::success();5253llvm::Error e = llvm::make_error<llvm::StringError>(54llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),55llvm::inconvertibleErrorCode());56// Pop error message from the stack.57lua_pop(m_lua_state, 1);58return e;59}6061llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) {62lua_pushlightuserdata(m_lua_state, baton);63const char *fmt_str = "return function(frame, bp_loc, ...) {0} end";64std::string func_str = llvm::formatv(fmt_str, body).str();65if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {66llvm::Error e = llvm::make_error<llvm::StringError>(67llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),68llvm::inconvertibleErrorCode());69// Pop error message from the stack.70lua_pop(m_lua_state, 2);71return e;72}73lua_settable(m_lua_state, LUA_REGISTRYINDEX);74return llvm::Error::success();75}7677llvm::Expected<bool>78Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,79lldb::BreakpointLocationSP bp_loc_sp,80StructuredData::ObjectSP extra_args_sp) {8182lua_pushlightuserdata(m_lua_state, baton);83lua_gettable(m_lua_state, LUA_REGISTRYINDEX);84StructuredDataImpl extra_args_impl(std::move(extra_args_sp));85return lua::SWIGBridge::LLDBSwigLuaBreakpointCallbackFunction(86m_lua_state, stop_frame_sp, bp_loc_sp, extra_args_impl);87}8889llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) {90lua_pushlightuserdata(m_lua_state, baton);91const char *fmt_str = "return function(frame, wp, ...) {0} end";92std::string func_str = llvm::formatv(fmt_str, body).str();93if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) {94llvm::Error e = llvm::make_error<llvm::StringError>(95llvm::formatv("{0}", lua_tostring(m_lua_state, -1)),96llvm::inconvertibleErrorCode());97// Pop error message from the stack.98lua_pop(m_lua_state, 2);99return e;100}101lua_settable(m_lua_state, LUA_REGISTRYINDEX);102return llvm::Error::success();103}104105llvm::Expected<bool>106Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,107lldb::WatchpointSP wp_sp) {108109lua_pushlightuserdata(m_lua_state, baton);110lua_gettable(m_lua_state, LUA_REGISTRYINDEX);111return lua::SWIGBridge::LLDBSwigLuaWatchpointCallbackFunction(112m_lua_state, stop_frame_sp, wp_sp);113}114115llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {116int error =117luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer");118if (error == LUA_OK) {119// Pop buffer120lua_pop(m_lua_state, 1);121return llvm::Error::success();122}123124llvm::Error e = llvm::make_error<llvm::StringError>(125llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),126llvm::inconvertibleErrorCode());127// Pop error message from the stack.128lua_pop(m_lua_state, 1);129return e;130}131132llvm::Error Lua::LoadModule(llvm::StringRef filename) {133const FileSpec file(filename);134if (!FileSystem::Instance().Exists(file)) {135return llvm::make_error<llvm::StringError>("invalid path",136llvm::inconvertibleErrorCode());137}138139if (file.GetFileNameExtension() != ".lua") {140return llvm::make_error<llvm::StringError>("invalid extension",141llvm::inconvertibleErrorCode());142}143144int error = luaL_loadfile(m_lua_state, filename.data()) ||145lua_pcall(m_lua_state, 0, 1, 0);146if (error != LUA_OK) {147llvm::Error e = llvm::make_error<llvm::StringError>(148llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),149llvm::inconvertibleErrorCode());150// Pop error message from the stack.151lua_pop(m_lua_state, 1);152return e;153}154155ConstString module_name = file.GetFileNameStrippingExtension();156lua_setglobal(m_lua_state, module_name.GetCString());157return llvm::Error::success();158}159160llvm::Error Lua::ChangeIO(FILE *out, FILE *err) {161assert(out != nullptr);162assert(err != nullptr);163164lua_getglobal(m_lua_state, "io");165166lua_getfield(m_lua_state, -1, "stdout");167if (luaL_Stream *s = static_cast<luaL_Stream *>(168luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {169s->f = out;170lua_pop(m_lua_state, 1);171} else {172lua_pop(m_lua_state, 2);173return llvm::make_error<llvm::StringError>("could not get stdout",174llvm::inconvertibleErrorCode());175}176177lua_getfield(m_lua_state, -1, "stderr");178if (luaL_Stream *s = static_cast<luaL_Stream *>(179luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {180s->f = out;181lua_pop(m_lua_state, 1);182} else {183lua_pop(m_lua_state, 2);184return llvm::make_error<llvm::StringError>("could not get stderr",185llvm::inconvertibleErrorCode());186}187188lua_pop(m_lua_state, 1);189return llvm::Error::success();190}191192193