lua

A copy of the Lua development repository
Log | Files | Refs | README

ldblib.c (13211B)


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