• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/program.c

  1 /*
  2  * Copyright (C) 2022 Jo-Philipp Wich <jo@mein.io>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 #include <assert.h>
 18 #include <errno.h>
 19 
 20 #include "ucode/program.h"
 21 #include "ucode/source.h"
 22 #include "ucode/vallist.h"
 23 #include "ucode/chunk.h"
 24 #include "ucode/vm.h"
 25 #include "ucode/platform.h"
 26 
 27 
 28 uc_program_t *
 29 uc_program_new(void)
 30 {
 31         uc_program_t *prog;
 32 
 33         prog = xalloc(sizeof(*prog));
 34 
 35         prog->header.type = UC_PROGRAM;
 36         prog->header.refcount = 1;
 37 
 38         prog->functions.next = &prog->functions;
 39         prog->functions.prev = &prog->functions;
 40 
 41         uc_vallist_init(&prog->constants);
 42 
 43         return prog;
 44 }
 45 
 46 uc_function_t *
 47 uc_program_function_new(uc_program_t *prog, const char *name, uc_source_t *source, size_t srcpos)
 48 {
 49         uc_function_t *func;
 50         size_t namelen = 0;
 51 
 52         if (name)
 53                 namelen = strlen(name);
 54 
 55         func = xalloc(sizeof(*func) + namelen + 1);
 56 
 57         if (name)
 58                 strcpy(func->name, name);
 59 
 60         for (func->srcidx = 0; func->srcidx < prog->sources.count; func->srcidx++)
 61                 if (prog->sources.entries[func->srcidx] == source)
 62                         break;
 63 
 64         if (func->srcidx >= prog->sources.count)
 65                 uc_vector_push(&prog->sources, uc_source_get(source));
 66 
 67         func->nargs = 0;
 68         func->nupvals = 0;
 69         func->srcpos = srcpos;
 70         func->program = prog;
 71         func->vararg = false;
 72 
 73         uc_chunk_init(&func->chunk);
 74         ucv_ref(&prog->functions, &func->progref);
 75 
 76         return func;
 77 }
 78 
 79 size_t
 80 uc_program_function_id(uc_program_t *prog, uc_function_t *func)
 81 {
 82         size_t i = 1;
 83 
 84         uc_program_function_foreach(prog, fn) {
 85                 if (fn == func)
 86                         return i;
 87 
 88                 i++;
 89         }
 90 
 91         return 0;
 92 }
 93 
 94 uc_function_t *
 95 uc_program_function_load(uc_program_t *prog, size_t id)
 96 {
 97         size_t i = 1;
 98 
 99         uc_program_function_foreach(prog, fn)
100                 if (i++ == id)
101                         return fn;
102 
103         return NULL;
104 }
105 
106 uc_source_t *
107 uc_program_function_source(uc_function_t *fn)
108 {
109         assert(fn->srcidx < fn->program->sources.count);
110 
111         return fn->program->sources.entries[fn->srcidx];
112 }
113 
114 size_t
115 uc_program_function_srcpos(uc_function_t *fn, size_t off)
116 {
117         if (!fn)
118                 return 0;
119 
120         return fn->srcpos + uc_chunk_debug_get_srcpos(&fn->chunk, off);
121 }
122 
123 void
124 uc_program_function_free(uc_function_t *func)
125 {
126         if (!func)
127                 return;
128 
129         ucv_unref(&func->progref);
130         uc_chunk_free(&func->chunk);
131         free(func);
132 }
133 
134 uc_value_t *
135 uc_program_get_constant(uc_program_t *prog, size_t idx)
136 {
137         return uc_vallist_get(&prog->constants, idx);
138 }
139 
140 ssize_t
141 uc_program_add_constant(uc_program_t *prog, uc_value_t *val)
142 {
143         return uc_vallist_add(&prog->constants, val);
144 }
145 
146 static void
147 write_u16(size_t value, FILE *file)
148 {
149         uint16_t n;
150 
151         if (sizeof(value) > sizeof(n))
152                 assert(value <= UINT16_MAX);
153 
154         n = htobe16((uint16_t)value);
155 
156         fwrite(&n, 1, sizeof(n), file);
157 }
158 
159 static void
160 write_u32(size_t value, FILE *file)
161 {
162         uint32_t n;
163 
164         if (sizeof(value) > sizeof(n))
165                 assert(value <= UINT32_MAX);
166 
167         n = htobe32((uint32_t)value);
168 
169         fwrite(&n, 1, sizeof(n), file);
170 }
171 
172 static void
173 write_u64(uint64_t value, FILE *file)
174 {
175         uint64_t n;
176 
177         if (sizeof(value) > sizeof(n))
178                 assert(value <= UINT64_MAX);
179 
180         n = htobe64((uint64_t)value);
181 
182         fwrite(&n, 1, sizeof(n), file);
183 }
184 
185 static void
186 _write_vector(size_t count, size_t itemsize, void *data, FILE *file)
187 {
188         size_t pad = (~(count * itemsize) + 1) & (sizeof(uint32_t) - 1);
189         char z[sizeof(uint32_t) - 1] = { 0 };
190 
191         write_u32(count, file);
192         fwrite(data, itemsize, count, file);
193         fwrite(z, 1, pad, file);
194 }
195 
196 #define write_vector(vec, file) \
197         _write_vector((vec)->count, sizeof((vec)->entries[0]), (vec)->entries, file)
198 
199 #define write_string(str, file) \
200         _write_vector(strlen(str) + 1, 1, str, file)
201 
202 static void
203 write_vallist(uc_value_list_t *vallist, FILE *file)
204 {
205         size_t i;
206 
207         /* write index */
208         write_u32(vallist->isize, file);
209 
210         for (i = 0; i < vallist->isize; i++)
211                 write_u64(vallist->index[i], file);
212 
213         /* write data */
214         write_u32(vallist->dsize, file);
215         fwrite(vallist->data, 1, vallist->dsize, file);
216 }
217 
218 enum {
219         UC_PROGRAM_F_DEBUG      = (1 << 0),
220         UC_PROGRAM_F_SOURCEINFO = (1 << 1),
221         UC_PROGRAM_F_SOURCEBUF  = (1 << 2),
222         UC_PROGRAM_F_EXPORTS    = (1 << 3),
223 };
224 
225 enum {
226         UC_FUNCTION_F_IS_ARROW       = (1 << 0),
227         UC_FUNCTION_F_IS_VARARG      = (1 << 1),
228         UC_FUNCTION_F_IS_STRICT      = (1 << 2),
229         UC_FUNCTION_F_HAS_EXCEPTIONS = (1 << 3),
230         UC_FUNCTION_F_HAS_NAME       = (1 << 4),
231         UC_FUNCTION_F_HAS_VARDBG     = (1 << 5),
232         UC_FUNCTION_F_HAS_OFFSETDBG  = (1 << 6),
233         UC_FUNCTION_F_IS_MODULE      = (1 << 7),
234 };
235 
236 static void
237 write_chunk(uc_chunk_t *chunk, FILE *file, uint32_t flags)
238 {
239         size_t i, slot;
240 
241         /* write bytecode data */
242         write_vector(chunk, file);
243 
244         /* write exception ranges */
245         if (flags & UC_FUNCTION_F_HAS_EXCEPTIONS) {
246                 write_u32(chunk->ehranges.count, file);
247 
248                 for (i = 0; i < chunk->ehranges.count; i++) {
249                         write_u32(chunk->ehranges.entries[i].from,   file);
250                         write_u32(chunk->ehranges.entries[i].to,     file);
251                         write_u32(chunk->ehranges.entries[i].target, file);
252                         write_u32(chunk->ehranges.entries[i].slot,   file);
253                 }
254         }
255 
256         /* write variable info */
257         if (flags & UC_FUNCTION_F_HAS_VARDBG) {
258                 write_u32(chunk->debuginfo.variables.count, file);
259 
260                 for (i = 0; i < chunk->debuginfo.variables.count; i++) {
261                         slot = chunk->debuginfo.variables.entries[i].slot;
262 
263                         if (slot >= ((size_t)-1 / 2))
264                                 slot = ((uint32_t)-1 / 2) + (slot - ((size_t)-1 / 2));
265 
266                         write_u32(chunk->debuginfo.variables.entries[i].from,    file);
267                         write_u32(chunk->debuginfo.variables.entries[i].to,      file);
268                         write_u32(slot,                                          file);
269                         write_u32(chunk->debuginfo.variables.entries[i].nameidx, file);
270                 }
271 
272                 write_vallist(&chunk->debuginfo.varnames, file);
273         }
274 
275         /* write offset info */
276         if (flags & UC_FUNCTION_F_HAS_OFFSETDBG)
277                 write_vector(&chunk->debuginfo.offsets, file);
278 }
279 
280 static void
281 write_function(uc_function_t *func, FILE *file, bool debug)
282 {
283         uint32_t flags = 0;
284 
285         if (func->arrow)
286                 flags |= UC_FUNCTION_F_IS_ARROW;
287 
288         if (func->vararg)
289                 flags |= UC_FUNCTION_F_IS_VARARG;
290 
291         if (func->strict)
292                 flags |= UC_FUNCTION_F_IS_STRICT;
293 
294         if (func->module)
295                 flags |= UC_FUNCTION_F_IS_MODULE;
296 
297         if (func->chunk.ehranges.count)
298                 flags |= UC_FUNCTION_F_HAS_EXCEPTIONS;
299 
300         if (debug && func->name[0])
301                 flags |= UC_FUNCTION_F_HAS_NAME;
302 
303         if (debug && func->chunk.debuginfo.variables.count)
304                 flags |= UC_FUNCTION_F_HAS_VARDBG;
305 
306         if (debug && func->chunk.debuginfo.offsets.count)
307                 flags |= UC_FUNCTION_F_HAS_OFFSETDBG;
308 
309         write_u32(flags, file);
310 
311         if (flags & UC_FUNCTION_F_HAS_NAME)
312                 write_string(func->name, file);
313 
314         write_u16(func->nargs, file);
315         write_u16(func->nupvals, file);
316         write_u32(func->srcidx, file);
317         write_u32(func->srcpos, file);
318 
319         write_chunk(&func->chunk, file, flags);
320 }
321 
322 static bool
323 write_exports(FILE *file, uc_source_t *source, uint32_t flags, const char *subj)
324 {
325         size_t i, num_exports = source->exports.count - 1;
326         uc_value_t *sym;
327 
328         if (flags & UC_PROGRAM_F_EXPORTS)
329         {
330                 /* write export count */
331                 write_u32(num_exports, file);
332 
333                 /* write each export name */
334                 for (i = 1; i <= num_exports; i++)
335                 {
336                         sym = source->exports.entries[i];
337 
338                         if (ucv_type(sym) == UC_STRING)
339                                 _write_vector(ucv_string_length(sym) + 1, 1,
340                                               ucv_string_get(sym), file);
341                         else if (ucv_type(sym) == UC_NULL)
342                                 write_u32(0xffffffff, file);
343                         else
344                                 assert(0);
345                 }
346         }
347 
348         return true;
349 }
350 
351 void
352 uc_program_write(uc_program_t *prog, FILE *file, bool debug)
353 {
354         uint32_t flags = (UCODE_BYTECODE_VERSION & 0xff) << 24;
355         size_t i = 0;
356 
357         if (debug)
358                 flags |= UC_PROGRAM_F_DEBUG;
359 
360         if (debug && prog->sources.count)
361                 flags |= UC_PROGRAM_F_SOURCEINFO;
362 
363         if (prog->sources.count && prog->sources.entries[0]->exports.count)
364                 flags |= UC_PROGRAM_F_EXPORTS;
365 
366         /* magic word + flags */
367         write_u32(UC_PRECOMPILED_BYTECODE_MAGIC, file);
368         write_u32(flags, file);
369 
370         /* write source information */
371         if (flags & UC_PROGRAM_F_SOURCEINFO) {
372                 write_u32(prog->sources.count, file);
373 
374                 for (i = 0; i < prog->sources.count; i++) {
375                         /* write source file name */
376                         write_string(prog->sources.entries[i]->filename, file);
377 
378                         /* include source buffer if program was compiled from stdin */
379                         if (prog->sources.entries[i]->buffer)
380                                 write_string(prog->sources.entries[i]->buffer, file);
381                         else
382                                 //write_string("", file);
383                                 write_u32(0, file);
384 
385                         /* write lineinfo data */
386                         write_vector(&prog->sources.entries[i]->lineinfo, file);
387                 }
388         }
389 
390         /* write constants */
391         write_vallist(&prog->constants, file);
392 
393         /* write export symbols */
394         write_exports(file, prog->sources.entries[0], flags, "exports");
395 
396         /* write program sections */
397         i = 0;
398         uc_program_function_foreach(prog, fn1) {
399                 (void)fn1;
400                 i++;
401         }
402 
403         write_u32(i, file);
404 
405         uc_program_function_foreach(prog, fn2)
406                 write_function(fn2, file, debug);
407 }
408 
409 static bool
410 read_error(FILE *file, char **errp, const char *subject, size_t rlen, size_t len)
411 {
412         const char *reason;
413 
414         if (feof(file))
415                 reason = "Premature EOF";
416         else
417                 reason = strerror(errno);
418 
419         if (errp)
420                 xasprintf(errp,
421                           "%s while reading %s at offset %ld, got %zu of %zu bytes\n",
422                           reason, subject, ftell(file) - rlen, rlen, len);
423 
424         return false;
425 }
426 
427 static bool
428 skip_padding(FILE *file, size_t len, char **errp)
429 {
430         size_t pad = (~len + 1) & (sizeof(uint32_t) - 1), rlen;
431         char buf[sizeof(uint32_t) - 1];
432 
433         if (pad != 0) {
434                 rlen = fread(buf, 1, pad, file);
435 
436                 if (rlen != pad)
437                         return read_error(file, errp, "padding", rlen, pad);
438         }
439 
440         return true;
441 }
442 
443 static bool
444 read_u32(FILE *file, uint32_t *n, const char *subj, char **errp)
445 {
446         size_t rlen = fread(n, 1, sizeof(*n), file);
447 
448         if (rlen != sizeof(*n)) {
449                 *n = 0;
450 
451                 return read_error(file, errp, subj ? subj : "uint32_t", rlen, sizeof(*n));
452         }
453 
454         *n = be32toh(*n);
455 
456         return true;
457 }
458 
459 static bool
460 read_u64(FILE *file, uint64_t *n, const char *subj, char **errp)
461 {
462         size_t rlen = fread(n, 1, sizeof(*n), file);
463 
464         if (rlen != sizeof(*n)) {
465                 *n = 0;
466 
467                 return read_error(file, errp, subj ? subj : "uint64_t", rlen, sizeof(*n));
468         }
469 
470         *n = be64toh(*n);
471 
472         return true;
473 }
474 
475 static bool
476 read_size_t(FILE *file, size_t *n, size_t size, const char *subj, char **errp)
477 {
478         union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; } nval;
479         size_t rlen;
480 
481         rlen = fread(&nval.u64, 1, size, file);
482 
483         if (rlen != size) {
484                 *n = 0;
485 
486                 if (!subj) {
487                         switch (size) {
488                         case 1: subj = "uint8_t";  break;
489                         case 2: subj = "uint16_t"; break;
490                         case 4: subj = "uint32_t"; break;
491                         case 8: subj = "uint64_t"; break;
492                         }
493                 }
494 
495                 return read_error(file, errp, subj, rlen, sizeof(nval));
496         }
497 
498         switch (size) {
499         case 1: *n = (size_t)        nval.u8;   break;
500         case 2: *n = (size_t)be16toh(nval.u16); break;
501         case 4: *n = (size_t)be32toh(nval.u32); break;
502         case 8: *n = (size_t)be64toh(nval.u64); break;
503         }
504 
505         return true;
506 }
507 
508 static bool
509 _read_vector(FILE *file, void *ptr, size_t itemsize, const char *subj, char **errp)
510 {
511         struct { size_t count; void *data; } *vec = ptr;
512         size_t rlen, len;
513         char subjbuf[64];
514 
515         snprintf(subjbuf, sizeof(subjbuf), "%s vector size", subj);
516 
517         if (!read_size_t(file, &vec->count, sizeof(uint32_t), subjbuf, errp))
518                 return false;
519 
520         vec->data = xcalloc(vec->count, itemsize);
521 
522         len = vec->count;
523         rlen = fread(vec->data, itemsize, len, file);
524 
525         if (rlen != len) {
526                 free(vec->data);
527 
528                 vec->count = 0;
529                 vec->data = NULL;
530 
531                 snprintf(subjbuf, sizeof(subjbuf), "%s vector data", subj);
532 
533                 return read_error(file, errp, subjbuf, rlen * itemsize, len * itemsize);
534         }
535 
536         return skip_padding(file, vec->count * itemsize, errp);
537 }
538 
539 #define read_vector(file, vec, subj, errp) \
540         _read_vector(file, vec, sizeof((vec)->entries[0]), subj, errp)
541 
542 static bool
543 read_string(FILE *file, char *dst, size_t len, const char *subj, char **errp)
544 {
545         size_t rlen;
546 
547         rlen = fread(dst, 1, len, file);
548 
549         if (rlen != len)
550                 return read_error(file, errp, subj, rlen, len);
551 
552         return skip_padding(file, len, errp);
553 }
554 
555 static bool
556 read_vallist(FILE *file, uc_value_list_t *vallist, const char *subj, char **errp)
557 {
558         char subjbuf[64];
559         size_t i;
560 
561         /* read index */
562         snprintf(subjbuf, sizeof(subjbuf), "%s index size", subj);
563 
564         if (!read_size_t(file, &vallist->isize, sizeof(uint32_t), subjbuf, errp))
565                 goto out;
566 
567         vallist->index = xcalloc(sizeof(vallist->index[0]), vallist->isize);
568 
569         for (i = 0; i < vallist->isize; i++) {
570                 snprintf(subjbuf, sizeof(subjbuf), "%s index entry %zu of %zu", subj, i, vallist->isize);
571 
572                 if (!read_u64(file, &vallist->index[i], subjbuf, errp))
573                         goto out;
574         }
575 
576         /* read data */
577         snprintf(subjbuf, sizeof(subjbuf), "%s data size", subj);
578 
579         if (!read_size_t(file, &vallist->dsize, sizeof(uint32_t), subjbuf, errp))
580                 goto out;
581 
582         vallist->data = xalloc(vallist->dsize);
583 
584         snprintf(subjbuf, sizeof(subjbuf), "%s data", subj);
585 
586         if (!read_string(file, vallist->data, vallist->dsize, subj, errp))
587                 goto out;
588 
589         return true;
590 
591 out:
592         free(vallist->index);
593         free(vallist->data);
594 
595         vallist->isize = 0;
596         vallist->index = NULL;
597 
598         vallist->dsize = 0;
599         vallist->data = NULL;
600 
601         return false;
602 }
603 
604 static bool
605 read_exports(FILE *file, uc_source_t *source, uint32_t flags, const char *subj, char **errp)
606 {
607         size_t i, num_exports, len;
608         uc_stringbuf_t *buf;
609         uc_value_t *symname;
610         char subjbuf[64];
611 
612         if (flags & UC_PROGRAM_F_EXPORTS)
613         {
614                 /* read export count */
615                 snprintf(subjbuf, sizeof(subjbuf), "%s count", subj);
616 
617                 if (!read_size_t(file, &num_exports, sizeof(uint32_t), subjbuf, errp))
618                         return false;
619 
620                 /* read export symbol names */
621                 for (i = 0; i < num_exports; i++)
622                 {
623                         snprintf(subjbuf, sizeof(subjbuf), "%s entry %zu of %zu size",
624                                          subj, i, num_exports);
625 
626                         if (!read_size_t(file, &len, sizeof(uint32_t), subjbuf, errp))
627                                 return false;
628 
629                         if (len < 0xffffffff) {
630                                 snprintf(subjbuf, sizeof(subjbuf), "%s entry %zu of %zu name",
631                                                 subj, i, num_exports);
632 
633                                 buf = ucv_stringbuf_new();
634                                 printbuf_memset(buf, -1, 0, len + 1);
635 
636                                 if (!read_string(file, buf->buf + buf->bpos - len - 1, len, subjbuf, errp))
637                                 {
638                                         printbuf_free(buf);
639                                         return false;
640                                 }
641 
642                                 symname = ucv_stringbuf_finish(buf);
643                         }
644                         else {
645                                 symname = NULL;
646                         }
647 
648                         uc_source_export_add(source, symname);
649                         ucv_put(symname);
650                 }
651         }
652 
653         return true;
654 }
655 
656 static uc_source_t *
657 read_sourceinfo(uc_source_t *input, uint32_t flags, char **errp, uc_program_t *program)
658 {
659         char *path = NULL, *code = NULL;
660         uc_source_t *source = NULL;
661         size_t len, count;
662 
663         if (flags & UC_PROGRAM_F_SOURCEINFO) {
664                 if (!read_size_t(input->fp, &count, sizeof(uint32_t), "amount of source entries", errp))
665                         return NULL;
666 
667                 while (count > 0) {
668                         if (!read_size_t(input->fp, &len, sizeof(uint32_t), "sourceinfo filename length", errp))
669                                 return NULL;
670 
671                         path = xalloc(len);
672 
673                         if (!read_string(input->fp, path, len, "sourceinfo filename", errp)) {
674                                 free(path);
675 
676                                 return NULL;
677                         }
678 
679                         if (!read_size_t(input->fp, &len, sizeof(uint32_t), "sourceinfo code buffer length", errp)) {
680                                 free(path);
681 
682                                 return NULL;
683                         }
684 
685                         if (len > 0) {
686                                 code = xalloc(len);
687 
688                                 if (!read_string(input->fp, code, len, "sourceinfo code buffer data", errp)) {
689                                         free(code);
690                                         free(path);
691 
692                                         return NULL;
693                                 }
694 
695                                 source = uc_source_new_buffer(path, code, len);
696                         }
697                         else {
698                                 source = uc_source_new_file(path);
699 
700                                 if (!source) {
701                                         fprintf(stderr, "Unable to open source file %s: %s\n", path, strerror(errno));
702                                         source = uc_source_new_buffer(path, xstrdup(""), 0);
703                                 }
704                         }
705 
706                         if (!read_vector(input->fp, &source->lineinfo, "sourceinfo lineinfo", errp)) {
707                                 uc_source_put(source);
708                                 free(path);
709 
710                                 return NULL;
711                         }
712 
713                         uc_source_runpath_set(source, input->runpath);
714                         uc_vector_push(&program->sources, source);
715 
716                         free(path);
717 
718                         count--;
719                 }
720         }
721         else {
722                 source = uc_source_new_buffer("[no source]", xstrdup(""), 0);
723 
724                 uc_source_runpath_set(source, input->runpath);
725                 uc_vector_push(&program->sources, source);
726         }
727 
728         return source;
729 }
730 
731 static bool
732 read_chunk(FILE *file, uc_chunk_t *chunk, uint32_t flags, const char *subj, char **errp)
733 {
734         uc_varrange_t *varrange;
735         uc_ehrange_t *ehrange;
736         char subjbuf[192];
737         size_t i;
738 
739         /* read bytecode data */
740         snprintf(subjbuf, sizeof(subjbuf), "%s byte code", subj);
741 
742         if (!read_vector(file, chunk, subjbuf, errp))
743                 goto out;
744 
745         /* read exception ranges */
746         if (flags & UC_FUNCTION_F_HAS_EXCEPTIONS) {
747                 snprintf(subjbuf, sizeof(subjbuf), "%s exception ranges count", subj);
748 
749                 if (!read_size_t(file, &chunk->ehranges.count, sizeof(uint32_t), subjbuf, errp))
750                         goto out;
751 
752                 chunk->ehranges.entries = xcalloc(
753                         sizeof(chunk->ehranges.entries[0]),
754                         chunk->ehranges.count);
755 
756                 for (i = 0; i < chunk->ehranges.count; i++) {
757                         snprintf(subjbuf, sizeof(subjbuf), "%s exception range %zu of %zu offset",
758                                 subj, i, chunk->ehranges.count);
759 
760                         ehrange = &chunk->ehranges.entries[i];
761 
762                         if (!read_size_t(file, &ehrange->from,   sizeof(uint32_t), subjbuf, errp) ||
763                             !read_size_t(file, &ehrange->to,     sizeof(uint32_t), subjbuf, errp) ||
764                             !read_size_t(file, &ehrange->target, sizeof(uint32_t), subjbuf, errp) ||
765                             !read_size_t(file, &ehrange->slot,   sizeof(uint32_t), subjbuf, errp))
766                                 goto out;
767                 }
768         }
769 
770         /* read variable info */
771         if (flags & UC_FUNCTION_F_HAS_VARDBG) {
772                 snprintf(subjbuf, sizeof(subjbuf), "%s variable scopes count", subj);
773 
774                 if (!read_size_t(file, &chunk->debuginfo.variables.count, sizeof(uint32_t), subjbuf, errp))
775                         goto out;
776 
777                 chunk->debuginfo.variables.entries = xcalloc(
778                         sizeof(chunk->debuginfo.variables.entries[0]),
779                         chunk->debuginfo.variables.count);
780 
781                 for (i = 0; i < chunk->debuginfo.variables.count; i++) {
782                         snprintf(subjbuf, sizeof(subjbuf), "%s variable scope %zu of %zu offset",
783                                 subj, i, chunk->debuginfo.variables.count);
784 
785                         varrange = &chunk->debuginfo.variables.entries[i];
786 
787                         if (!read_size_t(file, &varrange->from,    sizeof(uint32_t), subjbuf, errp) ||
788                             !read_size_t(file, &varrange->to,      sizeof(uint32_t), subjbuf, errp) ||
789                             !read_size_t(file, &varrange->slot,    sizeof(uint32_t), subjbuf, errp) ||
790                             !read_size_t(file, &varrange->nameidx, sizeof(uint32_t), subjbuf, errp))
791                             goto out;
792 
793                         if (varrange->slot >= ((uint32_t)-1 / 2))
794                                 varrange->slot = ((size_t)-1 / 2) + (varrange->slot - ((uint32_t)-1 / 2));
795                 }
796 
797                 snprintf(subjbuf, sizeof(subjbuf), "%s variable names", subj);
798 
799                 if (!read_vallist(file, &chunk->debuginfo.varnames, subjbuf, errp))
800                         goto out;
801         }
802 
803         /* read offset info */
804         if (flags & UC_FUNCTION_F_HAS_OFFSETDBG) {
805                 snprintf(subjbuf, sizeof(subjbuf), "%s source offsets", subj);
806 
807                 if (!read_vector(file, &chunk->debuginfo.offsets, subjbuf, errp))
808                         goto out;
809         }
810 
811         return true;
812 
813 out:
814         uc_vallist_free(&chunk->debuginfo.varnames);
815 
816         free(chunk->entries);
817         free(chunk->ehranges.entries);
818         free(chunk->debuginfo.variables.entries);
819 
820         chunk->count = 0;
821         chunk->entries = NULL;
822 
823         chunk->ehranges.count = 0;
824         chunk->ehranges.entries = NULL;
825 
826         chunk->debuginfo.variables.count = 0;
827         chunk->debuginfo.variables.entries = NULL;
828 
829         return false;
830 }
831 
832 static bool
833 read_function(FILE *file, uc_program_t *program, size_t idx, char **errp)
834 {
835         size_t nargs, nupvals, srcidx, srcpos;
836         char subjbuf[64], *name = NULL;
837         uc_function_t *func = NULL;
838         uc_source_t *source;
839         uint32_t flags, u32;
840 
841         snprintf(subjbuf, sizeof(subjbuf), "function #%zu flags", idx);
842 
843         if (!read_u32(file, &flags, subjbuf, errp))
844                 goto out;
845 
846         if (flags & UC_FUNCTION_F_HAS_NAME) {
847                 snprintf(subjbuf, sizeof(subjbuf), "function #%zu name length", idx);
848 
849                 if (!read_u32(file, &u32, subjbuf, errp))
850                         goto out;
851 
852                 name = xalloc(u32);
853 
854                 snprintf(subjbuf, sizeof(subjbuf), "function #%zu name", idx);
855 
856                 if (!read_string(file, name, u32, subjbuf, errp))
857                         goto out;
858         }
859 
860         snprintf(subjbuf, sizeof(subjbuf), "function #%zu (%s) arg count and offset", idx, name ? name : "-");
861 
862         if (!read_size_t(file, &nargs,   sizeof(uint16_t), subjbuf, errp) ||
863             !read_size_t(file, &nupvals, sizeof(uint16_t), subjbuf, errp) ||
864             !read_size_t(file, &srcidx,  sizeof(uint32_t), subjbuf, errp) ||
865             !read_size_t(file, &srcpos,  sizeof(uint32_t), subjbuf, errp)) {
866                 goto out;
867         }
868 
869         // FIXME
870         if (srcidx < program->sources.count)
871                 source = program->sources.entries[srcidx];
872         else
873                 source = program->sources.entries[0];
874 
875         func = (uc_function_t *)uc_program_function_new(program, name, source, srcpos);
876         func->arrow   = (flags & UC_FUNCTION_F_IS_ARROW);
877         func->vararg  = (flags & UC_FUNCTION_F_IS_VARARG);
878         func->strict  = (flags & UC_FUNCTION_F_IS_STRICT);
879         func->module  = (flags & UC_FUNCTION_F_IS_MODULE);
880         func->nargs   = nargs;
881         func->nupvals = nupvals;
882 
883         snprintf(subjbuf, sizeof(subjbuf), "function #%zu (%s) body", idx, name ? name : "-");
884 
885         if (!read_chunk(file, &func->chunk, flags, subjbuf, errp))
886                 goto out;
887 
888         free(name);
889 
890         return true;
891 
892 out:
893         free(name);
894 
895         return false;
896 }
897 
898 uc_program_t *
899 uc_program_load(uc_source_t *input, char **errp)
900 {
901         uc_program_t *program = NULL;
902         uint32_t flags, nfuncs, i;
903 
904         if (!read_u32(input->fp, &i, "file magic", errp))
905                 goto out;
906 
907         if (i != UC_PRECOMPILED_BYTECODE_MAGIC) {
908                 xasprintf(errp, "Invalid file magic\n");
909                 goto out;
910         }
911 
912         if (!read_u32(input->fp, &flags, "program flags", errp))
913                 goto out;
914 
915         if ((flags >> 24) != UCODE_BYTECODE_VERSION) {
916                 xasprintf(errp, 
917                         "Bytecode version mismatch, got 0x%02x, expected 0x%02x\n",
918                         flags >> 24, UCODE_BYTECODE_VERSION);
919                 goto out;
920         }
921 
922         program = uc_program_new();
923 
924         if (!read_sourceinfo(input, flags, errp, program))
925                 goto out;
926 
927         if (!read_vallist(input->fp, &program->constants, "constants", errp))
928                 goto out;
929 
930         if (!read_exports(input->fp, program->sources.entries[0], flags,
931                                           "exports", errp))
932                 goto out;
933 
934         if (!read_u32(input->fp, &nfuncs, "function count", errp))
935                 goto out;
936 
937         for (i = 0; i < nfuncs; i++)
938                 if (!read_function(input->fp, program, i, errp))
939                         goto out;
940 
941         return program;
942 
943 out:
944         uc_program_put(program);
945 
946         return NULL;
947 }
948 
949 uc_function_t *
950 uc_program_entry(uc_program_t *program)
951 {
952         if (program->functions.prev == &program->functions)
953                 return NULL;
954 
955         return (uc_function_t *)program->functions.prev;
956 }
957 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt