Document workaround for multilib vs. cross-compiler conflict.
[luajit-2.0.git] / src / lib_debug.c
blobc5f3040f0c18ed6c4e8c15604ee28931a7bd9c94
1 /*
2 ** Debug library.
3 ** Copyright (C) 2005-2023 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 */
9 #define lib_debug_c
10 #define LUA_LIB
12 #include "lua.h"
13 #include "lauxlib.h"
14 #include "lualib.h"
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"
22 /* ------------------------------------------------------------------------ */
24 #define LJLIB_MODULE_debug
26 LJLIB_CF(debug_getregistry)
28 copyTV(L, L->top++, registry(L));
29 return 1;
32 LJLIB_CF(debug_getmetatable)
34 lj_lib_checkany(L, 1);
35 if (!lua_getmetatable(L, 1)) {
36 setnilV(L->top-1);
38 return 1;
41 LJLIB_CF(debug_setmetatable)
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;
52 LJLIB_CF(debug_getfenv)
54 lj_lib_checkany(L, 1);
55 lua_getfenv(L, 1);
56 return 1;
59 LJLIB_CF(debug_setfenv)
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;
68 /* ------------------------------------------------------------------------ */
70 static void settabss(lua_State *L, const char *i, const char *v)
72 lua_pushstring(L, v);
73 lua_setfield(L, -2, i);
76 static void settabsi(lua_State *L, const char *i, int v)
78 lua_pushinteger(L, v);
79 lua_setfield(L, -2, i);
82 static void settabsb(lua_State *L, const char *i, int v)
84 lua_pushboolean(L, v);
85 lua_setfield(L, -2, i);
88 static lua_State *getthread(lua_State *L, int *arg)
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;
99 static void treatstackoption(lua_State *L, lua_State *L1, const char *fname)
101 if (L == L1) {
102 lua_pushvalue(L, -2);
103 lua_remove(L, -3);
105 else
106 lua_xmove(L1, L, 1);
107 lua_setfield(L, -2, fname);
110 LJLIB_CF(debug_getinfo)
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;
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);
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;
156 if (opt_L) treatstackoption(L, L1, "activelines");
157 if (opt_f) treatstackoption(L, L1, "func");
158 return 1; /* Return result table. */
161 LJLIB_CF(debug_getlocal)
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;
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;
187 LJLIB_CF(debug_setlocal)
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;
201 static int debug_getupvalue(lua_State *L, int get)
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;
214 return 0;
217 LJLIB_CF(debug_getupvalue)
219 return debug_getupvalue(L, 1);
222 LJLIB_CF(debug_setupvalue)
224 lj_lib_checkany(L, 3);
225 return debug_getupvalue(L, 0);
228 LJLIB_CF(debug_upvalueid)
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 setlightudV(L->top-1, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
235 (void *)&fn->c.upvalue[n]);
236 return 1;
239 LJLIB_CF(debug_upvaluejoin)
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];
254 setgcrefr(*p[0], *p[1]);
255 lj_gc_objbarrier(L, fn[0], gcref(*p[1]));
256 return 0;
259 #if LJ_52
260 LJLIB_CF(debug_getuservalue)
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;
271 LJLIB_CF(debug_setuservalue)
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;
282 #endif
284 /* ------------------------------------------------------------------------ */
286 static const char KEY_HOOK = 'h';
288 static void hookf(lua_State *L, lua_Debug *ar)
290 static const char *const hooknames[] =
291 {"call", "return", "line", "count", "tail return"};
292 lua_pushlightuserdata(L, (void *)&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);
303 static int makemask(const char *smask, int count)
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;
313 static char *unmakemask(int mask, char *smask)
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;
323 LJLIB_CF(debug_sethook)
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);
337 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
338 lua_pushvalue(L, arg+1);
339 lua_rawset(L, LUA_REGISTRYINDEX);
340 lua_sethook(L, func, mask, count);
341 return 0;
344 LJLIB_CF(debug_gethook)
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 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
353 lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
355 lua_pushstring(L, unmakemask(mask, buff));
356 lua_pushinteger(L, lua_gethookcount(L));
357 return 3;
360 /* ------------------------------------------------------------------------ */
362 LJLIB_CF(debug_debug)
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);
376 lua_settop(L, 0); /* remove eventual returns */
380 /* ------------------------------------------------------------------------ */
382 #define LEVELS1 12 /* size of the first part of the stack */
383 #define LEVELS2 10 /* size of the second part of the stack */
385 LJLIB_CF(debug_traceback)
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;
397 /* ------------------------------------------------------------------------ */
399 #include "lj_libdef.h"
401 LUALIB_API int luaopen_debug(lua_State *L)
403 LJ_LIB_REG(L, LUA_DBLIBNAME, debug);
404 return 1;