1 /* $NetBSD: ldump.c,v 1.12 2023/06/08 21:12:08 nikita Exp $ */ 2 3 /* 4 ** Id: ldump.c 5 ** save precompiled Lua chunks 6 ** See Copyright Notice in lua.h 7 */ 8 9 #define ldump_c 10 #define LUA_CORE 11 12 #include "lprefix.h" 13 14 15 #ifndef _KERNEL 16 #include <limits.h> 17 #include <stddef.h> 18 #endif /* _KERNEL */ 19 20 #include "lua.h" 21 22 #include "lobject.h" 23 #include "lstate.h" 24 #include "lundump.h" 25 26 27 typedef struct { 28 lua_State *L; 29 lua_Writer writer; 30 void *data; 31 int strip; 32 int status; 33 } DumpState; 34 35 36 /* 37 ** All high-level dumps go through dumpVector; you can change it to 38 ** change the endianness of the result 39 */ 40 #define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0])) 41 42 #define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char)) 43 44 45 static void dumpBlock (DumpState *D, const void *b, size_t size) { 46 if (D->status == 0 && size > 0) { 47 lua_unlock(D->L); 48 D->status = (*D->writer)(D->L, b, size, D->data); 49 lua_lock(D->L); 50 } 51 } 52 53 54 #define dumpVar(D,x) dumpVector(D,&x,1) 55 56 57 static void dumpByte (DumpState *D, int y) { 58 lu_byte x = (lu_byte)y; 59 dumpVar(D, x); 60 } 61 62 63 #ifdef _KERNEL 64 /* dumpInt Buff Size */ 65 #define DIBS ((sizeof(size_t) * 8 / 7) + 1) 66 #endif /* _KERNEL */ 67 #ifndef _KERNEL 68 /* 69 ** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6" 70 ** rounds up the division.) 71 */ 72 #define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7) 73 #endif /* _KERNEL */ 74 75 76 static void dumpSize (DumpState *D, size_t x) { 77 lu_byte buff[DIBS]; 78 int n = 0; 79 do { 80 buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */ 81 x >>= 7; 82 } while (x != 0); 83 buff[DIBS - 1] |= 0x80; /* mark last byte */ 84 dumpVector(D, buff + DIBS - n, n); 85 } 86 87 88 static void dumpInt (DumpState *D, int x) { 89 dumpSize(D, x); 90 } 91 92 93 static void dumpNumber (DumpState *D, lua_Number x) { 94 dumpVar(D, x); 95 } 96 97 98 static void dumpInteger (DumpState *D, lua_Integer x) { 99 dumpVar(D, x); 100 } 101 102 103 static void dumpString (DumpState *D, const TString *s) { 104 if (s == NULL) 105 dumpSize(D, 0); 106 else { 107 size_t size = tsslen(s); 108 const char *str = getstr(s); 109 dumpSize(D, size + 1); 110 dumpVector(D, str, size); 111 } 112 } 113 114 115 static void dumpCode (DumpState *D, const Proto *f) { 116 dumpInt(D, f->sizecode); 117 dumpVector(D, f->code, f->sizecode); 118 } 119 120 121 static void dumpFunction(DumpState *D, const Proto *f, TString *psource); 122 123 static void dumpConstants (DumpState *D, const Proto *f) { 124 int i; 125 int n = f->sizek; 126 dumpInt(D, n); 127 for (i = 0; i < n; i++) { 128 const TValue *o = &f->k[i]; 129 int tt = ttypetag(o); 130 dumpByte(D, tt); 131 switch (tt) { 132 #ifndef _KERNEL 133 case LUA_VNUMFLT: 134 dumpNumber(D, fltvalue(o)); 135 break; 136 #endif /* _KERNEL */ 137 case LUA_VNUMINT: 138 dumpInteger(D, ivalue(o)); 139 break; 140 case LUA_VSHRSTR: 141 case LUA_VLNGSTR: 142 dumpString(D, tsvalue(o)); 143 break; 144 default: 145 lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE); 146 } 147 } 148 } 149 150 151 static void dumpProtos (DumpState *D, const Proto *f) { 152 int i; 153 int n = f->sizep; 154 dumpInt(D, n); 155 for (i = 0; i < n; i++) 156 dumpFunction(D, f->p[i], f->source); 157 } 158 159 160 static void dumpUpvalues (DumpState *D, const Proto *f) { 161 int i, n = f->sizeupvalues; 162 dumpInt(D, n); 163 for (i = 0; i < n; i++) { 164 dumpByte(D, f->upvalues[i].instack); 165 dumpByte(D, f->upvalues[i].idx); 166 dumpByte(D, f->upvalues[i].kind); 167 } 168 } 169 170 171 static void dumpDebug (DumpState *D, const Proto *f) { 172 int i, n; 173 n = (D->strip) ? 0 : f->sizelineinfo; 174 dumpInt(D, n); 175 dumpVector(D, f->lineinfo, n); 176 n = (D->strip) ? 0 : f->sizeabslineinfo; 177 dumpInt(D, n); 178 for (i = 0; i < n; i++) { 179 dumpInt(D, f->abslineinfo[i].pc); 180 dumpInt(D, f->abslineinfo[i].line); 181 } 182 n = (D->strip) ? 0 : f->sizelocvars; 183 dumpInt(D, n); 184 for (i = 0; i < n; i++) { 185 dumpString(D, f->locvars[i].varname); 186 dumpInt(D, f->locvars[i].startpc); 187 dumpInt(D, f->locvars[i].endpc); 188 } 189 n = (D->strip) ? 0 : f->sizeupvalues; 190 dumpInt(D, n); 191 for (i = 0; i < n; i++) 192 dumpString(D, f->upvalues[i].name); 193 } 194 195 196 static void dumpFunction (DumpState *D, const Proto *f, TString *psource) { 197 if (D->strip || f->source == psource) 198 dumpString(D, NULL); /* no debug info or same source as its parent */ 199 else 200 dumpString(D, f->source); 201 dumpInt(D, f->linedefined); 202 dumpInt(D, f->lastlinedefined); 203 dumpByte(D, f->numparams); 204 dumpByte(D, f->is_vararg); 205 dumpByte(D, f->maxstacksize); 206 dumpCode(D, f); 207 dumpConstants(D, f); 208 dumpUpvalues(D, f); 209 dumpProtos(D, f); 210 dumpDebug(D, f); 211 } 212 213 214 static void dumpHeader (DumpState *D) { 215 dumpLiteral(D, LUA_SIGNATURE); 216 dumpByte(D, LUAC_VERSION); 217 dumpByte(D, LUAC_FORMAT); 218 dumpLiteral(D, LUAC_DATA); 219 dumpByte(D, sizeof(Instruction)); 220 dumpByte(D, sizeof(lua_Integer)); 221 dumpByte(D, sizeof(lua_Number)); 222 dumpInteger(D, LUAC_INT); 223 dumpNumber(D, LUAC_NUM); 224 } 225 226 227 /* 228 ** dump Lua function as precompiled chunk 229 */ 230 int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, 231 int strip) { 232 DumpState D; 233 D.L = L; 234 D.writer = w; 235 D.data = data; 236 D.strip = strip; 237 D.status = 0; 238 dumpHeader(&D); 239 dumpByte(&D, f->sizeupvalues); 240 dumpFunction(&D, f, NULL); 241 return D.status; 242 } 243 244