LCOV - code coverage report
Current view: top level - src - ldblib.c Coverage Total Hit
Test: Lua 5.3.6 Lines: 97.5 % 236 230
Test Date: 2024-04-28 10:23:15
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              : ** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $
       3              : ** Interface from Lua to its debug API
       4              : ** See Copyright Notice in lua.h
       5              : */
       6              : 
       7              : #define ldblib_c
       8              : #define LUA_LIB
       9              : 
      10              : #include "lprefix.h"
      11              : 
      12              : 
      13              : #include <stdio.h>
      14              : #include <stdlib.h>
      15              : #include <string.h>
      16              : 
      17              : #include "lua.h"
      18              : 
      19              : #include "lauxlib.h"
      20              : #include "lualib.h"
      21              : 
      22              : 
      23              : /*
      24              : ** The hook table at registry[&HOOKKEY] maps threads to their current
      25              : ** hook function. (We only need the unique address of 'HOOKKEY'.)
      26              : */
      27              : static const int HOOKKEY = 0;
      28              : 
      29              : 
      30              : /*
      31              : ** If L1 != L, L1 can be in any state, and therefore there are no
      32              : ** guarantees about its stack space; any push in L1 must be
      33              : ** checked.
      34              : */
      35           13 : static void checkstack (lua_State *L, lua_State *L1, int n) {
      36           13 :   if (L != L1 && !lua_checkstack(L1, n))
      37            0 :     luaL_error(L, "stack overflow");
      38           13 : }
      39              : 
      40              : 
      41            1 : static int db_getregistry (lua_State *L) {
      42            1 :   lua_pushvalue(L, LUA_REGISTRYINDEX);
      43            1 :   return 1;
      44              : }
      45              : 
      46              : 
      47            6 : static int db_getmetatable (lua_State *L) {
      48            6 :   luaL_checkany(L, 1);
      49            6 :   if (!lua_getmetatable(L, 1)) {
      50            3 :     lua_pushnil(L);  /* no metatable */
      51              :   }
      52            6 :   return 1;
      53              : }
      54              : 
      55              : 
      56            5 : static int db_setmetatable (lua_State *L) {
      57            5 :   int t = lua_type(L, 2);
      58            5 :   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
      59              :                     "nil or table expected");
      60            4 :   lua_settop(L, 2);
      61            4 :   lua_setmetatable(L, 1);
      62            4 :   return 1;  /* return 1st argument */
      63              : }
      64              : 
      65              : 
      66            4 : static int db_getuservalue (lua_State *L) {
      67            4 :   if (lua_type(L, 1) != LUA_TUSERDATA)
      68            1 :     lua_pushnil(L);
      69              :   else
      70            3 :     lua_getuservalue(L, 1);
      71            4 :   return 1;
      72              : }
      73              : 
      74              : 
      75            3 : static int db_setuservalue (lua_State *L) {
      76            3 :   luaL_checktype(L, 1, LUA_TUSERDATA);
      77            2 :   luaL_checkany(L, 2);
      78            2 :   lua_settop(L, 2);
      79            2 :   lua_setuservalue(L, 1);
      80            2 :   return 1;
      81              : }
      82              : 
      83              : 
      84              : /*
      85              : ** Auxiliary function used by several library functions: check for
      86              : ** an optional thread as function's first argument and set 'arg' with
      87              : ** 1 if this argument is present (so that functions can skip it to
      88              : ** access their other arguments)
      89              : */
      90           20 : static lua_State *getthread (lua_State *L, int *arg) {
      91           20 :   if (lua_isthread(L, 1)) {
      92            1 :     *arg = 1;
      93            1 :     return lua_tothread(L, 1);
      94              :   }
      95              :   else {
      96           19 :     *arg = 0;
      97           19 :     return L;  /* function will operate over current thread */
      98              :   }
      99              : }
     100              : 
     101              : 
     102              : /*
     103              : ** Variations of 'lua_settable', used by 'db_getinfo' to put results
     104              : ** from 'lua_getinfo' into result table. Key is always a string;
     105              : ** value can be a string, an int, or a boolean.
     106              : */
     107           10 : static void settabss (lua_State *L, const char *k, const char *v) {
     108           10 :   lua_pushstring(L, v);
     109           10 :   lua_setfield(L, -2, k);
     110           10 : }
     111              : 
     112           10 : static void settabsi (lua_State *L, const char *k, int v) {
     113           10 :   lua_pushinteger(L, v);
     114           10 :   lua_setfield(L, -2, k);
     115           10 : }
     116              : 
     117            4 : static void settabsb (lua_State *L, const char *k, int v) {
     118            4 :   lua_pushboolean(L, v);
     119            4 :   lua_setfield(L, -2, k);
     120            4 : }
     121              : 
     122              : 
     123              : /*
     124              : ** In function 'db_getinfo', the call to 'lua_getinfo' may push
     125              : ** results on the stack; later it creates the result table to put
     126              : ** these objects. Function 'treatstackoption' puts the result from
     127              : ** 'lua_getinfo' on top of the result table so that it can call
     128              : ** 'lua_setfield'.
     129              : */
     130            3 : static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
     131            3 :   if (L == L1)
     132            3 :     lua_rotate(L, -2, 1);  /* exchange object and table */
     133              :   else
     134            0 :     lua_xmove(L1, L, 1);  /* move object to the "main" stack */
     135            3 :   lua_setfield(L, -2, fname);  /* put object into table */
     136            3 : }
     137              : 
     138              : 
     139              : /*
     140              : ** Calls 'lua_getinfo' and collects all results in a new table.
     141              : ** L1 needs stack space for an optional input (function) plus
     142              : ** two optional outputs (function and line table) from function
     143              : ** 'lua_getinfo'.
     144              : */
     145            6 : static int db_getinfo (lua_State *L) {
     146              :   lua_Debug ar;
     147              :   int arg;
     148            6 :   lua_State *L1 = getthread(L, &arg);
     149            6 :   const char *options = luaL_optstring(L, arg+2, "flnStu");
     150            6 :   checkstack(L, L1, 3);
     151            6 :   if (lua_isfunction(L, arg + 1)) {  /* info about a function? */
     152            3 :     options = lua_pushfstring(L, ">%s", options);  /* add '>' to 'options' */
     153            3 :     lua_pushvalue(L, arg + 1);  /* move function to 'L1' stack */
     154            3 :     lua_xmove(L, L1, 1);
     155              :   }
     156              :   else {  /* stack level */
     157            3 :     if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
     158            1 :       lua_pushnil(L);  /* level out of range */
     159            1 :       return 1;
     160              :     }
     161              :   }
     162            4 :   if (!lua_getinfo(L1, options, &ar))
     163            1 :     return luaL_argerror(L, arg+2, "invalid option");
     164            3 :   lua_newtable(L);  /* table to collect results */
     165            3 :   if (strchr(options, 'S')) {
     166            2 :     settabss(L, "source", ar.source);
     167            2 :     settabss(L, "short_src", ar.short_src);
     168            2 :     settabsi(L, "linedefined", ar.linedefined);
     169            2 :     settabsi(L, "lastlinedefined", ar.lastlinedefined);
     170            2 :     settabss(L, "what", ar.what);
     171              :   }
     172            3 :   if (strchr(options, 'l'))
     173            2 :     settabsi(L, "currentline", ar.currentline);
     174            3 :   if (strchr(options, 'u')) {
     175            2 :     settabsi(L, "nups", ar.nups);
     176            2 :     settabsi(L, "nparams", ar.nparams);
     177            2 :     settabsb(L, "isvararg", ar.isvararg);
     178              :   }
     179            3 :   if (strchr(options, 'n')) {
     180            2 :     settabss(L, "name", ar.name);
     181            2 :     settabss(L, "namewhat", ar.namewhat);
     182              :   }
     183            3 :   if (strchr(options, 't'))
     184            2 :     settabsb(L, "istailcall", ar.istailcall);
     185            3 :   if (strchr(options, 'L'))
     186            1 :     treatstackoption(L, L1, "activelines");
     187            3 :   if (strchr(options, 'f'))
     188            2 :     treatstackoption(L, L1, "func");
     189            3 :   return 1;  /* return table */
     190              : }
     191              : 
     192              : 
     193            3 : static int db_getlocal (lua_State *L) {
     194              :   int arg;
     195            3 :   lua_State *L1 = getthread(L, &arg);
     196              :   lua_Debug ar;
     197              :   const char *name;
     198            3 :   int nvar = (int)luaL_checkinteger(L, arg + 2);  /* local-variable index */
     199            3 :   if (lua_isfunction(L, arg + 1)) {  /* function argument? */
     200            1 :     lua_pushvalue(L, arg + 1);  /* push function */
     201            1 :     lua_pushstring(L, lua_getlocal(L, NULL, nvar));  /* push local name */
     202            1 :     return 1;  /* return only name (there is no value) */
     203              :   }
     204              :   else {  /* stack-level argument */
     205            2 :     int level = (int)luaL_checkinteger(L, arg + 1);
     206            2 :     if (!lua_getstack(L1, level, &ar))  /* out of range? */
     207            1 :       return luaL_argerror(L, arg+1, "level out of range");
     208            1 :     checkstack(L, L1, 1);
     209            1 :     name = lua_getlocal(L1, &ar, nvar);
     210            1 :     if (name) {
     211            1 :       lua_xmove(L1, L, 1);  /* move local value */
     212            1 :       lua_pushstring(L, name);  /* push name */
     213            1 :       lua_rotate(L, -2, 1);  /* re-order */
     214            1 :       return 2;
     215              :     }
     216              :     else {
     217            0 :       lua_pushnil(L);  /* no name (nor value) */
     218            0 :       return 1;
     219              :     }
     220              :   }
     221              : }
     222              : 
     223              : 
     224            3 : static int db_setlocal (lua_State *L) {
     225              :   int arg;
     226              :   const char *name;
     227            3 :   lua_State *L1 = getthread(L, &arg);
     228              :   lua_Debug ar;
     229            3 :   int level = (int)luaL_checkinteger(L, arg + 1);
     230            3 :   int nvar = (int)luaL_checkinteger(L, arg + 2);
     231            3 :   if (!lua_getstack(L1, level, &ar))  /* out of range? */
     232            1 :     return luaL_argerror(L, arg+1, "level out of range");
     233            2 :   luaL_checkany(L, arg+3);
     234            2 :   lua_settop(L, arg+3);
     235            2 :   checkstack(L, L1, 1);
     236            2 :   lua_xmove(L, L1, 1);
     237            2 :   name = lua_setlocal(L1, &ar, nvar);
     238            2 :   if (name == NULL)
     239            1 :     lua_pop(L1, 1);  /* pop value (if not popped by 'lua_setlocal') */
     240            2 :   lua_pushstring(L, name);
     241            2 :   return 1;
     242              : }
     243              : 
     244              : 
     245              : /*
     246              : ** get (if 'get' is true) or set an upvalue from a closure
     247              : */
     248            3 : static int auxupvalue (lua_State *L, int get) {
     249              :   const char *name;
     250            3 :   int n = (int)luaL_checkinteger(L, 2);  /* upvalue index */
     251            3 :   luaL_checktype(L, 1, LUA_TFUNCTION);  /* closure */
     252            3 :   name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
     253            3 :   if (name == NULL) return 0;
     254            2 :   lua_pushstring(L, name);
     255            2 :   lua_insert(L, -(get+1));  /* no-op if get is false */
     256            2 :   return get + 1;
     257              : }
     258              : 
     259              : 
     260            1 : static int db_getupvalue (lua_State *L) {
     261            1 :   return auxupvalue(L, 1);
     262              : }
     263              : 
     264              : 
     265            2 : static int db_setupvalue (lua_State *L) {
     266            2 :   luaL_checkany(L, 3);
     267            2 :   return auxupvalue(L, 0);
     268              : }
     269              : 
     270              : 
     271              : /*
     272              : ** Check whether a given upvalue from a given closure exists and
     273              : ** returns its index
     274              : */
     275            6 : static int checkupval (lua_State *L, int argf, int argnup) {
     276            6 :   int nup = (int)luaL_checkinteger(L, argnup);  /* upvalue index */
     277            6 :   luaL_checktype(L, argf, LUA_TFUNCTION);  /* closure */
     278            4 :   luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,
     279              :                    "invalid upvalue index");
     280            4 :   return nup;
     281              : }
     282              : 
     283              : 
     284            1 : static int db_upvalueid (lua_State *L) {
     285            1 :   int n = checkupval(L, 1, 2);
     286            1 :   lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
     287            1 :   return 1;
     288              : }
     289              : 
     290              : 
     291            3 : static int db_upvaluejoin (lua_State *L) {
     292            3 :   int n1 = checkupval(L, 1, 2);
     293            2 :   int n2 = checkupval(L, 3, 4);
     294            1 :   luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
     295            1 :   luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
     296            1 :   lua_upvaluejoin(L, 1, n1, 3, n2);
     297            1 :   return 0;
     298              : }
     299              : 
     300              : 
     301              : /*
     302              : ** Call hook function registered at hook table for the current
     303              : ** thread (if there is one)
     304              : */
     305          227 : static void hookf (lua_State *L, lua_Debug *ar) {
     306              :   static const char *const hooknames[] =
     307              :     {"call", "return", "line", "count", "tail call"};
     308          227 :   lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
     309          227 :   lua_pushthread(L);
     310          227 :   if (lua_rawget(L, -2) == LUA_TFUNCTION) {  /* is there a hook function? */
     311          227 :     lua_pushstring(L, hooknames[(int)ar->event]);  /* push event name */
     312          227 :     if (ar->currentline >= 0)
     313            0 :       lua_pushinteger(L, ar->currentline);  /* push current line */
     314          227 :     else lua_pushnil(L);
     315              :     lua_assert(lua_getinfo(L, "lS", ar));
     316          227 :     lua_call(L, 2, 0);  /* call hook function */
     317              :   }
     318          227 : }
     319              : 
     320              : 
     321              : /*
     322              : ** Convert a string mask (for 'sethook') into a bit mask
     323              : */
     324            1 : static int makemask (const char *smask, int count) {
     325            1 :   int mask = 0;
     326            1 :   if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
     327            1 :   if (strchr(smask, 'r')) mask |= LUA_MASKRET;
     328            1 :   if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
     329            1 :   if (count > 0) mask |= LUA_MASKCOUNT;
     330            1 :   return mask;
     331              : }
     332              : 
     333              : 
     334              : /*
     335              : ** Convert a bit mask (for 'gethook') into a string mask
     336              : */
     337            3 : static char *unmakemask (int mask, char *smask) {
     338            3 :   int i = 0;
     339            3 :   if (mask & LUA_MASKCALL) smask[i++] = 'c';
     340            3 :   if (mask & LUA_MASKRET) smask[i++] = 'r';
     341            3 :   if (mask & LUA_MASKLINE) smask[i++] = 'l';
     342            3 :   smask[i] = '\0';
     343            3 :   return smask;
     344              : }
     345              : 
     346              : 
     347            2 : static int db_sethook (lua_State *L) {
     348              :   int arg, mask, count;
     349              :   lua_Hook func;
     350            2 :   lua_State *L1 = getthread(L, &arg);
     351            2 :   if (lua_isnoneornil(L, arg+1)) {  /* no hook? */
     352            1 :     lua_settop(L, arg+1);
     353            1 :     func = NULL; mask = 0; count = 0;  /* turn off hooks */
     354              :   }
     355              :   else {
     356            1 :     const char *smask = luaL_checkstring(L, arg+2);
     357            1 :     luaL_checktype(L, arg+1, LUA_TFUNCTION);
     358            1 :     count = (int)luaL_optinteger(L, arg + 3, 0);
     359            1 :     func = hookf; mask = makemask(smask, count);
     360              :   }
     361            2 :   if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) {
     362            1 :     lua_createtable(L, 0, 2);  /* create a hook table */
     363            1 :     lua_pushvalue(L, -1);
     364            1 :     lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY);  /* set it in position */
     365            1 :     lua_pushstring(L, "k");
     366            1 :     lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
     367            1 :     lua_pushvalue(L, -1);
     368            1 :     lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */
     369              :   }
     370            2 :   checkstack(L, L1, 1);
     371            2 :   lua_pushthread(L1); lua_xmove(L1, L, 1);  /* key (thread) */
     372            2 :   lua_pushvalue(L, arg + 1);  /* value (hook function) */
     373            2 :   lua_rawset(L, -3);  /* hooktable[L1] = new Lua hook */
     374            2 :   lua_sethook(L1, func, mask, count);
     375            2 :   return 0;
     376              : }
     377              : 
     378              : 
     379            3 : static int db_gethook (lua_State *L) {
     380              :   int arg;
     381            3 :   lua_State *L1 = getthread(L, &arg);
     382              :   char buff[5];
     383            3 :   int mask = lua_gethookmask(L1);
     384            3 :   lua_Hook hook = lua_gethook(L1);
     385            3 :   if (hook == NULL)  /* no hook? */
     386            1 :     lua_pushnil(L);
     387            2 :   else if (hook != hookf)  /* external hook? */
     388            0 :     lua_pushliteral(L, "external hook");
     389              :   else {  /* hook table must exist */
     390            2 :     lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
     391            2 :     checkstack(L, L1, 1);
     392            2 :     lua_pushthread(L1); lua_xmove(L1, L, 1);
     393            2 :     lua_rawget(L, -2);   /* 1st result = hooktable[L1] */
     394            2 :     lua_remove(L, -2);  /* remove hook table */
     395              :   }
     396            3 :   lua_pushstring(L, unmakemask(mask, buff));  /* 2nd result = mask */
     397            3 :   lua_pushinteger(L, lua_gethookcount(L1));  /* 3rd result = count */
     398            3 :   return 3;
     399              : }
     400              : 
     401              : 
     402            1 : static int db_debug (lua_State *L) {
     403            2 :   for (;;) {
     404              :     char buffer[250];
     405            3 :     lua_writestringerror("%s", "lua_debug> ");
     406            3 :     if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
     407            3 :         strcmp(buffer, "cont\n") == 0)
     408            1 :       return 0;
     409            4 :     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
     410            2 :         lua_pcall(L, 0, 0, 0))
     411            1 :       lua_writestringerror("%s\n", lua_tostring(L, -1));
     412            2 :     lua_settop(L, 0);  /* remove eventual returns */
     413              :   }
     414              : }
     415              : 
     416              : 
     417            3 : static int db_traceback (lua_State *L) {
     418              :   int arg;
     419            3 :   lua_State *L1 = getthread(L, &arg);
     420            3 :   const char *msg = lua_tostring(L, arg + 1);
     421            3 :   if (msg == NULL && !lua_isnoneornil(L, arg + 1))  /* non-string 'msg'? */
     422            1 :     lua_pushvalue(L, arg + 1);  /* return it untouched */
     423              :   else {
     424            2 :     int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
     425            2 :     luaL_traceback(L, L1, msg, level);
     426              :   }
     427            3 :   return 1;
     428              : }
     429              : 
     430              : 
     431              : static const luaL_Reg dblib[] = {
     432              :   {"debug", db_debug},
     433              :   {"getuservalue", db_getuservalue},
     434              :   {"gethook", db_gethook},
     435              :   {"getinfo", db_getinfo},
     436              :   {"getlocal", db_getlocal},
     437              :   {"getregistry", db_getregistry},
     438              :   {"getmetatable", db_getmetatable},
     439              :   {"getupvalue", db_getupvalue},
     440              :   {"upvaluejoin", db_upvaluejoin},
     441              :   {"upvalueid", db_upvalueid},
     442              :   {"setuservalue", db_setuservalue},
     443              :   {"sethook", db_sethook},
     444              :   {"setlocal", db_setlocal},
     445              :   {"setmetatable", db_setmetatable},
     446              :   {"setupvalue", db_setupvalue},
     447              :   {"traceback", db_traceback},
     448              :   {NULL, NULL}
     449              : };
     450              : 
     451              : 
     452           86 : LUAMOD_API int luaopen_debug (lua_State *L) {
     453           86 :   luaL_newlib(L, dblib);
     454           86 :   return 1;
     455              : }
     456              : 
        

Generated by: LCOV version 2.0-1