1 | /* |
2 | ** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $ |
3 | ** save precompiled Lua chunks |
4 | ** See Copyright Notice in lua.h |
5 | */ |
6 | |
7 | #define ldump_c |
8 | #define LUA_CORE |
9 | |
10 | #include "lprefix.h" |
11 | |
12 | |
13 | #include <stddef.h> |
14 | |
15 | #include "lua.h" |
16 | |
17 | #include "lobject.h" |
18 | #include "lstate.h" |
19 | #include "lundump.h" |
20 | |
21 | |
22 | typedef struct { |
23 | lua_State *L; |
24 | lua_Writer writer; |
25 | void *data; |
26 | int strip; |
27 | int status; |
28 | } DumpState; |
29 | |
30 | |
31 | /* |
32 | ** All high-level dumps go through DumpVector; you can change it to |
33 | ** change the endianness of the result |
34 | */ |
35 | #define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) |
36 | |
37 | #define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) |
38 | |
39 | |
40 | static void DumpBlock (const void *b, size_t size, DumpState *D) { |
41 | if (D->status == 0 && size > 0) { |
42 | lua_unlock(D->L); |
43 | D->status = (*D->writer)(D->L, b, size, D->data); |
44 | lua_lock(D->L); |
45 | } |
46 | } |
47 | |
48 | |
49 | #define DumpVar(x,D) DumpVector(&x,1,D) |
50 | |
51 | |
52 | static void DumpByte (int y, DumpState *D) { |
53 | lu_byte x = (lu_byte)y; |
54 | DumpVar(x, D); |
55 | } |
56 | |
57 | |
58 | static void DumpInt (int x, DumpState *D) { |
59 | DumpVar(x, D); |
60 | } |
61 | |
62 | |
63 | static void DumpNumber (lua_Number x, DumpState *D) { |
64 | DumpVar(x, D); |
65 | } |
66 | |
67 | |
68 | static void DumpInteger (lua_Integer x, DumpState *D) { |
69 | DumpVar(x, D); |
70 | } |
71 | |
72 | |
73 | static void DumpString (const TString *s, DumpState *D) { |
74 | if (s == NULL) |
75 | DumpByte(0, D); |
76 | else { |
77 | size_t size = tsslen(s) + 1; /* include trailing '\0' */ |
78 | const char *str = getstr(s); |
79 | if (size < 0xFF) |
80 | DumpByte(cast_int(size), D); |
81 | else { |
82 | DumpByte(0xFF, D); |
83 | DumpVar(size, D); |
84 | } |
85 | DumpVector(str, size - 1, D); /* no need to save '\0' */ |
86 | } |
87 | } |
88 | |
89 | |
90 | static void DumpCode (const Proto *f, DumpState *D) { |
91 | DumpInt(f->sizecode, D); |
92 | DumpVector(f->code, f->sizecode, D); |
93 | } |
94 | |
95 | |
96 | static void DumpFunction(const Proto *f, TString *psource, DumpState *D); |
97 | |
98 | static void DumpConstants (const Proto *f, DumpState *D) { |
99 | int i; |
100 | int n = f->sizek; |
101 | DumpInt(n, D); |
102 | for (i = 0; i < n; i++) { |
103 | const TValue *o = &f->k[i]; |
104 | DumpByte(ttype(o), D); |
105 | switch (ttype(o)) { |
106 | case LUA_TNIL: |
107 | break; |
108 | case LUA_TBOOLEAN: |
109 | DumpByte(bvalue(o), D); |
110 | break; |
111 | case LUA_TNUMFLT: |
112 | DumpNumber(fltvalue(o), D); |
113 | break; |
114 | case LUA_TNUMINT: |
115 | DumpInteger(ivalue(o), D); |
116 | break; |
117 | case LUA_TSHRSTR: |
118 | case LUA_TLNGSTR: |
119 | DumpString(tsvalue(o), D); |
120 | break; |
121 | default: |
122 | lua_assert(0); |
123 | } |
124 | } |
125 | } |
126 | |
127 | |
128 | static void DumpProtos (const Proto *f, DumpState *D) { |
129 | int i; |
130 | int n = f->sizep; |
131 | DumpInt(n, D); |
132 | for (i = 0; i < n; i++) |
133 | DumpFunction(f->p[i], f->source, D); |
134 | } |
135 | |
136 | |
137 | static void DumpUpvalues (const Proto *f, DumpState *D) { |
138 | int i, n = f->sizeupvalues; |
139 | DumpInt(n, D); |
140 | for (i = 0; i < n; i++) { |
141 | DumpByte(f->upvalues[i].instack, D); |
142 | DumpByte(f->upvalues[i].idx, D); |
143 | } |
144 | } |
145 | |
146 | |
147 | static void DumpDebug (const Proto *f, DumpState *D) { |
148 | int i, n; |
149 | n = (D->strip) ? 0 : f->sizelineinfo; |
150 | DumpInt(n, D); |
151 | DumpVector(f->lineinfo, n, D); |
152 | n = (D->strip) ? 0 : f->sizelocvars; |
153 | DumpInt(n, D); |
154 | for (i = 0; i < n; i++) { |
155 | DumpString(f->locvars[i].varname, D); |
156 | DumpInt(f->locvars[i].startpc, D); |
157 | DumpInt(f->locvars[i].endpc, D); |
158 | } |
159 | n = (D->strip) ? 0 : f->sizeupvalues; |
160 | DumpInt(n, D); |
161 | for (i = 0; i < n; i++) |
162 | DumpString(f->upvalues[i].name, D); |
163 | } |
164 | |
165 | |
166 | static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { |
167 | if (D->strip || f->source == psource) |
168 | DumpString(NULL, D); /* no debug info or same source as its parent */ |
169 | else |
170 | DumpString(f->source, D); |
171 | DumpInt(f->linedefined, D); |
172 | DumpInt(f->lastlinedefined, D); |
173 | DumpByte(f->numparams, D); |
174 | DumpByte(f->is_vararg, D); |
175 | DumpByte(f->maxstacksize, D); |
176 | DumpCode(f, D); |
177 | DumpConstants(f, D); |
178 | DumpUpvalues(f, D); |
179 | DumpProtos(f, D); |
180 | DumpDebug(f, D); |
181 | } |
182 | |
183 | |
184 | static void (DumpState *D) { |
185 | DumpLiteral(LUA_SIGNATURE, D); |
186 | DumpByte(LUAC_VERSION, D); |
187 | DumpByte(LUAC_FORMAT, D); |
188 | DumpLiteral(LUAC_DATA, D); |
189 | DumpByte(sizeof(int), D); |
190 | DumpByte(sizeof(size_t), D); |
191 | DumpByte(sizeof(Instruction), D); |
192 | DumpByte(sizeof(lua_Integer), D); |
193 | DumpByte(sizeof(lua_Number), D); |
194 | DumpInteger(LUAC_INT, D); |
195 | DumpNumber(LUAC_NUM, D); |
196 | } |
197 | |
198 | |
199 | /* |
200 | ** dump Lua function as precompiled chunk |
201 | */ |
202 | int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, |
203 | int strip) { |
204 | DumpState D; |
205 | D.L = L; |
206 | D.writer = w; |
207 | D.data = data; |
208 | D.strip = strip; |
209 | D.status = 0; |
210 | DumpHeader(&D); |
211 | DumpByte(f->sizeupvalues, &D); |
212 | DumpFunction(f, NULL, &D); |
213 | return D.status; |
214 | } |
215 | |
216 | |