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