Line data Source code
1 : /*
2 : ** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $
3 : ** Interface from Lua to its debug API
4 : ** See Copyright Notice in lua.h
5 : */
6 :
7 : #define ldblib_c
8 : #define LUA_LIB
9 :
10 : #include "lprefix.h"
11 :
12 :
13 : #include <stdio.h>
14 : #include <stdlib.h>
15 : #include <string.h>
16 :
17 : #include "lua.h"
18 :
19 : #include "lauxlib.h"
20 : #include "lualib.h"
21 :
22 :
23 : /*
24 : ** The hook table at registry[&HOOKKEY] maps threads to their current
25 : ** hook function. (We only need the unique address of 'HOOKKEY'.)
26 : */
27 : static const int HOOKKEY = 0;
28 :
29 :
30 : /*
31 : ** If L1 != L, L1 can be in any state, and therefore there are no
32 : ** guarantees about its stack space; any push in L1 must be
33 : ** checked.
34 : */
35 13 : static void checkstack (lua_State *L, lua_State *L1, int n) {
36 13 : if (L != L1 && !lua_checkstack(L1, n))
37 0 : luaL_error(L, "stack overflow");
38 13 : }
39 :
40 :
41 1 : static int db_getregistry (lua_State *L) {
42 1 : lua_pushvalue(L, LUA_REGISTRYINDEX);
43 1 : return 1;
44 : }
45 :
46 :
47 6 : static int db_getmetatable (lua_State *L) {
48 6 : luaL_checkany(L, 1);
49 6 : if (!lua_getmetatable(L, 1)) {
50 3 : lua_pushnil(L); /* no metatable */
51 : }
52 6 : return 1;
53 : }
54 :
55 :
56 5 : static int db_setmetatable (lua_State *L) {
57 5 : int t = lua_type(L, 2);
58 5 : luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
59 : "nil or table expected");
60 4 : lua_settop(L, 2);
61 4 : lua_setmetatable(L, 1);
62 4 : return 1; /* return 1st argument */
63 : }
64 :
65 :
66 4 : static int db_getuservalue (lua_State *L) {
67 4 : if (lua_type(L, 1) != LUA_TUSERDATA)
68 1 : lua_pushnil(L);
69 : else
70 3 : lua_getuservalue(L, 1);
71 4 : return 1;
72 : }
73 :
74 :
75 3 : static int db_setuservalue (lua_State *L) {
76 3 : luaL_checktype(L, 1, LUA_TUSERDATA);
77 2 : luaL_checkany(L, 2);
78 2 : lua_settop(L, 2);
79 2 : lua_setuservalue(L, 1);
80 2 : return 1;
81 : }
82 :
83 :
84 : /*
85 : ** Auxiliary function used by several library functions: check for
86 : ** an optional thread as function's first argument and set 'arg' with
87 : ** 1 if this argument is present (so that functions can skip it to
88 : ** access their other arguments)
89 : */
90 20 : static lua_State *getthread (lua_State *L, int *arg) {
91 20 : if (lua_isthread(L, 1)) {
92 1 : *arg = 1;
93 1 : return lua_tothread(L, 1);
94 : }
95 : else {
96 19 : *arg = 0;
97 19 : return L; /* function will operate over current thread */
98 : }
99 : }
100 :
101 :
102 : /*
103 : ** Variations of 'lua_settable', used by 'db_getinfo' to put results
104 : ** from 'lua_getinfo' into result table. Key is always a string;
105 : ** value can be a string, an int, or a boolean.
106 : */
107 10 : static void settabss (lua_State *L, const char *k, const char *v) {
108 10 : lua_pushstring(L, v);
109 10 : lua_setfield(L, -2, k);
110 10 : }
111 :
112 10 : static void settabsi (lua_State *L, const char *k, int v) {
113 10 : lua_pushinteger(L, v);
114 10 : lua_setfield(L, -2, k);
115 10 : }
116 :
117 4 : static void settabsb (lua_State *L, const char *k, int v) {
118 4 : lua_pushboolean(L, v);
119 4 : lua_setfield(L, -2, k);
120 4 : }
121 :
122 :
123 : /*
124 : ** In function 'db_getinfo', the call to 'lua_getinfo' may push
125 : ** results on the stack; later it creates the result table to put
126 : ** these objects. Function 'treatstackoption' puts the result from
127 : ** 'lua_getinfo' on top of the result table so that it can call
128 : ** 'lua_setfield'.
129 : */
130 3 : static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
131 3 : if (L == L1)
132 3 : lua_rotate(L, -2, 1); /* exchange object and table */
133 : else
134 0 : lua_xmove(L1, L, 1); /* move object to the "main" stack */
135 3 : lua_setfield(L, -2, fname); /* put object into table */
136 3 : }
137 :
138 :
139 : /*
140 : ** Calls 'lua_getinfo' and collects all results in a new table.
141 : ** L1 needs stack space for an optional input (function) plus
142 : ** two optional outputs (function and line table) from function
143 : ** 'lua_getinfo'.
144 : */
145 6 : static int db_getinfo (lua_State *L) {
146 : lua_Debug ar;
147 : int arg;
148 6 : lua_State *L1 = getthread(L, &arg);
149 6 : const char *options = luaL_optstring(L, arg+2, "flnStu");
150 6 : checkstack(L, L1, 3);
151 6 : if (lua_isfunction(L, arg + 1)) { /* info about a function? */
152 3 : options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
153 3 : lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
154 3 : lua_xmove(L, L1, 1);
155 : }
156 : else { /* stack level */
157 3 : if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
158 1 : lua_pushnil(L); /* level out of range */
159 1 : return 1;
160 : }
161 : }
162 4 : if (!lua_getinfo(L1, options, &ar))
163 1 : return luaL_argerror(L, arg+2, "invalid option");
164 3 : lua_newtable(L); /* table to collect results */
165 3 : if (strchr(options, 'S')) {
166 2 : settabss(L, "source", ar.source);
167 2 : settabss(L, "short_src", ar.short_src);
168 2 : settabsi(L, "linedefined", ar.linedefined);
169 2 : settabsi(L, "lastlinedefined", ar.lastlinedefined);
170 2 : settabss(L, "what", ar.what);
171 : }
172 3 : if (strchr(options, 'l'))
173 2 : settabsi(L, "currentline", ar.currentline);
174 3 : if (strchr(options, 'u')) {
175 2 : settabsi(L, "nups", ar.nups);
176 2 : settabsi(L, "nparams", ar.nparams);
177 2 : settabsb(L, "isvararg", ar.isvararg);
178 : }
179 3 : if (strchr(options, 'n')) {
180 2 : settabss(L, "name", ar.name);
181 2 : settabss(L, "namewhat", ar.namewhat);
182 : }
183 3 : if (strchr(options, 't'))
184 2 : settabsb(L, "istailcall", ar.istailcall);
185 3 : if (strchr(options, 'L'))
186 1 : treatstackoption(L, L1, "activelines");
187 3 : if (strchr(options, 'f'))
188 2 : treatstackoption(L, L1, "func");
189 3 : return 1; /* return table */
190 : }
191 :
192 :
193 3 : static int db_getlocal (lua_State *L) {
194 : int arg;
195 3 : lua_State *L1 = getthread(L, &arg);
196 : lua_Debug ar;
197 : const char *name;
198 3 : int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */
199 3 : if (lua_isfunction(L, arg + 1)) { /* function argument? */
200 1 : lua_pushvalue(L, arg + 1); /* push function */
201 1 : lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
202 1 : return 1; /* return only name (there is no value) */
203 : }
204 : else { /* stack-level argument */
205 2 : int level = (int)luaL_checkinteger(L, arg + 1);
206 2 : if (!lua_getstack(L1, level, &ar)) /* out of range? */
207 1 : return luaL_argerror(L, arg+1, "level out of range");
208 1 : checkstack(L, L1, 1);
209 1 : name = lua_getlocal(L1, &ar, nvar);
210 1 : if (name) {
211 1 : lua_xmove(L1, L, 1); /* move local value */
212 1 : lua_pushstring(L, name); /* push name */
213 1 : lua_rotate(L, -2, 1); /* re-order */
214 1 : return 2;
215 : }
216 : else {
217 0 : lua_pushnil(L); /* no name (nor value) */
218 0 : return 1;
219 : }
220 : }
221 : }
222 :
223 :
224 3 : static int db_setlocal (lua_State *L) {
225 : int arg;
226 : const char *name;
227 3 : lua_State *L1 = getthread(L, &arg);
228 : lua_Debug ar;
229 3 : int level = (int)luaL_checkinteger(L, arg + 1);
230 3 : int nvar = (int)luaL_checkinteger(L, arg + 2);
231 3 : if (!lua_getstack(L1, level, &ar)) /* out of range? */
232 1 : return luaL_argerror(L, arg+1, "level out of range");
233 2 : luaL_checkany(L, arg+3);
234 2 : lua_settop(L, arg+3);
235 2 : checkstack(L, L1, 1);
236 2 : lua_xmove(L, L1, 1);
237 2 : name = lua_setlocal(L1, &ar, nvar);
238 2 : if (name == NULL)
239 1 : lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */
240 2 : lua_pushstring(L, name);
241 2 : return 1;
242 : }
243 :
244 :
245 : /*
246 : ** get (if 'get' is true) or set an upvalue from a closure
247 : */
248 3 : static int auxupvalue (lua_State *L, int get) {
249 : const char *name;
250 3 : int n = (int)luaL_checkinteger(L, 2); /* upvalue index */
251 3 : luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */
252 3 : name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
253 3 : if (name == NULL) return 0;
254 2 : lua_pushstring(L, name);
255 2 : lua_insert(L, -(get+1)); /* no-op if get is false */
256 2 : return get + 1;
257 : }
258 :
259 :
260 1 : static int db_getupvalue (lua_State *L) {
261 1 : return auxupvalue(L, 1);
262 : }
263 :
264 :
265 2 : static int db_setupvalue (lua_State *L) {
266 2 : luaL_checkany(L, 3);
267 2 : return auxupvalue(L, 0);
268 : }
269 :
270 :
271 : /*
272 : ** Check whether a given upvalue from a given closure exists and
273 : ** returns its index
274 : */
275 6 : static int checkupval (lua_State *L, int argf, int argnup) {
276 6 : int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */
277 6 : luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */
278 4 : luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,
279 : "invalid upvalue index");
280 4 : return nup;
281 : }
282 :
283 :
284 1 : static int db_upvalueid (lua_State *L) {
285 1 : int n = checkupval(L, 1, 2);
286 1 : lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
287 1 : return 1;
288 : }
289 :
290 :
291 3 : static int db_upvaluejoin (lua_State *L) {
292 3 : int n1 = checkupval(L, 1, 2);
293 2 : int n2 = checkupval(L, 3, 4);
294 1 : luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
295 1 : luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
296 1 : lua_upvaluejoin(L, 1, n1, 3, n2);
297 1 : return 0;
298 : }
299 :
300 :
301 : /*
302 : ** Call hook function registered at hook table for the current
303 : ** thread (if there is one)
304 : */
305 227 : static void hookf (lua_State *L, lua_Debug *ar) {
306 : static const char *const hooknames[] =
307 : {"call", "return", "line", "count", "tail call"};
308 227 : lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
309 227 : lua_pushthread(L);
310 227 : if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */
311 227 : lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */
312 227 : if (ar->currentline >= 0)
313 0 : lua_pushinteger(L, ar->currentline); /* push current line */
314 227 : else lua_pushnil(L);
315 : lua_assert(lua_getinfo(L, "lS", ar));
316 227 : lua_call(L, 2, 0); /* call hook function */
317 : }
318 227 : }
319 :
320 :
321 : /*
322 : ** Convert a string mask (for 'sethook') into a bit mask
323 : */
324 1 : static int makemask (const char *smask, int count) {
325 1 : int mask = 0;
326 1 : if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
327 1 : if (strchr(smask, 'r')) mask |= LUA_MASKRET;
328 1 : if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
329 1 : if (count > 0) mask |= LUA_MASKCOUNT;
330 1 : return mask;
331 : }
332 :
333 :
334 : /*
335 : ** Convert a bit mask (for 'gethook') into a string mask
336 : */
337 3 : static char *unmakemask (int mask, char *smask) {
338 3 : int i = 0;
339 3 : if (mask & LUA_MASKCALL) smask[i++] = 'c';
340 3 : if (mask & LUA_MASKRET) smask[i++] = 'r';
341 3 : if (mask & LUA_MASKLINE) smask[i++] = 'l';
342 3 : smask[i] = '\0';
343 3 : return smask;
344 : }
345 :
346 :
347 2 : static int db_sethook (lua_State *L) {
348 : int arg, mask, count;
349 : lua_Hook func;
350 2 : lua_State *L1 = getthread(L, &arg);
351 2 : if (lua_isnoneornil(L, arg+1)) { /* no hook? */
352 1 : lua_settop(L, arg+1);
353 1 : func = NULL; mask = 0; count = 0; /* turn off hooks */
354 : }
355 : else {
356 1 : const char *smask = luaL_checkstring(L, arg+2);
357 1 : luaL_checktype(L, arg+1, LUA_TFUNCTION);
358 1 : count = (int)luaL_optinteger(L, arg + 3, 0);
359 1 : func = hookf; mask = makemask(smask, count);
360 : }
361 2 : if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) {
362 1 : lua_createtable(L, 0, 2); /* create a hook table */
363 1 : lua_pushvalue(L, -1);
364 1 : lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */
365 1 : lua_pushstring(L, "k");
366 1 : lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
367 1 : lua_pushvalue(L, -1);
368 1 : lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
369 : }
370 2 : checkstack(L, L1, 1);
371 2 : lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
372 2 : lua_pushvalue(L, arg + 1); /* value (hook function) */
373 2 : lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
374 2 : lua_sethook(L1, func, mask, count);
375 2 : return 0;
376 : }
377 :
378 :
379 3 : static int db_gethook (lua_State *L) {
380 : int arg;
381 3 : lua_State *L1 = getthread(L, &arg);
382 : char buff[5];
383 3 : int mask = lua_gethookmask(L1);
384 3 : lua_Hook hook = lua_gethook(L1);
385 3 : if (hook == NULL) /* no hook? */
386 1 : lua_pushnil(L);
387 2 : else if (hook != hookf) /* external hook? */
388 0 : lua_pushliteral(L, "external hook");
389 : else { /* hook table must exist */
390 2 : lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
391 2 : checkstack(L, L1, 1);
392 2 : lua_pushthread(L1); lua_xmove(L1, L, 1);
393 2 : lua_rawget(L, -2); /* 1st result = hooktable[L1] */
394 2 : lua_remove(L, -2); /* remove hook table */
395 : }
396 3 : lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */
397 3 : lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */
398 3 : return 3;
399 : }
400 :
401 :
402 1 : static int db_debug (lua_State *L) {
403 2 : for (;;) {
404 : char buffer[250];
405 3 : lua_writestringerror("%s", "lua_debug> ");
406 3 : if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
407 3 : strcmp(buffer, "cont\n") == 0)
408 1 : return 0;
409 4 : if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
410 2 : lua_pcall(L, 0, 0, 0))
411 1 : lua_writestringerror("%s\n", lua_tostring(L, -1));
412 2 : lua_settop(L, 0); /* remove eventual returns */
413 : }
414 : }
415 :
416 :
417 3 : static int db_traceback (lua_State *L) {
418 : int arg;
419 3 : lua_State *L1 = getthread(L, &arg);
420 3 : const char *msg = lua_tostring(L, arg + 1);
421 3 : if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
422 1 : lua_pushvalue(L, arg + 1); /* return it untouched */
423 : else {
424 2 : int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
425 2 : luaL_traceback(L, L1, msg, level);
426 : }
427 3 : return 1;
428 : }
429 :
430 :
431 : static const luaL_Reg dblib[] = {
432 : {"debug", db_debug},
433 : {"getuservalue", db_getuservalue},
434 : {"gethook", db_gethook},
435 : {"getinfo", db_getinfo},
436 : {"getlocal", db_getlocal},
437 : {"getregistry", db_getregistry},
438 : {"getmetatable", db_getmetatable},
439 : {"getupvalue", db_getupvalue},
440 : {"upvaluejoin", db_upvaluejoin},
441 : {"upvalueid", db_upvalueid},
442 : {"setuservalue", db_setuservalue},
443 : {"sethook", db_sethook},
444 : {"setlocal", db_setlocal},
445 : {"setmetatable", db_setmetatable},
446 : {"setupvalue", db_setupvalue},
447 : {"traceback", db_traceback},
448 : {NULL, NULL}
449 : };
450 :
451 :
452 86 : LUAMOD_API int luaopen_debug (lua_State *L) {
453 86 : luaL_newlib(L, dblib);
454 86 : return 1;
455 : }
456 :
|