xref: /freebsd/contrib/lua/src/lundump.c (revision a9490b81b032b43cdb3c8c76b4d01bbad9ff82c1)
18e3e3a7aSWarner Losh /*
20495ed39SKyle Evans ** $Id: lundump.c $
38e3e3a7aSWarner Losh ** load precompiled Lua chunks
48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h
58e3e3a7aSWarner Losh */
68e3e3a7aSWarner Losh 
78e3e3a7aSWarner Losh #define lundump_c
88e3e3a7aSWarner Losh #define LUA_CORE
98e3e3a7aSWarner Losh 
108e3e3a7aSWarner Losh #include "lprefix.h"
118e3e3a7aSWarner Losh 
128e3e3a7aSWarner Losh 
130495ed39SKyle Evans #include <limits.h>
148e3e3a7aSWarner Losh #include <string.h>
158e3e3a7aSWarner Losh 
168e3e3a7aSWarner Losh #include "lua.h"
178e3e3a7aSWarner Losh 
188e3e3a7aSWarner Losh #include "ldebug.h"
198e3e3a7aSWarner Losh #include "ldo.h"
208e3e3a7aSWarner Losh #include "lfunc.h"
218e3e3a7aSWarner Losh #include "lmem.h"
228e3e3a7aSWarner Losh #include "lobject.h"
238e3e3a7aSWarner Losh #include "lstring.h"
248e3e3a7aSWarner Losh #include "lundump.h"
258e3e3a7aSWarner Losh #include "lzio.h"
268e3e3a7aSWarner Losh 
278e3e3a7aSWarner Losh 
288e3e3a7aSWarner Losh #if !defined(luai_verifycode)
290495ed39SKyle Evans #define luai_verifycode(L,f)  /* empty */
308e3e3a7aSWarner Losh #endif
318e3e3a7aSWarner Losh 
328e3e3a7aSWarner Losh 
338e3e3a7aSWarner Losh typedef struct {
348e3e3a7aSWarner Losh   lua_State *L;
358e3e3a7aSWarner Losh   ZIO *Z;
368e3e3a7aSWarner Losh   const char *name;
378e3e3a7aSWarner Losh } LoadState;
388e3e3a7aSWarner Losh 
398e3e3a7aSWarner Losh 
error(LoadState * S,const char * why)408e3e3a7aSWarner Losh static l_noret error (LoadState *S, const char *why) {
410495ed39SKyle Evans   luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
428e3e3a7aSWarner Losh   luaD_throw(S->L, LUA_ERRSYNTAX);
438e3e3a7aSWarner Losh }
448e3e3a7aSWarner Losh 
458e3e3a7aSWarner Losh 
468e3e3a7aSWarner Losh /*
470495ed39SKyle Evans ** All high-level loads go through loadVector; you can change it to
488e3e3a7aSWarner Losh ** adapt to the endianness of the input
498e3e3a7aSWarner Losh */
500495ed39SKyle Evans #define loadVector(S,b,n)	loadBlock(S,b,(n)*sizeof((b)[0]))
518e3e3a7aSWarner Losh 
loadBlock(LoadState * S,void * b,size_t size)520495ed39SKyle Evans static void loadBlock (LoadState *S, void *b, size_t size) {
538e3e3a7aSWarner Losh   if (luaZ_read(S->Z, b, size) != 0)
540495ed39SKyle Evans     error(S, "truncated chunk");
558e3e3a7aSWarner Losh }
568e3e3a7aSWarner Losh 
578e3e3a7aSWarner Losh 
580495ed39SKyle Evans #define loadVar(S,x)		loadVector(S,&x,1)
598e3e3a7aSWarner Losh 
608e3e3a7aSWarner Losh 
loadByte(LoadState * S)610495ed39SKyle Evans static lu_byte loadByte (LoadState *S) {
620495ed39SKyle Evans   int b = zgetc(S->Z);
630495ed39SKyle Evans   if (b == EOZ)
640495ed39SKyle Evans     error(S, "truncated chunk");
650495ed39SKyle Evans   return cast_byte(b);
660495ed39SKyle Evans }
670495ed39SKyle Evans 
680495ed39SKyle Evans 
loadUnsigned(LoadState * S,size_t limit)690495ed39SKyle Evans static size_t loadUnsigned (LoadState *S, size_t limit) {
700495ed39SKyle Evans   size_t x = 0;
710495ed39SKyle Evans   int b;
720495ed39SKyle Evans   limit >>= 7;
730495ed39SKyle Evans   do {
740495ed39SKyle Evans     b = loadByte(S);
750495ed39SKyle Evans     if (x >= limit)
760495ed39SKyle Evans       error(S, "integer overflow");
770495ed39SKyle Evans     x = (x << 7) | (b & 0x7f);
780495ed39SKyle Evans   } while ((b & 0x80) == 0);
798e3e3a7aSWarner Losh   return x;
808e3e3a7aSWarner Losh }
818e3e3a7aSWarner Losh 
828e3e3a7aSWarner Losh 
loadSize(LoadState * S)830495ed39SKyle Evans static size_t loadSize (LoadState *S) {
840495ed39SKyle Evans   return loadUnsigned(S, ~(size_t)0);
858e3e3a7aSWarner Losh }
868e3e3a7aSWarner Losh 
878e3e3a7aSWarner Losh 
loadInt(LoadState * S)880495ed39SKyle Evans static int loadInt (LoadState *S) {
890495ed39SKyle Evans   return cast_int(loadUnsigned(S, INT_MAX));
900495ed39SKyle Evans }
910495ed39SKyle Evans 
920495ed39SKyle Evans 
loadNumber(LoadState * S)930495ed39SKyle Evans static lua_Number loadNumber (LoadState *S) {
948e3e3a7aSWarner Losh   lua_Number x;
950495ed39SKyle Evans   loadVar(S, x);
968e3e3a7aSWarner Losh   return x;
978e3e3a7aSWarner Losh }
988e3e3a7aSWarner Losh 
998e3e3a7aSWarner Losh 
loadInteger(LoadState * S)1000495ed39SKyle Evans static lua_Integer loadInteger (LoadState *S) {
1018e3e3a7aSWarner Losh   lua_Integer x;
1020495ed39SKyle Evans   loadVar(S, x);
1038e3e3a7aSWarner Losh   return x;
1048e3e3a7aSWarner Losh }
1058e3e3a7aSWarner Losh 
1068e3e3a7aSWarner Losh 
1070495ed39SKyle Evans /*
1080495ed39SKyle Evans ** Load a nullable string into prototype 'p'.
1090495ed39SKyle Evans */
loadStringN(LoadState * S,Proto * p)1100495ed39SKyle Evans static TString *loadStringN (LoadState *S, Proto *p) {
111bf9580a1SKyle Evans   lua_State *L = S->L;
112bf9580a1SKyle Evans   TString *ts;
1130495ed39SKyle Evans   size_t size = loadSize(S);
1140495ed39SKyle Evans   if (size == 0)  /* no string? */
1158e3e3a7aSWarner Losh     return NULL;
1168e3e3a7aSWarner Losh   else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */
1178e3e3a7aSWarner Losh     char buff[LUAI_MAXSHORTLEN];
1180495ed39SKyle Evans     loadVector(S, buff, size);  /* load string into buffer */
1190495ed39SKyle Evans     ts = luaS_newlstr(L, buff, size);  /* create string */
1208e3e3a7aSWarner Losh   }
1218e3e3a7aSWarner Losh   else {  /* long string */
1220495ed39SKyle Evans     ts = luaS_createlngstrobj(L, size);  /* create string */
123*a9490b81SWarner Losh     setsvalue2s(L, L->top.p, ts);  /* anchor it ('loadVector' can GC) */
124bf9580a1SKyle Evans     luaD_inctop(L);
1250495ed39SKyle Evans     loadVector(S, getstr(ts), size);  /* load directly in final place */
126*a9490b81SWarner Losh     L->top.p--;  /* pop string */
1278e3e3a7aSWarner Losh   }
128bf9580a1SKyle Evans   luaC_objbarrier(L, p, ts);
129bf9580a1SKyle Evans   return ts;
1308e3e3a7aSWarner Losh }
1318e3e3a7aSWarner Losh 
1328e3e3a7aSWarner Losh 
1330495ed39SKyle Evans /*
1340495ed39SKyle Evans ** Load a non-nullable string into prototype 'p'.
1350495ed39SKyle Evans */
loadString(LoadState * S,Proto * p)1360495ed39SKyle Evans static TString *loadString (LoadState *S, Proto *p) {
1370495ed39SKyle Evans   TString *st = loadStringN(S, p);
1380495ed39SKyle Evans   if (st == NULL)
1390495ed39SKyle Evans     error(S, "bad format for constant string");
1400495ed39SKyle Evans   return st;
1418e3e3a7aSWarner Losh }
1428e3e3a7aSWarner Losh 
1438e3e3a7aSWarner Losh 
loadCode(LoadState * S,Proto * f)1440495ed39SKyle Evans static void loadCode (LoadState *S, Proto *f) {
1450495ed39SKyle Evans   int n = loadInt(S);
1460495ed39SKyle Evans   f->code = luaM_newvectorchecked(S->L, n, Instruction);
1470495ed39SKyle Evans   f->sizecode = n;
1480495ed39SKyle Evans   loadVector(S, f->code, n);
1490495ed39SKyle Evans }
1508e3e3a7aSWarner Losh 
1518e3e3a7aSWarner Losh 
1520495ed39SKyle Evans static void loadFunction(LoadState *S, Proto *f, TString *psource);
1530495ed39SKyle Evans 
1540495ed39SKyle Evans 
loadConstants(LoadState * S,Proto * f)1550495ed39SKyle Evans static void loadConstants (LoadState *S, Proto *f) {
1568e3e3a7aSWarner Losh   int i;
1570495ed39SKyle Evans   int n = loadInt(S);
1580495ed39SKyle Evans   f->k = luaM_newvectorchecked(S->L, n, TValue);
1598e3e3a7aSWarner Losh   f->sizek = n;
1608e3e3a7aSWarner Losh   for (i = 0; i < n; i++)
1618e3e3a7aSWarner Losh     setnilvalue(&f->k[i]);
1628e3e3a7aSWarner Losh   for (i = 0; i < n; i++) {
1638e3e3a7aSWarner Losh     TValue *o = &f->k[i];
1640495ed39SKyle Evans     int t = loadByte(S);
1658e3e3a7aSWarner Losh     switch (t) {
1660495ed39SKyle Evans       case LUA_VNIL:
1678e3e3a7aSWarner Losh         setnilvalue(o);
1688e3e3a7aSWarner Losh         break;
1690495ed39SKyle Evans       case LUA_VFALSE:
1700495ed39SKyle Evans         setbfvalue(o);
1718e3e3a7aSWarner Losh         break;
1720495ed39SKyle Evans       case LUA_VTRUE:
1730495ed39SKyle Evans         setbtvalue(o);
1748e3e3a7aSWarner Losh         break;
1750495ed39SKyle Evans       case LUA_VNUMFLT:
1760495ed39SKyle Evans         setfltvalue(o, loadNumber(S));
1778e3e3a7aSWarner Losh         break;
1780495ed39SKyle Evans       case LUA_VNUMINT:
1790495ed39SKyle Evans         setivalue(o, loadInteger(S));
1808e3e3a7aSWarner Losh         break;
1810495ed39SKyle Evans       case LUA_VSHRSTR:
1820495ed39SKyle Evans       case LUA_VLNGSTR:
1830495ed39SKyle Evans         setsvalue2n(S->L, o, loadString(S, f));
1840495ed39SKyle Evans         break;
1850495ed39SKyle Evans       default: lua_assert(0);
1868e3e3a7aSWarner Losh     }
1878e3e3a7aSWarner Losh   }
1888e3e3a7aSWarner Losh }
1898e3e3a7aSWarner Losh 
1908e3e3a7aSWarner Losh 
loadProtos(LoadState * S,Proto * f)1910495ed39SKyle Evans static void loadProtos (LoadState *S, Proto *f) {
1928e3e3a7aSWarner Losh   int i;
1930495ed39SKyle Evans   int n = loadInt(S);
1940495ed39SKyle Evans   f->p = luaM_newvectorchecked(S->L, n, Proto *);
1958e3e3a7aSWarner Losh   f->sizep = n;
1968e3e3a7aSWarner Losh   for (i = 0; i < n; i++)
1978e3e3a7aSWarner Losh     f->p[i] = NULL;
1988e3e3a7aSWarner Losh   for (i = 0; i < n; i++) {
1998e3e3a7aSWarner Losh     f->p[i] = luaF_newproto(S->L);
200bf9580a1SKyle Evans     luaC_objbarrier(S->L, f, f->p[i]);
2010495ed39SKyle Evans     loadFunction(S, f->p[i], f->source);
2028e3e3a7aSWarner Losh   }
2038e3e3a7aSWarner Losh }
2048e3e3a7aSWarner Losh 
2058e3e3a7aSWarner Losh 
2060495ed39SKyle Evans /*
2070495ed39SKyle Evans ** Load the upvalues for a function. The names must be filled first,
2080495ed39SKyle Evans ** because the filling of the other fields can raise read errors and
2090495ed39SKyle Evans ** the creation of the error message can call an emergency collection;
2100495ed39SKyle Evans ** in that case all prototypes must be consistent for the GC.
2110495ed39SKyle Evans */
loadUpvalues(LoadState * S,Proto * f)2120495ed39SKyle Evans static void loadUpvalues (LoadState *S, Proto *f) {
2138e3e3a7aSWarner Losh   int i, n;
2140495ed39SKyle Evans   n = loadInt(S);
2150495ed39SKyle Evans   f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
2168e3e3a7aSWarner Losh   f->sizeupvalues = n;
2170495ed39SKyle Evans   for (i = 0; i < n; i++)  /* make array valid for GC */
2188e3e3a7aSWarner Losh     f->upvalues[i].name = NULL;
2190495ed39SKyle Evans   for (i = 0; i < n; i++) {  /* following calls can raise errors */
2200495ed39SKyle Evans     f->upvalues[i].instack = loadByte(S);
2210495ed39SKyle Evans     f->upvalues[i].idx = loadByte(S);
2220495ed39SKyle Evans     f->upvalues[i].kind = loadByte(S);
2238e3e3a7aSWarner Losh   }
2248e3e3a7aSWarner Losh }
2258e3e3a7aSWarner Losh 
2268e3e3a7aSWarner Losh 
loadDebug(LoadState * S,Proto * f)2270495ed39SKyle Evans static void loadDebug (LoadState *S, Proto *f) {
2288e3e3a7aSWarner Losh   int i, n;
2290495ed39SKyle Evans   n = loadInt(S);
2300495ed39SKyle Evans   f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
2318e3e3a7aSWarner Losh   f->sizelineinfo = n;
2320495ed39SKyle Evans   loadVector(S, f->lineinfo, n);
2330495ed39SKyle Evans   n = loadInt(S);
2340495ed39SKyle Evans   f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
2350495ed39SKyle Evans   f->sizeabslineinfo = n;
2360495ed39SKyle Evans   for (i = 0; i < n; i++) {
2370495ed39SKyle Evans     f->abslineinfo[i].pc = loadInt(S);
2380495ed39SKyle Evans     f->abslineinfo[i].line = loadInt(S);
2390495ed39SKyle Evans   }
2400495ed39SKyle Evans   n = loadInt(S);
2410495ed39SKyle Evans   f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
2428e3e3a7aSWarner Losh   f->sizelocvars = n;
2438e3e3a7aSWarner Losh   for (i = 0; i < n; i++)
2448e3e3a7aSWarner Losh     f->locvars[i].varname = NULL;
2458e3e3a7aSWarner Losh   for (i = 0; i < n; i++) {
2460495ed39SKyle Evans     f->locvars[i].varname = loadStringN(S, f);
2470495ed39SKyle Evans     f->locvars[i].startpc = loadInt(S);
2480495ed39SKyle Evans     f->locvars[i].endpc = loadInt(S);
2498e3e3a7aSWarner Losh   }
2500495ed39SKyle Evans   n = loadInt(S);
251*a9490b81SWarner Losh   if (n != 0)  /* does it have debug information? */
252*a9490b81SWarner Losh     n = f->sizeupvalues;  /* must be this many */
2538e3e3a7aSWarner Losh   for (i = 0; i < n; i++)
2540495ed39SKyle Evans     f->upvalues[i].name = loadStringN(S, f);
2558e3e3a7aSWarner Losh }
2568e3e3a7aSWarner Losh 
2578e3e3a7aSWarner Losh 
loadFunction(LoadState * S,Proto * f,TString * psource)2580495ed39SKyle Evans static void loadFunction (LoadState *S, Proto *f, TString *psource) {
2590495ed39SKyle Evans   f->source = loadStringN(S, f);
2608e3e3a7aSWarner Losh   if (f->source == NULL)  /* no source in dump? */
2618e3e3a7aSWarner Losh     f->source = psource;  /* reuse parent's source */
2620495ed39SKyle Evans   f->linedefined = loadInt(S);
2630495ed39SKyle Evans   f->lastlinedefined = loadInt(S);
2640495ed39SKyle Evans   f->numparams = loadByte(S);
2650495ed39SKyle Evans   f->is_vararg = loadByte(S);
2660495ed39SKyle Evans   f->maxstacksize = loadByte(S);
2670495ed39SKyle Evans   loadCode(S, f);
2680495ed39SKyle Evans   loadConstants(S, f);
2690495ed39SKyle Evans   loadUpvalues(S, f);
2700495ed39SKyle Evans   loadProtos(S, f);
2710495ed39SKyle Evans   loadDebug(S, f);
2728e3e3a7aSWarner Losh }
2738e3e3a7aSWarner Losh 
2748e3e3a7aSWarner Losh 
checkliteral(LoadState * S,const char * s,const char * msg)2758e3e3a7aSWarner Losh static void checkliteral (LoadState *S, const char *s, const char *msg) {
2768e3e3a7aSWarner Losh   char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
2778e3e3a7aSWarner Losh   size_t len = strlen(s);
2780495ed39SKyle Evans   loadVector(S, buff, len);
2798e3e3a7aSWarner Losh   if (memcmp(s, buff, len) != 0)
2808e3e3a7aSWarner Losh     error(S, msg);
2818e3e3a7aSWarner Losh }
2828e3e3a7aSWarner Losh 
2838e3e3a7aSWarner Losh 
fchecksize(LoadState * S,size_t size,const char * tname)2848e3e3a7aSWarner Losh static void fchecksize (LoadState *S, size_t size, const char *tname) {
2850495ed39SKyle Evans   if (loadByte(S) != size)
2860495ed39SKyle Evans     error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
2878e3e3a7aSWarner Losh }
2888e3e3a7aSWarner Losh 
2898e3e3a7aSWarner Losh 
2908e3e3a7aSWarner Losh #define checksize(S,t)	fchecksize(S,sizeof(t),#t)
2918e3e3a7aSWarner Losh 
checkHeader(LoadState * S)2928e3e3a7aSWarner Losh static void checkHeader (LoadState *S) {
2930495ed39SKyle Evans   /* skip 1st char (already read and checked) */
2940495ed39SKyle Evans   checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
2950495ed39SKyle Evans   if (loadByte(S) != LUAC_VERSION)
2960495ed39SKyle Evans     error(S, "version mismatch");
2970495ed39SKyle Evans   if (loadByte(S) != LUAC_FORMAT)
2980495ed39SKyle Evans     error(S, "format mismatch");
2990495ed39SKyle Evans   checkliteral(S, LUAC_DATA, "corrupted chunk");
3008e3e3a7aSWarner Losh   checksize(S, Instruction);
3018e3e3a7aSWarner Losh   checksize(S, lua_Integer);
3028e3e3a7aSWarner Losh   checksize(S, lua_Number);
3030495ed39SKyle Evans   if (loadInteger(S) != LUAC_INT)
3040495ed39SKyle Evans     error(S, "integer format mismatch");
3050495ed39SKyle Evans   if (loadNumber(S) != LUAC_NUM)
3060495ed39SKyle Evans     error(S, "float format mismatch");
3078e3e3a7aSWarner Losh }
3088e3e3a7aSWarner Losh 
3098e3e3a7aSWarner Losh 
3108e3e3a7aSWarner Losh /*
3110495ed39SKyle Evans ** Load precompiled chunk.
3128e3e3a7aSWarner Losh */
luaU_undump(lua_State * L,ZIO * Z,const char * name)3138e3e3a7aSWarner Losh LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
3148e3e3a7aSWarner Losh   LoadState S;
3158e3e3a7aSWarner Losh   LClosure *cl;
3168e3e3a7aSWarner Losh   if (*name == '@' || *name == '=')
3178e3e3a7aSWarner Losh     S.name = name + 1;
3188e3e3a7aSWarner Losh   else if (*name == LUA_SIGNATURE[0])
3198e3e3a7aSWarner Losh     S.name = "binary string";
3208e3e3a7aSWarner Losh   else
3218e3e3a7aSWarner Losh     S.name = name;
3228e3e3a7aSWarner Losh   S.L = L;
3238e3e3a7aSWarner Losh   S.Z = Z;
3248e3e3a7aSWarner Losh   checkHeader(&S);
3250495ed39SKyle Evans   cl = luaF_newLclosure(L, loadByte(&S));
326*a9490b81SWarner Losh   setclLvalue2s(L, L->top.p, cl);
3278e3e3a7aSWarner Losh   luaD_inctop(L);
3288e3e3a7aSWarner Losh   cl->p = luaF_newproto(L);
329bf9580a1SKyle Evans   luaC_objbarrier(L, cl, cl->p);
3300495ed39SKyle Evans   loadFunction(&S, cl->p, NULL);
3318e3e3a7aSWarner Losh   lua_assert(cl->nupvalues == cl->p->sizeupvalues);
3320495ed39SKyle Evans   luai_verifycode(L, cl->p);
3338e3e3a7aSWarner Losh   return cl;
3348e3e3a7aSWarner Losh }
3358e3e3a7aSWarner Losh 
336