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 27typedef 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 45static 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 57static 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 76static 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 88static void dumpInt (DumpState *D, int x) { 89 dumpSize(D, x); 90} 91 92 93static void dumpNumber (DumpState *D, lua_Number x) { 94 dumpVar(D, x); 95} 96 97 98static void dumpInteger (DumpState *D, lua_Integer x) { 99 dumpVar(D, x); 100} 101 102 103static 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 115static void dumpCode (DumpState *D, const Proto *f) { 116 dumpInt(D, f->sizecode); 117 dumpVector(D, f->code, f->sizecode); 118} 119 120 121static void dumpFunction(DumpState *D, const Proto *f, TString *psource); 122 123static 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 151static 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 160static 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 171static 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 196static 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 214static 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*/ 230int 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