diff options
Diffstat (limited to 'src/lib_debug.c')
-rw-r--r-- | src/lib_debug.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/src/lib_debug.c b/src/lib_debug.c new file mode 100644 index 00000000..0e6c35e5 --- /dev/null +++ b/src/lib_debug.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* | ||
2 | ** Debug library. | ||
3 | ** Copyright (C) 2005-2009 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 | */ | ||
8 | |||
9 | #define lib_debug_c | ||
10 | #define LUA_LIB | ||
11 | |||
12 | #include "lua.h" | ||
13 | #include "lauxlib.h" | ||
14 | #include "lualib.h" | ||
15 | |||
16 | #include "lj_obj.h" | ||
17 | #include "lj_err.h" | ||
18 | #include "lj_lib.h" | ||
19 | |||
20 | /* ------------------------------------------------------------------------ */ | ||
21 | |||
22 | #define LJLIB_MODULE_debug | ||
23 | |||
24 | LJLIB_CF(debug_getregistry) | ||
25 | { | ||
26 | copyTV(L, L->top++, registry(L)); | ||
27 | return 1; | ||
28 | } | ||
29 | |||
30 | LJLIB_CF(debug_getmetatable) | ||
31 | { | ||
32 | lj_lib_checkany(L, 1); | ||
33 | if (!lua_getmetatable(L, 1)) { | ||
34 | setnilV(L->top-1); | ||
35 | } | ||
36 | return 1; | ||
37 | } | ||
38 | |||
39 | LJLIB_CF(debug_setmetatable) | ||
40 | { | ||
41 | lj_lib_checktabornil(L, 2); | ||
42 | L->top = L->base+2; | ||
43 | lua_setmetatable(L, 1); | ||
44 | setboolV(L->top-1, 1); | ||
45 | return 1; | ||
46 | } | ||
47 | |||
48 | LJLIB_CF(debug_getfenv) | ||
49 | { | ||
50 | lj_lib_checkany(L, 1); | ||
51 | lua_getfenv(L, 1); | ||
52 | return 1; | ||
53 | } | ||
54 | |||
55 | LJLIB_CF(debug_setfenv) | ||
56 | { | ||
57 | lj_lib_checktab(L, 2); | ||
58 | L->top = L->base+2; | ||
59 | if (!lua_setfenv(L, 1)) | ||
60 | lj_err_caller(L, LJ_ERR_SETFENV); | ||
61 | return 1; | ||
62 | } | ||
63 | |||
64 | /* ------------------------------------------------------------------------ */ | ||
65 | |||
66 | static void settabss(lua_State *L, const char *i, const char *v) | ||
67 | { | ||
68 | lua_pushstring(L, v); | ||
69 | lua_setfield(L, -2, i); | ||
70 | } | ||
71 | |||
72 | static void settabsi(lua_State *L, const char *i, int v) | ||
73 | { | ||
74 | lua_pushinteger(L, v); | ||
75 | lua_setfield(L, -2, i); | ||
76 | } | ||
77 | |||
78 | static lua_State *getthread(lua_State *L, int *arg) | ||
79 | { | ||
80 | if (L->base < L->top && tvisthread(L->base)) { | ||
81 | *arg = 1; | ||
82 | return threadV(L->base); | ||
83 | } else { | ||
84 | *arg = 0; | ||
85 | return L; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static void treatstackoption(lua_State *L, lua_State *L1, const char *fname) | ||
90 | { | ||
91 | if (L == L1) { | ||
92 | lua_pushvalue(L, -2); | ||
93 | lua_remove(L, -3); | ||
94 | } | ||
95 | else | ||
96 | lua_xmove(L1, L, 1); | ||
97 | lua_setfield(L, -2, fname); | ||
98 | } | ||
99 | |||
100 | LJLIB_CF(debug_getinfo) | ||
101 | { | ||
102 | lua_Debug ar; | ||
103 | int arg; | ||
104 | lua_State *L1 = getthread(L, &arg); | ||
105 | const char *options = luaL_optstring(L, arg+2, "flnSu"); | ||
106 | if (lua_isnumber(L, arg+1)) { | ||
107 | if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { | ||
108 | setnilV(L->top-1); | ||
109 | return 1; | ||
110 | } | ||
111 | } else if (L->base+arg < L->top && tvisfunc(L->base+arg)) { | ||
112 | options = lua_pushfstring(L, ">%s", options); | ||
113 | setfuncV(L1, L1->top++, funcV(L->base+arg)); | ||
114 | } else { | ||
115 | lj_err_arg(L, arg+1, LJ_ERR_NOFUNCL); | ||
116 | } | ||
117 | if (!lua_getinfo(L1, options, &ar)) | ||
118 | lj_err_arg(L, arg+2, LJ_ERR_INVOPT); | ||
119 | lua_createtable(L, 0, 16); | ||
120 | if (strchr(options, 'S')) { | ||
121 | settabss(L, "source", ar.source); | ||
122 | settabss(L, "short_src", ar.short_src); | ||
123 | settabsi(L, "linedefined", ar.linedefined); | ||
124 | settabsi(L, "lastlinedefined", ar.lastlinedefined); | ||
125 | settabss(L, "what", ar.what); | ||
126 | } | ||
127 | if (strchr(options, 'l')) | ||
128 | settabsi(L, "currentline", ar.currentline); | ||
129 | if (strchr(options, 'u')) | ||
130 | settabsi(L, "nups", ar.nups); | ||
131 | if (strchr(options, 'n')) { | ||
132 | settabss(L, "name", ar.name); | ||
133 | settabss(L, "namewhat", ar.namewhat); | ||
134 | } | ||
135 | if (strchr(options, 'L')) | ||
136 | treatstackoption(L, L1, "activelines"); | ||
137 | if (strchr(options, 'f')) | ||
138 | treatstackoption(L, L1, "func"); | ||
139 | return 1; /* return table */ | ||
140 | } | ||
141 | |||
142 | LJLIB_CF(debug_getlocal) | ||
143 | { | ||
144 | int arg; | ||
145 | lua_State *L1 = getthread(L, &arg); | ||
146 | lua_Debug ar; | ||
147 | const char *name; | ||
148 | if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar)) | ||
149 | lj_err_arg(L, arg+1, LJ_ERR_LVLRNG); | ||
150 | name = lua_getlocal(L1, &ar, lj_lib_checkint(L, arg+2)); | ||
151 | if (name) { | ||
152 | lua_xmove(L1, L, 1); | ||
153 | lua_pushstring(L, name); | ||
154 | lua_pushvalue(L, -2); | ||
155 | return 2; | ||
156 | } else { | ||
157 | setnilV(L->top-1); | ||
158 | return 1; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | LJLIB_CF(debug_setlocal) | ||
163 | { | ||
164 | int arg; | ||
165 | lua_State *L1 = getthread(L, &arg); | ||
166 | lua_Debug ar; | ||
167 | TValue *tv; | ||
168 | if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar)) | ||
169 | lj_err_arg(L, arg+1, LJ_ERR_LVLRNG); | ||
170 | tv = lj_lib_checkany(L, arg+3); | ||
171 | copyTV(L1, L1->top++, tv); | ||
172 | lua_pushstring(L, lua_setlocal(L1, &ar, lj_lib_checkint(L, arg+2))); | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | static int debug_getupvalue(lua_State *L, int get) | ||
177 | { | ||
178 | int32_t n = lj_lib_checkint(L, 2); | ||
179 | if (isluafunc(lj_lib_checkfunc(L, 1))) { | ||
180 | const char *name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); | ||
181 | if (name) { | ||
182 | lua_pushstring(L, name); | ||
183 | if (!get) return 1; | ||
184 | copyTV(L, L->top, L->top-2); | ||
185 | L->top++; | ||
186 | return 2; | ||
187 | } | ||
188 | } | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | LJLIB_CF(debug_getupvalue) | ||
193 | { | ||
194 | return debug_getupvalue(L, 1); | ||
195 | } | ||
196 | |||
197 | LJLIB_CF(debug_setupvalue) | ||
198 | { | ||
199 | lj_lib_checkany(L, 3); | ||
200 | return debug_getupvalue(L, 0); | ||
201 | } | ||
202 | |||
203 | /* ------------------------------------------------------------------------ */ | ||
204 | |||
205 | static const char KEY_HOOK = 'h'; | ||
206 | |||
207 | static void hookf(lua_State *L, lua_Debug *ar) | ||
208 | { | ||
209 | static const char *const hooknames[] = | ||
210 | {"call", "return", "line", "count", "tail return"}; | ||
211 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||
212 | lua_rawget(L, LUA_REGISTRYINDEX); | ||
213 | if (lua_isfunction(L, -1)) { | ||
214 | lua_pushstring(L, hooknames[(int)ar->event]); | ||
215 | if (ar->currentline >= 0) | ||
216 | lua_pushinteger(L, ar->currentline); | ||
217 | else lua_pushnil(L); | ||
218 | lua_call(L, 2, 0); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static int makemask(const char *smask, int count) | ||
223 | { | ||
224 | int mask = 0; | ||
225 | if (strchr(smask, 'c')) mask |= LUA_MASKCALL; | ||
226 | if (strchr(smask, 'r')) mask |= LUA_MASKRET; | ||
227 | if (strchr(smask, 'l')) mask |= LUA_MASKLINE; | ||
228 | if (count > 0) mask |= LUA_MASKCOUNT; | ||
229 | return mask; | ||
230 | } | ||
231 | |||
232 | static char *unmakemask(int mask, char *smask) | ||
233 | { | ||
234 | int i = 0; | ||
235 | if (mask & LUA_MASKCALL) smask[i++] = 'c'; | ||
236 | if (mask & LUA_MASKRET) smask[i++] = 'r'; | ||
237 | if (mask & LUA_MASKLINE) smask[i++] = 'l'; | ||
238 | smask[i] = '\0'; | ||
239 | return smask; | ||
240 | } | ||
241 | |||
242 | LJLIB_CF(debug_sethook) | ||
243 | { | ||
244 | int arg, mask, count; | ||
245 | lua_Hook func; | ||
246 | (void)getthread(L, &arg); | ||
247 | if (lua_isnoneornil(L, arg+1)) { | ||
248 | lua_settop(L, arg+1); | ||
249 | func = NULL; mask = 0; count = 0; /* turn off hooks */ | ||
250 | } else { | ||
251 | const char *smask = luaL_checkstring(L, arg+2); | ||
252 | luaL_checktype(L, arg+1, LUA_TFUNCTION); | ||
253 | count = luaL_optint(L, arg+3, 0); | ||
254 | func = hookf; mask = makemask(smask, count); | ||
255 | } | ||
256 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||
257 | lua_pushvalue(L, arg+1); | ||
258 | lua_rawset(L, LUA_REGISTRYINDEX); | ||
259 | lua_sethook(L, func, mask, count); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | LJLIB_CF(debug_gethook) | ||
264 | { | ||
265 | char buff[5]; | ||
266 | int mask = lua_gethookmask(L); | ||
267 | lua_Hook hook = lua_gethook(L); | ||
268 | if (hook != NULL && hook != hookf) { /* external hook? */ | ||
269 | lua_pushliteral(L, "external hook"); | ||
270 | } else { | ||
271 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||
272 | lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ | ||
273 | } | ||
274 | lua_pushstring(L, unmakemask(mask, buff)); | ||
275 | lua_pushinteger(L, lua_gethookcount(L)); | ||
276 | return 3; | ||
277 | } | ||
278 | |||
279 | /* ------------------------------------------------------------------------ */ | ||
280 | |||
281 | LJLIB_CF(debug_debug) | ||
282 | { | ||
283 | for (;;) { | ||
284 | char buffer[250]; | ||
285 | fputs("lua_debug> ", stderr); | ||
286 | if (fgets(buffer, sizeof(buffer), stdin) == 0 || | ||
287 | strcmp(buffer, "cont\n") == 0) | ||
288 | return 0; | ||
289 | if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || | ||
290 | lua_pcall(L, 0, 0, 0)) { | ||
291 | fputs(lua_tostring(L, -1), stderr); | ||
292 | fputs("\n", stderr); | ||
293 | } | ||
294 | lua_settop(L, 0); /* remove eventual returns */ | ||
295 | } | ||
296 | } | ||
297 | |||
298 | /* ------------------------------------------------------------------------ */ | ||
299 | |||
300 | #define LEVELS1 12 /* size of the first part of the stack */ | ||
301 | #define LEVELS2 10 /* size of the second part of the stack */ | ||
302 | |||
303 | LJLIB_CF(debug_traceback) | ||
304 | { | ||
305 | int level; | ||
306 | int firstpart = 1; /* still before eventual `...' */ | ||
307 | int arg; | ||
308 | lua_State *L1 = getthread(L, &arg); | ||
309 | lua_Debug ar; | ||
310 | if (lua_isnumber(L, arg+2)) { | ||
311 | level = (int)lua_tointeger(L, arg+2); | ||
312 | lua_pop(L, 1); | ||
313 | } | ||
314 | else | ||
315 | level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ | ||
316 | if (lua_gettop(L) == arg) | ||
317 | lua_pushliteral(L, ""); | ||
318 | else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */ | ||
319 | else lua_pushliteral(L, "\n"); | ||
320 | lua_pushliteral(L, "stack traceback:"); | ||
321 | while (lua_getstack(L1, level++, &ar)) { | ||
322 | if (level > LEVELS1 && firstpart) { | ||
323 | /* no more than `LEVELS2' more levels? */ | ||
324 | if (!lua_getstack(L1, level+LEVELS2, &ar)) { | ||
325 | level--; /* keep going */ | ||
326 | } else { | ||
327 | lua_pushliteral(L, "\n\t..."); /* too many levels */ | ||
328 | /* This only works with LuaJIT 2.x. Avoids O(n^2) behaviour. */ | ||
329 | lua_getstack(L1, -10, &ar); | ||
330 | level = ar.i_ci - LEVELS2; | ||
331 | } | ||
332 | firstpart = 0; | ||
333 | continue; | ||
334 | } | ||
335 | lua_pushliteral(L, "\n\t"); | ||
336 | lua_getinfo(L1, "Snl", &ar); | ||
337 | lua_pushfstring(L, "%s:", ar.short_src); | ||
338 | if (ar.currentline > 0) | ||
339 | lua_pushfstring(L, "%d:", ar.currentline); | ||
340 | if (*ar.namewhat != '\0') { /* is there a name? */ | ||
341 | lua_pushfstring(L, " in function " LUA_QS, ar.name); | ||
342 | } else { | ||
343 | if (*ar.what == 'm') /* main? */ | ||
344 | lua_pushfstring(L, " in main chunk"); | ||
345 | else if (*ar.what == 'C' || *ar.what == 't') | ||
346 | lua_pushliteral(L, " ?"); /* C function or tail call */ | ||
347 | else | ||
348 | lua_pushfstring(L, " in function <%s:%d>", | ||
349 | ar.short_src, ar.linedefined); | ||
350 | } | ||
351 | lua_concat(L, lua_gettop(L) - arg); | ||
352 | } | ||
353 | lua_concat(L, lua_gettop(L) - arg); | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | /* ------------------------------------------------------------------------ */ | ||
358 | |||
359 | #include "lj_libdef.h" | ||
360 | |||
361 | LUALIB_API int luaopen_debug(lua_State *L) | ||
362 | { | ||
363 | LJ_LIB_REG(L, debug); | ||
364 | return 1; | ||
365 | } | ||
366 | |||