/* ** undump.c ** load bytecodes from files */ char* rcs_undump="$Id: undump.c,v 1.21 1996/11/18 11:18:29 lhf Exp lhf $"; #include #include #include "auxlib.h" #include "opcode.h" #include "luamem.h" #include "table.h" #include "undump.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(FILE* D) { Word w; fread(&w,sizeof(w),1,D); if (swapword) { Byte* p=(Byte*)&w; Byte t; t=p[0]; p[0]=p[1]; p[1]=t; } return w; } static int LoadSize(FILE* D) { Word hi=LoadWord(D); Word lo=LoadWord(D); int s=(hi<<16)|lo; if ((Word)s != s) lua_error("code too long"); return s; } static void* LoadBlock(int size, FILE* D) { void* b=luaI_malloc(size); fread(b,size,1,D); return b; } static char* LoadString(FILE* D) { int size=LoadWord(D); char *b=luaI_buffer(size); fread(b,size,1,D); return b; } static char* LoadNewString(FILE* D) { return LoadBlock(LoadWord(D),D); } static void LoadFunction(FILE* D) { TFunc* tf=new(TFunc); tf->next=NULL; tf->locvars=NULL; tf->size=LoadSize(D); tf->lineDefined=LoadWord(D); if (IsMain(tf)) /* new main */ { tf->fileName=LoadNewString(D); Main=lastF=tf; } else /* fix PUSHFUNCTION */ { tf->marked=LoadWord(D); tf->fileName=Main->fileName; memcpy(Main->code+tf->marked,&tf,sizeof(tf)); lastF=lastF->next=tf; } tf->code=LoadBlock(tf->size,D); if (swapword || swapfloat) FixCode(tf->code,tf->code+tf->size); while (1) /* unthread */ { int c=getc(D); if (c==ID_VAR) /* global var */ { int i=LoadWord(D); char* s=LoadString(D); int v=luaI_findsymbolbyname(s); Unthread(tf->code,i,v); } else if (c==ID_STR) /* constant string */ { int i=LoadWord(D); char* s=LoadString(D); int v=luaI_findconstantbyname(s); Unthread(tf->code,i,v); } else { ungetc(c,D); break; } } } static void LoadSignature(FILE* D) { char* s=SIGNATURE; while (*s!=0 && getc(D)==*s) ++s; if (*s!=0) lua_error("cannot load binary file: bad signature"); } static void LoadHeader(FILE* D) { Word w,tw=TEST_WORD; float f,tf=TEST_FLOAT; int version; LoadSignature(D); version=getc(D); if (version>0x23) /* after 2.5 */ { int oldsizeofW=getc(D); int oldsizeofF=getc(D); int oldsizeofP=getc(D); 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,sizeof(TFunc*)); } fread(&w,sizeof(w),1,D); /* test word */ if (w!=tw) { swapword=1; } fread(&f,sizeof(f),1,D); /* 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(FILE* D) { LoadHeader(D); while (1) { int c=getc(D); if (c==ID_FUN) LoadFunction(D); else { ungetc(c,D); break; } } } /* ** load one chunk from a file. ** return list of functions found, headed by main, or NULL at EOF. */ TFunc* luaI_undump1(FILE* D) { while (1) { int c=getc(D); if (c==ID_CHUNK) { LoadChunk(D); return Main; } else if (c==EOF) return NULL; else lua_error("not a lua binary file"); } } /* ** load and run all chunks in a file */ int luaI_undump(FILE* D) { TFunc* m; while ((m=luaI_undump1(D))) { int status=luaI_dorun(m); luaI_freefunc(m); if (status!=0) return status; } return 0; }