/* ** undump.c ** load bytecodes from files */ char* rcs_undump="$Id: undump.c,v 1.24 1997/06/17 18:19:17 roberto Exp roberto $"; #include #include #include "auxlib.h" #include "opcode.h" #include "luamem.h" #include "table.h" #include "undump.h" #include "zio.h" static int swapword=0; static int swapfloat=0; static TFunc* Main=NULL; /* functions in a chunk */ static TFunc* lastF=NULL; static void FixCode(Byte* code, Byte* end) /* swap words */ { Byte* p; for (p=code; p!=end;) { int op=*p; switch (op) { case PUSHNIL: case PUSH0: case PUSH1: case PUSH2: case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: case PUSHLOCAL8: case PUSHLOCAL9: case PUSHINDEXED: case STORELOCAL0: case STORELOCAL1: case STORELOCAL2: case STORELOCAL3: case STORELOCAL4: case STORELOCAL5: case STORELOCAL6: case STORELOCAL7: case STORELOCAL8: case STORELOCAL9: case STOREINDEXED0: case ADJUST0: case EQOP: case LTOP: case LEOP: case GTOP: case GEOP: case ADDOP: case SUBOP: case MULTOP: case DIVOP: case POWOP: case CONCOP: case MINUSOP: case NOTOP: case POP: case RETCODE0: p++; break; case PUSHBYTE: case PUSHLOCAL: case STORELOCAL: case STOREINDEXED: case STORELIST0: case ADJUST: case RETCODE: case VARARGS: case STOREMAP: p+=2; break; case STORELIST: case CALLFUNC: p+=3; break; case PUSHFUNCTION: p+=5; /* TODO: use sizeof(TFunc*) or old? */ break; case PUSHWORD: case PUSHSELF: case CREATEARRAY: case ONTJMP: case ONFJMP: case JMP: case UPJMP: case IFFJMP: case IFFUPJMP: case SETLINE: case PUSHSTRING: case PUSHGLOBAL: case STOREGLOBAL: { Byte t; t=p[1]; p[1]=p[2]; p[2]=t; p+=3; break; } case PUSHFLOAT: /* assumes sizeof(float)==4 */ { Byte t; t=p[1]; p[1]=p[4]; p[4]=t; t=p[2]; p[2]=p[3]; p[3]=t; p+=5; break; } case STORERECORD: { int n=*++p; p++; while (n--) { Byte t; t=p[0]; p[0]=p[1]; p[1]=t; p+=2; } break; } default: luaL_verror("corrupt binary file: bad opcode %d at %d\n", op,(int)(p-code)); break; } } } static void Unthread(Byte* code, int i, int v) { while (i!=0) { Word w; Byte* p=code+i; memcpy(&w,p,sizeof(w)); i=w; w=v; memcpy(p,&w,sizeof(w)); } } static int LoadWord(ZIO* Z) { Word w; zread(Z,&w,sizeof(w)); if (swapword) { Byte* p=(Byte*)&w; Byte t; t=p[0]; p[0]=p[1]; p[1]=t; } return w; } static int LoadSize(ZIO* Z) { Word hi=LoadWord(Z); Word lo=LoadWord(Z); int s=(hi<<16)|lo; if ((Word)s != s) lua_error("code too long"); return s; } static void* LoadBlock(int size, ZIO* Z) { void* b=luaI_malloc(size); zread(Z,b,size); return b; } static char* LoadString(ZIO* Z) { int size=LoadWord(Z); char *b=luaI_buffer(size); zread(Z,b,size); return b; } static char* LoadNewString(ZIO* Z) { return LoadBlock(LoadWord(Z),Z); } static void LoadFunction(ZIO* Z) { int size; TFunc* tf=new(TFunc); tf->next=NULL; tf->locvars=NULL; size=LoadSize(Z); tf->lineDefined=LoadWord(Z); if (IsMain(tf)) /* new main */ { tf->fileName=LoadNewString(Z); Main=lastF=tf; } else /* fix PUSHFUNCTION */ { tf->marked=LoadWord(Z); tf->fileName=Main->fileName; memcpy(Main->code+tf->marked,&tf,sizeof(tf)); lastF=lastF->next=tf; } tf->code=LoadBlock(size,Z); if (swapword || swapfloat) FixCode(tf->code,tf->code+size); while (1) /* unthread */ { int c=zgetc(Z); if (c==ID_VAR) /* global var */ { int i=LoadWord(Z); char* s=LoadString(Z); int v=luaI_findsymbolbyname(s); Unthread(tf->code,i,v); } else if (c==ID_STR) /* constant string */ { int i=LoadWord(Z); char* s=LoadString(Z); int v=luaI_findconstantbyname(s); Unthread(tf->code,i,v); } else { zungetc(Z); break; } } } static void LoadSignature(ZIO* Z) { char* s=SIGNATURE; while (*s!=0 && zgetc(Z)==*s) ++s; if (*s!=0) lua_error("cannot load binary file: bad signature"); } static void LoadHeader(ZIO* Z) { Word w,tw=TEST_WORD; float f,tf=TEST_FLOAT; int version; LoadSignature(Z); version=zgetc(Z); if (version>0x23) /* after 2.5 */ { int oldsizeofW=zgetc(Z); int oldsizeofF=zgetc(Z); int oldsizeofP=zgetc(Z); if (oldsizeofW!=2) luaL_verror( "cannot load binary file created on machine with sizeof(Word)=%d; " "expected 2",oldsizeofW); if (oldsizeofF!=4) luaL_verror( "cannot load binary file created on machine with sizeof(float)=%d; " "expected 4\nnot an IEEE machine?",oldsizeofF); if (oldsizeofP!=sizeof(TFunc*)) /* TODO: pack? */ luaL_verror( "cannot load binary file created on machine with sizeof(TFunc*)=%d; " "expected %d",oldsizeofP,(int)sizeof(TFunc*)); } zread(Z,&w,sizeof(w)); /* test word */ if (w!=tw) { swapword=1; } zread(Z,&f,sizeof(f)); /* test float */ if (f!=tf) { Byte* p=(Byte*)&f; Byte t; swapfloat=1; t=p[0]; p[0]=p[3]; p[3]=t; t=p[1]; p[1]=p[2]; p[2]=t; if (f!=tf) /* TODO: try another perm? */ lua_error("cannot load binary file: unknown float representation"); } } static void LoadChunk(ZIO* Z) { LoadHeader(Z); while (1) { int c=zgetc(Z); if (c==ID_FUN) LoadFunction(Z); else { zungetc(Z); break; } } } /* ** load one chunk from a file. ** return list of functions found, headed by main, or NULL at EOF. */ TFunc* luaI_undump1(ZIO* Z) { int c=zgetc(Z); if (c==ID_CHUNK) { LoadChunk(Z); return Main; } else if (c!=EOZ) lua_error("not a lua binary file"); return NULL; } /* ** load and run all chunks in a file */ int luaI_undump(ZIO* Z) { TFunc* m; while ((m=luaI_undump1(Z))) { int status=luaI_dorun(m); luaI_freefunc(m); if (status!=0) return status; } return 0; }