LCOV - code coverage report
Current view: top level - src - ldblib.c Coverage Total Hit
Test: Lua 5.1.5 Lines: 94.3 % 229 216
Test Date: 2024-04-28 10:23:09
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              : ** $Id: ldblib.c,v 1.104.1.4 2009/08/04 18:50:18 roberto Exp $
       3              : ** Interface from Lua to its debug API
       4              : ** See Copyright Notice in lua.h
       5              : */
       6              : 
       7              : 
       8              : #include <stdio.h>
       9              : #include <stdlib.h>
      10              : #include <string.h>
      11              : 
      12              : #define ldblib_c
      13              : #define LUA_LIB
      14              : 
      15              : #include "lua.h"
      16              : 
      17              : #include "lauxlib.h"
      18              : #include "lualib.h"
      19              : 
      20              : 
      21              : 
      22            1 : static int db_getregistry (lua_State *L) {
      23            1 :   lua_pushvalue(L, LUA_REGISTRYINDEX);
      24            1 :   return 1;
      25              : }
      26              : 
      27              : 
      28            6 : static int db_getmetatable (lua_State *L) {
      29            6 :   luaL_checkany(L, 1);
      30            6 :   if (!lua_getmetatable(L, 1)) {
      31            3 :     lua_pushnil(L);  /* no metatable */
      32              :   }
      33            6 :   return 1;
      34              : }
      35              : 
      36              : 
      37            5 : static int db_setmetatable (lua_State *L) {
      38            5 :   int t = lua_type(L, 2);
      39            5 :   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
      40              :                     "nil or table expected");
      41            4 :   lua_settop(L, 2);
      42            4 :   lua_pushboolean(L, lua_setmetatable(L, 1));
      43            4 :   return 1;
      44              : }
      45              : 
      46              : 
      47           13 : static int db_getfenv (lua_State *L) {
      48           13 :   luaL_checkany(L, 1);
      49           13 :   lua_getfenv(L, 1);
      50           13 :   return 1;
      51              : }
      52              : 
      53              : 
      54            4 : static int db_setfenv (lua_State *L) {
      55            4 :   luaL_checktype(L, 2, LUA_TTABLE);
      56            4 :   lua_settop(L, 2);
      57            4 :   if (lua_setfenv(L, 1) == 0)
      58            1 :     luaL_error(L, LUA_QL("setfenv")
      59              :                   " cannot change environment of given object");
      60            3 :   return 1;
      61              : }
      62              : 
      63              : 
      64           10 : static void settabss (lua_State *L, const char *i, const char *v) {
      65           10 :   lua_pushstring(L, v);
      66           10 :   lua_setfield(L, -2, i);
      67           10 : }
      68              : 
      69              : 
      70            8 : static void settabsi (lua_State *L, const char *i, int v) {
      71            8 :   lua_pushinteger(L, v);
      72            8 :   lua_setfield(L, -2, i);
      73            8 : }
      74              : 
      75              : 
      76           21 : static lua_State *getthread (lua_State *L, int *arg) {
      77           21 :   if (lua_isthread(L, 1)) {
      78            1 :     *arg = 1;
      79            1 :     return lua_tothread(L, 1);
      80              :   }
      81              :   else {
      82           20 :     *arg = 0;
      83           20 :     return L;
      84              :   }
      85              : }
      86              : 
      87              : 
      88            3 : static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
      89            3 :   if (L == L1) {
      90            3 :     lua_pushvalue(L, -2);
      91            3 :     lua_remove(L, -3);
      92              :   }
      93              :   else
      94            0 :     lua_xmove(L1, L, 1);
      95            3 :   lua_setfield(L, -2, fname);
      96            3 : }
      97              : 
      98              : 
      99            6 : static int db_getinfo (lua_State *L) {
     100              :   lua_Debug ar;
     101              :   int arg;
     102            6 :   lua_State *L1 = getthread(L, &arg);
     103            6 :   const char *options = luaL_optstring(L, arg+2, "flnSu");
     104            6 :   if (lua_isnumber(L, arg+1)) {
     105            2 :     if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
     106            1 :       lua_pushnil(L);  /* level out of range */
     107            1 :       return 1;
     108              :     }
     109              :   }
     110            4 :   else if (lua_isfunction(L, arg+1)) {
     111            3 :     lua_pushfstring(L, ">%s", options);
     112            3 :     options = lua_tostring(L, -1);
     113            3 :     lua_pushvalue(L, arg+1);
     114            3 :     lua_xmove(L, L1, 1);
     115              :   }
     116              :   else
     117            1 :     return luaL_argerror(L, arg+1, "function or level expected");
     118            4 :   if (!lua_getinfo(L1, options, &ar))
     119            1 :     return luaL_argerror(L, arg+2, "invalid option");
     120            3 :   lua_createtable(L, 0, 2);
     121            3 :   if (strchr(options, 'S')) {
     122            2 :     settabss(L, "source", ar.source);
     123            2 :     settabss(L, "short_src", ar.short_src);
     124            2 :     settabsi(L, "linedefined", ar.linedefined);
     125            2 :     settabsi(L, "lastlinedefined", ar.lastlinedefined);
     126            2 :     settabss(L, "what", ar.what);
     127              :   }
     128            3 :   if (strchr(options, 'l'))
     129            2 :     settabsi(L, "currentline", ar.currentline);
     130            3 :   if (strchr(options, 'u'))
     131            2 :     settabsi(L, "nups", ar.nups);
     132            3 :   if (strchr(options, 'n')) {
     133            2 :     settabss(L, "name", ar.name);
     134            2 :     settabss(L, "namewhat", ar.namewhat);
     135              :   }
     136            3 :   if (strchr(options, 'L'))
     137            1 :     treatstackoption(L, L1, "activelines");
     138            3 :   if (strchr(options, 'f'))
     139            2 :     treatstackoption(L, L1, "func");
     140            3 :   return 1;  /* return table */
     141              : }
     142              :     
     143              : 
     144            2 : static int db_getlocal (lua_State *L) {
     145              :   int arg;
     146            2 :   lua_State *L1 = getthread(L, &arg);
     147              :   lua_Debug ar;
     148              :   const char *name;
     149            2 :   if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
     150            1 :     return luaL_argerror(L, arg+1, "level out of range");
     151            1 :   name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
     152            1 :   if (name) {
     153            1 :     lua_xmove(L1, L, 1);
     154            1 :     lua_pushstring(L, name);
     155            1 :     lua_pushvalue(L, -2);
     156            1 :     return 2;
     157              :   }
     158              :   else {
     159            0 :     lua_pushnil(L);
     160            0 :     return 1;
     161              :   }
     162              : }
     163              : 
     164              : 
     165            3 : static int db_setlocal (lua_State *L) {
     166              :   int arg;
     167            3 :   lua_State *L1 = getthread(L, &arg);
     168              :   lua_Debug ar;
     169            3 :   if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
     170            1 :     return luaL_argerror(L, arg+1, "level out of range");
     171            2 :   luaL_checkany(L, arg+3);
     172            2 :   lua_settop(L, arg+3);
     173            2 :   lua_xmove(L, L1, 1);
     174            2 :   lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
     175            2 :   return 1;
     176              : }
     177              : 
     178              : 
     179            3 : static int auxupvalue (lua_State *L, int get) {
     180              :   const char *name;
     181            3 :   int n = luaL_checkint(L, 2);
     182            3 :   luaL_checktype(L, 1, LUA_TFUNCTION);
     183            3 :   if (lua_iscfunction(L, 1)) return 0;  /* cannot touch C upvalues from Lua */
     184            3 :   name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
     185            3 :   if (name == NULL) return 0;
     186            2 :   lua_pushstring(L, name);
     187            2 :   lua_insert(L, -(get+1));
     188            2 :   return get + 1;
     189              : }
     190              : 
     191              : 
     192            1 : static int db_getupvalue (lua_State *L) {
     193            1 :   return auxupvalue(L, 1);
     194              : }
     195              : 
     196              : 
     197            2 : static int db_setupvalue (lua_State *L) {
     198            2 :   luaL_checkany(L, 3);
     199            2 :   return auxupvalue(L, 0);
     200              : }
     201              : 
     202              : 
     203              : 
     204              : static const char KEY_HOOK = 'h';
     205              : 
     206              : 
     207          243 : static void hookf (lua_State *L, lua_Debug *ar) {
     208              :   static const char *const hooknames[] =
     209              :     {"call", "return", "line", "count", "tail return"};
     210          243 :   lua_pushlightuserdata(L, (void *)&KEY_HOOK);
     211          243 :   lua_rawget(L, LUA_REGISTRYINDEX);
     212          243 :   lua_pushlightuserdata(L, L);
     213          243 :   lua_rawget(L, -2);
     214          243 :   if (lua_isfunction(L, -1)) {
     215          243 :     lua_pushstring(L, hooknames[(int)ar->event]);
     216          243 :     if (ar->currentline >= 0)
     217            0 :       lua_pushinteger(L, ar->currentline);
     218          243 :     else lua_pushnil(L);
     219              :     lua_assert(lua_getinfo(L, "lS", ar));
     220          243 :     lua_call(L, 2, 0);
     221              :   }
     222          243 : }
     223              : 
     224              : 
     225            1 : static int makemask (const char *smask, int count) {
     226            1 :   int mask = 0;
     227            1 :   if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
     228            1 :   if (strchr(smask, 'r')) mask |= LUA_MASKRET;
     229            1 :   if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
     230            1 :   if (count > 0) mask |= LUA_MASKCOUNT;
     231            1 :   return mask;
     232              : }
     233              : 
     234              : 
     235            3 : static char *unmakemask (int mask, char *smask) {
     236            3 :   int i = 0;
     237            3 :   if (mask & LUA_MASKCALL) smask[i++] = 'c';
     238            3 :   if (mask & LUA_MASKRET) smask[i++] = 'r';
     239            3 :   if (mask & LUA_MASKLINE) smask[i++] = 'l';
     240            3 :   smask[i] = '\0';
     241            3 :   return smask;
     242              : }
     243              : 
     244              : 
     245            5 : static void gethooktable (lua_State *L) {
     246            5 :   lua_pushlightuserdata(L, (void *)&KEY_HOOK);
     247            5 :   lua_rawget(L, LUA_REGISTRYINDEX);
     248            5 :   if (!lua_istable(L, -1)) {
     249            1 :     lua_pop(L, 1);
     250            1 :     lua_createtable(L, 0, 1);
     251            1 :     lua_pushlightuserdata(L, (void *)&KEY_HOOK);
     252            1 :     lua_pushvalue(L, -2);
     253            1 :     lua_rawset(L, LUA_REGISTRYINDEX);
     254              :   }
     255            5 : }
     256              : 
     257              : 
     258            2 : static int db_sethook (lua_State *L) {
     259              :   int arg, mask, count;
     260              :   lua_Hook func;
     261            2 :   lua_State *L1 = getthread(L, &arg);
     262            2 :   if (lua_isnoneornil(L, arg+1)) {
     263            1 :     lua_settop(L, arg+1);
     264            1 :     func = NULL; mask = 0; count = 0;  /* turn off hooks */
     265              :   }
     266              :   else {
     267            1 :     const char *smask = luaL_checkstring(L, arg+2);
     268            1 :     luaL_checktype(L, arg+1, LUA_TFUNCTION);
     269            1 :     count = luaL_optint(L, arg+3, 0);
     270            1 :     func = hookf; mask = makemask(smask, count);
     271              :   }
     272            2 :   gethooktable(L);
     273            2 :   lua_pushlightuserdata(L, L1);
     274            2 :   lua_pushvalue(L, arg+1);
     275            2 :   lua_rawset(L, -3);  /* set new hook */
     276            2 :   lua_pop(L, 1);  /* remove hook table */
     277            2 :   lua_sethook(L1, func, mask, count);  /* set hooks */
     278            2 :   return 0;
     279              : }
     280              : 
     281              : 
     282            3 : static int db_gethook (lua_State *L) {
     283              :   int arg;
     284            3 :   lua_State *L1 = getthread(L, &arg);
     285              :   char buff[5];
     286            3 :   int mask = lua_gethookmask(L1);
     287            3 :   lua_Hook hook = lua_gethook(L1);
     288            3 :   if (hook != NULL && hook != hookf)  /* external hook? */
     289            0 :     lua_pushliteral(L, "external hook");
     290              :   else {
     291            3 :     gethooktable(L);
     292            3 :     lua_pushlightuserdata(L, L1);
     293            3 :     lua_rawget(L, -2);   /* get hook */
     294            3 :     lua_remove(L, -2);  /* remove hook table */
     295              :   }
     296            3 :   lua_pushstring(L, unmakemask(mask, buff));
     297            3 :   lua_pushinteger(L, lua_gethookcount(L1));
     298            3 :   return 3;
     299              : }
     300              : 
     301              : 
     302            1 : static int db_debug (lua_State *L) {
     303            2 :   for (;;) {
     304              :     char buffer[250];
     305            3 :     fputs("lua_debug> ", stderr);
     306            3 :     if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
     307            3 :         strcmp(buffer, "cont\n") == 0)
     308            1 :       return 0;
     309            4 :     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
     310            2 :         lua_pcall(L, 0, 0, 0)) {
     311            1 :       fputs(lua_tostring(L, -1), stderr);
     312            1 :       fputs("\n", stderr);
     313              :     }
     314            2 :     lua_settop(L, 0);  /* remove eventual returns */
     315              :   }
     316              : }
     317              : 
     318              : 
     319              : #define LEVELS1 12      /* size of the first part of the stack */
     320              : #define LEVELS2 10      /* size of the second part of the stack */
     321              : 
     322            5 : static int db_errorfb (lua_State *L) {
     323              :   int level;
     324            5 :   int firstpart = 1;  /* still before eventual `...' */
     325              :   int arg;
     326            5 :   lua_State *L1 = getthread(L, &arg);
     327              :   lua_Debug ar;
     328            5 :   if (lua_isnumber(L, arg+2)) {
     329            2 :     level = (int)lua_tointeger(L, arg+2);
     330            2 :     lua_pop(L, 1);
     331              :   }
     332              :   else
     333            3 :     level = (L == L1) ? 1 : 0;  /* level 0 may be this own function */
     334            5 :   if (lua_gettop(L) == arg)
     335            1 :     lua_pushliteral(L, "");
     336            4 :   else if (!lua_isstring(L, arg+1)) return 1;  /* message is not a string */
     337            3 :   else lua_pushliteral(L, "\n");
     338            4 :   lua_pushliteral(L, "stack traceback:");
     339           14 :   while (lua_getstack(L1, level++, &ar)) {
     340           10 :     if (level > LEVELS1 && firstpart) {
     341              :       /* no more than `LEVELS2' more levels? */
     342            0 :       if (!lua_getstack(L1, level+LEVELS2, &ar))
     343            0 :         level--;  /* keep going */
     344              :       else {
     345            0 :         lua_pushliteral(L, "\n\t...");  /* too many levels */
     346            0 :         while (lua_getstack(L1, level+LEVELS2, &ar))  /* find last levels */
     347            0 :           level++;
     348              :       }
     349            0 :       firstpart = 0;
     350            0 :       continue;
     351              :     }
     352           10 :     lua_pushliteral(L, "\n\t");
     353           10 :     lua_getinfo(L1, "Snl", &ar);
     354           10 :     lua_pushfstring(L, "%s:", ar.short_src);
     355           10 :     if (ar.currentline > 0)
     356            4 :       lua_pushfstring(L, "%d:", ar.currentline);
     357           10 :     if (*ar.namewhat != '\0')  /* is there a name? */
     358            2 :         lua_pushfstring(L, " in function " LUA_QS, ar.name);
     359              :     else {
     360            8 :       if (*ar.what == 'm')  /* main? */
     361            4 :         lua_pushfstring(L, " in main chunk");
     362            4 :       else if (*ar.what == 'C' || *ar.what == 't')
     363            4 :         lua_pushliteral(L, " ?");  /* C function or tail call */
     364              :       else
     365            0 :         lua_pushfstring(L, " in function <%s:%d>",
     366              :                            ar.short_src, ar.linedefined);
     367              :     }
     368           10 :     lua_concat(L, lua_gettop(L) - arg);
     369              :   }
     370            4 :   lua_concat(L, lua_gettop(L) - arg);
     371            4 :   return 1;
     372              : }
     373              : 
     374              : 
     375              : static const luaL_Reg dblib[] = {
     376              :   {"debug", db_debug},
     377              :   {"getfenv", db_getfenv},
     378              :   {"gethook", db_gethook},
     379              :   {"getinfo", db_getinfo},
     380              :   {"getlocal", db_getlocal},
     381              :   {"getregistry", db_getregistry},
     382              :   {"getmetatable", db_getmetatable},
     383              :   {"getupvalue", db_getupvalue},
     384              :   {"setfenv", db_setfenv},
     385              :   {"sethook", db_sethook},
     386              :   {"setlocal", db_setlocal},
     387              :   {"setmetatable", db_setmetatable},
     388              :   {"setupvalue", db_setupvalue},
     389              :   {"traceback", db_errorfb},
     390              :   {NULL, NULL}
     391              : };
     392              : 
     393              : 
     394           83 : LUALIB_API int luaopen_debug (lua_State *L) {
     395           83 :   luaL_register(L, LUA_DBLIBNAME, dblib);
     396           83 :   return 1;
     397              : }
     398              : 
        

Generated by: LCOV version 2.0-1