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