LCOV - code coverage report
Current view: top level - src - ldblib.c Coverage Total Hit
Test: Lua 5.2.4 Lines: 97.0 % 235 228
Test Date: 2024-04-28 10:23:12
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              : ** $Id: ldblib.c,v 1.132.1.2 2015/02/19 17:16:55 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              : #define HOOKKEY         "_HKEY"
      22              : 
      23              : 
      24           14 : static void checkstack (lua_State *L, lua_State *L1, int n) {
      25           14 :   if (L != L1 && !lua_checkstack(L1, n))
      26            0 :     luaL_error(L, "stack overflow");
      27           14 : }
      28              : 
      29              : 
      30            1 : static int db_getregistry (lua_State *L) {
      31            1 :   lua_pushvalue(L, LUA_REGISTRYINDEX);
      32            1 :   return 1;
      33              : }
      34              : 
      35              : 
      36            6 : static int db_getmetatable (lua_State *L) {
      37            6 :   luaL_checkany(L, 1);
      38            6 :   if (!lua_getmetatable(L, 1)) {
      39            3 :     lua_pushnil(L);  /* no metatable */
      40              :   }
      41            6 :   return 1;
      42              : }
      43              : 
      44              : 
      45            5 : static int db_setmetatable (lua_State *L) {
      46            5 :   int t = lua_type(L, 2);
      47            5 :   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
      48              :                     "nil or table expected");
      49            4 :   lua_settop(L, 2);
      50            4 :   lua_setmetatable(L, 1);
      51            4 :   return 1;  /* return 1st argument */
      52              : }
      53              : 
      54              : 
      55            4 : static int db_getuservalue (lua_State *L) {
      56            4 :   if (lua_type(L, 1) != LUA_TUSERDATA)
      57            1 :     lua_pushnil(L);
      58              :   else
      59            3 :     lua_getuservalue(L, 1);
      60            4 :   return 1;
      61              : }
      62              : 
      63              : 
      64            3 : static int db_setuservalue (lua_State *L) {
      65            3 :   if (lua_type(L, 1) == LUA_TLIGHTUSERDATA)
      66            0 :     luaL_argerror(L, 1, "full userdata expected, got light userdata");
      67            3 :   luaL_checktype(L, 1, LUA_TUSERDATA);
      68            2 :   if (!lua_isnoneornil(L, 2))
      69            1 :     luaL_checktype(L, 2, LUA_TTABLE);
      70            2 :   lua_settop(L, 2);
      71            2 :   lua_setuservalue(L, 1);
      72            2 :   return 1;
      73              : }
      74              : 
      75              : 
      76           10 : static void settabss (lua_State *L, const char *i, const char *v) {
      77           10 :   lua_pushstring(L, v);
      78           10 :   lua_setfield(L, -2, i);
      79           10 : }
      80              : 
      81              : 
      82           10 : static void settabsi (lua_State *L, const char *i, int v) {
      83           10 :   lua_pushinteger(L, v);
      84           10 :   lua_setfield(L, -2, i);
      85           10 : }
      86              : 
      87              : 
      88            4 : static void settabsb (lua_State *L, const char *i, int v) {
      89            4 :   lua_pushboolean(L, v);
      90            4 :   lua_setfield(L, -2, i);
      91            4 : }
      92              : 
      93              : 
      94           20 : static lua_State *getthread (lua_State *L, int *arg) {
      95           20 :   if (lua_isthread(L, 1)) {
      96            1 :     *arg = 1;
      97            1 :     return lua_tothread(L, 1);
      98              :   }
      99              :   else {
     100           19 :     *arg = 0;
     101           19 :     return L;
     102              :   }
     103              : }
     104              : 
     105              : 
     106            3 : static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
     107            3 :   if (L == L1) {
     108            3 :     lua_pushvalue(L, -2);
     109            3 :     lua_remove(L, -3);
     110              :   }
     111              :   else
     112            0 :     lua_xmove(L1, L, 1);
     113            3 :   lua_setfield(L, -2, fname);
     114            3 : }
     115              : 
     116              : 
     117            6 : static int db_getinfo (lua_State *L) {
     118              :   lua_Debug ar;
     119              :   int arg;
     120            6 :   lua_State *L1 = getthread(L, &arg);
     121            6 :   const char *options = luaL_optstring(L, arg+2, "flnStu");
     122            6 :   checkstack(L, L1, 3);
     123            6 :   if (lua_isnumber(L, arg+1)) {
     124            2 :     if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
     125            1 :       lua_pushnil(L);  /* level out of range */
     126            1 :       return 1;
     127              :     }
     128              :   }
     129            4 :   else if (lua_isfunction(L, arg+1)) {
     130            3 :     lua_pushfstring(L, ">%s", options);
     131            3 :     options = lua_tostring(L, -1);
     132            3 :     lua_pushvalue(L, arg+1);
     133            3 :     lua_xmove(L, L1, 1);
     134              :   }
     135              :   else
     136            1 :     return luaL_argerror(L, arg+1, "function or level expected");
     137            4 :   if (!lua_getinfo(L1, options, &ar))
     138            1 :     return luaL_argerror(L, arg+2, "invalid option");
     139            3 :   lua_createtable(L, 0, 2);
     140            3 :   if (strchr(options, 'S')) {
     141            2 :     settabss(L, "source", ar.source);
     142            2 :     settabss(L, "short_src", ar.short_src);
     143            2 :     settabsi(L, "linedefined", ar.linedefined);
     144            2 :     settabsi(L, "lastlinedefined", ar.lastlinedefined);
     145            2 :     settabss(L, "what", ar.what);
     146              :   }
     147            3 :   if (strchr(options, 'l'))
     148            2 :     settabsi(L, "currentline", ar.currentline);
     149            3 :   if (strchr(options, 'u')) {
     150            2 :     settabsi(L, "nups", ar.nups);
     151            2 :     settabsi(L, "nparams", ar.nparams);
     152            2 :     settabsb(L, "isvararg", ar.isvararg);
     153              :   }
     154            3 :   if (strchr(options, 'n')) {
     155            2 :     settabss(L, "name", ar.name);
     156            2 :     settabss(L, "namewhat", ar.namewhat);
     157              :   }
     158            3 :   if (strchr(options, 't'))
     159            2 :     settabsb(L, "istailcall", ar.istailcall);
     160            3 :   if (strchr(options, 'L'))
     161            1 :     treatstackoption(L, L1, "activelines");
     162            3 :   if (strchr(options, 'f'))
     163            2 :     treatstackoption(L, L1, "func");
     164            3 :   return 1;  /* return table */
     165              : }
     166              : 
     167              : 
     168            3 : static int db_getlocal (lua_State *L) {
     169              :   int arg;
     170            3 :   lua_State *L1 = getthread(L, &arg);
     171              :   lua_Debug ar;
     172              :   const char *name;
     173            3 :   int nvar = luaL_checkint(L, arg+2);  /* local-variable index */
     174            3 :   if (lua_isfunction(L, arg + 1)) {  /* function argument? */
     175            1 :     lua_pushvalue(L, arg + 1);  /* push function */
     176            1 :     lua_pushstring(L, lua_getlocal(L, NULL, nvar));  /* push local name */
     177            1 :     return 1;
     178              :   }
     179              :   else {  /* stack-level argument */
     180            2 :     if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
     181            1 :       return luaL_argerror(L, arg+1, "level out of range");
     182            1 :     checkstack(L, L1, 1);
     183            1 :     name = lua_getlocal(L1, &ar, nvar);
     184            1 :     if (name) {
     185            1 :       lua_xmove(L1, L, 1);  /* push local value */
     186            1 :       lua_pushstring(L, name);  /* push name */
     187            1 :       lua_pushvalue(L, -2);  /* re-order */
     188            1 :       return 2;
     189              :     }
     190              :     else {
     191            0 :       lua_pushnil(L);  /* no name (nor value) */
     192            0 :       return 1;
     193              :     }
     194              :   }
     195              : }
     196              : 
     197              : 
     198            3 : static int db_setlocal (lua_State *L) {
     199              :   int arg;
     200            3 :   lua_State *L1 = getthread(L, &arg);
     201              :   lua_Debug ar;
     202            3 :   if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
     203            1 :     return luaL_argerror(L, arg+1, "level out of range");
     204            2 :   luaL_checkany(L, arg+3);
     205            2 :   lua_settop(L, arg+3);
     206            2 :   checkstack(L, L1, 1);
     207            2 :   lua_xmove(L, L1, 1);
     208            2 :   lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
     209            2 :   return 1;
     210              : }
     211              : 
     212              : 
     213            3 : static int auxupvalue (lua_State *L, int get) {
     214              :   const char *name;
     215            3 :   int n = luaL_checkint(L, 2);
     216            3 :   luaL_checktype(L, 1, LUA_TFUNCTION);
     217            3 :   name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
     218            3 :   if (name == NULL) return 0;
     219            2 :   lua_pushstring(L, name);
     220            2 :   lua_insert(L, -(get+1));
     221            2 :   return get + 1;
     222              : }
     223              : 
     224              : 
     225            1 : static int db_getupvalue (lua_State *L) {
     226            1 :   return auxupvalue(L, 1);
     227              : }
     228              : 
     229              : 
     230            2 : static int db_setupvalue (lua_State *L) {
     231            2 :   luaL_checkany(L, 3);
     232            2 :   return auxupvalue(L, 0);
     233              : }
     234              : 
     235              : 
     236            6 : static int checkupval (lua_State *L, int argf, int argnup) {
     237              :   lua_Debug ar;
     238            6 :   int nup = luaL_checkint(L, argnup);
     239            6 :   luaL_checktype(L, argf, LUA_TFUNCTION);
     240            4 :   lua_pushvalue(L, argf);
     241            4 :   lua_getinfo(L, ">u", &ar);
     242            4 :   luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index");
     243            4 :   return nup;
     244              : }
     245              : 
     246              : 
     247            1 : static int db_upvalueid (lua_State *L) {
     248            1 :   int n = checkupval(L, 1, 2);
     249            1 :   lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
     250            1 :   return 1;
     251              : }
     252              : 
     253              : 
     254            3 : static int db_upvaluejoin (lua_State *L) {
     255            3 :   int n1 = checkupval(L, 1, 2);
     256            2 :   int n2 = checkupval(L, 3, 4);
     257            1 :   luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
     258            1 :   luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
     259            1 :   lua_upvaluejoin(L, 1, n1, 3, n2);
     260            1 :   return 0;
     261              : }
     262              : 
     263              : 
     264              : #define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
     265              : 
     266              : 
     267          227 : static void hookf (lua_State *L, lua_Debug *ar) {
     268              :   static const char *const hooknames[] =
     269              :     {"call", "return", "line", "count", "tail call"};
     270          227 :   gethooktable(L);
     271          227 :   lua_pushthread(L);
     272          227 :   lua_rawget(L, -2);
     273          227 :   if (lua_isfunction(L, -1)) {
     274          227 :     lua_pushstring(L, hooknames[(int)ar->event]);
     275          227 :     if (ar->currentline >= 0)
     276            0 :       lua_pushinteger(L, ar->currentline);
     277          227 :     else lua_pushnil(L);
     278              :     lua_assert(lua_getinfo(L, "lS", ar));
     279          227 :     lua_call(L, 2, 0);
     280              :   }
     281          227 : }
     282              : 
     283              : 
     284            1 : static int makemask (const char *smask, int count) {
     285            1 :   int mask = 0;
     286            1 :   if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
     287            1 :   if (strchr(smask, 'r')) mask |= LUA_MASKRET;
     288            1 :   if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
     289            1 :   if (count > 0) mask |= LUA_MASKCOUNT;
     290            1 :   return mask;
     291              : }
     292              : 
     293              : 
     294            3 : static char *unmakemask (int mask, char *smask) {
     295            3 :   int i = 0;
     296            3 :   if (mask & LUA_MASKCALL) smask[i++] = 'c';
     297            3 :   if (mask & LUA_MASKRET) smask[i++] = 'r';
     298            3 :   if (mask & LUA_MASKLINE) smask[i++] = 'l';
     299            3 :   smask[i] = '\0';
     300            3 :   return smask;
     301              : }
     302              : 
     303              : 
     304            2 : static int db_sethook (lua_State *L) {
     305              :   int arg, mask, count;
     306              :   lua_Hook func;
     307            2 :   lua_State *L1 = getthread(L, &arg);
     308            2 :   if (lua_isnoneornil(L, arg+1)) {
     309            1 :     lua_settop(L, arg+1);
     310            1 :     func = NULL; mask = 0; count = 0;  /* turn off hooks */
     311              :   }
     312              :   else {
     313            1 :     const char *smask = luaL_checkstring(L, arg+2);
     314            1 :     luaL_checktype(L, arg+1, LUA_TFUNCTION);
     315            1 :     count = luaL_optint(L, arg+3, 0);
     316            1 :     func = hookf; mask = makemask(smask, count);
     317              :   }
     318            2 :   if (gethooktable(L) == 0) {  /* creating hook table? */
     319            1 :     lua_pushstring(L, "k");
     320            1 :     lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
     321            1 :     lua_pushvalue(L, -1);
     322            1 :     lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */
     323              :   }
     324            2 :   checkstack(L, L1, 1);
     325            2 :   lua_pushthread(L1); lua_xmove(L1, L, 1);
     326            2 :   lua_pushvalue(L, arg+1);
     327            2 :   lua_rawset(L, -3);  /* set new hook */
     328            2 :   lua_sethook(L1, func, mask, count);  /* set hooks */
     329            2 :   return 0;
     330              : }
     331              : 
     332              : 
     333            3 : static int db_gethook (lua_State *L) {
     334              :   int arg;
     335            3 :   lua_State *L1 = getthread(L, &arg);
     336              :   char buff[5];
     337            3 :   int mask = lua_gethookmask(L1);
     338            3 :   lua_Hook hook = lua_gethook(L1);
     339            3 :   if (hook != NULL && hook != hookf)  /* external hook? */
     340            0 :     lua_pushliteral(L, "external hook");
     341              :   else {
     342            3 :     gethooktable(L);
     343            3 :     checkstack(L, L1, 1);
     344            3 :     lua_pushthread(L1); lua_xmove(L1, L, 1);
     345            3 :     lua_rawget(L, -2);   /* get hook */
     346            3 :     lua_remove(L, -2);  /* remove hook table */
     347              :   }
     348            3 :   lua_pushstring(L, unmakemask(mask, buff));
     349            3 :   lua_pushinteger(L, lua_gethookcount(L1));
     350            3 :   return 3;
     351              : }
     352              : 
     353              : 
     354            1 : static int db_debug (lua_State *L) {
     355            2 :   for (;;) {
     356              :     char buffer[250];
     357            3 :     luai_writestringerror("%s", "lua_debug> ");
     358            3 :     if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
     359            3 :         strcmp(buffer, "cont\n") == 0)
     360            1 :       return 0;
     361            4 :     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
     362            2 :         lua_pcall(L, 0, 0, 0))
     363            1 :       luai_writestringerror("%s\n", lua_tostring(L, -1));
     364            2 :     lua_settop(L, 0);  /* remove eventual returns */
     365              :   }
     366              : }
     367              : 
     368              : 
     369            3 : static int db_traceback (lua_State *L) {
     370              :   int arg;
     371            3 :   lua_State *L1 = getthread(L, &arg);
     372            3 :   const char *msg = lua_tostring(L, arg + 1);
     373            3 :   if (msg == NULL && !lua_isnoneornil(L, arg + 1))  /* non-string 'msg'? */
     374            1 :     lua_pushvalue(L, arg + 1);  /* return it untouched */
     375              :   else {
     376            2 :     int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0);
     377            2 :     luaL_traceback(L, L1, msg, level);
     378              :   }
     379            3 :   return 1;
     380              : }
     381              : 
     382              : 
     383              : static const luaL_Reg dblib[] = {
     384              :   {"debug", db_debug},
     385              :   {"getuservalue", db_getuservalue},
     386              :   {"gethook", db_gethook},
     387              :   {"getinfo", db_getinfo},
     388              :   {"getlocal", db_getlocal},
     389              :   {"getregistry", db_getregistry},
     390              :   {"getmetatable", db_getmetatable},
     391              :   {"getupvalue", db_getupvalue},
     392              :   {"upvaluejoin", db_upvaluejoin},
     393              :   {"upvalueid", db_upvalueid},
     394              :   {"setuservalue", db_setuservalue},
     395              :   {"sethook", db_sethook},
     396              :   {"setlocal", db_setlocal},
     397              :   {"setmetatable", db_setmetatable},
     398              :   {"setupvalue", db_setupvalue},
     399              :   {"traceback", db_traceback},
     400              :   {NULL, NULL}
     401              : };
     402              : 
     403              : 
     404           86 : LUAMOD_API int luaopen_debug (lua_State *L) {
     405           86 :   luaL_newlib(L, dblib);
     406           86 :   return 1;
     407              : }
     408              : 
        

Generated by: LCOV version 2.0-1