1 /*
2 ** dump.c - mruby binary dumper (mrbc binary format)
3 **
4 ** See Copyright Notice in mruby.h
5 */
6
7 #include <string.h>
8 #include <limits.h>
9 #include <math.h>
10 #include <mruby/dump.h>
11 #include <mruby/string.h>
12 #include <mruby/irep.h>
13 #include <mruby/numeric.h>
14 #include <mruby/debug.h>
15
16 #ifndef MRB_WITHOUT_FLOAT
17 #ifdef MRB_USE_FLOAT
18 #define MRB_FLOAT_FMT "%.9g"
19 #else
20 #define MRB_FLOAT_FMT "%.17g"
21 #endif
22 #endif
23
24 static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
25
26 #if UINT32_MAX > SIZE_MAX
27 # error This code cannot be built on your environment.
28 #endif
29
30 static size_t
write_padding(uint8_t * buf)31 write_padding(uint8_t *buf)
32 {
33 const size_t align = MRB_DUMP_ALIGNMENT;
34 size_t pad_len = -(intptr_t)buf & (align-1);
35 if (pad_len > 0) {
36 memset(buf, 0, pad_len);
37 }
38 return pad_len;
39 }
40
41 static size_t
get_irep_header_size(mrb_state * mrb)42 get_irep_header_size(mrb_state *mrb)
43 {
44 size_t size = 0;
45
46 size += sizeof(uint32_t) * 1;
47 size += sizeof(uint16_t) * 3;
48
49 return size;
50 }
51
52 static ptrdiff_t
write_irep_header(mrb_state * mrb,mrb_irep * irep,uint8_t * buf)53 write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
54 {
55 uint8_t *cur = buf;
56
57 cur += uint32_to_bin((uint32_t)get_irep_record_size_1(mrb, irep), cur); /* record size */
58 cur += uint16_to_bin((uint16_t)irep->nlocals, cur); /* number of local variable */
59 cur += uint16_to_bin((uint16_t)irep->nregs, cur); /* number of register variable */
60 cur += uint16_to_bin((uint16_t)irep->rlen, cur); /* number of child irep */
61
62 return cur - buf;
63 }
64
65
66 static size_t
get_iseq_block_size(mrb_state * mrb,mrb_irep * irep)67 get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
68 {
69 size_t size = 0;
70
71 size += sizeof(uint32_t); /* ilen */
72 size += sizeof(uint32_t); /* max padding */
73 size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
74
75 return size;
76 }
77
78 static ptrdiff_t
write_iseq_block(mrb_state * mrb,mrb_irep * irep,uint8_t * buf,uint8_t flags)79 write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)
80 {
81 uint8_t *cur = buf;
82
83 cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
84 cur += write_padding(cur);
85 memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code));
86 cur += irep->ilen * sizeof(mrb_code);
87
88 return cur - buf;
89 }
90
91 #ifndef MRB_WITHOUT_FLOAT
92 static mrb_value
float_to_str(mrb_state * mrb,mrb_value flt)93 float_to_str(mrb_state *mrb, mrb_value flt)
94 {
95 mrb_float f = mrb_float(flt);
96
97 if (isinf(f)) {
98 return f < 0 ? mrb_str_new_lit(mrb, "I") : mrb_str_new_lit(mrb, "i");
99 }
100 return mrb_float_to_str(mrb, flt, MRB_FLOAT_FMT);
101 }
102 #endif
103
104 static size_t
get_pool_block_size(mrb_state * mrb,mrb_irep * irep)105 get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
106 {
107 int pool_no;
108 size_t size = 0;
109 mrb_value str;
110
111 size += sizeof(uint32_t); /* plen */
112 size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */
113
114 for (pool_no = 0; pool_no < irep->plen; pool_no++) {
115 int ai = mrb_gc_arena_save(mrb);
116
117 switch (mrb_type(irep->pool[pool_no])) {
118 case MRB_TT_FIXNUM:
119 str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
120 {
121 mrb_int len = RSTRING_LEN(str);
122 mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
123 size += (size_t)len;
124 }
125 break;
126
127 #ifndef MRB_WITHOUT_FLOAT
128 case MRB_TT_FLOAT:
129 str = float_to_str(mrb, irep->pool[pool_no]);
130 {
131 mrb_int len = RSTRING_LEN(str);
132 mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
133 size += (size_t)len;
134 }
135 break;
136 #endif
137
138 case MRB_TT_STRING:
139 {
140 mrb_int len = RSTRING_LEN(irep->pool[pool_no]);
141 mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
142 size += (size_t)len;
143 }
144 break;
145
146 default:
147 break;
148 }
149 mrb_gc_arena_restore(mrb, ai);
150 }
151
152 return size;
153 }
154
155 static ptrdiff_t
write_pool_block(mrb_state * mrb,mrb_irep * irep,uint8_t * buf)156 write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
157 {
158 int pool_no;
159 uint8_t *cur = buf;
160 uint16_t len;
161 mrb_value str;
162 const char *char_ptr;
163
164 cur += uint32_to_bin(irep->plen, cur); /* number of pool */
165
166 for (pool_no = 0; pool_no < irep->plen; pool_no++) {
167 int ai = mrb_gc_arena_save(mrb);
168
169 switch (mrb_type(irep->pool[pool_no])) {
170 case MRB_TT_FIXNUM:
171 cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */
172 str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
173 break;
174
175 #ifndef MRB_WITHOUT_FLOAT
176 case MRB_TT_FLOAT:
177 cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */
178 str = float_to_str(mrb, irep->pool[pool_no]);
179 break;
180 #endif
181
182 case MRB_TT_STRING:
183 cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */
184 str = irep->pool[pool_no];
185 break;
186
187 default:
188 continue;
189 }
190
191 char_ptr = RSTRING_PTR(str);
192 {
193 mrb_int tlen = RSTRING_LEN(str);
194 mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX);
195 len = (uint16_t)tlen;
196 }
197
198 cur += uint16_to_bin(len, cur); /* data length */
199 memcpy(cur, char_ptr, (size_t)len);
200 cur += len;
201
202 mrb_gc_arena_restore(mrb, ai);
203 }
204
205 return cur - buf;
206 }
207
208
209 static size_t
get_syms_block_size(mrb_state * mrb,mrb_irep * irep)210 get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
211 {
212 size_t size = 0;
213 int sym_no;
214 mrb_int len;
215
216 size += sizeof(uint32_t); /* slen */
217 for (sym_no = 0; sym_no < irep->slen; sym_no++) {
218 size += sizeof(uint16_t); /* snl(n) */
219 if (irep->syms[sym_no] != 0) {
220 mrb_sym_name_len(mrb, irep->syms[sym_no], &len);
221 size += len + 1; /* sn(n) + null char */
222 }
223 }
224
225 return size;
226 }
227
228 static ptrdiff_t
write_syms_block(mrb_state * mrb,mrb_irep * irep,uint8_t * buf)229 write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
230 {
231 int sym_no;
232 uint8_t *cur = buf;
233 const char *name;
234
235 cur += uint32_to_bin(irep->slen, cur); /* number of symbol */
236
237 for (sym_no = 0; sym_no < irep->slen; sym_no++) {
238 if (irep->syms[sym_no] != 0) {
239 mrb_int len;
240
241 name = mrb_sym_name_len(mrb, irep->syms[sym_no], &len);
242
243 mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX);
244 cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */
245 memcpy(cur, name, len); /* symbol name */
246 cur += (uint16_t)len;
247 *cur++ = '\0';
248 }
249 else {
250 cur += uint16_to_bin(MRB_DUMP_NULL_SYM_LEN, cur); /* length of symbol name */
251 }
252 }
253
254 return cur - buf;
255 }
256
257 static size_t
get_irep_record_size_1(mrb_state * mrb,mrb_irep * irep)258 get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
259 {
260 size_t size = 0;
261
262 size += get_irep_header_size(mrb);
263 size += get_iseq_block_size(mrb, irep);
264 size += get_pool_block_size(mrb, irep);
265 size += get_syms_block_size(mrb, irep);
266 return size;
267 }
268
269 static size_t
get_irep_record_size(mrb_state * mrb,mrb_irep * irep)270 get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
271 {
272 size_t size = 0;
273 int irep_no;
274
275 size = get_irep_record_size_1(mrb, irep);
276 for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
277 size += get_irep_record_size(mrb, irep->reps[irep_no]);
278 }
279 return size;
280 }
281
282 static int
write_irep_record(mrb_state * mrb,mrb_irep * irep,uint8_t * bin,size_t * irep_record_size,uint8_t flags)283 write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags)
284 {
285 int i;
286 uint8_t *src = bin;
287
288 if (irep == NULL) {
289 return MRB_DUMP_INVALID_IREP;
290 }
291
292 *irep_record_size = get_irep_record_size_1(mrb, irep);
293 if (*irep_record_size == 0) {
294 return MRB_DUMP_GENERAL_FAILURE;
295 }
296
297 bin += write_irep_header(mrb, irep, bin);
298 bin += write_iseq_block(mrb, irep, bin, flags);
299 bin += write_pool_block(mrb, irep, bin);
300 bin += write_syms_block(mrb, irep, bin);
301
302 for (i = 0; i < irep->rlen; i++) {
303 int result;
304 size_t rsize;
305
306 result = write_irep_record(mrb, irep->reps[i], bin, &rsize, flags);
307 if (result != MRB_DUMP_OK) {
308 return result;
309 }
310 bin += rsize;
311 }
312 *irep_record_size = bin - src;
313 return MRB_DUMP_OK;
314 }
315
316 static uint32_t
write_footer(mrb_state * mrb,uint8_t * bin)317 write_footer(mrb_state *mrb, uint8_t *bin)
318 {
319 struct rite_binary_footer footer;
320
321 memcpy(footer.section_ident, RITE_BINARY_EOF, sizeof(footer.section_ident));
322 uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size);
323 memcpy(bin, &footer, sizeof(struct rite_binary_footer));
324
325 return sizeof(struct rite_binary_footer);
326 }
327
328
329 static int
write_section_irep_header(mrb_state * mrb,size_t section_size,uint8_t * bin)330 write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
331 {
332 struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
333
334 memcpy(header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(header->section_ident));
335
336 mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX);
337 uint32_to_bin((uint32_t)section_size, header->section_size);
338 memcpy(header->rite_version, RITE_VM_VER, sizeof(header->rite_version));
339
340 return MRB_DUMP_OK;
341 }
342
343 static int
write_section_irep(mrb_state * mrb,mrb_irep * irep,uint8_t * bin,size_t * len_p,uint8_t flags)344 write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags)
345 {
346 int result;
347 size_t rsize = 0;
348 uint8_t *cur = bin;
349
350 if (mrb == NULL || bin == NULL) {
351 return MRB_DUMP_INVALID_ARGUMENT;
352 }
353
354 cur += sizeof(struct rite_section_irep_header);
355
356 result = write_irep_record(mrb, irep, cur, &rsize, flags);
357 if (result != MRB_DUMP_OK) {
358 return result;
359 }
360 *len_p = cur - bin + rsize;
361 write_section_irep_header(mrb, *len_p, bin);
362
363 return MRB_DUMP_OK;
364 }
365
366 static size_t
get_debug_record_size(mrb_state * mrb,mrb_irep * irep)367 get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
368 {
369 size_t ret = 0;
370 uint16_t f_idx;
371 int i;
372
373 ret += sizeof(uint32_t); /* record size */
374 ret += sizeof(uint16_t); /* file count */
375
376 for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
377 mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx];
378
379 ret += sizeof(uint32_t); /* position */
380 ret += sizeof(uint16_t); /* filename index */
381
382 /* lines */
383 ret += sizeof(uint32_t); /* entry count */
384 ret += sizeof(uint8_t); /* line type */
385 switch (file->line_type) {
386 case mrb_debug_line_ary:
387 ret += sizeof(uint16_t) * (size_t)(file->line_entry_count);
388 break;
389
390 case mrb_debug_line_flat_map:
391 ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count);
392 break;
393
394 default: mrb_assert(0); break;
395 }
396 }
397 for (i=0; i<irep->rlen; i++) {
398 ret += get_debug_record_size(mrb, irep->reps[i]);
399 }
400
401 return ret;
402 }
403
404 static int
find_filename_index(const mrb_sym * ary,int ary_len,mrb_sym s)405 find_filename_index(const mrb_sym *ary, int ary_len, mrb_sym s)
406 {
407 int i;
408
409 for (i = 0; i < ary_len; ++i) {
410 if (ary[i] == s) { return i; }
411 }
412 return -1;
413 }
414
415 static size_t
get_filename_table_size(mrb_state * mrb,mrb_irep * irep,mrb_sym ** fp,uint16_t * lp)416 get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *lp)
417 {
418 mrb_sym *filenames = *fp;
419 size_t size = 0;
420 mrb_irep_debug_info *di = irep->debug_info;
421 int i;
422
423 mrb_assert(lp);
424 for (i = 0; i < di->flen; ++i) {
425 mrb_irep_debug_info_file *file;
426 mrb_int filename_len;
427
428 file = di->files[i];
429 if (find_filename_index(filenames, *lp, file->filename_sym) == -1) {
430 /* register filename */
431 *lp += 1;
432 *fp = filenames = (mrb_sym *)mrb_realloc(mrb, filenames, sizeof(mrb_sym) * (*lp));
433 filenames[*lp - 1] = file->filename_sym;
434
435 /* filename */
436 mrb_sym_name_len(mrb, file->filename_sym, &filename_len);
437 size += sizeof(uint16_t) + (size_t)filename_len;
438 }
439 }
440 for (i=0; i<irep->rlen; i++) {
441 size += get_filename_table_size(mrb, irep->reps[i], fp, lp);
442 }
443 return size;
444 }
445
446 static size_t
write_debug_record_1(mrb_state * mrb,mrb_irep * irep,uint8_t * bin,mrb_sym const * filenames,uint16_t filenames_len)447 write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
448 {
449 uint8_t *cur;
450 uint16_t f_idx;
451 ptrdiff_t ret;
452
453 cur = bin + sizeof(uint32_t); /* skip record size */
454 cur += uint16_to_bin(irep->debug_info->flen, cur); /* file count */
455
456 for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
457 int filename_idx;
458 const mrb_irep_debug_info_file *file = irep->debug_info->files[f_idx];
459
460 /* position */
461 cur += uint32_to_bin(file->start_pos, cur);
462
463 /* filename index */
464 filename_idx = find_filename_index(filenames, filenames_len,
465 file->filename_sym);
466 mrb_assert_int_fit(int, filename_idx, uint16_t, UINT16_MAX);
467 cur += uint16_to_bin((uint16_t)filename_idx, cur);
468
469 /* lines */
470 cur += uint32_to_bin(file->line_entry_count, cur);
471 cur += uint8_to_bin(file->line_type, cur);
472 switch (file->line_type) {
473 case mrb_debug_line_ary: {
474 uint32_t l;
475 for (l = 0; l < file->line_entry_count; ++l) {
476 cur += uint16_to_bin(file->lines.ary[l], cur);
477 }
478 } break;
479
480 case mrb_debug_line_flat_map: {
481 uint32_t line;
482 for (line = 0; line < file->line_entry_count; ++line) {
483 cur += uint32_to_bin(file->lines.flat_map[line].start_pos, cur);
484 cur += uint16_to_bin(file->lines.flat_map[line].line, cur);
485 }
486 } break;
487
488 default: mrb_assert(0); break;
489 }
490 }
491
492 ret = cur - bin;
493 mrb_assert_int_fit(ptrdiff_t, ret, uint32_t, UINT32_MAX);
494 uint32_to_bin((uint32_t)ret, bin);
495
496 mrb_assert_int_fit(ptrdiff_t, ret, size_t, SIZE_MAX);
497 return (size_t)ret;
498 }
499
500 static size_t
write_debug_record(mrb_state * mrb,mrb_irep * irep,uint8_t * bin,mrb_sym const * filenames,uint16_t filenames_len)501 write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
502 {
503 size_t size, len;
504 int irep_no;
505
506 size = len = write_debug_record_1(mrb, irep, bin, filenames, filenames_len);
507 bin += len;
508 for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
509 len = write_debug_record(mrb, irep->reps[irep_no], bin, filenames, filenames_len);
510 bin += len;
511 size += len;
512 }
513
514 mrb_assert(size == get_debug_record_size(mrb, irep));
515 return size;
516 }
517
518 static int
write_section_debug(mrb_state * mrb,mrb_irep * irep,uint8_t * cur,mrb_sym const * filenames,uint16_t filenames_len)519 write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const *filenames, uint16_t filenames_len)
520 {
521 size_t section_size = 0;
522 const uint8_t *bin = cur;
523 struct rite_section_debug_header *header;
524 size_t dlen;
525 uint16_t i;
526 char const *sym; mrb_int sym_len;
527
528 if (mrb == NULL || cur == NULL) {
529 return MRB_DUMP_INVALID_ARGUMENT;
530 }
531
532 header = (struct rite_section_debug_header *)bin;
533 cur += sizeof(struct rite_section_debug_header);
534 section_size += sizeof(struct rite_section_debug_header);
535
536 /* filename table */
537 cur += uint16_to_bin(filenames_len, cur);
538 section_size += sizeof(uint16_t);
539 for (i = 0; i < filenames_len; ++i) {
540 sym = mrb_sym_name_len(mrb, filenames[i], &sym_len);
541 mrb_assert(sym);
542 cur += uint16_to_bin((uint16_t)sym_len, cur);
543 memcpy(cur, sym, sym_len);
544 cur += sym_len;
545 section_size += sizeof(uint16_t) + sym_len;
546 }
547
548 /* debug records */
549 dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len);
550 section_size += dlen;
551
552 memcpy(header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(header->section_ident));
553 mrb_assert(section_size <= INT32_MAX);
554 uint32_to_bin((uint32_t)section_size, header->section_size);
555
556 return MRB_DUMP_OK;
557 }
558
559 static void
create_lv_sym_table(mrb_state * mrb,const mrb_irep * irep,mrb_sym ** syms,uint32_t * syms_len)560 create_lv_sym_table(mrb_state *mrb, const mrb_irep *irep, mrb_sym **syms, uint32_t *syms_len)
561 {
562 int i;
563
564 if (*syms == NULL) {
565 *syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * 1);
566 }
567
568 for (i = 0; i + 1 < irep->nlocals; ++i) {
569 mrb_sym const name = irep->lv[i].name;
570 if (name == 0) continue;
571 if (find_filename_index(*syms, *syms_len, name) != -1) continue;
572
573 ++(*syms_len);
574 *syms = (mrb_sym*)mrb_realloc(mrb, *syms, sizeof(mrb_sym) * (*syms_len));
575 (*syms)[*syms_len - 1] = name;
576 }
577
578 for (i = 0; i < irep->rlen; ++i) {
579 create_lv_sym_table(mrb, irep->reps[i], syms, syms_len);
580 }
581 }
582
583 static int
write_lv_sym_table(mrb_state * mrb,uint8_t ** start,mrb_sym const * syms,uint32_t syms_len)584 write_lv_sym_table(mrb_state *mrb, uint8_t **start, mrb_sym const *syms, uint32_t syms_len)
585 {
586 uint8_t *cur = *start;
587 uint32_t i;
588 const char *str;
589 mrb_int str_len;
590
591 cur += uint32_to_bin(syms_len, cur);
592
593 for (i = 0; i < syms_len; ++i) {
594 str = mrb_sym_name_len(mrb, syms[i], &str_len);
595 cur += uint16_to_bin((uint16_t)str_len, cur);
596 memcpy(cur, str, str_len);
597 cur += str_len;
598 }
599
600 *start = cur;
601
602 return MRB_DUMP_OK;
603 }
604
605 static int
write_lv_record(mrb_state * mrb,const mrb_irep * irep,uint8_t ** start,mrb_sym const * syms,uint32_t syms_len)606 write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym const *syms, uint32_t syms_len)
607 {
608 uint8_t *cur = *start;
609 int i;
610
611 for (i = 0; i + 1 < irep->nlocals; ++i) {
612 if (irep->lv[i].name == 0) {
613 cur += uint16_to_bin(RITE_LV_NULL_MARK, cur);
614 cur += uint16_to_bin(0, cur);
615 }
616 else {
617 int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i].name);
618 mrb_assert(sym_idx != -1); /* local variable name must be in syms */
619
620 cur += uint16_to_bin(sym_idx, cur);
621 cur += uint16_to_bin(irep->lv[i].r, cur);
622 }
623 }
624
625 for (i = 0; i < irep->rlen; ++i) {
626 write_lv_record(mrb, irep->reps[i], &cur, syms, syms_len);
627 }
628
629 *start = cur;
630
631 return MRB_DUMP_OK;
632 }
633
634 static size_t
get_lv_record_size(mrb_state * mrb,mrb_irep * irep)635 get_lv_record_size(mrb_state *mrb, mrb_irep *irep)
636 {
637 size_t ret = 0;
638 int i;
639
640 ret += (sizeof(uint16_t) + sizeof(uint16_t)) * (irep->nlocals - 1);
641
642 for (i = 0; i < irep->rlen; ++i) {
643 ret += get_lv_record_size(mrb, irep->reps[i]);
644 }
645
646 return ret;
647 }
648
649 static size_t
get_lv_section_size(mrb_state * mrb,mrb_irep * irep,mrb_sym const * syms,uint32_t syms_len)650 get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_t syms_len)
651 {
652 size_t ret = 0, i;
653
654 ret += sizeof(uint32_t); /* syms_len */
655 ret += sizeof(uint16_t) * syms_len; /* symbol name lengths */
656 for (i = 0; i < syms_len; ++i) {
657 mrb_int str_len;
658 mrb_sym_name_len(mrb, syms[i], &str_len);
659 ret += str_len;
660 }
661
662 ret += get_lv_record_size(mrb, irep);
663
664 return ret;
665 }
666
667 static int
write_section_lv(mrb_state * mrb,mrb_irep * irep,uint8_t * start,mrb_sym const * syms,uint32_t const syms_len)668 write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const *syms, uint32_t const syms_len)
669 {
670 uint8_t *cur = start;
671 struct rite_section_lv_header *header;
672 ptrdiff_t diff;
673 int result = MRB_DUMP_OK;
674
675 if (mrb == NULL || cur == NULL) {
676 return MRB_DUMP_INVALID_ARGUMENT;
677 }
678
679 header = (struct rite_section_lv_header*)cur;
680 cur += sizeof(struct rite_section_lv_header);
681
682 result = write_lv_sym_table(mrb, &cur, syms, syms_len);
683 if (result != MRB_DUMP_OK) {
684 goto lv_section_exit;
685 }
686
687 result = write_lv_record(mrb, irep, &cur, syms, syms_len);
688 if (result != MRB_DUMP_OK) {
689 goto lv_section_exit;
690 }
691
692 memcpy(header->section_ident, RITE_SECTION_LV_IDENT, sizeof(header->section_ident));
693
694 diff = cur - start;
695 mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
696 uint32_to_bin((uint32_t)diff, header->section_size);
697
698 lv_section_exit:
699 return result;
700 }
701
702 static int
write_rite_binary_header(mrb_state * mrb,size_t binary_size,uint8_t * bin,uint8_t flags)703 write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8_t flags)
704 {
705 struct rite_binary_header *header = (struct rite_binary_header *)bin;
706 uint16_t crc;
707 uint32_t offset;
708
709 memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident));
710 memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
711 memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
712 memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
713 mrb_assert(binary_size <= UINT32_MAX);
714 uint32_to_bin((uint32_t)binary_size, header->binary_size);
715
716 offset = (uint32_t)((&(header->binary_crc[0]) - bin) + sizeof(uint16_t));
717 crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0);
718 uint16_to_bin(crc, header->binary_crc);
719
720 return MRB_DUMP_OK;
721 }
722
723 static mrb_bool
debug_info_defined_p(mrb_irep * irep)724 debug_info_defined_p(mrb_irep *irep)
725 {
726 int i;
727
728 if (!irep->debug_info) return FALSE;
729 for (i=0; i<irep->rlen; i++) {
730 if (!debug_info_defined_p(irep->reps[i])) return FALSE;
731 }
732 return TRUE;
733 }
734
735 static mrb_bool
lv_defined_p(mrb_irep * irep)736 lv_defined_p(mrb_irep *irep)
737 {
738 int i;
739
740 if (irep->lv) { return TRUE; }
741
742 for (i = 0; i < irep->rlen; ++i) {
743 if (lv_defined_p(irep->reps[i])) { return TRUE; }
744 }
745
746 return FALSE;
747 }
748
749 static int
dump_irep(mrb_state * mrb,mrb_irep * irep,uint8_t flags,uint8_t ** bin,size_t * bin_size)750 dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
751 {
752 int result = MRB_DUMP_GENERAL_FAILURE;
753 size_t malloc_size;
754 size_t section_irep_size;
755 size_t section_lineno_size = 0, section_lv_size = 0;
756 uint8_t *cur = NULL;
757 mrb_bool const debug_info_defined = debug_info_defined_p(irep), lv_defined = lv_defined_p(irep);
758 mrb_sym *lv_syms = NULL; uint32_t lv_syms_len = 0;
759 mrb_sym *filenames = NULL; uint16_t filenames_len = 0;
760
761 if (mrb == NULL) {
762 *bin = NULL;
763 return MRB_DUMP_GENERAL_FAILURE;
764 }
765
766 section_irep_size = sizeof(struct rite_section_irep_header);
767 section_irep_size += get_irep_record_size(mrb, irep);
768
769 /* DEBUG section size */
770 if (flags & DUMP_DEBUG_INFO) {
771 if (debug_info_defined) {
772 section_lineno_size += sizeof(struct rite_section_debug_header);
773 /* filename table */
774 filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) + 1);
775
776 /* filename table size */
777 section_lineno_size += sizeof(uint16_t);
778 section_lineno_size += get_filename_table_size(mrb, irep, &filenames, &filenames_len);
779
780 section_lineno_size += get_debug_record_size(mrb, irep);
781 }
782 }
783
784 if (lv_defined) {
785 section_lv_size += sizeof(struct rite_section_lv_header);
786 create_lv_sym_table(mrb, irep, &lv_syms, &lv_syms_len);
787 section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len);
788 }
789
790 malloc_size = sizeof(struct rite_binary_header) +
791 section_irep_size + section_lineno_size + section_lv_size +
792 sizeof(struct rite_binary_footer);
793 cur = *bin = (uint8_t*)mrb_malloc(mrb, malloc_size);
794 cur += sizeof(struct rite_binary_header);
795
796 result = write_section_irep(mrb, irep, cur, §ion_irep_size, flags);
797 if (result != MRB_DUMP_OK) {
798 goto error_exit;
799 }
800 cur += section_irep_size;
801 *bin_size = sizeof(struct rite_binary_header) +
802 section_irep_size + section_lineno_size + section_lv_size +
803 sizeof(struct rite_binary_footer);
804
805 /* write DEBUG section */
806 if (flags & DUMP_DEBUG_INFO) {
807 if (debug_info_defined) {
808 result = write_section_debug(mrb, irep, cur, filenames, filenames_len);
809 if (result != MRB_DUMP_OK) {
810 goto error_exit;
811 }
812 }
813 cur += section_lineno_size;
814 }
815
816 if (lv_defined) {
817 result = write_section_lv(mrb, irep, cur, lv_syms, lv_syms_len);
818 if (result != MRB_DUMP_OK) {
819 goto error_exit;
820 }
821 cur += section_lv_size;
822 }
823
824 write_footer(mrb, cur);
825 write_rite_binary_header(mrb, *bin_size, *bin, flags);
826
827 error_exit:
828 if (result != MRB_DUMP_OK) {
829 mrb_free(mrb, *bin);
830 *bin = NULL;
831 }
832 mrb_free(mrb, lv_syms);
833 mrb_free(mrb, filenames);
834 return result;
835 }
836
837 int
mrb_dump_irep(mrb_state * mrb,mrb_irep * irep,uint8_t flags,uint8_t ** bin,size_t * bin_size)838 mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
839 {
840 return dump_irep(mrb, irep, flags, bin, bin_size);
841 }
842
843 #ifndef MRB_DISABLE_STDIO
844
845 int
mrb_dump_irep_binary(mrb_state * mrb,mrb_irep * irep,uint8_t flags,FILE * fp)846 mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
847 {
848 uint8_t *bin = NULL;
849 size_t bin_size = 0;
850 int result;
851
852 if (fp == NULL) {
853 return MRB_DUMP_INVALID_ARGUMENT;
854 }
855
856 result = dump_irep(mrb, irep, flags, &bin, &bin_size);
857 if (result == MRB_DUMP_OK) {
858 if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) {
859 result = MRB_DUMP_WRITE_FAULT;
860 }
861 }
862
863 mrb_free(mrb, bin);
864 return result;
865 }
866
867 int
mrb_dump_irep_cfunc(mrb_state * mrb,mrb_irep * irep,uint8_t flags,FILE * fp,const char * initname)868 mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
869 {
870 uint8_t *bin = NULL;
871 size_t bin_size = 0, bin_idx = 0;
872 int result;
873
874 if (fp == NULL || initname == NULL || initname[0] == '\0') {
875 return MRB_DUMP_INVALID_ARGUMENT;
876 }
877 result = dump_irep(mrb, irep, flags, &bin, &bin_size);
878 if (result == MRB_DUMP_OK) {
879 if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */
880 mrb_free(mrb, bin);
881 return MRB_DUMP_WRITE_FAULT;
882 }
883 if (fprintf(fp,
884 "#ifdef __cplusplus\n"
885 "extern const uint8_t %s[];\n"
886 "#endif\n"
887 "const uint8_t\n"
888 "#if defined __GNUC__\n"
889 "__attribute__((aligned(%u)))\n"
890 "#elif defined _MSC_VER\n"
891 "__declspec(align(%u))\n"
892 "#endif\n"
893 "%s[] = {",
894 initname,
895 (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) {
896 mrb_free(mrb, bin);
897 return MRB_DUMP_WRITE_FAULT;
898 }
899 while (bin_idx < bin_size) {
900 if (bin_idx % 16 == 0) {
901 if (fputs("\n", fp) == EOF) {
902 mrb_free(mrb, bin);
903 return MRB_DUMP_WRITE_FAULT;
904 }
905 }
906 if (fprintf(fp, "0x%02x,", bin[bin_idx++]) < 0) {
907 mrb_free(mrb, bin);
908 return MRB_DUMP_WRITE_FAULT;
909 }
910 }
911 if (fputs("\n};\n", fp) == EOF) {
912 mrb_free(mrb, bin);
913 return MRB_DUMP_WRITE_FAULT;
914 }
915 }
916
917 mrb_free(mrb, bin);
918 return result;
919 }
920
921 #endif /* MRB_DISABLE_STDIO */
922