mirror of
https://github.com/nodemcu/nodemcu-firmware.git
synced 2025-01-30 21:12:55 +08:00
526d21dab4
The PR removed the bulk of non-newlib headers from the NodeMCU source base. app/libc has now been cut down to the bare minimum overrides to shadow the corresponding functions in the SDK's libc. The old c_xyz.h headerfiles have been nuked in favour of the standard <xyz.h> headers, with a few exceptions over in sdk-overrides. Again, shipping a libc.a without headers is a terrible thing to do. We're still living on a prayer that libc was configured the same was as a default-configured xtensa gcc toolchain assumes it is. That part I cannot do anything about, unfortunately, but it's no worse than it has been before. This enables our source files to compile successfully using the standard header files, and use the typical malloc()/calloc()/realloc()/free(), the strwhatever()s and memwhatever()s. These end up, through macro and linker magic, mapped to the appropriate SDK or ROM functions.
445 lines
12 KiB
C
445 lines
12 KiB
C
/*
|
|
** $Id: ldblib.c,v 1.104.1.4 2009/08/04 18:50:18 roberto Exp $
|
|
** Interface from Lua to its debug API
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
|
|
|
|
#define ldblib_c
|
|
#define LUA_LIB
|
|
#define LUAC_CROSS_FILE
|
|
|
|
#include "lua.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "lauxlib.h"
|
|
#include "lualib.h"
|
|
#include "lstring.h"
|
|
#include "lflash.h"
|
|
#include "lrotable.h"
|
|
|
|
#include "user_modules.h"
|
|
|
|
static int db_getregistry (lua_State *L) {
|
|
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
|
return 1;
|
|
}
|
|
|
|
static int db_getstrings (lua_State *L) {
|
|
size_t i,n=0;
|
|
stringtable *tb;
|
|
GCObject *o;
|
|
#ifndef LUA_CROSS_COMPILER
|
|
const char *opt = lua_tolstring (L, 1, &n);
|
|
if (n==3 && memcmp(opt, "ROM", 4) == 0) {
|
|
if (G(L)->ROstrt.hash == NULL)
|
|
return 0;
|
|
tb = &G(L)->ROstrt;
|
|
}
|
|
else
|
|
#endif
|
|
tb = &G(L)->strt;
|
|
lua_settop(L, 0);
|
|
lua_createtable(L, tb->nuse, 0); /* create table the same size as the strt */
|
|
for (i=0, n=1; i<tb->size; i++) {
|
|
for(o = tb->hash[i]; o; o=o->gch.next) {
|
|
TString *ts =cast(TString *, o);
|
|
lua_pushnil(L);
|
|
setsvalue2s(L, L->top-1, ts);
|
|
lua_rawseti(L, -2, n++); /* enumerate the strt, adding elements */
|
|
}
|
|
}
|
|
lua_getfield(L, LUA_GLOBALSINDEX, "table");
|
|
lua_getfield(L, -1, "sort"); /* look up table.sort function */
|
|
lua_replace(L, -2); /* dump the table table */
|
|
lua_pushvalue(L, -2); /* duplicate the strt_copy ref */
|
|
lua_call(L, 1, 0); /* table.sort(strt_copy) */
|
|
return 1;
|
|
}
|
|
|
|
|
|
#ifndef LUA_USE_BUILTIN_DEBUG_MINIMAL
|
|
|
|
static int db_getmetatable (lua_State *L) {
|
|
luaL_checkany(L, 1);
|
|
if (!lua_getmetatable(L, 1)) {
|
|
lua_pushnil(L); /* no metatable */
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int db_setmetatable (lua_State *L) {
|
|
int t = lua_type(L, 2);
|
|
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
|
|
"nil or table expected");
|
|
lua_settop(L, 2);
|
|
lua_pushboolean(L, lua_setmetatable(L, 1));
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int db_getfenv (lua_State *L) {
|
|
luaL_checkany(L, 1);
|
|
lua_getfenv(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int db_setfenv (lua_State *L) {
|
|
luaL_checktype(L, 2, LUA_TTABLE);
|
|
lua_settop(L, 2);
|
|
if (lua_setfenv(L, 1) == 0)
|
|
luaL_error(L, LUA_QL("setfenv")
|
|
" cannot change environment of given object");
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void settabss (lua_State *L, const char *i, const char *v) {
|
|
lua_pushstring(L, v);
|
|
lua_setfield(L, -2, i);
|
|
}
|
|
|
|
|
|
static void settabsi (lua_State *L, const char *i, int v) {
|
|
lua_pushinteger(L, v);
|
|
lua_setfield(L, -2, i);
|
|
}
|
|
|
|
#endif
|
|
static lua_State *getthread (lua_State *L, int *arg) {
|
|
if (lua_isthread(L, 1)) {
|
|
*arg = 1;
|
|
return lua_tothread(L, 1);
|
|
}
|
|
else {
|
|
*arg = 0;
|
|
return L;
|
|
}
|
|
}
|
|
#ifndef LUA_USE_BUILTIN_DEBUG_MINIMAL
|
|
|
|
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
|
|
if (L == L1) {
|
|
lua_pushvalue(L, -2);
|
|
lua_remove(L, -3);
|
|
}
|
|
else
|
|
lua_xmove(L1, L, 1);
|
|
lua_setfield(L, -2, fname);
|
|
}
|
|
|
|
|
|
static int db_getinfo (lua_State *L) {
|
|
lua_Debug ar;
|
|
int arg;
|
|
lua_State *L1 = getthread(L, &arg);
|
|
const char *options = luaL_optstring(L, arg+2, "flnSu");
|
|
if (lua_isnumber(L, arg+1)) {
|
|
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
|
|
lua_pushnil(L); /* level out of range */
|
|
return 1;
|
|
}
|
|
}
|
|
else if (lua_isfunction(L, arg+1) || lua_islightfunction(L, arg+1)) {
|
|
lua_pushfstring(L, ">%s", options);
|
|
options = lua_tostring(L, -1);
|
|
lua_pushvalue(L, arg+1);
|
|
lua_xmove(L, L1, 1);
|
|
}
|
|
else
|
|
return luaL_argerror(L, arg+1, "function or level expected");
|
|
if (!lua_getinfo(L1, options, &ar))
|
|
return luaL_argerror(L, arg+2, "invalid option");
|
|
lua_createtable(L, 0, 2);
|
|
if (strchr(options, 'S')) {
|
|
settabss(L, "source", ar.source);
|
|
settabss(L, "short_src", ar.short_src);
|
|
settabsi(L, "linedefined", ar.linedefined);
|
|
settabsi(L, "lastlinedefined", ar.lastlinedefined);
|
|
settabss(L, "what", ar.what);
|
|
}
|
|
if (strchr(options, 'l'))
|
|
settabsi(L, "currentline", ar.currentline);
|
|
if (strchr(options, 'u'))
|
|
settabsi(L, "nups", ar.nups);
|
|
if (strchr(options, 'n')) {
|
|
settabss(L, "name", ar.name);
|
|
settabss(L, "namewhat", ar.namewhat);
|
|
}
|
|
if (strchr(options, 'L'))
|
|
treatstackoption(L, L1, "activelines");
|
|
if (strchr(options, 'f'))
|
|
treatstackoption(L, L1, "func");
|
|
return 1; /* return table */
|
|
}
|
|
|
|
|
|
static int db_getlocal (lua_State *L) {
|
|
int arg;
|
|
lua_State *L1 = getthread(L, &arg);
|
|
lua_Debug ar;
|
|
const char *name;
|
|
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
|
|
return luaL_argerror(L, arg+1, "level out of range");
|
|
name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
|
|
if (name) {
|
|
lua_xmove(L1, L, 1);
|
|
lua_pushstring(L, name);
|
|
lua_pushvalue(L, -2);
|
|
return 2;
|
|
}
|
|
else {
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
static int db_setlocal (lua_State *L) {
|
|
int arg;
|
|
lua_State *L1 = getthread(L, &arg);
|
|
lua_Debug ar;
|
|
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
|
|
return luaL_argerror(L, arg+1, "level out of range");
|
|
luaL_checkany(L, arg+3);
|
|
lua_settop(L, arg+3);
|
|
lua_xmove(L, L1, 1);
|
|
lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int auxupvalue (lua_State *L, int get) {
|
|
const char *name;
|
|
int n = luaL_checkint(L, 2);
|
|
luaL_checktype(L, 1, LUA_TFUNCTION);
|
|
if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */
|
|
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
|
|
if (name == NULL) return 0;
|
|
lua_pushstring(L, name);
|
|
lua_insert(L, -(get+1));
|
|
return get + 1;
|
|
}
|
|
|
|
|
|
static int db_getupvalue (lua_State *L) {
|
|
return auxupvalue(L, 1);
|
|
}
|
|
|
|
|
|
static int db_setupvalue (lua_State *L) {
|
|
luaL_checkany(L, 3);
|
|
return auxupvalue(L, 0);
|
|
}
|
|
|
|
|
|
|
|
static const char KEY_HOOK = 'h';
|
|
|
|
|
|
static void hookf (lua_State *L, lua_Debug *ar) {
|
|
static const char *const hooknames[] =
|
|
{"call", "return", "line", "count", "tail return"};
|
|
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
|
lua_pushlightuserdata(L, L);
|
|
lua_rawget(L, -2);
|
|
if (lua_isfunction(L, -1)) {
|
|
lua_pushstring(L, hooknames[(int)ar->event]);
|
|
if (ar->currentline >= 0)
|
|
lua_pushinteger(L, ar->currentline);
|
|
else lua_pushnil(L);
|
|
lua_assert(lua_getinfo(L, "lS", ar));
|
|
lua_call(L, 2, 0);
|
|
}
|
|
}
|
|
|
|
|
|
static int makemask (const char *smask, int count) {
|
|
int mask = 0;
|
|
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
|
|
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
|
|
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
|
|
if (count > 0) mask |= LUA_MASKCOUNT;
|
|
return mask;
|
|
}
|
|
|
|
|
|
static char *unmakemask (int mask, char *smask) {
|
|
int i = 0;
|
|
if (mask & LUA_MASKCALL) smask[i++] = 'c';
|
|
if (mask & LUA_MASKRET) smask[i++] = 'r';
|
|
if (mask & LUA_MASKLINE) smask[i++] = 'l';
|
|
smask[i] = '\0';
|
|
return smask;
|
|
}
|
|
|
|
|
|
static void gethooktable (lua_State *L) {
|
|
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
|
if (!lua_istable(L, -1)) {
|
|
lua_pop(L, 1);
|
|
lua_createtable(L, 0, 1);
|
|
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
|
lua_pushvalue(L, -2);
|
|
lua_rawset(L, LUA_REGISTRYINDEX);
|
|
}
|
|
}
|
|
|
|
|
|
static int db_sethook (lua_State *L) {
|
|
int arg, mask, count;
|
|
lua_Hook func;
|
|
lua_State *L1 = getthread(L, &arg);
|
|
if (lua_isnoneornil(L, arg+1)) {
|
|
lua_settop(L, arg+1);
|
|
func = NULL; mask = 0; count = 0; /* turn off hooks */
|
|
}
|
|
else {
|
|
const char *smask = luaL_checkstring(L, arg+2);
|
|
luaL_checkanyfunction(L, arg+1);
|
|
count = luaL_optint(L, arg+3, 0);
|
|
func = hookf; mask = makemask(smask, count);
|
|
}
|
|
gethooktable(L);
|
|
lua_pushlightuserdata(L, L1);
|
|
lua_pushvalue(L, arg+1);
|
|
lua_rawset(L, -3); /* set new hook */
|
|
lua_pop(L, 1); /* remove hook table */
|
|
lua_sethook(L1, func, mask, count); /* set hooks */
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int db_gethook (lua_State *L) {
|
|
int arg;
|
|
lua_State *L1 = getthread(L, &arg);
|
|
char buff[5];
|
|
int mask = lua_gethookmask(L1);
|
|
lua_Hook hook = lua_gethook(L1);
|
|
if (hook != NULL && hook != hookf) /* external hook? */
|
|
lua_pushliteral(L, "external hook");
|
|
else {
|
|
gethooktable(L);
|
|
lua_pushlightuserdata(L, L1);
|
|
lua_rawget(L, -2); /* get hook */
|
|
lua_remove(L, -2); /* remove hook table */
|
|
}
|
|
lua_pushstring(L, unmakemask(mask, buff));
|
|
lua_pushinteger(L, lua_gethookcount(L1));
|
|
return 3;
|
|
}
|
|
|
|
|
|
static int db_debug (lua_State *L) {
|
|
for (;;) {
|
|
char buffer[LUA_MAXINPUT];
|
|
#if defined(LUA_USE_STDIO)
|
|
fputs("lua_debug> ", c_stderr);
|
|
if (fgets(buffer, sizeof(buffer), c_stdin) == 0 ||
|
|
#else
|
|
// luai_writestringerror("%s", "lua_debug>");
|
|
if (lua_readline(L, buffer, "lua_debug>") == 0 ||
|
|
#endif
|
|
strcmp(buffer, "cont\n") == 0)
|
|
return 0;
|
|
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
|
lua_pcall(L, 0, 0, 0)) {
|
|
#if defined(LUA_USE_STDIO)
|
|
fputs(lua_tostring(L, -1), c_stderr);
|
|
fputs("\n", c_stderr);
|
|
#else
|
|
luai_writestringerror("%s\n", lua_tostring(L, -1));
|
|
#endif
|
|
}
|
|
lua_settop(L, 0); /* remove eventual returns */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#define LEVELS1 12 /* size of the first part of the stack */
|
|
#define LEVELS2 10 /* size of the second part of the stack */
|
|
|
|
static int db_errorfb (lua_State *L) {
|
|
int level;
|
|
int firstpart = 1; /* still before eventual `...' */
|
|
int arg;
|
|
lua_State *L1 = getthread(L, &arg);
|
|
lua_Debug ar;
|
|
if (lua_isnumber(L, arg+2)) {
|
|
level = (int)lua_tointeger(L, arg+2);
|
|
lua_pop(L, 1);
|
|
}
|
|
else
|
|
level = (L == L1) ? 1 : 0; /* level 0 may be this own function */
|
|
if (lua_gettop(L) == arg)
|
|
lua_pushliteral(L, "");
|
|
else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */
|
|
else lua_pushliteral(L, "\n");
|
|
lua_pushliteral(L, "stack traceback:");
|
|
while (lua_getstack(L1, level++, &ar)) {
|
|
if (level > LEVELS1 && firstpart) {
|
|
/* no more than `LEVELS2' more levels? */
|
|
if (!lua_getstack(L1, level+LEVELS2, &ar))
|
|
level--; /* keep going */
|
|
else {
|
|
lua_pushliteral(L, "\n\t..."); /* too many levels */
|
|
while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */
|
|
level++;
|
|
}
|
|
firstpart = 0;
|
|
continue;
|
|
}
|
|
lua_pushliteral(L, "\n\t");
|
|
lua_getinfo(L1, "Snl", &ar);
|
|
lua_pushfstring(L, "%s:", ar.short_src);
|
|
if (ar.currentline > 0)
|
|
lua_pushfstring(L, "%d:", ar.currentline);
|
|
if (*ar.namewhat != '\0') /* is there a name? */
|
|
lua_pushfstring(L, " in function " LUA_QS, ar.name);
|
|
else {
|
|
if (*ar.what == 'm') /* main? */
|
|
lua_pushfstring(L, " in main chunk");
|
|
else if (*ar.what == 'C' || *ar.what == 't')
|
|
lua_pushliteral(L, " ?"); /* C function or tail call */
|
|
else
|
|
lua_pushfstring(L, " in function <%s:%d>",
|
|
ar.short_src, ar.linedefined);
|
|
}
|
|
lua_concat(L, lua_gettop(L) - arg);
|
|
}
|
|
lua_concat(L, lua_gettop(L) - arg);
|
|
return 1;
|
|
}
|
|
|
|
LROT_PUBLIC_BEGIN(dblib)
|
|
#ifndef LUA_USE_BUILTIN_DEBUG_MINIMAL
|
|
LROT_FUNCENTRY( debug, db_debug )
|
|
LROT_FUNCENTRY( getfenv, db_getfenv )
|
|
LROT_FUNCENTRY( gethook, db_gethook )
|
|
LROT_FUNCENTRY( getinfo, db_getinfo )
|
|
LROT_FUNCENTRY( getlocal, db_getlocal )
|
|
#endif
|
|
LROT_FUNCENTRY( getregistry, db_getregistry )
|
|
LROT_FUNCENTRY( getstrings, db_getstrings )
|
|
#ifndef LUA_USE_BUILTIN_DEBUG_MINIMAL
|
|
LROT_FUNCENTRY( getmetatable, db_getmetatable )
|
|
LROT_FUNCENTRY( getupvalue, db_getupvalue )
|
|
LROT_FUNCENTRY( setfenv, db_setfenv )
|
|
LROT_FUNCENTRY( sethook, db_sethook )
|
|
LROT_FUNCENTRY( setlocal, db_setlocal )
|
|
LROT_FUNCENTRY( setmetatable, db_setmetatable )
|
|
LROT_FUNCENTRY( setupvalue, db_setupvalue )
|
|
#endif
|
|
LROT_FUNCENTRY( traceback, db_errorfb )
|
|
LROT_END(dblib, NULL, 0)
|
|
|
|
LUALIB_API int luaopen_debug (lua_State *L) {
|
|
return 0;
|
|
}
|