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 25static int db_getregistry (lua_State *L) { 26 lua_pushvalue(L, LUA_REGISTRYINDEX); 27 return 1; 28} 29 30 31static 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 40static 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 50static 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 59static 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 71static 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 77static void settabsi (lua_State *L, const char *i, int v) { 78 lua_pushinteger(L, v); 79 lua_setfield(L, -2, i); 80} 81 82 83static void settabsb (lua_State *L, const char *i, int v) { 84 lua_pushboolean(L, v); 85 lua_setfield(L, -2, i); 86} 87 88 89static 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 101static 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 112static 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 162static 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 191static 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 205static 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 217static int db_getupvalue (lua_State *L) { 218 return auxupvalue(L, 1); 219} 220 221 222static int db_setupvalue (lua_State *L) { 223 luaL_checkany(L, 3); 224 return auxupvalue(L, 0); 225} 226 227 228static 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 239static 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 246static 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 259static 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 276static 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 286static 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 296static 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 324static 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 344static 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 359static 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 373static 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 394LUAMOD_API int luaopen_debug (lua_State *L) { 395 luaL_newlib(L, dblib); 396 return 1; 397} 398 399