diff options
Diffstat (limited to 'src/lj_err.c')
-rw-r--r-- | src/lj_err.c | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/src/lj_err.c b/src/lj_err.c new file mode 100644 index 00000000..a723af48 --- /dev/null +++ b/src/lj_err.c | |||
@@ -0,0 +1,763 @@ | |||
1 | /* | ||
2 | ** Error handling and debugging API. | ||
3 | ** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h | ||
4 | ** | ||
5 | ** 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 lj_err_c | ||
10 | #define LUA_CORE | ||
11 | |||
12 | #include "lj_obj.h" | ||
13 | #include "lj_err.h" | ||
14 | #include "lj_str.h" | ||
15 | #include "lj_tab.h" | ||
16 | #include "lj_func.h" | ||
17 | #include "lj_state.h" | ||
18 | #include "lj_frame.h" | ||
19 | #include "lj_bc.h" | ||
20 | #include "lj_trace.h" | ||
21 | #include "lj_vm.h" | ||
22 | |||
23 | /* -- Error messages ------------------------------------------------------ */ | ||
24 | |||
25 | /* Error message strings. */ | ||
26 | static const char *lj_err_allmsg = | ||
27 | #define ERRDEF(name, msg) msg "\0" | ||
28 | #include "lj_errmsg.h" | ||
29 | ; | ||
30 | |||
31 | #define err2msg(em) (lj_err_allmsg+(int)(em)) | ||
32 | |||
33 | /* -- Frame and function introspection ------------------------------------ */ | ||
34 | |||
35 | static BCPos currentpc(lua_State *L, GCfunc *fn, cTValue *nextframe) | ||
36 | { | ||
37 | const BCIns *ins; | ||
38 | lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD); | ||
39 | if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */ | ||
40 | return ~(BCPos)0; | ||
41 | } else if (nextframe == NULL) { /* Lua function on top. */ | ||
42 | ins = cframe_Lpc(L); /* Only happens during error/hook handling. */ | ||
43 | } else { | ||
44 | if (frame_islua(nextframe)) { | ||
45 | ins = frame_pc(nextframe); | ||
46 | } else if (frame_iscont(nextframe)) { | ||
47 | ins = frame_contpc(nextframe); | ||
48 | } else { | ||
49 | /* Lua function below errfunc/gc/hook: find cframe to get the PC. */ | ||
50 | void *cf = cframe_raw(L->cframe); | ||
51 | TValue *f = L->base-1; | ||
52 | while (f > nextframe) { | ||
53 | if (frame_islua(f)) { | ||
54 | f = frame_prevl(f); | ||
55 | } else { | ||
56 | if (frame_isc(f)) | ||
57 | cf = cframe_raw(cframe_prev(cf)); | ||
58 | f = frame_prevd(f); | ||
59 | } | ||
60 | } | ||
61 | if (cframe_prev(cf)) | ||
62 | cf = cframe_raw(cframe_prev(cf)); | ||
63 | ins = cframe_pc(cf); | ||
64 | } | ||
65 | } | ||
66 | return (BCPos)((ins - funcproto(fn)->bc) - 1); | ||
67 | } | ||
68 | |||
69 | static BCLine currentline(lua_State *L, GCfunc *fn, cTValue *nextframe) | ||
70 | { | ||
71 | BCPos pc = currentpc(L, fn, nextframe); | ||
72 | if (pc != ~(BCPos)0) { | ||
73 | GCproto *pt = funcproto(fn); | ||
74 | lua_assert(pc < pt->sizebc); | ||
75 | return pt->lineinfo ? pt->lineinfo[pc] : 0; | ||
76 | } else { | ||
77 | return -1; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | static const char *getvarname(const GCproto *pt, BCPos pc, BCReg slot) | ||
82 | { | ||
83 | MSize i; | ||
84 | for (i = 0; i < pt->sizevarinfo && pt->varinfo[i].startpc <= pc; i++) | ||
85 | if (pc < pt->varinfo[i].endpc && slot-- == 0) | ||
86 | return strdata(pt->varinfo[i].name); | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | static const char *getobjname(GCproto *pt, const BCIns *ip, BCReg slot, | ||
91 | const char **name) | ||
92 | { | ||
93 | const char *lname; | ||
94 | restart: | ||
95 | lname = getvarname(pt, (BCPos)(ip - pt->bc), slot); | ||
96 | if (lname != NULL) { *name = lname; return "local"; } | ||
97 | while (--ip >= pt->bc) { | ||
98 | BCIns ins = *ip; | ||
99 | BCOp op = bc_op(ins); | ||
100 | BCReg ra = bc_a(ins); | ||
101 | if (bcmode_a(op) == BCMbase) { | ||
102 | if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins))) | ||
103 | return NULL; | ||
104 | } else if (bcmode_a(op) == BCMdst && ra == slot) { | ||
105 | switch (bc_op(ins)) { | ||
106 | case BC_MOV: | ||
107 | if (ra == slot) { slot = bc_d(ins); goto restart; } | ||
108 | break; | ||
109 | case BC_GGET: | ||
110 | *name = strdata(gco2str(gcref(pt->k.gc[~bc_d(ins)]))); | ||
111 | return "global"; | ||
112 | case BC_TGETS: | ||
113 | *name = strdata(gco2str(gcref(pt->k.gc[~bc_c(ins)]))); | ||
114 | if (ip > pt->bc) { | ||
115 | BCIns insp = ip[-1]; | ||
116 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 && | ||
117 | bc_d(insp) == bc_b(ins)) | ||
118 | return "method"; | ||
119 | } | ||
120 | return "field"; | ||
121 | case BC_UGET: | ||
122 | *name = pt->uvname ? strdata(pt->uvname[bc_d(ins)]) : "?"; | ||
123 | return "upvalue"; | ||
124 | default: | ||
125 | return NULL; | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | static const char *getfuncname(lua_State *L, TValue *frame, const char **name) | ||
133 | { | ||
134 | MMS mm; | ||
135 | const BCIns *ip; | ||
136 | TValue *pframe; | ||
137 | GCfunc *fn; | ||
138 | BCPos pc; | ||
139 | if (frame_isvarg(frame)) | ||
140 | frame = frame_prevd(frame); | ||
141 | pframe = frame_prev(frame); | ||
142 | fn = frame_func(pframe); | ||
143 | pc = currentpc(L, fn, frame); | ||
144 | if (pc == ~(BCPos)0) | ||
145 | return NULL; | ||
146 | lua_assert(pc < funcproto(fn)->sizebc); | ||
147 | ip = &funcproto(fn)->bc[pc]; | ||
148 | mm = bcmode_mm(bc_op(*ip)); | ||
149 | if (mm == MM_call) { | ||
150 | BCReg slot = bc_a(*ip); | ||
151 | if (bc_op(*ip) == BC_ITERC) slot -= 3; | ||
152 | return getobjname(funcproto(fn), ip, slot, name); | ||
153 | } else if (mm != MM_MAX) { | ||
154 | *name = strdata(strref(G(L)->mmname[mm])); | ||
155 | return "metamethod"; | ||
156 | } else { | ||
157 | return NULL; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | void lj_err_pushloc(lua_State *L, GCproto *pt, BCPos pc) | ||
162 | { | ||
163 | GCstr *name = pt->chunkname; | ||
164 | if (name) { | ||
165 | const char *s = strdata(name); | ||
166 | MSize i, len = name->len; | ||
167 | BCLine line; | ||
168 | if (pc) | ||
169 | line = pt->lineinfo ? pt->lineinfo[pc-1] : 0; | ||
170 | else | ||
171 | line = pt->linedefined; | ||
172 | if (*s == '@') { | ||
173 | s++; len--; | ||
174 | for (i = len; i > 0; i--) | ||
175 | if (s[i] == '/' || s[i] == '\\') { | ||
176 | s += i+1; | ||
177 | break; | ||
178 | } | ||
179 | lj_str_pushf(L, "%s:%d", s, line); | ||
180 | } else if (len > 40) { | ||
181 | lj_str_pushf(L, "%p:%d", pt, line); | ||
182 | } else if (*s == '=') { | ||
183 | lj_str_pushf(L, "%s:%d", s+1, line); | ||
184 | } else { | ||
185 | lj_str_pushf(L, "\"%s\":%d", s, line); | ||
186 | } | ||
187 | } else { | ||
188 | lj_str_pushf(L, "%p:%u", pt, pc); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static void err_chunkid(char *out, const char *src) | ||
193 | { | ||
194 | if (*src == '=') { | ||
195 | strncpy(out, src+1, LUA_IDSIZE); /* remove first char */ | ||
196 | out[LUA_IDSIZE-1] = '\0'; /* ensures null termination */ | ||
197 | } else if (*src == '@') { /* out = "source", or "...source" */ | ||
198 | size_t l = strlen(++src); /* skip the `@' */ | ||
199 | if (l >= LUA_IDSIZE) { | ||
200 | src += l-(LUA_IDSIZE-4); /* get last part of file name */ | ||
201 | strcpy(out, "..."); | ||
202 | out += 3; | ||
203 | } | ||
204 | strcpy(out, src); | ||
205 | } else { /* out = [string "string"] */ | ||
206 | size_t len; /* Length, up to first control char. */ | ||
207 | for (len = 0; len < LUA_IDSIZE-11; len++) | ||
208 | if (((const unsigned char *)src)[len] < ' ') break; | ||
209 | strcpy(out, "[string \""); out += 9; | ||
210 | if (src[len] != '\0') { /* must truncate? */ | ||
211 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; | ||
212 | strncpy(out, src, len); out += len; | ||
213 | strcpy(out, "..."); out += 3; | ||
214 | } else { | ||
215 | strcpy(out, src); out += len; | ||
216 | } | ||
217 | strcpy(out, "\"]"); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | /* -- Public debug API ---------------------------------------------------- */ | ||
222 | |||
223 | static TValue *findlocal(lua_State *L, const lua_Debug *ar, | ||
224 | const char **name, BCReg slot) | ||
225 | { | ||
226 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; | ||
227 | uint32_t size = (uint32_t)ar->i_ci >> 16; | ||
228 | TValue *frame = L->stack + offset; | ||
229 | TValue *nextframe = size ? frame + size : NULL; | ||
230 | GCfunc *fn = frame_func(frame); | ||
231 | BCPos pc = currentpc(L, fn, nextframe); | ||
232 | if (pc != ~(BCPos)0 && | ||
233 | (*name = getvarname(funcproto(fn), pc, slot-1)) != NULL) | ||
234 | ; | ||
235 | else if (slot > 0 && frame + slot < (nextframe ? nextframe : L->top)) | ||
236 | *name = "(*temporary)"; | ||
237 | else | ||
238 | *name = NULL; | ||
239 | return frame+slot; | ||
240 | } | ||
241 | |||
242 | LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n) | ||
243 | { | ||
244 | const char *name; | ||
245 | TValue *o = findlocal(L, ar, &name, (BCReg)n); | ||
246 | if (name) { | ||
247 | copyTV(L, L->top, o); | ||
248 | incr_top(L); | ||
249 | } | ||
250 | return name; | ||
251 | } | ||
252 | |||
253 | |||
254 | LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n) | ||
255 | { | ||
256 | const char *name; | ||
257 | TValue *o = findlocal(L, ar, &name, (BCReg)n); | ||
258 | if (name) | ||
259 | copyTV(L, o, L->top-1); | ||
260 | L->top--; | ||
261 | return name; | ||
262 | } | ||
263 | |||
264 | LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) | ||
265 | { | ||
266 | int status = 1; | ||
267 | TValue *frame = NULL; | ||
268 | TValue *nextframe = NULL; | ||
269 | GCfunc *fn; | ||
270 | if (*what == '>') { | ||
271 | TValue *func = L->top - 1; | ||
272 | api_check(L, tvisfunc(func)); | ||
273 | fn = funcV(func); | ||
274 | L->top--; | ||
275 | what++; | ||
276 | } else { | ||
277 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; | ||
278 | uint32_t size = (uint32_t)ar->i_ci >> 16; | ||
279 | lua_assert(offset != 0); | ||
280 | frame = L->stack + offset; | ||
281 | if (size) nextframe = frame + size; | ||
282 | lua_assert(frame<=L->maxstack && (!nextframe || nextframe<=L->maxstack)); | ||
283 | fn = frame_func(frame); | ||
284 | lua_assert(fn->c.gct == ~LJ_TFUNC); | ||
285 | } | ||
286 | for (; *what; what++) { | ||
287 | switch (*what) { | ||
288 | case 'S': | ||
289 | if (isluafunc(fn)) { | ||
290 | ar->source = strdata(funcproto(fn)->chunkname); | ||
291 | ar->linedefined = cast_int(funcproto(fn)->linedefined); | ||
292 | ar->lastlinedefined = cast_int(funcproto(fn)->lastlinedefined); | ||
293 | ar->what = (ar->linedefined == 0) ? "main" : "Lua"; | ||
294 | } else { | ||
295 | ar->source = "=[C]"; | ||
296 | ar->linedefined = -1; | ||
297 | ar->lastlinedefined = -1; | ||
298 | ar->what = "C"; | ||
299 | } | ||
300 | err_chunkid(ar->short_src, ar->source); | ||
301 | break; | ||
302 | case 'l': | ||
303 | ar->currentline = frame ? currentline(L, fn, nextframe) : -1; | ||
304 | break; | ||
305 | case 'u': | ||
306 | ar->nups = fn->c.nupvalues; | ||
307 | break; | ||
308 | case 'n': | ||
309 | ar->namewhat = frame ? getfuncname(L, frame, &ar->name) : NULL; | ||
310 | if (ar->namewhat == NULL) { | ||
311 | ar->namewhat = ""; | ||
312 | ar->name = NULL; | ||
313 | } | ||
314 | break; | ||
315 | case 'f': | ||
316 | setfuncV(L, L->top, fn); | ||
317 | incr_top(L); | ||
318 | break; | ||
319 | case 'L': | ||
320 | if (isluafunc(fn)) { | ||
321 | GCtab *t = lj_tab_new(L, 0, 0); | ||
322 | BCLine *lineinfo = funcproto(fn)->lineinfo; | ||
323 | uint32_t i, szl = funcproto(fn)->sizelineinfo; | ||
324 | for (i = 0; i < szl; i++) | ||
325 | setboolV(lj_tab_setint(L, t, lineinfo[i]), 1); | ||
326 | settabV(L, L->top, t); | ||
327 | } else { | ||
328 | setnilV(L->top); | ||
329 | } | ||
330 | incr_top(L); | ||
331 | break; | ||
332 | default: | ||
333 | status = 0; /* Bad option. */ | ||
334 | break; | ||
335 | } | ||
336 | } | ||
337 | return status; | ||
338 | } | ||
339 | |||
340 | cTValue *lj_err_getframe(lua_State *L, int level, int *size) | ||
341 | { | ||
342 | cTValue *frame, *nextframe; | ||
343 | /* Traverse frames backwards. */ | ||
344 | for (nextframe = frame = L->base-1; frame > L->stack; ) { | ||
345 | if (frame_gc(frame) == obj2gco(L)) | ||
346 | level++; /* Skip dummy frames. See lj_meta_call(). */ | ||
347 | if (level-- == 0) { | ||
348 | *size = cast_int(nextframe - frame); | ||
349 | return frame; /* Level found. */ | ||
350 | } | ||
351 | nextframe = frame; | ||
352 | if (frame_islua(frame)) { | ||
353 | frame = frame_prevl(frame); | ||
354 | } else { | ||
355 | if (frame_isvarg(frame)) | ||
356 | level++; /* Skip vararg pseudo-frame. */ | ||
357 | frame = frame_prevd(frame); | ||
358 | } | ||
359 | } | ||
360 | *size = level; | ||
361 | return NULL; /* Level not found. */ | ||
362 | } | ||
363 | |||
364 | LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar) | ||
365 | { | ||
366 | int size; | ||
367 | cTValue *frame = lj_err_getframe(L, level, &size); | ||
368 | if (frame) { | ||
369 | ar->i_ci = (size << 16) + cast_int(frame - L->stack); | ||
370 | return 1; | ||
371 | } else { | ||
372 | ar->i_ci = level - size; | ||
373 | return 0; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /* -- Error handling ------------------------------------------------------ */ | ||
378 | |||
379 | /* Return string object for error message. */ | ||
380 | LJ_NOINLINE GCstr *lj_err_str(lua_State *L, ErrMsg em) | ||
381 | { | ||
382 | return lj_str_newz(L, err2msg(em)); | ||
383 | } | ||
384 | |||
385 | /* Unwind Lua stack and add error message on top. */ | ||
386 | LJ_NOINLINE static void unwindstack(lua_State *L, TValue *top, int errcode) | ||
387 | { | ||
388 | lj_func_closeuv(L, top); | ||
389 | switch (errcode) { | ||
390 | case LUA_ERRMEM: | ||
391 | setstrV(L, top, lj_err_str(L, LJ_ERR_ERRMEM)); | ||
392 | break; | ||
393 | case LUA_ERRERR: | ||
394 | setstrV(L, top, lj_err_str(L, LJ_ERR_ERRERR)); | ||
395 | break; | ||
396 | case LUA_ERRSYNTAX: | ||
397 | case LUA_ERRRUN: | ||
398 | copyTV(L, top, L->top - 1); | ||
399 | break; | ||
400 | default: | ||
401 | lua_assert(0); | ||
402 | break; | ||
403 | } | ||
404 | L->top = top+1; | ||
405 | lj_state_relimitstack(L); | ||
406 | } | ||
407 | |||
408 | /* Throw error. Find catch frame, unwind stack and continue. */ | ||
409 | LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode) | ||
410 | { | ||
411 | TValue *frame = L->base-1; | ||
412 | void *cf = L->cframe; | ||
413 | global_State *g = G(L); | ||
414 | if (L->status == LUA_ERRERR+1) { /* Don't touch the stack during lua_open. */ | ||
415 | lj_vm_unwind_c(cf, errcode); | ||
416 | goto uncaught; /* unreachable */ | ||
417 | } | ||
418 | lj_trace_abort(g); | ||
419 | setgcrefnull(g->jit_L); | ||
420 | L->status = 0; | ||
421 | while (cf) { | ||
422 | if (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ | ||
423 | TValue *top = restorestack(L, -cframe_nres(cf)); | ||
424 | if (frame < top) { | ||
425 | L->cframe = cframe_prev(cf); | ||
426 | L->base = frame+1; | ||
427 | unwindstack(L, top, errcode); | ||
428 | lj_vm_unwind_c(cf, errcode); | ||
429 | goto uncaught; /* unreachable */ | ||
430 | } | ||
431 | } | ||
432 | if (frame <= L->stack) | ||
433 | break; | ||
434 | switch (frame_typep(frame)) { | ||
435 | case FRAME_LUA: | ||
436 | case FRAME_LUAP: | ||
437 | frame = frame_prevl(frame); | ||
438 | break; | ||
439 | case FRAME_C: | ||
440 | if (cframe_canyield(cf)) goto uncaught; | ||
441 | cf = cframe_prev(cf); | ||
442 | /* fallthrough */ | ||
443 | case FRAME_CONT: | ||
444 | case FRAME_VARG: | ||
445 | frame = frame_prevd(frame); | ||
446 | break; | ||
447 | case FRAME_CP: | ||
448 | L->cframe = cframe_prev(cf); | ||
449 | L->base = frame_prevd(frame) + 1; | ||
450 | unwindstack(L, frame, errcode); | ||
451 | lj_vm_unwind_c(cf, errcode); | ||
452 | goto uncaught; /* unreachable */ | ||
453 | case FRAME_PCALL: | ||
454 | hook_leave(g); | ||
455 | /* fallthrough */ | ||
456 | case FRAME_PCALLH: | ||
457 | L->cframe = cf; | ||
458 | L->base = frame_prevd(frame) + 1; | ||
459 | unwindstack(L, L->base, errcode); | ||
460 | lj_vm_unwind_ff(cf); | ||
461 | goto uncaught; /* unreachable */ | ||
462 | default: | ||
463 | lua_assert(0); | ||
464 | goto uncaught; | ||
465 | } | ||
466 | } | ||
467 | /* No catch frame found. Must be a resume or an unprotected error. */ | ||
468 | uncaught: | ||
469 | L->status = cast_byte(errcode); | ||
470 | L->cframe = NULL; | ||
471 | if (cframe_canyield(cf)) { /* Resume? */ | ||
472 | unwindstack(L, L->top, errcode); | ||
473 | lj_vm_unwind_c(cf, errcode); | ||
474 | } | ||
475 | /* Better rethrow on main thread than panic. */ | ||
476 | { | ||
477 | if (L != mainthread(g)) | ||
478 | lj_err_throw(mainthread(g), errcode); | ||
479 | if (g->panic) { | ||
480 | L->base = L->stack+1; | ||
481 | unwindstack(L, L->base, errcode); | ||
482 | g->panic(L); | ||
483 | } | ||
484 | } | ||
485 | exit(EXIT_FAILURE); | ||
486 | } | ||
487 | |||
488 | /* Find error function for runtime errors. Requires an extra stack traversal. */ | ||
489 | static ptrdiff_t finderrfunc(lua_State *L) | ||
490 | { | ||
491 | TValue *frame = L->base-1; | ||
492 | void *cf = L->cframe; | ||
493 | while (frame > L->stack) { | ||
494 | lua_assert(cf != NULL); | ||
495 | while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ | ||
496 | if (frame >= restorestack(L, -cframe_nres(cf))) | ||
497 | break; | ||
498 | if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */ | ||
499 | return cframe_errfunc(cf); | ||
500 | cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */ | ||
501 | if (cf == NULL) | ||
502 | return 0; | ||
503 | } | ||
504 | switch (frame_typep(frame)) { | ||
505 | case FRAME_LUA: | ||
506 | case FRAME_LUAP: | ||
507 | frame = frame_prevl(frame); | ||
508 | break; | ||
509 | case FRAME_C: | ||
510 | if (cframe_canyield(cf)) return 0; | ||
511 | cf = cframe_prev(cf); | ||
512 | /* fallthrough */ | ||
513 | case FRAME_CONT: | ||
514 | case FRAME_VARG: | ||
515 | frame = frame_prevd(frame); | ||
516 | break; | ||
517 | case FRAME_CP: | ||
518 | if (cframe_errfunc(cf) >= 0) | ||
519 | return cframe_errfunc(cf); | ||
520 | frame = frame_prevd(frame); | ||
521 | break; | ||
522 | case FRAME_PCALL: | ||
523 | case FRAME_PCALLH: | ||
524 | if (frame_ftsz(frame) >= (ptrdiff_t)(2*sizeof(TValue))) /* xpcall? */ | ||
525 | return savestack(L, frame-1); /* Point to xpcall's errorfunc. */ | ||
526 | return 0; | ||
527 | default: | ||
528 | lua_assert(0); | ||
529 | return 0; | ||
530 | } | ||
531 | } | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* Runtime error. */ | ||
536 | LJ_NOINLINE void lj_err_run(lua_State *L) | ||
537 | { | ||
538 | ptrdiff_t ef = finderrfunc(L); | ||
539 | if (ef) { | ||
540 | TValue *errfunc = restorestack(L, ef); | ||
541 | TValue *top = L->top; | ||
542 | lj_trace_abort(G(L)); | ||
543 | if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) | ||
544 | lj_err_throw(L, LUA_ERRERR); | ||
545 | L->status = LUA_ERRERR; | ||
546 | copyTV(L, top, top-1); | ||
547 | copyTV(L, top-1, errfunc); | ||
548 | L->top = top+1; | ||
549 | lj_vm_call(L, top, 1+1); /* Stack: |errfunc|msg| -> |msg| */ | ||
550 | } | ||
551 | lj_err_throw(L, LUA_ERRRUN); | ||
552 | } | ||
553 | |||
554 | /* Add location to error message. */ | ||
555 | LJ_NOINLINE static void err_loc(lua_State *L, const char *msg, | ||
556 | cTValue *frame, cTValue *nextframe) | ||
557 | { | ||
558 | if (frame) { | ||
559 | GCfunc *fn = frame_func(frame); | ||
560 | if (isluafunc(fn)) { | ||
561 | char buff[LUA_IDSIZE]; | ||
562 | BCLine line = currentline(L, fn, nextframe); | ||
563 | err_chunkid(buff, strdata(funcproto(fn)->chunkname)); | ||
564 | lj_str_pushf(L, "%s:%d: %s", buff, line, msg); | ||
565 | return; | ||
566 | } | ||
567 | } | ||
568 | lj_str_pushf(L, "%s", msg); | ||
569 | } | ||
570 | |||
571 | /* Formatted runtime error message. */ | ||
572 | LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...) | ||
573 | { | ||
574 | const char *msg; | ||
575 | va_list argp; | ||
576 | va_start(argp, em); | ||
577 | if (curr_funcisL(L)) L->top = curr_topL(L); | ||
578 | msg = lj_str_pushvf(L, err2msg(em), argp); | ||
579 | va_end(argp); | ||
580 | err_loc(L, msg, L->base-1, NULL); | ||
581 | lj_err_run(L); | ||
582 | } | ||
583 | |||
584 | /* Non-vararg variant for better calling conventions. */ | ||
585 | LJ_NOINLINE void lj_err_msg(lua_State *L, ErrMsg em) | ||
586 | { | ||
587 | err_msgv(L, em); | ||
588 | } | ||
589 | |||
590 | /* Lexer error. */ | ||
591 | LJ_NOINLINE void lj_err_lex(lua_State *L, const char *src, const char *tok, | ||
592 | BCLine line, ErrMsg em, va_list argp) | ||
593 | { | ||
594 | char buff[LUA_IDSIZE]; | ||
595 | const char *msg; | ||
596 | err_chunkid(buff, src); | ||
597 | msg = lj_str_pushvf(L, err2msg(em), argp); | ||
598 | msg = lj_str_pushf(L, "%s:%d: %s", buff, line, msg); | ||
599 | if (tok) | ||
600 | lj_str_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tok); | ||
601 | lj_err_throw(L, LUA_ERRSYNTAX); | ||
602 | } | ||
603 | |||
604 | /* Typecheck error for operands. */ | ||
605 | LJ_NOINLINE void lj_err_optype(lua_State *L, cTValue *o, ErrMsg opm) | ||
606 | { | ||
607 | const char *tname = typename(o); | ||
608 | const char *oname = NULL; | ||
609 | const char *opname = err2msg(opm); | ||
610 | if (curr_funcisL(L)) { | ||
611 | GCproto *pt = curr_proto(L); | ||
612 | const BCIns *pc = cframe_Lpc(L) - 1; | ||
613 | const char *kind = getobjname(pt, pc, (BCReg)(o - L->base), &oname); | ||
614 | if (kind) | ||
615 | err_msgv(L, LJ_ERR_BADOPRT, opname, kind, oname, tname); | ||
616 | } | ||
617 | err_msgv(L, LJ_ERR_BADOPRV, opname, tname); | ||
618 | } | ||
619 | |||
620 | /* Typecheck error for ordered comparisons. */ | ||
621 | LJ_NOINLINE void lj_err_comp(lua_State *L, cTValue *o1, cTValue *o2) | ||
622 | { | ||
623 | const char *t1 = typename(o1); | ||
624 | const char *t2 = typename(o2); | ||
625 | err_msgv(L, t1 == t2 ? LJ_ERR_BADCMPV : LJ_ERR_BADCMPT, t1, t2); | ||
626 | /* This assumes the two "boolean" entries are commoned by the C compiler. */ | ||
627 | } | ||
628 | |||
629 | /* Typecheck error for __call. */ | ||
630 | LJ_NOINLINE void lj_err_optype_call(lua_State *L, TValue *o) | ||
631 | { | ||
632 | /* Gross hack if lua_[p]call or pcall/xpcall fail for a non-callable object: | ||
633 | ** L->base still points to the caller. So add a dummy frame with L instead | ||
634 | ** of a function. See lua_getstack(). | ||
635 | */ | ||
636 | const BCIns *pc = cframe_Lpc(L); | ||
637 | if (((ptrdiff_t)pc & FRAME_TYPE) != FRAME_LUA) { | ||
638 | const char *tname = typename(o); | ||
639 | setframe_pc(o, pc); | ||
640 | setframe_gc(o, obj2gco(L)); | ||
641 | L->top = L->base = o+1; | ||
642 | err_msgv(L, LJ_ERR_BADCALL, tname); | ||
643 | } | ||
644 | lj_err_optype(L, o, LJ_ERR_OPCALL); | ||
645 | } | ||
646 | |||
647 | /* Error in context of caller. */ | ||
648 | LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) | ||
649 | { | ||
650 | cTValue *frame = L->base-1; | ||
651 | cTValue *pframe = frame_islua(frame) ? frame_prevl(frame) : NULL; | ||
652 | err_loc(L, msg, pframe, frame); | ||
653 | lj_err_run(L); | ||
654 | } | ||
655 | |||
656 | /* Formatted error in context of caller. */ | ||
657 | LJ_NOINLINE void lj_err_callerv(lua_State *L, ErrMsg em, ...) | ||
658 | { | ||
659 | const char *msg; | ||
660 | va_list argp; | ||
661 | va_start(argp, em); | ||
662 | msg = lj_str_pushvf(L, err2msg(em), argp); | ||
663 | va_end(argp); | ||
664 | lj_err_callermsg(L, msg); | ||
665 | } | ||
666 | |||
667 | /* Error in context of caller. */ | ||
668 | LJ_NOINLINE void lj_err_caller(lua_State *L, ErrMsg em) | ||
669 | { | ||
670 | lj_err_callermsg(L, err2msg(em)); | ||
671 | } | ||
672 | |||
673 | /* Argument error message. */ | ||
674 | LJ_NORET LJ_NOINLINE static void err_argmsg(lua_State *L, int narg, | ||
675 | const char *msg) | ||
676 | { | ||
677 | const char *fname = "?"; | ||
678 | const char *ftype = getfuncname(L, L->base - 1, &fname); | ||
679 | if (ftype && ftype[3] == 'h' && --narg == 0) /* Check for "method". */ | ||
680 | msg = lj_str_pushf(L, err2msg(LJ_ERR_BADSELF), fname, msg); | ||
681 | else | ||
682 | msg = lj_str_pushf(L, err2msg(LJ_ERR_BADARG), narg, fname, msg); | ||
683 | lj_err_callermsg(L, msg); | ||
684 | } | ||
685 | |||
686 | /* Formatted argument error. */ | ||
687 | LJ_NOINLINE void lj_err_argv(lua_State *L, int narg, ErrMsg em, ...) | ||
688 | { | ||
689 | const char *msg; | ||
690 | va_list argp; | ||
691 | va_start(argp, em); | ||
692 | msg = lj_str_pushvf(L, err2msg(em), argp); | ||
693 | va_end(argp); | ||
694 | err_argmsg(L, narg, msg); | ||
695 | } | ||
696 | |||
697 | /* Argument error. */ | ||
698 | LJ_NOINLINE void lj_err_arg(lua_State *L, int narg, ErrMsg em) | ||
699 | { | ||
700 | err_argmsg(L, narg, err2msg(em)); | ||
701 | } | ||
702 | |||
703 | /* Typecheck error for arguments. */ | ||
704 | LJ_NOINLINE void lj_err_argtype(lua_State *L, int narg, const char *xname) | ||
705 | { | ||
706 | TValue *o = L->base + narg-1; | ||
707 | const char *tname = o < L->top ? typename(o) : lj_obj_typename[0]; | ||
708 | const char *msg = lj_str_pushf(L, err2msg(LJ_ERR_BADTYPE), xname, tname); | ||
709 | err_argmsg(L, narg, msg); | ||
710 | } | ||
711 | |||
712 | /* Typecheck error for arguments. */ | ||
713 | LJ_NOINLINE void lj_err_argt(lua_State *L, int narg, int tt) | ||
714 | { | ||
715 | lj_err_argtype(L, narg, lj_obj_typename[tt+1]); | ||
716 | } | ||
717 | |||
718 | /* -- Public error handling API ------------------------------------------- */ | ||
719 | |||
720 | LUA_API lua_CFunction lua_atpanic(lua_State *L, lua_CFunction panicf) | ||
721 | { | ||
722 | lua_CFunction old = G(L)->panic; | ||
723 | G(L)->panic = panicf; | ||
724 | return old; | ||
725 | } | ||
726 | |||
727 | /* Forwarders for the public API (C calling convention and no LJ_NORET). */ | ||
728 | LUA_API int lua_error(lua_State *L) | ||
729 | { | ||
730 | lj_err_run(L); | ||
731 | return 0; /* unreachable */ | ||
732 | } | ||
733 | |||
734 | LUALIB_API int luaL_argerror(lua_State *L, int narg, const char *msg) | ||
735 | { | ||
736 | err_argmsg(L, narg, msg); | ||
737 | return 0; /* unreachable */ | ||
738 | } | ||
739 | |||
740 | LUALIB_API int luaL_typerror(lua_State *L, int narg, const char *xname) | ||
741 | { | ||
742 | lj_err_argtype(L, narg, xname); | ||
743 | return 0; /* unreachable */ | ||
744 | } | ||
745 | |||
746 | LUALIB_API void luaL_where(lua_State *L, int level) | ||
747 | { | ||
748 | int size; | ||
749 | cTValue *frame = lj_err_getframe(L, level, &size); | ||
750 | err_loc(L, "", frame, size ? frame+size : NULL); | ||
751 | } | ||
752 | |||
753 | LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...) | ||
754 | { | ||
755 | const char *msg; | ||
756 | va_list argp; | ||
757 | va_start(argp, fmt); | ||
758 | msg = lj_str_pushvf(L, fmt, argp); | ||
759 | va_end(argp); | ||
760 | lj_err_callermsg(L, msg); | ||
761 | return 0; /* unreachable */ | ||
762 | } | ||
763 | |||