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