1 /*
2 ** $Id: luac.c,v 1.69 2011/11/29 17:46:33 lhf Exp $
3 ** Lua compiler (saves bytecodes to files; also list bytecodes)
4 ** See Copyright Notice in lua.h
5 */
6 
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #define luac_c
13 #define LUA_CORE
14 
15 #include "lua.h"
16 #include "lauxlib.h"
17 
18 #include "lobject.h"
19 #include "lstate.h"
20 #include "lundump.h"
21 
22 static void PrintFunction(const Proto* f, int full);
23 #define luaU_print PrintFunction
24 
25 #define PROGNAME "luac"        /* default program name */
26 #define OUTPUT PROGNAME ".out" /* default output file */
27 
28 static int listing = 0;                 /* list bytecodes? */
29 static int dumping = 1;                 /* dump bytecodes? */
30 static int stripping = 0;               /* strip debug information? */
31 static char Output[] = {OUTPUT};        /* default output file name */
32 static const char* output = Output;     /* actual output file name */
33 static const char* progname = PROGNAME; /* actual program name */
34 
fatal(const char * message)35 static void fatal(const char* message)
36 {
37 	fprintf(stderr, "%s: %s\n", progname, message);
38 	exit(EXIT_FAILURE);
39 }
40 
cannot(const char * what)41 static void cannot(const char* what)
42 {
43 	fprintf(stderr, "%s: cannot %s %s: %s\n", progname, what, output, strerror(errno));
44 	exit(EXIT_FAILURE);
45 }
46 
usage(const char * message)47 static void usage(const char* message)
48 {
49 	if (*message == '-')
50 		fprintf(stderr, "%s: unrecognized option " LUA_QS "\n", progname, message);
51 	else
52 		fprintf(stderr, "%s: %s\n", progname, message);
53 	fprintf(stderr,
54 			"usage: %s [options] [filenames]\n"
55 			"Available options are:\n"
56 			"  -l       list (use -l -l for full listing)\n"
57 			"  -o name  output to file " LUA_QL("name")
58 				" (default is \"%s\")\n"
59 				"  -p       parse only\n"
60 				"  -s       strip debug information\n"
61 				"  -v       show version information\n"
62 				"  --       stop handling options\n"
63 				"  -        stop handling options and process stdin\n",
64 			progname, Output);
65 	exit(EXIT_FAILURE);
66 }
67 
68 #define IS(s) (strcmp(argv[i], s) == 0)
69 
doargs(int argc,char * argv[])70 static int doargs(int argc, char* argv[])
71 {
72 	int i;
73 	int version = 0;
74 	if (argv[0] != NULL && *argv[0] != 0) progname = argv[0];
75 	for (i = 1; i < argc; i++)
76 	{
77 		if (*argv[i] != '-') /* end of options; keep it */
78 			break;
79 		else if (IS("--")) /* end of options; skip it */
80 		{
81 			++i;
82 			if (version) ++version;
83 			break;
84 		}
85 		else if (IS("-")) /* end of options; use stdin */
86 			break;
87 		else if (IS("-l")) /* list */
88 			++listing;
89 		else if (IS("-o")) /* output file */
90 		{
91 			output = argv[++i];
92 			if (output == NULL || *output == 0 || (*output == '-' && output[1] != 0))
93 				usage(LUA_QL("-o") " needs argument");
94 			if (IS("-")) output = NULL;
95 		}
96 		else if (IS("-p")) /* parse only */
97 			dumping = 0;
98 		else if (IS("-s")) /* strip debug information */
99 			stripping = 1;
100 		else if (IS("-v")) /* show version */
101 			++version;
102 		else /* unknown option */
103 			usage(argv[i]);
104 	}
105 	if (i == argc && (listing || !dumping))
106 	{
107 		dumping = 0;
108 		argv[--i] = Output;
109 	}
110 	if (version)
111 	{
112 		printf("%s\n", LUA_COPYRIGHT);
113 		if (version == argc - 1) exit(EXIT_SUCCESS);
114 	}
115 	return i;
116 }
117 
118 #define FUNCTION "(function()end)();"
119 
reader(lua_State * L,void * ud,size_t * size)120 static const char* reader(lua_State* L, void* ud, size_t* size)
121 {
122 	UNUSED(L);
123 	if ((*(int*)ud)--)
124 	{
125 		*size = sizeof(FUNCTION) - 1;
126 		return FUNCTION;
127 	}
128 	else
129 	{
130 		*size = 0;
131 		return NULL;
132 	}
133 }
134 
135 #define toproto(L, i) getproto(L->top + (i))
136 
combine(lua_State * L,int n)137 static const Proto* combine(lua_State* L, int n)
138 {
139 	if (n == 1)
140 		return toproto(L, -1);
141 	else
142 	{
143 		Proto* f;
144 		int i = n;
145 		if (lua_load(L, reader, &i, "=(" PROGNAME ")", NULL) != LUA_OK) fatal(lua_tostring(L, -1));
146 		f = toproto(L, -1);
147 		for (i = 0; i < n; i++)
148 		{
149 			f->p[i] = toproto(L, i - n - 1);
150 			if (f->p[i]->sizeupvalues > 0) f->p[i]->upvalues[0].instack = 0;
151 		}
152 		f->sizelineinfo = 0;
153 		return f;
154 	}
155 }
156 
writer(lua_State * L,const void * p,size_t size,void * u)157 static int writer(lua_State* L, const void* p, size_t size, void* u)
158 {
159 	UNUSED(L);
160 	return (fwrite(p, size, 1, (FILE*)u) != 1) && (size != 0);
161 }
162 
pmain(lua_State * L)163 static int pmain(lua_State* L)
164 {
165 	int argc = (int)lua_tointeger(L, 1);
166 	char** argv = (char**)lua_touserdata(L, 2);
167 	const Proto* f;
168 	int i;
169 	if (!lua_checkstack(L, argc)) fatal("too many input files");
170 	for (i = 0; i < argc; i++)
171 	{
172 		const char* filename = IS("-") ? NULL : argv[i];
173 		if (luaL_loadfile(L, filename) != LUA_OK) fatal(lua_tostring(L, -1));
174 	}
175 	f = combine(L, argc);
176 	if (listing) luaU_print(f, listing > 1);
177 	if (dumping)
178 	{
179 		FILE* D = (output == NULL) ? stdout : fopen(output, "wb");
180 		if (D == NULL) cannot("open");
181 		lua_lock(L);
182 		luaU_dump(L, f, writer, D, stripping);
183 		lua_unlock(L);
184 		if (ferror(D)) cannot("write");
185 		if (fclose(D)) cannot("close");
186 	}
187 	return 0;
188 }
189 
main(int argc,char * argv[])190 int main(int argc, char* argv[])
191 {
192 	lua_State* L;
193 	int i = doargs(argc, argv);
194 	argc -= i;
195 	argv += i;
196 	if (argc <= 0) usage("no input files given");
197 	L = luaL_newstate();
198 	if (L == NULL) fatal("cannot create state: not enough memory");
199 	lua_pushcfunction(L, &pmain);
200 	lua_pushinteger(L, argc);
201 	lua_pushlightuserdata(L, argv);
202 	if (lua_pcall(L, 2, 0, 0) != LUA_OK) fatal(lua_tostring(L, -1));
203 	lua_close(L);
204 	return EXIT_SUCCESS;
205 }
206 
207 /*
208 ** $Id: print.c,v 1.69 2013/07/04 01:03:46 lhf Exp $
209 ** print bytecodes
210 ** See Copyright Notice in lua.h
211 */
212 
213 #include <ctype.h>
214 #include <stdio.h>
215 
216 #define luac_c
217 #define LUA_CORE
218 
219 #include "ldebug.h"
220 #include "lobject.h"
221 #include "lopcodes.h"
222 
223 #define VOID(p) ((const void*)(p))
224 
PrintString(const TString * ts)225 static void PrintString(const TString* ts)
226 {
227 	const char* s = getstr(ts);
228 	size_t i, n = ts->tsv.len;
229 	printf("%c", '"');
230 	for (i = 0; i < n; i++)
231 	{
232 		int c = (int)(unsigned char)s[i];
233 		switch (c)
234 		{
235 			case '"':
236 				printf("\\\"");
237 				break;
238 			case '\\':
239 				printf("\\\\");
240 				break;
241 			case '\a':
242 				printf("\\a");
243 				break;
244 			case '\b':
245 				printf("\\b");
246 				break;
247 			case '\f':
248 				printf("\\f");
249 				break;
250 			case '\n':
251 				printf("\\n");
252 				break;
253 			case '\r':
254 				printf("\\r");
255 				break;
256 			case '\t':
257 				printf("\\t");
258 				break;
259 			case '\v':
260 				printf("\\v");
261 				break;
262 			default:
263 				if (isprint(c))
264 					printf("%c", c);
265 				else
266 					printf("\\%03d", c);
267 		}
268 	}
269 	printf("%c", '"');
270 }
271 
PrintConstant(const Proto * f,int i)272 static void PrintConstant(const Proto* f, int i)
273 {
274 	const TValue* o = &f->k[i];
275 	switch (ttypenv(o))
276 	{
277 		case LUA_TNIL:
278 			printf("nil");
279 			break;
280 		case LUA_TBOOLEAN:
281 			printf(bvalue(o) ? "true" : "false");
282 			break;
283 		case LUA_TNUMBER:
284 			printf(LUA_NUMBER_FMT, nvalue(o));
285 			break;
286 		case LUA_TSTRING:
287 			PrintString(rawtsvalue(o));
288 			break;
289 		default: /* cannot happen */
290 			printf("? type=%d", ttype(o));
291 			break;
292 	}
293 }
294 
295 #define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
296 #define MYK(x) (-1 - (x))
297 
PrintCode(const Proto * f)298 static void PrintCode(const Proto* f)
299 {
300 	const Instruction* code = f->code;
301 	int pc, n = f->sizecode;
302 	for (pc = 0; pc < n; pc++)
303 	{
304 		Instruction i = code[pc];
305 		OpCode o = GET_OPCODE(i);
306 		int a = GETARG_A(i);
307 		int b = GETARG_B(i);
308 		int c = GETARG_C(i);
309 		int ax = GETARG_Ax(i);
310 		int bx = GETARG_Bx(i);
311 		int sbx = GETARG_sBx(i);
312 		int line = getfuncline(f, pc);
313 		printf("\t%d\t", pc + 1);
314 		if (line > 0)
315 			printf("[%d]\t", line);
316 		else
317 			printf("[-]\t");
318 		printf("%-9s\t", luaP_opnames[o]);
319 		switch (getOpMode(o))
320 		{
321 			case iABC:
322 				printf("%d", a);
323 				if (getBMode(o) != OpArgN) printf(" %d", ISK(b) ? (MYK(INDEXK(b))) : b);
324 				if (getCMode(o) != OpArgN) printf(" %d", ISK(c) ? (MYK(INDEXK(c))) : c);
325 				break;
326 			case iABx:
327 				printf("%d", a);
328 				if (getBMode(o) == OpArgK) printf(" %d", MYK(bx));
329 				if (getBMode(o) == OpArgU) printf(" %d", bx);
330 				break;
331 			case iAsBx:
332 				printf("%d %d", a, sbx);
333 				break;
334 			case iAx:
335 				printf("%d", MYK(ax));
336 				break;
337 		}
338 		switch (o)
339 		{
340 			case OP_LOADK:
341 				printf("\t; ");
342 				PrintConstant(f, bx);
343 				break;
344 			case OP_GETUPVAL:
345 			case OP_SETUPVAL:
346 				printf("\t; %s", UPVALNAME(b));
347 				break;
348 			case OP_GETTABUP:
349 				printf("\t; %s", UPVALNAME(b));
350 				if (ISK(c))
351 				{
352 					printf(" ");
353 					PrintConstant(f, INDEXK(c));
354 				}
355 				break;
356 			case OP_SETTABUP:
357 				printf("\t; %s", UPVALNAME(a));
358 				if (ISK(b))
359 				{
360 					printf(" ");
361 					PrintConstant(f, INDEXK(b));
362 				}
363 				if (ISK(c))
364 				{
365 					printf(" ");
366 					PrintConstant(f, INDEXK(c));
367 				}
368 				break;
369 			case OP_GETTABLE:
370 			case OP_SELF:
371 				if (ISK(c))
372 				{
373 					printf("\t; ");
374 					PrintConstant(f, INDEXK(c));
375 				}
376 				break;
377 			case OP_SETTABLE:
378 			case OP_ADD:
379 			case OP_SUB:
380 			case OP_MUL:
381 			case OP_DIV:
382 			case OP_POW:
383 			case OP_EQ:
384 			case OP_LT:
385 			case OP_LE:
386 				if (ISK(b) || ISK(c))
387 				{
388 					printf("\t; ");
389 					if (ISK(b))
390 						PrintConstant(f, INDEXK(b));
391 					else
392 						printf("-");
393 					printf(" ");
394 					if (ISK(c))
395 						PrintConstant(f, INDEXK(c));
396 					else
397 						printf("-");
398 				}
399 				break;
400 			case OP_JMP:
401 			case OP_FORLOOP:
402 			case OP_FORPREP:
403 			case OP_TFORLOOP:
404 				printf("\t; to %d", sbx + pc + 2);
405 				break;
406 			case OP_CLOSURE:
407 				printf("\t; %p", VOID(f->p[bx]));
408 				break;
409 			case OP_SETLIST:
410 				if (c == 0)
411 					printf("\t; %d", (int)code[++pc]);
412 				else
413 					printf("\t; %d", c);
414 				break;
415 			case OP_EXTRAARG:
416 				printf("\t; ");
417 				PrintConstant(f, ax);
418 				break;
419 			default:
420 				break;
421 		}
422 		printf("\n");
423 	}
424 }
425 
426 #define SS(x) ((x == 1) ? "" : "s")
427 #define S(x) (int)(x), SS(x)
428 
PrintHeader(const Proto * f)429 static void PrintHeader(const Proto* f)
430 {
431 	const char* s = f->source ? getstr(f->source) : "=?";
432 	if (*s == '@' || *s == '=')
433 		s++;
434 	else if (*s == LUA_SIGNATURE[0])
435 		s = "(bstring)";
436 	else
437 		s = "(string)";
438 	printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
439 		   (f->linedefined == 0) ? "main" : "function", s,
440 		   f->linedefined, f->lastlinedefined,
441 		   S(f->sizecode), VOID(f));
442 	printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
443 		   (int)(f->numparams), f->is_vararg ? "+" : "", SS(f->numparams),
444 		   S(f->maxstacksize), S(f->sizeupvalues));
445 	printf("%d local%s, %d constant%s, %d function%s\n",
446 		   S(f->sizelocvars), S(f->sizek), S(f->sizep));
447 }
448 
PrintDebug(const Proto * f)449 static void PrintDebug(const Proto* f)
450 {
451 	int i, n;
452 	n = f->sizek;
453 	printf("constants (%d) for %p:\n", n, VOID(f));
454 	for (i = 0; i < n; i++)
455 	{
456 		printf("\t%d\t", i + 1);
457 		PrintConstant(f, i);
458 		printf("\n");
459 	}
460 	n = f->sizelocvars;
461 	printf("locals (%d) for %p:\n", n, VOID(f));
462 	for (i = 0; i < n; i++)
463 	{
464 		printf("\t%d\t%s\t%d\t%d\n",
465 			   i, getstr(f->locvars[i].varname), f->locvars[i].startpc + 1, f->locvars[i].endpc + 1);
466 	}
467 	n = f->sizeupvalues;
468 	printf("upvalues (%d) for %p:\n", n, VOID(f));
469 	for (i = 0; i < n; i++)
470 	{
471 		printf("\t%d\t%s\t%d\t%d\n",
472 			   i, UPVALNAME(i), f->upvalues[i].instack, f->upvalues[i].idx);
473 	}
474 }
475 
PrintFunction(const Proto * f,int full)476 static void PrintFunction(const Proto* f, int full)
477 {
478 	int i, n = f->sizep;
479 	PrintHeader(f);
480 	PrintCode(f);
481 	if (full) PrintDebug(f);
482 	for (i = 0; i < n; i++) PrintFunction(f->p[i], full);
483 }
484