Skip to content
Snippets Groups Projects
Commit e608a737 authored by Timur Safin's avatar Timur Safin Committed by Igor Munkin
Browse files

debugger: retrieve @builtin/%s.lua sources

Extend Tarantool kernel internal API with the call
`tarantool.debug.getsources()` to allow to retrieve sources
of a Tarantool `builtin/*` modules to show them in the
debugger shell.

Created simple luatest script for checking consistency
of a values returned from `require 'tarantool'.debug.getsources()`
and an ctual script file content we expected to receive.

NO_DOC=see future commit
NO_CHANGELOG=see future commit
parent 03cb944f
No related branches found
No related tags found
No related merge requests found
......@@ -35,6 +35,7 @@
#include <libgen.h>
#endif
#include <assert.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
......@@ -89,6 +90,8 @@ LUALIB_API int
luaopen_zip(lua_State *L);
#endif
#define MAX_MODNAME 64
/**
* The single Lua state of the transaction processor (tx) thread.
*/
......@@ -424,6 +427,50 @@ static const char *lua_modules_preload[] = {
* {{{ box Lua library: common functions
*/
/*
* Retrieve builtin module sources, if available.
*/
static const char *
tarantool_debug_getsources(const char *modname)
{
for (size_t i = 0; lua_modules[i] != NULL; i += 2) {
const char *shortname = lua_modules[i];
const char *lua_code = lua_modules[i + 1];
assert(lua_code != NULL);
assert(strlen(shortname) + sizeof("@builtin/.lua") <=
MAX_MODNAME);
char fullname[MAX_MODNAME];
snprintf(fullname, sizeof(fullname), "@builtin/%s.lua",
shortname);
if (!strcmp(shortname, modname) || !strcmp(fullname, modname))
return lua_code;
}
return NULL;
}
/*
* LuaC implementation of a function to retrieve builtin module sources.
*/
static int
lbox_tarantool_debug_getsources(struct lua_State *L)
{
int index = lua_gettop(L);
if (index != 1)
luaL_error(L, "getsources() function expects one argument");
size_t len = 0;
const char *modname = luaL_checklstring(L, index, &len);
if (len <= 0)
goto ret_nil;
const char *code = tarantool_debug_getsources(modname);
if (code == NULL)
goto ret_nil;
lua_pushstring(L, code);
return 1;
ret_nil:
lua_pushnil(L);
return 1;
}
/**
* Convert lua number or string to lua cdata 64bit number.
*/
......@@ -707,6 +754,13 @@ luaopen_tarantool(lua_State *L)
lua_settable(L, -3);
lua_settable(L, -3); /* box.info.build */
/* debug */
lua_newtable(L);
lua_pushcfunction(L, lbox_tarantool_debug_getsources);
lua_setfield(L, -2, "getsources");
lua_setfield(L, -2, "debug");
lua_pop(L, 1);
return 1;
}
......@@ -806,7 +860,6 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv)
lua_pop(L, 1); /* _PRELOAD */
luaopen_tarantool(L);
lua_pop(L, 1);
lua_newtable(L);
lua_pushinteger(L, -1);
......
local t = require('luatest')
local fio = require('fio')
local g = t.group()
local function readfile(filename)
local f = assert(io.open(filename, "rb"))
return f:read('*a')
end
local files = {
'strict',
'debug',
'errno',
'fiber',
'env',
'datetime',
}
-- calculate reporsitory root using directory of a current
-- script, but get 2 directories above
local function repo_root()
local myself = fio.abspath(debug.getinfo(1,'S').source:gsub("^@", ""))
local root = fio.abspath(fio.dirname(myself) .. '/../..')
return root
end
g.test_tarantool_debug_getsources = function()
local git_root = repo_root()
t.assert_is_not(git_root, nil)
t.assert(fio.stat(git_root):is_dir())
local lua_src_dir = fio.pathjoin(git_root, '/src/lua')
t.assert_is_not(lua_src_dir, nil)
t.assert(fio.stat(lua_src_dir):is_dir())
local tnt = require('tarantool')
t.assert_is_not(tnt, nil)
local luadebug = tnt.debug
t.assert_is_not(luadebug, nil)
for _, file in pairs(files) do
local path = ('%s/%s.lua'):format(lua_src_dir, file)
local text = readfile(path)
t.assert_is_not(text, nil)
local source = luadebug.getsources(file)
t.assert_equals(source, text)
source = luadebug.getsources(('@builtin/%s.lua'):format(file))
t.assert_equals(source, text)
end
end
......@@ -248,14 +248,34 @@ end
local SOURCE_CACHE = {}
local function where(info, context_lines)
local filesource = info.source
local source = SOURCE_CACHE[info.source]
if not source then
source = {}
local filename = info.source:match("@(.*)")
if filename then
pcall(function() for line in io.lines(filename) do table.insert(source, line) end end)
elseif info.source then
for line in info.source:gmatch("(.-)\n") do table.insert(source, line) end
-- Tarantool builtin module
if filesource:match("@builtin/.*.lua") then
pcall(function()
local tnt_debug = require('tarantool').debug
local lua_code = tnt_debug.getsources(filesource)
for line in string.gmatch(lua_code, "([^\n]*)\n?") do
table.insert(source, line)
end
end)
else
-- external module - load file
local filename = filesource:match("@(.*)")
if filename then
pcall(function()
for line in io.lines(filename) do
table.insert(source, line)
end
end)
elseif filesource then
for line in info.source:gmatch("(.-)\n") do
table.insert(filesource, line)
end
end
end
SOURCE_CACHE[info.source] = source
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment