1/*
2** Debug library.
3** Copyright (C) 2005-2021 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_gc.h"
18#include "lj_err.h"
19#include "lj_debug.h"
20#include "lj_lib.h"
21
22/* ------------------------------------------------------------------------ */
23
24#define LJLIB_MODULE_debug
25
26LJLIB_CF(debug_getregistry)
27{
28 copyTV(L, L->top++, registry(L));
29 return 1;
30}
31
32LJLIB_CF(debug_getmetatable) LJLIB_REC(.)
33{
34 lj_lib_checkany(L, 1);
35 if (!lua_getmetatable(L, 1)) {
36 setnilV(L->top-1);
37 }
38 return 1;
39}
40
41LJLIB_CF(debug_setmetatable)
42{
43 lj_lib_checktabornil(L, 2);
44 L->top = L->base+2;
45 lua_setmetatable(L, 1);
46#if !LJ_52
47 setboolV(L->top-1, 1);
48#endif
49 return 1;
50}
51
52LJLIB_CF(debug_getfenv)
53{
54 lj_lib_checkany(L, 1);
55 lua_getfenv(L, 1);
56 return 1;
57}
58
59LJLIB_CF(debug_setfenv)
60{
61 lj_lib_checktab(L, 2);
62 L->top = L->base+2;
63 if (!lua_setfenv(L, 1))
64 lj_err_caller(L, LJ_ERR_SETFENV);
65 return 1;
66}
67
68/* ------------------------------------------------------------------------ */
69
70static void settabss(lua_State *L, const char *i, const char *v)
71{
72 lua_pushstring(L, v);
73 lua_setfield(L, -2, i);
74}
75
76static void settabsi(lua_State *L, const char *i, int v)
77{
78 lua_pushinteger(L, v);
79 lua_setfield(L, -2, i);
80}
81
82static void settabsb(lua_State *L, const char *i, int v)
83{
84 lua_pushboolean(L, v);
85 lua_setfield(L, -2, i);
86}
87
88static lua_State *getthread(lua_State *L, int *arg)
89{
90 if (L->base < L->top && tvisthread(L->base)) {
91 *arg = 1;
92 return threadV(L->base);
93 } else {
94 *arg = 0;
95 return L;
96 }
97}
98
99static void treatstackoption(lua_State *L, lua_State *L1, const char *fname)
100{
101 if (L == L1) {
102 lua_pushvalue(L, -2);
103 lua_remove(L, -3);
104 }
105 else
106 lua_xmove(L1, L, 1);
107 lua_setfield(L, -2, fname);
108}
109
110LJLIB_CF(debug_getinfo)
111{
112 lj_Debug ar;
113 int arg, opt_f = 0, opt_L = 0;
114 lua_State *L1 = getthread(L, &arg);
115 const char *options = luaL_optstring(L, arg+2, "flnSu");
116 if (lua_isnumber(L, arg+1)) {
117 if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), (lua_Debug *)&ar)) {
118 setnilV(L->top-1);
119 return 1;
120 }
121 } else if (L->base+arg < L->top && tvisfunc(L->base+arg)) {
122 options = lua_pushfstring(L, ">%s", options);
123 setfuncV(L1, L1->top++, funcV(L->base+arg));
124 } else {
125 lj_err_arg(L, arg+1, LJ_ERR_NOFUNCL);
126 }
127 if (!lj_debug_getinfo(L1, options, &ar, 1))
128 lj_err_arg(L, arg+2, LJ_ERR_INVOPT);
129 lua_createtable(L, 0, 16); /* Create result table. */
130 for (; *options; options++) {
131 switch (*options) {
132 case 'S':
133 settabss(L, "source", ar.source);
134 settabss(L, "short_src", ar.short_src);
135 settabsi(L, "linedefined", ar.linedefined);
136 settabsi(L, "lastlinedefined", ar.lastlinedefined);
137 settabss(L, "what", ar.what);
138 break;
139 case 'l':
140 settabsi(L, "currentline", ar.currentline);
141 break;
142 case 'u':
143 settabsi(L, "nups", ar.nups);
144 settabsi(L, "nparams", ar.nparams);
145 settabsb(L, "isvararg", ar.isvararg);
146 break;
147 case 'n':
148 settabss(L, "name", ar.name);
149 settabss(L, "namewhat", ar.namewhat);
150 break;
151 case 'f': opt_f = 1; break;
152 case 'L': opt_L = 1; break;
153 default: break;
154 }
155 }
156 if (opt_L) treatstackoption(L, L1, "activelines");
157 if (opt_f) treatstackoption(L, L1, "func");
158 return 1; /* Return result table. */
159}
160
161LJLIB_CF(debug_getlocal)
162{
163 int arg;
164 lua_State *L1 = getthread(L, &arg);
165 lua_Debug ar;
166 const char *name;
167 int slot = lj_lib_checkint(L, arg+2);
168 if (tvisfunc(L->base+arg)) {
169 L->top = L->base+arg+1;
170 lua_pushstring(L, lua_getlocal(L, NULL, slot));
171 return 1;
172 }
173 if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
174 lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
175 name = lua_getlocal(L1, &ar, slot);
176 if (name) {
177 lua_xmove(L1, L, 1);
178 lua_pushstring(L, name);
179 lua_pushvalue(L, -2);
180 return 2;
181 } else {
182 setnilV(L->top-1);
183 return 1;
184 }
185}
186
187LJLIB_CF(debug_setlocal)
188{
189 int arg;
190 lua_State *L1 = getthread(L, &arg);
191 lua_Debug ar;
192 TValue *tv;
193 if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
194 lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
195 tv = lj_lib_checkany(L, arg+3);
196 copyTV(L1, L1->top++, tv);
197 lua_pushstring(L, lua_setlocal(L1, &ar, lj_lib_checkint(L, arg+2)));
198 return 1;
199}
200
201static int debug_getupvalue(lua_State *L, int get)
202{
203 int32_t n = lj_lib_checkint(L, 2);
204 const char *name;
205 lj_lib_checkfunc(L, 1);
206 name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
207 if (name) {
208 lua_pushstring(L, name);
209 if (!get) return 1;
210 copyTV(L, L->top, L->top-2);
211 L->top++;
212 return 2;
213 }
214 return 0;
215}
216
217LJLIB_CF(debug_getupvalue)
218{
219 return debug_getupvalue(L, 1);
220}
221
222LJLIB_CF(debug_setupvalue)
223{
224 lj_lib_checkany(L, 3);
225 return debug_getupvalue(L, 0);
226}
227
228LJLIB_CF(debug_upvalueid)
229{
230 GCfunc *fn = lj_lib_checkfunc(L, 1);
231 int32_t n = lj_lib_checkint(L, 2) - 1;
232 if ((uint32_t)n >= fn->l.nupvalues)
233 lj_err_arg(L, 2, LJ_ERR_IDXRNG);
234 lua_pushlightuserdata(L, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
235 (void *)&fn->c.upvalue[n]);
236 return 1;
237}
238
239LJLIB_CF(debug_upvaluejoin)
240{
241 GCfunc *fn[2];
242 GCRef *p[2];
243 int i;
244 for (i = 0; i < 2; i++) {
245 int32_t n;
246 fn[i] = lj_lib_checkfunc(L, 2*i+1);
247 if (!isluafunc(fn[i]))
248 lj_err_arg(L, 2*i+1, LJ_ERR_NOLFUNC);
249 n = lj_lib_checkint(L, 2*i+2) - 1;
250 if ((uint32_t)n >= fn[i]->l.nupvalues)
251 lj_err_arg(L, 2*i+2, LJ_ERR_IDXRNG);
252 p[i] = &fn[i]->l.uvptr[n];
253 }
254 setgcrefr(*p[0], *p[1]);
255 lj_gc_objbarrier(L, fn[0], gcref(*p[1]));
256 return 0;
257}
258
259#if LJ_52
260LJLIB_CF(debug_getuservalue)
261{
262 TValue *o = L->base;
263 if (o < L->top && tvisudata(o))
264 settabV(L, o, tabref(udataV(o)->env));
265 else
266 setnilV(o);
267 L->top = o+1;
268 return 1;
269}
270
271LJLIB_CF(debug_setuservalue)
272{
273 TValue *o = L->base;
274 if (!(o < L->top && tvisudata(o)))
275 lj_err_argt(L, 1, LUA_TUSERDATA);
276 if (!(o+1 < L->top && tvistab(o+1)))
277 lj_err_argt(L, 2, LUA_TTABLE);
278 L->top = o+2;
279 lua_setfenv(L, 1);
280 return 1;
281}
282#endif
283
284/* ------------------------------------------------------------------------ */
285
286#define KEY_HOOK (U64x(80000000,00000000)|'h')
287
288static void hookf(lua_State *L, lua_Debug *ar)
289{
290 static const char *const hooknames[] =
291 {"call", "return", "line", "count", "tail return"};
292 (L->top++)->u64 = KEY_HOOK;
293 lua_rawget(L, LUA_REGISTRYINDEX);
294 if (lua_isfunction(L, -1)) {
295 lua_pushstring(L, hooknames[(int)ar->event]);
296 if (ar->currentline >= 0)
297 lua_pushinteger(L, ar->currentline);
298 else lua_pushnil(L);
299 lua_call(L, 2, 0);
300 }
301}
302
303static int makemask(const char *smask, int count)
304{
305 int mask = 0;
306 if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
307 if (strchr(smask, 'r')) mask |= LUA_MASKRET;
308 if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
309 if (count > 0) mask |= LUA_MASKCOUNT;
310 return mask;
311}
312
313static char *unmakemask(int mask, char *smask)
314{
315 int i = 0;
316 if (mask & LUA_MASKCALL) smask[i++] = 'c';
317 if (mask & LUA_MASKRET) smask[i++] = 'r';
318 if (mask & LUA_MASKLINE) smask[i++] = 'l';
319 smask[i] = '\0';
320 return smask;
321}
322
323LJLIB_CF(debug_sethook)
324{
325 int arg, mask, count;
326 lua_Hook func;
327 (void)getthread(L, &arg);
328 if (lua_isnoneornil(L, arg+1)) {
329 lua_settop(L, arg+1);
330 func = NULL; mask = 0; count = 0; /* turn off hooks */
331 } else {
332 const char *smask = luaL_checkstring(L, arg+2);
333 luaL_checktype(L, arg+1, LUA_TFUNCTION);
334 count = luaL_optint(L, arg+3, 0);
335 func = hookf; mask = makemask(smask, count);
336 }
337 (L->top++)->u64 = KEY_HOOK;
338 lua_pushvalue(L, arg+1);
339 lua_rawset(L, LUA_REGISTRYINDEX);
340 lua_sethook(L, func, mask, count);
341 return 0;
342}
343
344LJLIB_CF(debug_gethook)
345{
346 char buff[5];
347 int mask = lua_gethookmask(L);
348 lua_Hook hook = lua_gethook(L);
349 if (hook != NULL && hook != hookf) { /* external hook? */
350 lua_pushliteral(L, "external hook");
351 } else {
352 (L->top++)->u64 = KEY_HOOK;
353 lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
354 }
355 lua_pushstring(L, unmakemask(mask, buff));
356 lua_pushinteger(L, lua_gethookcount(L));
357 return 3;
358}
359
360/* ------------------------------------------------------------------------ */
361
362LJLIB_CF(debug_debug)
363{
364 for (;;) {
365 char buffer[250];
366 fputs("lua_debug> ", stderr);
367 if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
368 strcmp(buffer, "cont\n") == 0)
369 return 0;
370 if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
371 lua_pcall(L, 0, 0, 0)) {
372 const char *s = lua_tostring(L, -1);
373 fputs(s ? s : "(error object is not a string)", stderr);
374 fputs("\n", stderr);
375 }
376 lua_settop(L, 0); /* remove eventual returns */
377 }
378}
379
380/* ------------------------------------------------------------------------ */
381
382#define LEVELS1 12 /* size of the first part of the stack */
383#define LEVELS2 10 /* size of the second part of the stack */
384
385LJLIB_CF(debug_traceback)
386{
387 int arg;
388 lua_State *L1 = getthread(L, &arg);
389 const char *msg = lua_tostring(L, arg+1);
390 if (msg == NULL && L->top > L->base+arg)
391 L->top = L->base+arg+1;
392 else
393 luaL_traceback(L, L1, msg, lj_lib_optint(L, arg+2, (L == L1)));
394 return 1;
395}
396
397/* ------------------------------------------------------------------------ */
398
399#include "lj_libdef.h"
400
401LUALIB_API int luaopen_debug(lua_State *L)
402{
403 LJ_LIB_REG(L, LUA_DBLIBNAME, debug);
404 return 1;
405}
406
407