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