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