Line data Source code
1 : /*
2 : ** $Id: ldblib.c,v 1.132.1.2 2015/02/19 17:16:55 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 : #define HOOKKEY "_HKEY"
22 :
23 :
24 14 : static void checkstack (lua_State *L, lua_State *L1, int n) {
25 14 : if (L != L1 && !lua_checkstack(L1, n))
26 0 : luaL_error(L, "stack overflow");
27 14 : }
28 :
29 :
30 1 : static int db_getregistry (lua_State *L) {
31 1 : lua_pushvalue(L, LUA_REGISTRYINDEX);
32 1 : return 1;
33 : }
34 :
35 :
36 6 : static int db_getmetatable (lua_State *L) {
37 6 : luaL_checkany(L, 1);
38 6 : if (!lua_getmetatable(L, 1)) {
39 3 : lua_pushnil(L); /* no metatable */
40 : }
41 6 : return 1;
42 : }
43 :
44 :
45 5 : static int db_setmetatable (lua_State *L) {
46 5 : int t = lua_type(L, 2);
47 5 : luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
48 : "nil or table expected");
49 4 : lua_settop(L, 2);
50 4 : lua_setmetatable(L, 1);
51 4 : return 1; /* return 1st argument */
52 : }
53 :
54 :
55 4 : static int db_getuservalue (lua_State *L) {
56 4 : if (lua_type(L, 1) != LUA_TUSERDATA)
57 1 : lua_pushnil(L);
58 : else
59 3 : lua_getuservalue(L, 1);
60 4 : return 1;
61 : }
62 :
63 :
64 3 : static int db_setuservalue (lua_State *L) {
65 3 : if (lua_type(L, 1) == LUA_TLIGHTUSERDATA)
66 0 : luaL_argerror(L, 1, "full userdata expected, got light userdata");
67 3 : luaL_checktype(L, 1, LUA_TUSERDATA);
68 2 : if (!lua_isnoneornil(L, 2))
69 1 : luaL_checktype(L, 2, LUA_TTABLE);
70 2 : lua_settop(L, 2);
71 2 : lua_setuservalue(L, 1);
72 2 : return 1;
73 : }
74 :
75 :
76 10 : static void settabss (lua_State *L, const char *i, const char *v) {
77 10 : lua_pushstring(L, v);
78 10 : lua_setfield(L, -2, i);
79 10 : }
80 :
81 :
82 10 : static void settabsi (lua_State *L, const char *i, int v) {
83 10 : lua_pushinteger(L, v);
84 10 : lua_setfield(L, -2, i);
85 10 : }
86 :
87 :
88 4 : static void settabsb (lua_State *L, const char *i, int v) {
89 4 : lua_pushboolean(L, v);
90 4 : lua_setfield(L, -2, i);
91 4 : }
92 :
93 :
94 20 : static lua_State *getthread (lua_State *L, int *arg) {
95 20 : if (lua_isthread(L, 1)) {
96 1 : *arg = 1;
97 1 : return lua_tothread(L, 1);
98 : }
99 : else {
100 19 : *arg = 0;
101 19 : return L;
102 : }
103 : }
104 :
105 :
106 3 : static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
107 3 : if (L == L1) {
108 3 : lua_pushvalue(L, -2);
109 3 : lua_remove(L, -3);
110 : }
111 : else
112 0 : lua_xmove(L1, L, 1);
113 3 : lua_setfield(L, -2, fname);
114 3 : }
115 :
116 :
117 6 : static int db_getinfo (lua_State *L) {
118 : lua_Debug ar;
119 : int arg;
120 6 : lua_State *L1 = getthread(L, &arg);
121 6 : const char *options = luaL_optstring(L, arg+2, "flnStu");
122 6 : checkstack(L, L1, 3);
123 6 : if (lua_isnumber(L, arg+1)) {
124 2 : if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
125 1 : lua_pushnil(L); /* level out of range */
126 1 : return 1;
127 : }
128 : }
129 4 : else if (lua_isfunction(L, arg+1)) {
130 3 : lua_pushfstring(L, ">%s", options);
131 3 : options = lua_tostring(L, -1);
132 3 : lua_pushvalue(L, arg+1);
133 3 : lua_xmove(L, L1, 1);
134 : }
135 : else
136 1 : return luaL_argerror(L, arg+1, "function or level expected");
137 4 : if (!lua_getinfo(L1, options, &ar))
138 1 : return luaL_argerror(L, arg+2, "invalid option");
139 3 : lua_createtable(L, 0, 2);
140 3 : if (strchr(options, 'S')) {
141 2 : settabss(L, "source", ar.source);
142 2 : settabss(L, "short_src", ar.short_src);
143 2 : settabsi(L, "linedefined", ar.linedefined);
144 2 : settabsi(L, "lastlinedefined", ar.lastlinedefined);
145 2 : settabss(L, "what", ar.what);
146 : }
147 3 : if (strchr(options, 'l'))
148 2 : settabsi(L, "currentline", ar.currentline);
149 3 : if (strchr(options, 'u')) {
150 2 : settabsi(L, "nups", ar.nups);
151 2 : settabsi(L, "nparams", ar.nparams);
152 2 : settabsb(L, "isvararg", ar.isvararg);
153 : }
154 3 : if (strchr(options, 'n')) {
155 2 : settabss(L, "name", ar.name);
156 2 : settabss(L, "namewhat", ar.namewhat);
157 : }
158 3 : if (strchr(options, 't'))
159 2 : settabsb(L, "istailcall", ar.istailcall);
160 3 : if (strchr(options, 'L'))
161 1 : treatstackoption(L, L1, "activelines");
162 3 : if (strchr(options, 'f'))
163 2 : treatstackoption(L, L1, "func");
164 3 : return 1; /* return table */
165 : }
166 :
167 :
168 3 : static int db_getlocal (lua_State *L) {
169 : int arg;
170 3 : lua_State *L1 = getthread(L, &arg);
171 : lua_Debug ar;
172 : const char *name;
173 3 : int nvar = luaL_checkint(L, arg+2); /* local-variable index */
174 3 : if (lua_isfunction(L, arg + 1)) { /* function argument? */
175 1 : lua_pushvalue(L, arg + 1); /* push function */
176 1 : lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
177 1 : return 1;
178 : }
179 : else { /* stack-level argument */
180 2 : if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
181 1 : return luaL_argerror(L, arg+1, "level out of range");
182 1 : checkstack(L, L1, 1);
183 1 : name = lua_getlocal(L1, &ar, nvar);
184 1 : if (name) {
185 1 : lua_xmove(L1, L, 1); /* push local value */
186 1 : lua_pushstring(L, name); /* push name */
187 1 : lua_pushvalue(L, -2); /* re-order */
188 1 : return 2;
189 : }
190 : else {
191 0 : lua_pushnil(L); /* no name (nor value) */
192 0 : return 1;
193 : }
194 : }
195 : }
196 :
197 :
198 3 : static int db_setlocal (lua_State *L) {
199 : int arg;
200 3 : lua_State *L1 = getthread(L, &arg);
201 : lua_Debug ar;
202 3 : if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
203 1 : return luaL_argerror(L, arg+1, "level out of range");
204 2 : luaL_checkany(L, arg+3);
205 2 : lua_settop(L, arg+3);
206 2 : checkstack(L, L1, 1);
207 2 : lua_xmove(L, L1, 1);
208 2 : lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
209 2 : return 1;
210 : }
211 :
212 :
213 3 : static int auxupvalue (lua_State *L, int get) {
214 : const char *name;
215 3 : int n = luaL_checkint(L, 2);
216 3 : luaL_checktype(L, 1, LUA_TFUNCTION);
217 3 : name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
218 3 : if (name == NULL) return 0;
219 2 : lua_pushstring(L, name);
220 2 : lua_insert(L, -(get+1));
221 2 : return get + 1;
222 : }
223 :
224 :
225 1 : static int db_getupvalue (lua_State *L) {
226 1 : return auxupvalue(L, 1);
227 : }
228 :
229 :
230 2 : static int db_setupvalue (lua_State *L) {
231 2 : luaL_checkany(L, 3);
232 2 : return auxupvalue(L, 0);
233 : }
234 :
235 :
236 6 : static int checkupval (lua_State *L, int argf, int argnup) {
237 : lua_Debug ar;
238 6 : int nup = luaL_checkint(L, argnup);
239 6 : luaL_checktype(L, argf, LUA_TFUNCTION);
240 4 : lua_pushvalue(L, argf);
241 4 : lua_getinfo(L, ">u", &ar);
242 4 : luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index");
243 4 : return nup;
244 : }
245 :
246 :
247 1 : static int db_upvalueid (lua_State *L) {
248 1 : int n = checkupval(L, 1, 2);
249 1 : lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
250 1 : return 1;
251 : }
252 :
253 :
254 3 : static int db_upvaluejoin (lua_State *L) {
255 3 : int n1 = checkupval(L, 1, 2);
256 2 : int n2 = checkupval(L, 3, 4);
257 1 : luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
258 1 : luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
259 1 : lua_upvaluejoin(L, 1, n1, 3, n2);
260 1 : return 0;
261 : }
262 :
263 :
264 : #define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
265 :
266 :
267 227 : static void hookf (lua_State *L, lua_Debug *ar) {
268 : static const char *const hooknames[] =
269 : {"call", "return", "line", "count", "tail call"};
270 227 : gethooktable(L);
271 227 : lua_pushthread(L);
272 227 : lua_rawget(L, -2);
273 227 : if (lua_isfunction(L, -1)) {
274 227 : lua_pushstring(L, hooknames[(int)ar->event]);
275 227 : if (ar->currentline >= 0)
276 0 : lua_pushinteger(L, ar->currentline);
277 227 : else lua_pushnil(L);
278 : lua_assert(lua_getinfo(L, "lS", ar));
279 227 : lua_call(L, 2, 0);
280 : }
281 227 : }
282 :
283 :
284 1 : static int makemask (const char *smask, int count) {
285 1 : int mask = 0;
286 1 : if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
287 1 : if (strchr(smask, 'r')) mask |= LUA_MASKRET;
288 1 : if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
289 1 : if (count > 0) mask |= LUA_MASKCOUNT;
290 1 : return mask;
291 : }
292 :
293 :
294 3 : static char *unmakemask (int mask, char *smask) {
295 3 : int i = 0;
296 3 : if (mask & LUA_MASKCALL) smask[i++] = 'c';
297 3 : if (mask & LUA_MASKRET) smask[i++] = 'r';
298 3 : if (mask & LUA_MASKLINE) smask[i++] = 'l';
299 3 : smask[i] = '\0';
300 3 : return smask;
301 : }
302 :
303 :
304 2 : static int db_sethook (lua_State *L) {
305 : int arg, mask, count;
306 : lua_Hook func;
307 2 : lua_State *L1 = getthread(L, &arg);
308 2 : if (lua_isnoneornil(L, arg+1)) {
309 1 : lua_settop(L, arg+1);
310 1 : func = NULL; mask = 0; count = 0; /* turn off hooks */
311 : }
312 : else {
313 1 : const char *smask = luaL_checkstring(L, arg+2);
314 1 : luaL_checktype(L, arg+1, LUA_TFUNCTION);
315 1 : count = luaL_optint(L, arg+3, 0);
316 1 : func = hookf; mask = makemask(smask, count);
317 : }
318 2 : if (gethooktable(L) == 0) { /* creating hook table? */
319 1 : lua_pushstring(L, "k");
320 1 : lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
321 1 : lua_pushvalue(L, -1);
322 1 : lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
323 : }
324 2 : checkstack(L, L1, 1);
325 2 : lua_pushthread(L1); lua_xmove(L1, L, 1);
326 2 : lua_pushvalue(L, arg+1);
327 2 : lua_rawset(L, -3); /* set new hook */
328 2 : lua_sethook(L1, func, mask, count); /* set hooks */
329 2 : return 0;
330 : }
331 :
332 :
333 3 : static int db_gethook (lua_State *L) {
334 : int arg;
335 3 : lua_State *L1 = getthread(L, &arg);
336 : char buff[5];
337 3 : int mask = lua_gethookmask(L1);
338 3 : lua_Hook hook = lua_gethook(L1);
339 3 : if (hook != NULL && hook != hookf) /* external hook? */
340 0 : lua_pushliteral(L, "external hook");
341 : else {
342 3 : gethooktable(L);
343 3 : checkstack(L, L1, 1);
344 3 : lua_pushthread(L1); lua_xmove(L1, L, 1);
345 3 : lua_rawget(L, -2); /* get hook */
346 3 : lua_remove(L, -2); /* remove hook table */
347 : }
348 3 : lua_pushstring(L, unmakemask(mask, buff));
349 3 : lua_pushinteger(L, lua_gethookcount(L1));
350 3 : return 3;
351 : }
352 :
353 :
354 1 : static int db_debug (lua_State *L) {
355 2 : for (;;) {
356 : char buffer[250];
357 3 : luai_writestringerror("%s", "lua_debug> ");
358 3 : if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
359 3 : strcmp(buffer, "cont\n") == 0)
360 1 : return 0;
361 4 : if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
362 2 : lua_pcall(L, 0, 0, 0))
363 1 : luai_writestringerror("%s\n", lua_tostring(L, -1));
364 2 : lua_settop(L, 0); /* remove eventual returns */
365 : }
366 : }
367 :
368 :
369 3 : static int db_traceback (lua_State *L) {
370 : int arg;
371 3 : lua_State *L1 = getthread(L, &arg);
372 3 : const char *msg = lua_tostring(L, arg + 1);
373 3 : if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
374 1 : lua_pushvalue(L, arg + 1); /* return it untouched */
375 : else {
376 2 : int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0);
377 2 : luaL_traceback(L, L1, msg, level);
378 : }
379 3 : return 1;
380 : }
381 :
382 :
383 : static const luaL_Reg dblib[] = {
384 : {"debug", db_debug},
385 : {"getuservalue", db_getuservalue},
386 : {"gethook", db_gethook},
387 : {"getinfo", db_getinfo},
388 : {"getlocal", db_getlocal},
389 : {"getregistry", db_getregistry},
390 : {"getmetatable", db_getmetatable},
391 : {"getupvalue", db_getupvalue},
392 : {"upvaluejoin", db_upvaluejoin},
393 : {"upvalueid", db_upvalueid},
394 : {"setuservalue", db_setuservalue},
395 : {"sethook", db_sethook},
396 : {"setlocal", db_setlocal},
397 : {"setmetatable", db_setmetatable},
398 : {"setupvalue", db_setupvalue},
399 : {"traceback", db_traceback},
400 : {NULL, NULL}
401 : };
402 :
403 :
404 86 : LUAMOD_API int luaopen_debug (lua_State *L) {
405 86 : luaL_newlib(L, dblib);
406 86 : return 1;
407 : }
408 :
|