1 /* $NetBSD: luac.c,v 1.12 2023/06/08 21:12:08 nikita Exp $ */
2
3 /*
4 ** Id: luac.c
5 ** Lua compiler (saves bytecodes to files; also lists bytecodes)
6 ** See Copyright Notice in lua.h
7 */
8
9 #define luac_c
10 #define LUA_CORE
11
12 #include "lprefix.h"
13
14 #include <ctype.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include "lua.h"
21 #include "lauxlib.h"
22
23 #include "ldebug.h"
24 #include "lobject.h"
25 #include "lopcodes.h"
26 #include "lopnames.h"
27 #include "lstate.h"
28 #include "lundump.h"
29
30 static void PrintFunction(const Proto* f, int full);
31 #define luaU_print PrintFunction
32
33 #define PROGNAME "luac" /* default program name */
34 #define OUTPUT PROGNAME ".out" /* default output file */
35
36 static int listing=0; /* list bytecodes? */
37 static int dumping=1; /* dump bytecodes? */
38 static int stripping=0; /* strip debug information? */
39 static char Output[]={ OUTPUT }; /* default output file name */
40 static const char* output=Output; /* actual output file name */
41 static const char* progname=PROGNAME; /* actual program name */
42 static TString **tmname;
43
fatal(const char * message)44 static void fatal(const char* message)
45 {
46 fprintf(stderr,"%s: %s\n",progname,message);
47 exit(EXIT_FAILURE);
48 }
49
cannot(const char * what)50 static void cannot(const char* what)
51 {
52 fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
53 exit(EXIT_FAILURE);
54 }
55
usage(const char * message)56 static void usage(const char* message)
57 {
58 if (*message=='-')
59 fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message);
60 else
61 fprintf(stderr,"%s: %s\n",progname,message);
62 fprintf(stderr,
63 "usage: %s [options] [filenames]\n"
64 "Available options are:\n"
65 " -l list (use -l -l for full listing)\n"
66 " -o name output to file 'name' (default is \"%s\")\n"
67 " -p parse only\n"
68 " -s strip debug information\n"
69 " -v show version information\n"
70 " -- stop handling options\n"
71 " - stop handling options and process stdin\n"
72 ,progname,Output);
73 exit(EXIT_FAILURE);
74 }
75
76 #define IS(s) (strcmp(argv[i],s)==0)
77
doargs(int argc,char * argv[])78 static int doargs(int argc, char* argv[])
79 {
80 int i;
81 int version=0;
82 if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
83 for (i=1; i<argc; i++)
84 {
85 if (*argv[i]!='-') /* end of options; keep it */
86 break;
87 else if (IS("--")) /* end of options; skip it */
88 {
89 ++i;
90 if (version) ++version;
91 break;
92 }
93 else if (IS("-")) /* end of options; use stdin */
94 break;
95 else if (IS("-l")) /* list */
96 ++listing;
97 else if (IS("-o")) /* output file */
98 {
99 output=argv[++i];
100 if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
101 usage("'-o' needs argument");
102 if (IS("-")) output=NULL;
103 }
104 else if (IS("-p")) /* parse only */
105 dumping=0;
106 else if (IS("-s")) /* strip debug information */
107 stripping=1;
108 else if (IS("-v")) /* show version */
109 ++version;
110 else /* unknown option */
111 usage(argv[i]);
112 }
113 if (i==argc && (listing || !dumping))
114 {
115 dumping=0;
116 argv[--i]=Output;
117 }
118 if (version)
119 {
120 printf("%s\n",LUA_COPYRIGHT);
121 if (version==argc-1) exit(EXIT_SUCCESS);
122 }
123 return i;
124 }
125
126 #define FUNCTION "(function()end)();\n"
127
reader(lua_State * L,void * ud,size_t * size)128 static const char* reader(lua_State* L, void* ud, size_t* size)
129 {
130 UNUSED(L);
131 if ((*(int*)ud)--)
132 {
133 *size=sizeof(FUNCTION)-1;
134 return FUNCTION;
135 }
136 else
137 {
138 *size=0;
139 return NULL;
140 }
141 }
142
143 #define toproto(L,i) getproto(s2v(L->top.p+(i)))
144
combine(lua_State * L,int n)145 static const Proto* combine(lua_State* L, int n)
146 {
147 if (n==1)
148 return toproto(L,-1);
149 else
150 {
151 Proto* f;
152 int i=n;
153 if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1));
154 f=toproto(L,-1);
155 for (i=0; i<n; i++)
156 {
157 f->p[i]=toproto(L,i-n-1);
158 if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
159 }
160 return f;
161 }
162 }
163
writer(lua_State * L,const void * p,size_t size,void * u)164 static int writer(lua_State* L, const void* p, size_t size, void* u)
165 {
166 UNUSED(L);
167 return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
168 }
169
pmain(lua_State * L)170 static int pmain(lua_State* L)
171 {
172 int argc=(int)lua_tointeger(L,1);
173 char** argv=(char**)lua_touserdata(L,2);
174 const Proto* f;
175 int i;
176 tmname=G(L)->tmname;
177 if (!lua_checkstack(L,argc)) fatal("too many input files");
178 for (i=0; i<argc; i++)
179 {
180 const char* filename=IS("-") ? NULL : argv[i];
181 if (luaL_loadfile(L,filename)!=LUA_OK) fatal(lua_tostring(L,-1));
182 }
183 f=combine(L,argc);
184 if (listing) luaU_print(f,listing>1);
185 if (dumping)
186 {
187 FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
188 if (D==NULL) cannot("open");
189 lua_lock(L);
190 luaU_dump(L,f,writer,D,stripping);
191 lua_unlock(L);
192 if (ferror(D)) cannot("write");
193 if (fclose(D)) cannot("close");
194 }
195 return 0;
196 }
197
main(int argc,char * argv[])198 int main(int argc, char* argv[])
199 {
200 lua_State* L;
201 int i=doargs(argc,argv);
202 argc-=i; argv+=i;
203 if (argc<=0) usage("no input files given");
204 L=luaL_newstate();
205 if (L==NULL) fatal("cannot create state: not enough memory");
206 lua_pushcfunction(L,&pmain);
207 lua_pushinteger(L,argc);
208 lua_pushlightuserdata(L,argv);
209 if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1));
210 lua_close(L);
211 return EXIT_SUCCESS;
212 }
213
214 /*
215 ** print bytecodes
216 */
217
218 #define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
219 #define VOID(p) ((const void*)(p))
220 #define eventname(i) (getstr(tmname[i]))
221
PrintString(const TString * ts)222 static void PrintString(const TString* ts)
223 {
224 const char* s=getstr(ts);
225 size_t i,n=tsslen(ts);
226 printf("\"");
227 for (i=0; i<n; i++)
228 {
229 int c=(int)(unsigned char)s[i];
230 switch (c)
231 {
232 case '"':
233 printf("\\\"");
234 break;
235 case '\\':
236 printf("\\\\");
237 break;
238 case '\a':
239 printf("\\a");
240 break;
241 case '\b':
242 printf("\\b");
243 break;
244 case '\f':
245 printf("\\f");
246 break;
247 case '\n':
248 printf("\\n");
249 break;
250 case '\r':
251 printf("\\r");
252 break;
253 case '\t':
254 printf("\\t");
255 break;
256 case '\v':
257 printf("\\v");
258 break;
259 default:
260 if (isprint(c)) printf("%c",c); else printf("\\%03d",c);
261 break;
262 }
263 }
264 printf("\"");
265 }
266
PrintType(const Proto * f,int i)267 static void PrintType(const Proto* f, int i)
268 {
269 const TValue* o=&f->k[i];
270 switch (ttypetag(o))
271 {
272 case LUA_VNIL:
273 printf("N");
274 break;
275 case LUA_VFALSE:
276 case LUA_VTRUE:
277 printf("B");
278 break;
279 case LUA_VNUMFLT:
280 printf("F");
281 break;
282 case LUA_VNUMINT:
283 printf("I");
284 break;
285 case LUA_VSHRSTR:
286 case LUA_VLNGSTR:
287 printf("S");
288 break;
289 default: /* cannot happen */
290 printf("?%d",ttypetag(o));
291 break;
292 }
293 printf("\t");
294 }
295
PrintConstant(const Proto * f,int i)296 static void PrintConstant(const Proto* f, int i)
297 {
298 const TValue* o=&f->k[i];
299 switch (ttypetag(o))
300 {
301 case LUA_VNIL:
302 printf("nil");
303 break;
304 case LUA_VFALSE:
305 printf("false");
306 break;
307 case LUA_VTRUE:
308 printf("true");
309 break;
310 case LUA_VNUMFLT:
311 {
312 char buff[100];
313 #ifndef __NetBSD__
314 sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
315 #else /* __NetBSD__ */
316 l_sprintf(buff, sizeof(buff), LUA_NUMBER_FMT,fltvalue(o));
317 #endif /* __NetBSD__ */
318 printf("%s",buff);
319 if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
320 break;
321 }
322 case LUA_VNUMINT:
323 printf(LUA_INTEGER_FMT,ivalue(o));
324 break;
325 case LUA_VSHRSTR:
326 case LUA_VLNGSTR:
327 PrintString(tsvalue(o));
328 break;
329 default: /* cannot happen */
330 printf("?%d",ttypetag(o));
331 break;
332 }
333 }
334
335 #define COMMENT "\t; "
336 #define EXTRAARG GETARG_Ax(code[pc+1])
337 #define EXTRAARGC (EXTRAARG*(MAXARG_C+1))
338 #define ISK (isk ? "k" : "")
339
PrintCode(const Proto * f)340 static void PrintCode(const Proto* f)
341 {
342 const Instruction* code=f->code;
343 int pc,n=f->sizecode;
344 for (pc=0; pc<n; pc++)
345 {
346 Instruction i=code[pc];
347 OpCode o=GET_OPCODE(i);
348 int a=GETARG_A(i);
349 int b=GETARG_B(i);
350 int c=GETARG_C(i);
351 int ax=GETARG_Ax(i);
352 int bx=GETARG_Bx(i);
353 int sb=GETARG_sB(i);
354 int sc=GETARG_sC(i);
355 int sbx=GETARG_sBx(i);
356 int isk=GETARG_k(i);
357 int line=luaG_getfuncline(f,pc);
358 printf("\t%d\t",pc+1);
359 if (line>0) printf("[%d]\t",line); else printf("[-]\t");
360 printf("%-9s\t",opnames[o]);
361 switch (o)
362 {
363 case OP_MOVE:
364 printf("%d %d",a,b);
365 break;
366 case OP_LOADI:
367 printf("%d %d",a,sbx);
368 break;
369 case OP_LOADF:
370 printf("%d %d",a,sbx);
371 break;
372 case OP_LOADK:
373 printf("%d %d",a,bx);
374 printf(COMMENT); PrintConstant(f,bx);
375 break;
376 case OP_LOADKX:
377 printf("%d",a);
378 printf(COMMENT); PrintConstant(f,EXTRAARG);
379 break;
380 case OP_LOADFALSE:
381 printf("%d",a);
382 break;
383 case OP_LFALSESKIP:
384 printf("%d",a);
385 break;
386 case OP_LOADTRUE:
387 printf("%d",a);
388 break;
389 case OP_LOADNIL:
390 printf("%d %d",a,b);
391 printf(COMMENT "%d out",b+1);
392 break;
393 case OP_GETUPVAL:
394 printf("%d %d",a,b);
395 printf(COMMENT "%s",UPVALNAME(b));
396 break;
397 case OP_SETUPVAL:
398 printf("%d %d",a,b);
399 printf(COMMENT "%s",UPVALNAME(b));
400 break;
401 case OP_GETTABUP:
402 printf("%d %d %d",a,b,c);
403 printf(COMMENT "%s",UPVALNAME(b));
404 printf(" "); PrintConstant(f,c);
405 break;
406 case OP_GETTABLE:
407 printf("%d %d %d",a,b,c);
408 break;
409 case OP_GETI:
410 printf("%d %d %d",a,b,c);
411 break;
412 case OP_GETFIELD:
413 printf("%d %d %d",a,b,c);
414 printf(COMMENT); PrintConstant(f,c);
415 break;
416 case OP_SETTABUP:
417 printf("%d %d %d%s",a,b,c,ISK);
418 printf(COMMENT "%s",UPVALNAME(a));
419 printf(" "); PrintConstant(f,b);
420 if (isk) { printf(" "); PrintConstant(f,c); }
421 break;
422 case OP_SETTABLE:
423 printf("%d %d %d%s",a,b,c,ISK);
424 if (isk) { printf(COMMENT); PrintConstant(f,c); }
425 break;
426 case OP_SETI:
427 printf("%d %d %d%s",a,b,c,ISK);
428 if (isk) { printf(COMMENT); PrintConstant(f,c); }
429 break;
430 case OP_SETFIELD:
431 printf("%d %d %d%s",a,b,c,ISK);
432 printf(COMMENT); PrintConstant(f,b);
433 if (isk) { printf(" "); PrintConstant(f,c); }
434 break;
435 case OP_NEWTABLE:
436 printf("%d %d %d",a,b,c);
437 printf(COMMENT "%d",c+EXTRAARGC);
438 break;
439 case OP_SELF:
440 printf("%d %d %d%s",a,b,c,ISK);
441 if (isk) { printf(COMMENT); PrintConstant(f,c); }
442 break;
443 case OP_ADDI:
444 printf("%d %d %d",a,b,sc);
445 break;
446 case OP_ADDK:
447 printf("%d %d %d",a,b,c);
448 printf(COMMENT); PrintConstant(f,c);
449 break;
450 case OP_SUBK:
451 printf("%d %d %d",a,b,c);
452 printf(COMMENT); PrintConstant(f,c);
453 break;
454 case OP_MULK:
455 printf("%d %d %d",a,b,c);
456 printf(COMMENT); PrintConstant(f,c);
457 break;
458 case OP_MODK:
459 printf("%d %d %d",a,b,c);
460 printf(COMMENT); PrintConstant(f,c);
461 break;
462 case OP_POWK:
463 printf("%d %d %d",a,b,c);
464 printf(COMMENT); PrintConstant(f,c);
465 break;
466 case OP_DIVK:
467 printf("%d %d %d",a,b,c);
468 printf(COMMENT); PrintConstant(f,c);
469 break;
470 case OP_IDIVK:
471 printf("%d %d %d",a,b,c);
472 printf(COMMENT); PrintConstant(f,c);
473 break;
474 case OP_BANDK:
475 printf("%d %d %d",a,b,c);
476 printf(COMMENT); PrintConstant(f,c);
477 break;
478 case OP_BORK:
479 printf("%d %d %d",a,b,c);
480 printf(COMMENT); PrintConstant(f,c);
481 break;
482 case OP_BXORK:
483 printf("%d %d %d",a,b,c);
484 printf(COMMENT); PrintConstant(f,c);
485 break;
486 case OP_SHRI:
487 printf("%d %d %d",a,b,sc);
488 break;
489 case OP_SHLI:
490 printf("%d %d %d",a,b,sc);
491 break;
492 case OP_ADD:
493 printf("%d %d %d",a,b,c);
494 break;
495 case OP_SUB:
496 printf("%d %d %d",a,b,c);
497 break;
498 case OP_MUL:
499 printf("%d %d %d",a,b,c);
500 break;
501 case OP_MOD:
502 printf("%d %d %d",a,b,c);
503 break;
504 case OP_POW:
505 printf("%d %d %d",a,b,c);
506 break;
507 case OP_DIV:
508 printf("%d %d %d",a,b,c);
509 break;
510 case OP_IDIV:
511 printf("%d %d %d",a,b,c);
512 break;
513 case OP_BAND:
514 printf("%d %d %d",a,b,c);
515 break;
516 case OP_BOR:
517 printf("%d %d %d",a,b,c);
518 break;
519 case OP_BXOR:
520 printf("%d %d %d",a,b,c);
521 break;
522 case OP_SHL:
523 printf("%d %d %d",a,b,c);
524 break;
525 case OP_SHR:
526 printf("%d %d %d",a,b,c);
527 break;
528 case OP_MMBIN:
529 printf("%d %d %d",a,b,c);
530 printf(COMMENT "%s",eventname(c));
531 break;
532 case OP_MMBINI:
533 printf("%d %d %d %d",a,sb,c,isk);
534 printf(COMMENT "%s",eventname(c));
535 if (isk) printf(" flip");
536 break;
537 case OP_MMBINK:
538 printf("%d %d %d %d",a,b,c,isk);
539 printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b);
540 if (isk) printf(" flip");
541 break;
542 case OP_UNM:
543 printf("%d %d",a,b);
544 break;
545 case OP_BNOT:
546 printf("%d %d",a,b);
547 break;
548 case OP_NOT:
549 printf("%d %d",a,b);
550 break;
551 case OP_LEN:
552 printf("%d %d",a,b);
553 break;
554 case OP_CONCAT:
555 printf("%d %d",a,b);
556 break;
557 case OP_CLOSE:
558 printf("%d",a);
559 break;
560 case OP_TBC:
561 printf("%d",a);
562 break;
563 case OP_JMP:
564 printf("%d",GETARG_sJ(i));
565 printf(COMMENT "to %d",GETARG_sJ(i)+pc+2);
566 break;
567 case OP_EQ:
568 printf("%d %d %d",a,b,isk);
569 break;
570 case OP_LT:
571 printf("%d %d %d",a,b,isk);
572 break;
573 case OP_LE:
574 printf("%d %d %d",a,b,isk);
575 break;
576 case OP_EQK:
577 printf("%d %d %d",a,b,isk);
578 printf(COMMENT); PrintConstant(f,b);
579 break;
580 case OP_EQI:
581 printf("%d %d %d",a,sb,isk);
582 break;
583 case OP_LTI:
584 printf("%d %d %d",a,sb,isk);
585 break;
586 case OP_LEI:
587 printf("%d %d %d",a,sb,isk);
588 break;
589 case OP_GTI:
590 printf("%d %d %d",a,sb,isk);
591 break;
592 case OP_GEI:
593 printf("%d %d %d",a,sb,isk);
594 break;
595 case OP_TEST:
596 printf("%d %d",a,isk);
597 break;
598 case OP_TESTSET:
599 printf("%d %d %d",a,b,isk);
600 break;
601 case OP_CALL:
602 printf("%d %d %d",a,b,c);
603 printf(COMMENT);
604 if (b==0) printf("all in "); else printf("%d in ",b-1);
605 if (c==0) printf("all out"); else printf("%d out",c-1);
606 break;
607 case OP_TAILCALL:
608 printf("%d %d %d%s",a,b,c,ISK);
609 printf(COMMENT "%d in",b-1);
610 break;
611 case OP_RETURN:
612 printf("%d %d %d%s",a,b,c,ISK);
613 printf(COMMENT);
614 if (b==0) printf("all out"); else printf("%d out",b-1);
615 break;
616 case OP_RETURN0:
617 break;
618 case OP_RETURN1:
619 printf("%d",a);
620 break;
621 case OP_FORLOOP:
622 printf("%d %d",a,bx);
623 printf(COMMENT "to %d",pc-bx+2);
624 break;
625 case OP_FORPREP:
626 printf("%d %d",a,bx);
627 printf(COMMENT "exit to %d",pc+bx+3);
628 break;
629 case OP_TFORPREP:
630 printf("%d %d",a,bx);
631 printf(COMMENT "to %d",pc+bx+2);
632 break;
633 case OP_TFORCALL:
634 printf("%d %d",a,c);
635 break;
636 case OP_TFORLOOP:
637 printf("%d %d",a,bx);
638 printf(COMMENT "to %d",pc-bx+2);
639 break;
640 case OP_SETLIST:
641 printf("%d %d %d",a,b,c);
642 if (isk) printf(COMMENT "%d",c+EXTRAARGC);
643 break;
644 case OP_CLOSURE:
645 printf("%d %d",a,bx);
646 printf(COMMENT "%p",VOID(f->p[bx]));
647 break;
648 case OP_VARARG:
649 printf("%d %d",a,c);
650 printf(COMMENT);
651 if (c==0) printf("all out"); else printf("%d out",c-1);
652 break;
653 case OP_VARARGPREP:
654 printf("%d",a);
655 break;
656 case OP_EXTRAARG:
657 printf("%d",ax);
658 break;
659 #if 0
660 default:
661 printf("%d %d %d",a,b,c);
662 printf(COMMENT "not handled");
663 break;
664 #endif
665 }
666 printf("\n");
667 }
668 }
669
670
671 #define SS(x) ((x==1)?"":"s")
672 #define S(x) (int)(x),SS(x)
673
PrintHeader(const Proto * f)674 static void PrintHeader(const Proto* f)
675 {
676 const char* s=f->source ? getstr(f->source) : "=?";
677 if (*s=='@' || *s=='=')
678 s++;
679 else if (*s==LUA_SIGNATURE[0])
680 s="(bstring)";
681 else
682 s="(string)";
683 printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
684 (f->linedefined==0)?"main":"function",s,
685 f->linedefined,f->lastlinedefined,
686 S(f->sizecode),VOID(f));
687 printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
688 (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
689 S(f->maxstacksize),S(f->sizeupvalues));
690 printf("%d local%s, %d constant%s, %d function%s\n",
691 S(f->sizelocvars),S(f->sizek),S(f->sizep));
692 }
693
PrintDebug(const Proto * f)694 static void PrintDebug(const Proto* f)
695 {
696 int i,n;
697 n=f->sizek;
698 printf("constants (%d) for %p:\n",n,VOID(f));
699 for (i=0; i<n; i++)
700 {
701 printf("\t%d\t",i);
702 PrintType(f,i);
703 PrintConstant(f,i);
704 printf("\n");
705 }
706 n=f->sizelocvars;
707 printf("locals (%d) for %p:\n",n,VOID(f));
708 for (i=0; i<n; i++)
709 {
710 printf("\t%d\t%s\t%d\t%d\n",
711 i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
712 }
713 n=f->sizeupvalues;
714 printf("upvalues (%d) for %p:\n",n,VOID(f));
715 for (i=0; i<n; i++)
716 {
717 printf("\t%d\t%s\t%d\t%d\n",
718 i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
719 }
720 }
721
PrintFunction(const Proto * f,int full)722 static void PrintFunction(const Proto* f, int full)
723 {
724 int i,n=f->sizep;
725 PrintHeader(f);
726 PrintCode(f);
727 if (full) PrintDebug(f);
728 for (i=0; i<n; i++) PrintFunction(f->p[i],full);
729 }
730