Mercurial
comparison third_party/luajit/src/lib_debug.c @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | 94705b5986b3 |
| children |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 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 */ | |
| 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 | |
| 26 LJLIB_CF(debug_getregistry) | |
| 27 { | |
| 28 copyTV(L, L->top++, registry(L)); | |
| 29 return 1; | |
| 30 } | |
| 31 | |
| 32 LJLIB_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 | |
| 41 LJLIB_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 | |
| 52 LJLIB_CF(debug_getfenv) | |
| 53 { | |
| 54 lj_lib_checkany(L, 1); | |
| 55 lua_getfenv(L, 1); | |
| 56 return 1; | |
| 57 } | |
| 58 | |
| 59 LJLIB_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 | |
| 70 static 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 | |
| 76 static void settabsi(lua_State *L, const char *i, int v) | |
| 77 { | |
| 78 lua_pushinteger(L, v); | |
| 79 lua_setfield(L, -2, i); | |
| 80 } | |
| 81 | |
| 82 static void settabsb(lua_State *L, const char *i, int v) | |
| 83 { | |
| 84 lua_pushboolean(L, v); | |
| 85 lua_setfield(L, -2, i); | |
| 86 } | |
| 87 | |
| 88 static 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 | |
| 99 static 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 | |
| 110 LJLIB_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 | |
| 161 LJLIB_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 | |
| 187 LJLIB_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 | |
| 201 static 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 | |
| 217 LJLIB_CF(debug_getupvalue) | |
| 218 { | |
| 219 return debug_getupvalue(L, 1); | |
| 220 } | |
| 221 | |
| 222 LJLIB_CF(debug_setupvalue) | |
| 223 { | |
| 224 lj_lib_checkany(L, 3); | |
| 225 return debug_getupvalue(L, 0); | |
| 226 } | |
| 227 | |
| 228 LJLIB_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 | |
| 239 LJLIB_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 | |
| 260 LJLIB_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 | |
| 271 LJLIB_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 | |
| 288 static 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 | |
| 303 static 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 | |
| 313 static 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 | |
| 323 LJLIB_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 | |
| 344 LJLIB_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 | |
| 362 LJLIB_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 | |
| 385 LJLIB_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 | |
| 401 LUALIB_API int luaopen_debug(lua_State *L) | |
| 402 { | |
| 403 LJ_LIB_REG(L, LUA_DBLIBNAME, debug); | |
| 404 return 1; | |
| 405 } | |
| 406 |