lundump.c revision 1.3
1/*	$NetBSD: lundump.c,v 1.3 2015/02/02 14:03:05 lneto Exp $	*/
2
3/*
4** Id: lundump.c,v 2.41 2014/11/02 19:19:04 roberto Exp
5** load precompiled Lua chunks
6** See Copyright Notice in lua.h
7*/
8
9#define lundump_c
10#define LUA_CORE
11
12#include "lprefix.h"
13
14
15#ifndef _KERNEL
16#include <string.h>
17#endif
18
19#include "lua.h"
20
21#include "ldebug.h"
22#include "ldo.h"
23#include "lfunc.h"
24#include "lmem.h"
25#include "lobject.h"
26#include "lstring.h"
27#include "lundump.h"
28#include "lzio.h"
29
30
31#if !defined(luai_verifycode)
32#define luai_verifycode(L,b,f)  /* empty */
33#endif
34
35
36typedef struct {
37  lua_State *L;
38  ZIO *Z;
39  Mbuffer *b;
40  const char *name;
41} LoadState;
42
43
44static l_noret error(LoadState *S, const char *why) {
45  luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why);
46  luaD_throw(S->L, LUA_ERRSYNTAX);
47}
48
49
50/*
51** All high-level loads go through LoadVector; you can change it to
52** adapt to the endianness of the input
53*/
54#define LoadVector(S,b,n)	LoadBlock(S,b,(n)*sizeof((b)[0]))
55
56static void LoadBlock (LoadState *S, void *b, size_t size) {
57  if (luaZ_read(S->Z, b, size) != 0)
58    error(S, "truncated");
59}
60
61
62#define LoadVar(S,x)		LoadVector(S,&x,1)
63
64
65static lu_byte LoadByte (LoadState *S) {
66  lu_byte x;
67  LoadVar(S, x);
68  return x;
69}
70
71
72static int LoadInt (LoadState *S) {
73  int x;
74  LoadVar(S, x);
75  return x;
76}
77
78
79static lua_Number LoadNumber (LoadState *S) {
80  lua_Number x;
81  LoadVar(S, x);
82  return x;
83}
84
85
86static lua_Integer LoadInteger (LoadState *S) {
87  lua_Integer x;
88  LoadVar(S, x);
89  return x;
90}
91
92
93static TString *LoadString (LoadState *S) {
94  size_t size = LoadByte(S);
95  if (size == 0xFF)
96    LoadVar(S, size);
97  if (size == 0)
98    return NULL;
99  else {
100    char *s = luaZ_openspace(S->L, S->b, --size);
101    LoadVector(S, s, size);
102    return luaS_newlstr(S->L, s, size);
103  }
104}
105
106
107static void LoadCode (LoadState *S, Proto *f) {
108  int n = LoadInt(S);
109  f->code = luaM_newvector(S->L, n, Instruction);
110  f->sizecode = n;
111  LoadVector(S, f->code, n);
112}
113
114
115static void LoadFunction(LoadState *S, Proto *f, TString *psource);
116
117
118static void LoadConstants (LoadState *S, Proto *f) {
119  int i;
120  int n = LoadInt(S);
121  f->k = luaM_newvector(S->L, n, TValue);
122  f->sizek = n;
123  for (i = 0; i < n; i++)
124    setnilvalue(&f->k[i]);
125  for (i = 0; i < n; i++) {
126    TValue *o = &f->k[i];
127    int t = LoadByte(S);
128    switch (t) {
129    case LUA_TNIL:
130      setnilvalue(o);
131      break;
132    case LUA_TBOOLEAN:
133      setbvalue(o, LoadByte(S));
134      break;
135#ifndef _KERNEL
136    case LUA_TNUMFLT:
137      setfltvalue(o, LoadNumber(S));
138      break;
139#endif
140    case LUA_TNUMINT:
141      setivalue(o, LoadInteger(S));
142      break;
143    case LUA_TSHRSTR:
144    case LUA_TLNGSTR:
145      setsvalue2n(S->L, o, LoadString(S));
146      break;
147    default:
148      lua_assert(0);
149    }
150  }
151}
152
153
154static void LoadProtos (LoadState *S, Proto *f) {
155  int i;
156  int n = LoadInt(S);
157  f->p = luaM_newvector(S->L, n, Proto *);
158  f->sizep = n;
159  for (i = 0; i < n; i++)
160    f->p[i] = NULL;
161  for (i = 0; i < n; i++) {
162    f->p[i] = luaF_newproto(S->L);
163    LoadFunction(S, f->p[i], f->source);
164  }
165}
166
167
168static void LoadUpvalues (LoadState *S, Proto *f) {
169  int i, n;
170  n = LoadInt(S);
171  f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
172  f->sizeupvalues = n;
173  for (i = 0; i < n; i++)
174    f->upvalues[i].name = NULL;
175  for (i = 0; i < n; i++) {
176    f->upvalues[i].instack = LoadByte(S);
177    f->upvalues[i].idx = LoadByte(S);
178  }
179}
180
181
182static void LoadDebug (LoadState *S, Proto *f) {
183  int i, n;
184  n = LoadInt(S);
185  f->lineinfo = luaM_newvector(S->L, n, int);
186  f->sizelineinfo = n;
187  LoadVector(S, f->lineinfo, n);
188  n = LoadInt(S);
189  f->locvars = luaM_newvector(S->L, n, LocVar);
190  f->sizelocvars = n;
191  for (i = 0; i < n; i++)
192    f->locvars[i].varname = NULL;
193  for (i = 0; i < n; i++) {
194    f->locvars[i].varname = LoadString(S);
195    f->locvars[i].startpc = LoadInt(S);
196    f->locvars[i].endpc = LoadInt(S);
197  }
198  n = LoadInt(S);
199  for (i = 0; i < n; i++)
200    f->upvalues[i].name = LoadString(S);
201}
202
203
204static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
205  f->source = LoadString(S);
206  if (f->source == NULL)  /* no source in dump? */
207    f->source = psource;  /* reuse parent's source */
208  f->linedefined = LoadInt(S);
209  f->lastlinedefined = LoadInt(S);
210  f->numparams = LoadByte(S);
211  f->is_vararg = LoadByte(S);
212  f->maxstacksize = LoadByte(S);
213  LoadCode(S, f);
214  LoadConstants(S, f);
215  LoadUpvalues(S, f);
216  LoadProtos(S, f);
217  LoadDebug(S, f);
218}
219
220
221static void checkliteral (LoadState *S, const char *s, const char *msg) {
222  char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
223  size_t len = strlen(s);
224  LoadVector(S, buff, len);
225  if (memcmp(s, buff, len) != 0)
226    error(S, msg);
227}
228
229
230static void fchecksize (LoadState *S, size_t size, const char *tname) {
231  if (LoadByte(S) != size)
232    error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
233}
234
235
236#define checksize(S,t)	fchecksize(S,sizeof(t),#t)
237
238static void checkHeader (LoadState *S) {
239  checkliteral(S, LUA_SIGNATURE + 1, "not a");  /* 1st char already checked */
240  if (LoadByte(S) != LUAC_VERSION)
241    error(S, "version mismatch in");
242  if (LoadByte(S) != LUAC_FORMAT)
243    error(S, "format mismatch in");
244  checkliteral(S, LUAC_DATA, "corrupted");
245  checksize(S, int);
246  checksize(S, size_t);
247  checksize(S, Instruction);
248  checksize(S, lua_Integer);
249  checksize(S, lua_Number);
250  if (LoadInteger(S) != LUAC_INT)
251    error(S, "endianness mismatch in");
252  if (LoadNumber(S) != LUAC_NUM)
253    error(S, "float format mismatch in");
254}
255
256
257/*
258** load precompiled chunk
259*/
260LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
261                      const char *name) {
262  LoadState S;
263  LClosure *cl;
264  if (*name == '@' || *name == '=')
265    S.name = name + 1;
266  else if (*name == LUA_SIGNATURE[0])
267    S.name = "binary string";
268  else
269    S.name = name;
270  S.L = L;
271  S.Z = Z;
272  S.b = buff;
273  checkHeader(&S);
274  cl = luaF_newLclosure(L, LoadByte(&S));
275  setclLvalue(L, L->top, cl);
276  incr_top(L);
277  cl->p = luaF_newproto(L);
278  LoadFunction(&S, cl->p, NULL);
279  lua_assert(cl->nupvalues == cl->p->sizeupvalues);
280  luai_verifycode(L, buff, cl->p);
281  return cl;
282}
283
284