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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt