Fix 'f' and 'L' options for debug.getinfo() and lua_getinfo().
[luajit-2.0.git] / src / lib_debug.c
blobab504de7e9124cb7059ce11ad67d7943cc07b033
1 /*
2 ** Debug library.
3 ** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4 **
5 ** Major portions taken verbatim or adapted from the Lua interpreter.
6 ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
7 */
9 #define lib_debug_c
10 #define LUA_LIB
12 #include "lua.h"
13 #include "lauxlib.h"
14 #include "lualib.h"
16 #include "lj_obj.h"
17 #include "lj_err.h"
18 #include "lj_lib.h"
20 /* ------------------------------------------------------------------------ */
22 #define LJLIB_MODULE_debug
24 LJLIB_CF(debug_getregistry)
26 copyTV(L, L->top++, registry(L));
27 return 1;
30 LJLIB_CF(debug_getmetatable)
32 lj_lib_checkany(L, 1);
33 if (!lua_getmetatable(L, 1)) {
34 setnilV(L->top-1);
36 return 1;
39 LJLIB_CF(debug_setmetatable)
41 lj_lib_checktabornil(L, 2);
42 L->top = L->base+2;
43 lua_setmetatable(L, 1);
44 #if !LJ_52
45 setboolV(L->top-1, 1);
46 #endif
47 return 1;
50 LJLIB_CF(debug_getfenv)
52 lj_lib_checkany(L, 1);
53 lua_getfenv(L, 1);
54 return 1;
57 LJLIB_CF(debug_setfenv)
59 lj_lib_checktab(L, 2);
60 L->top = L->base+2;
61 if (!lua_setfenv(L, 1))
62 lj_err_caller(L, LJ_ERR_SETFENV);
63 return 1;
66 /* ------------------------------------------------------------------------ */
68 static void settabss(lua_State *L, const char *i, const char *v)
70 lua_pushstring(L, v);
71 lua_setfield(L, -2, i);
74 static void settabsi(lua_State *L, const char *i, int v)
76 lua_pushinteger(L, v);
77 lua_setfield(L, -2, i);
80 static lua_State *getthread(lua_State *L, int *arg)
82 if (L->base < L->top && tvisthread(L->base)) {
83 *arg = 1;
84 return threadV(L->base);
85 } else {
86 *arg = 0;
87 return L;
91 static void treatstackoption(lua_State *L, lua_State *L1, const char *fname)
93 if (L == L1) {
94 lua_pushvalue(L, -2);
95 lua_remove(L, -3);
97 else
98 lua_xmove(L1, L, 1);
99 lua_setfield(L, -2, fname);
102 LJLIB_CF(debug_getinfo)
104 lua_Debug ar;
105 int arg, opt_f = 0, opt_L = 0;
106 lua_State *L1 = getthread(L, &arg);
107 const char *options = luaL_optstring(L, arg+2, "flnSu");
108 if (lua_isnumber(L, arg+1)) {
109 if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
110 setnilV(L->top-1);
111 return 1;
113 } else if (L->base+arg < L->top && tvisfunc(L->base+arg)) {
114 options = lua_pushfstring(L, ">%s", options);
115 setfuncV(L1, L1->top++, funcV(L->base+arg));
116 } else {
117 lj_err_arg(L, arg+1, LJ_ERR_NOFUNCL);
119 if (!lua_getinfo(L1, options, &ar))
120 lj_err_arg(L, arg+2, LJ_ERR_INVOPT);
121 lua_createtable(L, 0, 16); /* Create result table. */
122 for (; *options; options++) {
123 switch (*options) {
124 case 'S':
125 settabss(L, "source", ar.source);
126 settabss(L, "short_src", ar.short_src);
127 settabsi(L, "linedefined", ar.linedefined);
128 settabsi(L, "lastlinedefined", ar.lastlinedefined);
129 settabss(L, "what", ar.what);
130 break;
131 case 'l':
132 settabsi(L, "currentline", ar.currentline);
133 break;
134 case 'u':
135 settabsi(L, "nups", ar.nups);
136 break;
137 case 'n':
138 settabss(L, "name", ar.name);
139 settabss(L, "namewhat", ar.namewhat);
140 break;
141 case 'f': opt_f = 1; break;
142 case 'L': opt_L = 1; break;
143 default: break;
146 if (opt_L) treatstackoption(L, L1, "activelines");
147 if (opt_f) treatstackoption(L, L1, "func");
148 return 1; /* Return result table. */
151 LJLIB_CF(debug_getlocal)
153 int arg;
154 lua_State *L1 = getthread(L, &arg);
155 lua_Debug ar;
156 const char *name;
157 int slot = lj_lib_checkint(L, arg+2);
158 if (tvisfunc(L->base+arg)) {
159 L->top = L->base+arg+1;
160 lua_pushstring(L, lua_getlocal(L, NULL, slot));
161 return 1;
163 if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
164 lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
165 name = lua_getlocal(L1, &ar, slot);
166 if (name) {
167 lua_xmove(L1, L, 1);
168 lua_pushstring(L, name);
169 lua_pushvalue(L, -2);
170 return 2;
171 } else {
172 setnilV(L->top-1);
173 return 1;
177 LJLIB_CF(debug_setlocal)
179 int arg;
180 lua_State *L1 = getthread(L, &arg);
181 lua_Debug ar;
182 TValue *tv;
183 if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
184 lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
185 tv = lj_lib_checkany(L, arg+3);
186 copyTV(L1, L1->top++, tv);
187 lua_pushstring(L, lua_setlocal(L1, &ar, lj_lib_checkint(L, arg+2)));
188 return 1;
191 static int debug_getupvalue(lua_State *L, int get)
193 int32_t n = lj_lib_checkint(L, 2);
194 const char *name;
195 lj_lib_checkfunc(L, 1);
196 name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
197 if (name) {
198 lua_pushstring(L, name);
199 if (!get) return 1;
200 copyTV(L, L->top, L->top-2);
201 L->top++;
202 return 2;
204 return 0;
207 LJLIB_CF(debug_getupvalue)
209 return debug_getupvalue(L, 1);
212 LJLIB_CF(debug_setupvalue)
214 lj_lib_checkany(L, 3);
215 return debug_getupvalue(L, 0);
218 /* ------------------------------------------------------------------------ */
220 static const char KEY_HOOK = 'h';
222 static void hookf(lua_State *L, lua_Debug *ar)
224 static const char *const hooknames[] =
225 {"call", "return", "line", "count", "tail return"};
226 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
227 lua_rawget(L, LUA_REGISTRYINDEX);
228 if (lua_isfunction(L, -1)) {
229 lua_pushstring(L, hooknames[(int)ar->event]);
230 if (ar->currentline >= 0)
231 lua_pushinteger(L, ar->currentline);
232 else lua_pushnil(L);
233 lua_call(L, 2, 0);
237 static int makemask(const char *smask, int count)
239 int mask = 0;
240 if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
241 if (strchr(smask, 'r')) mask |= LUA_MASKRET;
242 if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
243 if (count > 0) mask |= LUA_MASKCOUNT;
244 return mask;
247 static char *unmakemask(int mask, char *smask)
249 int i = 0;
250 if (mask & LUA_MASKCALL) smask[i++] = 'c';
251 if (mask & LUA_MASKRET) smask[i++] = 'r';
252 if (mask & LUA_MASKLINE) smask[i++] = 'l';
253 smask[i] = '\0';
254 return smask;
257 LJLIB_CF(debug_sethook)
259 int arg, mask, count;
260 lua_Hook func;
261 (void)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 } else {
266 const char *smask = luaL_checkstring(L, arg+2);
267 luaL_checktype(L, arg+1, LUA_TFUNCTION);
268 count = luaL_optint(L, arg+3, 0);
269 func = hookf; mask = makemask(smask, count);
271 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
272 lua_pushvalue(L, arg+1);
273 lua_rawset(L, LUA_REGISTRYINDEX);
274 lua_sethook(L, func, mask, count);
275 return 0;
278 LJLIB_CF(debug_gethook)
280 char buff[5];
281 int mask = lua_gethookmask(L);
282 lua_Hook hook = lua_gethook(L);
283 if (hook != NULL && hook != hookf) { /* external hook? */
284 lua_pushliteral(L, "external hook");
285 } else {
286 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
287 lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
289 lua_pushstring(L, unmakemask(mask, buff));
290 lua_pushinteger(L, lua_gethookcount(L));
291 return 3;
294 /* ------------------------------------------------------------------------ */
296 LJLIB_CF(debug_debug)
298 for (;;) {
299 char buffer[250];
300 fputs("lua_debug> ", stderr);
301 if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
302 strcmp(buffer, "cont\n") == 0)
303 return 0;
304 if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
305 lua_pcall(L, 0, 0, 0)) {
306 fputs(lua_tostring(L, -1), stderr);
307 fputs("\n", stderr);
309 lua_settop(L, 0); /* remove eventual returns */
313 /* ------------------------------------------------------------------------ */
315 #define LEVELS1 12 /* size of the first part of the stack */
316 #define LEVELS2 10 /* size of the second part of the stack */
318 LJLIB_CF(debug_traceback)
320 int level;
321 int firstpart = 1; /* still before eventual `...' */
322 int arg;
323 lua_State *L1 = getthread(L, &arg);
324 lua_Debug ar;
325 if (lua_isnumber(L, arg+2)) {
326 level = (int)lua_tointeger(L, arg+2);
327 lua_pop(L, 1);
329 else
330 level = (L == L1) ? 1 : 0; /* level 0 may be this own function */
331 if (lua_gettop(L) == arg)
332 lua_pushliteral(L, "");
333 else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */
334 else lua_pushliteral(L, "\n");
335 lua_pushliteral(L, "stack traceback:");
336 while (lua_getstack(L1, level++, &ar)) {
337 if (level > LEVELS1 && firstpart) {
338 /* no more than `LEVELS2' more levels? */
339 if (!lua_getstack(L1, level+LEVELS2, &ar)) {
340 level--; /* keep going */
341 } else {
342 lua_pushliteral(L, "\n\t..."); /* too many levels */
343 /* This only works with LuaJIT 2.x. Avoids O(n^2) behaviour. */
344 lua_getstack(L1, -10, &ar);
345 level = ar.i_ci - LEVELS2;
347 firstpart = 0;
348 continue;
350 lua_pushliteral(L, "\n\t");
351 lua_getinfo(L1, "Snl", &ar);
352 lua_pushfstring(L, "%s:", ar.short_src);
353 if (ar.currentline > 0)
354 lua_pushfstring(L, "%d:", ar.currentline);
355 if (*ar.namewhat != '\0') { /* is there a name? */
356 lua_pushfstring(L, " in function " LUA_QS, ar.name);
357 } else {
358 if (*ar.what == 'm') /* main? */
359 lua_pushfstring(L, " in main chunk");
360 else if (*ar.what == 'C' || *ar.what == 't')
361 lua_pushliteral(L, " ?"); /* C function or tail call */
362 else
363 lua_pushfstring(L, " in function <%s:%d>",
364 ar.short_src, ar.linedefined);
366 lua_concat(L, lua_gettop(L) - arg);
368 lua_concat(L, lua_gettop(L) - arg);
369 return 1;
372 /* ------------------------------------------------------------------------ */
374 #include "lj_libdef.h"
376 LUALIB_API int luaopen_debug(lua_State *L)
378 LJ_LIB_REG(L, LUA_DBLIBNAME, debug);
379 return 1;