• 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 };
223 
224 enum {
225         UC_FUNCTION_F_IS_ARROW       = (1 << 0),
226         UC_FUNCTION_F_IS_VARARG      = (1 << 1),
227         UC_FUNCTION_F_IS_STRICT      = (1 << 2),
228         UC_FUNCTION_F_HAS_EXCEPTIONS = (1 << 3),
229         UC_FUNCTION_F_HAS_NAME       = (1 << 4),
230         UC_FUNCTION_F_HAS_VARDBG     = (1 << 5),
231         UC_FUNCTION_F_HAS_OFFSETDBG  = (1 << 6),
232         UC_FUNCTION_F_IS_MODULE      = (1 << 7),
233 };
234 
235 static void
236 write_chunk(uc_chunk_t *chunk, FILE *file, uint32_t flags)
237 {
238         size_t i, slot;
239 
240         /* write bytecode data */
241         write_vector(chunk, file);
242 
243         /* write exception ranges */
244         if (flags & UC_FUNCTION_F_HAS_EXCEPTIONS) {
245                 write_u32(chunk->ehranges.count, file);
246 
247                 for (i = 0; i < chunk->ehranges.count; i++) {
248                         write_u32(chunk->ehranges.entries[i].from,   file);
249                         write_u32(chunk->ehranges.entries[i].to,     file);
250                         write_u32(chunk->ehranges.entries[i].target, file);
251                         write_u32(chunk->ehranges.entries[i].slot,   file);
252                 }
253         }
254 
255         /* write variable info */
256         if (flags & UC_FUNCTION_F_HAS_VARDBG) {
257                 write_u32(chunk->debuginfo.variables.count, file);
258 
259                 for (i = 0; i < chunk->debuginfo.variables.count; i++) {
260                         slot = chunk->debuginfo.variables.entries[i].slot;
261 
262                         if (slot >= ((size_t)-1 / 2))
263                                 slot = ((uint32_t)-1 / 2) + (slot - ((size_t)-1 / 2));
264 
265                         write_u32(chunk->debuginfo.variables.entries[i].from,    file);
266                         write_u32(chunk->debuginfo.variables.entries[i].to,      file);
267                         write_u32(slot,                                          file);
268                         write_u32(chunk->debuginfo.variables.entries[i].nameidx, file);
269                 }
270 
271                 write_vallist(&chunk->debuginfo.varnames, file);
272         }
273 
274         /* write offset info */
275         if (flags & UC_FUNCTION_F_HAS_OFFSETDBG)
276                 write_vector(&chunk->debuginfo.offsets, file);
277 }
278 
279 static void
280 write_function(uc_function_t *func, FILE *file, bool debug)
281 {
282         uint32_t flags = 0;
283 
284         if (func->arrow)
285                 flags |= UC_FUNCTION_F_IS_ARROW;
286 
287         if (func->vararg)
288                 flags |= UC_FUNCTION_F_IS_VARARG;
289 
290         if (func->strict)
291                 flags |= UC_FUNCTION_F_IS_STRICT;
292 
293         if (func->module)
294                 flags |= UC_FUNCTION_F_IS_MODULE;
295 
296         if (func->chunk.ehranges.count)
297                 flags |= UC_FUNCTION_F_HAS_EXCEPTIONS;
298 
299         if (debug && func->name[0])
300                 flags |= UC_FUNCTION_F_HAS_NAME;
301 
302         if (debug && func->chunk.debuginfo.variables.count)
303                 flags |= UC_FUNCTION_F_HAS_VARDBG;
304 
305         if (debug && func->chunk.debuginfo.offsets.count)
306                 flags |= UC_FUNCTION_F_HAS_OFFSETDBG;
307 
308         write_u32(flags, file);
309 
310         if (flags & UC_FUNCTION_F_HAS_NAME)
311                 write_string(func->name, file);
312 
313         write_u16(func->nargs, file);
314         write_u16(func->nupvals, file);
315         write_u32(func->srcidx, file);
316         write_u32(func->srcpos, file);
317 
318         write_chunk(&func->chunk, file, flags);
319 }
320 
321 void
322 uc_program_write(uc_program_t *prog, FILE *file, bool debug)
323 {
324         uint32_t flags = (UCODE_BYTECODE_VERSION & 0xff) << 24;
325         size_t i = 0;
326 
327         if (debug)
328                 flags |= UC_PROGRAM_F_DEBUG;
329 
330         if (debug && prog->sources.count)
331                 flags |= UC_PROGRAM_F_SOURCEINFO;
332 
333         /* magic word + flags */
334         write_u32(UC_PRECOMPILED_BYTECODE_MAGIC, file);
335         write_u32(flags, file);
336 
337         /* write source information */
338         if (flags & UC_PROGRAM_F_SOURCEINFO) {
339                 write_u32(prog->sources.count, file);
340 
341                 for (i = 0; i < prog->sources.count; i++) {
342                         /* write source file name */
343                         write_string(prog->sources.entries[i]->filename, file);
344 
345                         /* include source buffer if program was compiled from stdin */
346                         if (prog->sources.entries[i]->buffer)
347                                 write_string(prog->sources.entries[i]->buffer, file);
348                         else
349                                 //write_string("", file);
350                                 write_u32(0, file);
351 
352                         /* write lineinfo data */
353                         write_vector(&prog->sources.entries[i]->lineinfo, file);
354                 }
355         }
356 
357         /* write constants */
358         write_vallist(&prog->constants, file);
359 
360         /* write program sections */
361         i = 0;
362         uc_program_function_foreach(prog, fn1) {
363                 (void)fn1;
364                 i++;
365         }
366 
367         write_u32(i, file);
368 
369         uc_program_function_foreach(prog, fn2)
370                 write_function(fn2, file, debug);
371 }
372 
373 static bool
374 read_error(FILE *file, char **errp, const char *subject, size_t rlen, size_t len)
375 {
376         const char *reason;
377 
378         if (feof(file))
379                 reason = "Premature EOF";
380         else
381                 reason = strerror(errno);
382 
383         if (errp)
384                 xasprintf(errp,
385                           "%s while reading %s at offset %ld, got %zu of %zu bytes\n",
386                           reason, subject, ftell(file) - rlen, rlen, len);
387 
388         return false;
389 }
390 
391 static bool
392 skip_padding(FILE *file, size_t len, char **errp)
393 {
394         size_t pad = (~len + 1) & (sizeof(uint32_t) - 1), rlen;
395         char buf[sizeof(uint32_t) - 1];
396 
397         if (pad != 0) {
398                 rlen = fread(buf, 1, pad, file);
399 
400                 if (rlen != pad)
401                         return read_error(file, errp, "padding", rlen, pad);
402         }
403 
404         return true;
405 }
406 
407 static bool
408 read_u32(FILE *file, uint32_t *n, const char *subj, char **errp)
409 {
410         size_t rlen = fread(n, 1, sizeof(*n), file);
411 
412         if (rlen != sizeof(*n)) {
413                 *n = 0;
414 
415                 return read_error(file, errp, subj ? subj : "uint32_t", rlen, sizeof(*n));
416         }
417 
418         *n = be32toh(*n);
419 
420         return true;
421 }
422 
423 static bool
424 read_u64(FILE *file, uint64_t *n, const char *subj, char **errp)
425 {
426         size_t rlen = fread(n, 1, sizeof(*n), file);
427 
428         if (rlen != sizeof(*n)) {
429                 *n = 0;
430 
431                 return read_error(file, errp, subj ? subj : "uint64_t", rlen, sizeof(*n));
432         }
433 
434         *n = be64toh(*n);
435 
436         return true;
437 }
438 
439 static bool
440 read_size_t(FILE *file, size_t *n, size_t size, const char *subj, char **errp)
441 {
442         union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; } nval;
443         size_t rlen;
444 
445         rlen = fread(&nval.u64, 1, size, file);
446 
447         if (rlen != size) {
448                 *n = 0;
449 
450                 if (!subj) {
451                         switch (size) {
452                         case 1: subj = "uint8_t";  break;
453                         case 2: subj = "uint16_t"; break;
454                         case 4: subj = "uint32_t"; break;
455                         case 8: subj = "uint64_t"; break;
456                         }
457                 }
458 
459                 return read_error(file, errp, subj, rlen, sizeof(nval));
460         }
461 
462         switch (size) {
463         case 1: *n = (size_t)        nval.u8;   break;
464         case 2: *n = (size_t)be16toh(nval.u16); break;
465         case 4: *n = (size_t)be32toh(nval.u32); break;
466         case 8: *n = (size_t)be64toh(nval.u64); break;
467         }
468 
469         return true;
470 }
471 
472 static bool
473 _read_vector(FILE *file, void *ptr, size_t itemsize, const char *subj, char **errp)
474 {
475         struct { size_t count; void *data; } *vec = ptr;
476         size_t rlen, len;
477         char subjbuf[64];
478 
479         snprintf(subjbuf, sizeof(subjbuf), "%s vector size", subj);
480 
481         if (!read_size_t(file, &vec->count, sizeof(uint32_t), subjbuf, errp))
482                 return false;
483 
484         vec->data = xcalloc(vec->count, itemsize);
485 
486         len = vec->count;
487         rlen = fread(vec->data, itemsize, len, file);
488 
489         if (rlen != len) {
490                 free(vec->data);
491 
492                 vec->count = 0;
493                 vec->data = NULL;
494 
495                 snprintf(subjbuf, sizeof(subjbuf), "%s vector data", subj);
496 
497                 return read_error(file, errp, subjbuf, rlen * itemsize, len * itemsize);
498         }
499 
500         return skip_padding(file, vec->count * itemsize, errp);
501 }
502 
503 #define read_vector(file, vec, subj, errp) \
504         _read_vector(file, vec, sizeof((vec)->entries[0]), subj, errp)
505 
506 static bool
507 read_string(FILE *file, char *dst, size_t len, const char *subj, char **errp)
508 {
509         size_t rlen;
510 
511         rlen = fread(dst, 1, len, file);
512 
513         if (rlen != len)
514                 return read_error(file, errp, subj, rlen, len);
515 
516         return skip_padding(file, len, errp);
517 }
518 
519 static bool
520 read_vallist(FILE *file, uc_value_list_t *vallist, const char *subj, char **errp)
521 {
522         char subjbuf[64];
523         size_t i;
524 
525         /* read index */
526         snprintf(subjbuf, sizeof(subjbuf), "%s index size", subj);
527 
528         if (!read_size_t(file, &vallist->isize, sizeof(uint32_t), subjbuf, errp))
529                 goto out;
530 
531         vallist->index = xcalloc(sizeof(vallist->index[0]), vallist->isize);
532 
533         for (i = 0; i < vallist->isize; i++) {
534                 snprintf(subjbuf, sizeof(subjbuf), "%s index entry %zu of %zu", subj, i, vallist->isize);
535 
536                 if (!read_u64(file, &vallist->index[i], subjbuf, errp))
537                         goto out;
538         }
539 
540         /* read data */
541         snprintf(subjbuf, sizeof(subjbuf), "%s data size", subj);
542 
543         if (!read_size_t(file, &vallist->dsize, sizeof(uint32_t), subjbuf, errp))
544                 goto out;
545 
546         vallist->data = xalloc(vallist->dsize);
547 
548         snprintf(subjbuf, sizeof(subjbuf), "%s data", subj);
549 
550         if (!read_string(file, vallist->data, vallist->dsize, subj, errp))
551                 goto out;
552 
553         return true;
554 
555 out:
556         free(vallist->index);
557         free(vallist->data);
558 
559         vallist->isize = 0;
560         vallist->index = NULL;
561 
562         vallist->dsize = 0;
563         vallist->data = NULL;
564 
565         return false;
566 }
567 
568 static uc_source_t *
569 read_sourceinfo(uc_source_t *input, uint32_t flags, char **errp, uc_program_t *program)
570 {
571         char *path = NULL, *code = NULL;
572         uc_source_t *source = NULL;
573         size_t len, count;
574 
575         if (flags & UC_PROGRAM_F_SOURCEINFO) {
576                 if (!read_size_t(input->fp, &count, sizeof(uint32_t), "amount of source entries", errp))
577                         return NULL;
578 
579                 while (count > 0) {
580                         if (!read_size_t(input->fp, &len, sizeof(uint32_t), "sourceinfo filename length", errp))
581                                 return NULL;
582 
583                         path = xalloc(len);
584 
585                         if (!read_string(input->fp, path, len, "sourceinfo filename", errp)) {
586                                 free(path);
587 
588                                 return NULL;
589                         }
590 
591                         if (!read_size_t(input->fp, &len, sizeof(uint32_t), "sourceinfo code buffer length", errp)) {
592                                 free(path);
593 
594                                 return NULL;
595                         }
596 
597                         if (len > 0) {
598                                 code = xalloc(len);
599 
600                                 if (!read_string(input->fp, code, len, "sourceinfo code buffer data", errp)) {
601                                         free(code);
602                                         free(path);
603 
604                                         return NULL;
605                                 }
606 
607                                 source = uc_source_new_buffer(path, code, len);
608                         }
609                         else {
610                                 source = uc_source_new_file(path);
611 
612                                 if (!source) {
613                                         fprintf(stderr, "Unable to open source file %s: %s\n", path, strerror(errno));
614                                         source = uc_source_new_buffer(path, xstrdup(""), 0);
615                                 }
616                         }
617 
618                         if (!read_vector(input->fp, &source->lineinfo, "sourceinfo lineinfo", errp)) {
619                                 uc_source_put(source);
620                                 free(path);
621 
622                                 return NULL;
623                         }
624 
625                         uc_source_runpath_set(source, input->runpath);
626                         uc_vector_push(&program->sources, source);
627 
628                         free(path);
629 
630                         count--;
631                 }
632         }
633         else {
634                 source = uc_source_new_buffer("[no source]", xstrdup(""), 0);
635 
636                 uc_source_runpath_set(source, input->runpath);
637                 uc_vector_push(&program->sources, source);
638         }
639 
640         return source;
641 }
642 
643 static bool
644 read_chunk(FILE *file, uc_chunk_t *chunk, uint32_t flags, const char *subj, char **errp)
645 {
646         uc_varrange_t *varrange;
647         uc_ehrange_t *ehrange;
648         char subjbuf[192];
649         size_t i;
650 
651         /* read bytecode data */
652         snprintf(subjbuf, sizeof(subjbuf), "%s byte code", subj);
653 
654         if (!read_vector(file, chunk, subjbuf, errp))
655                 goto out;
656 
657         /* read exception ranges */
658         if (flags & UC_FUNCTION_F_HAS_EXCEPTIONS) {
659                 snprintf(subjbuf, sizeof(subjbuf), "%s exception ranges count", subj);
660 
661                 if (!read_size_t(file, &chunk->ehranges.count, sizeof(uint32_t), subjbuf, errp))
662                         goto out;
663 
664                 chunk->ehranges.entries = xcalloc(
665                         sizeof(chunk->ehranges.entries[0]),
666                         chunk->ehranges.count);
667 
668                 for (i = 0; i < chunk->ehranges.count; i++) {
669                         snprintf(subjbuf, sizeof(subjbuf), "%s exception range %zu of %zu offset",
670                                 subj, i, chunk->ehranges.count);
671 
672                         ehrange = &chunk->ehranges.entries[i];
673 
674                         if (!read_size_t(file, &ehrange->from,   sizeof(uint32_t), subjbuf, errp) ||
675                             !read_size_t(file, &ehrange->to,     sizeof(uint32_t), subjbuf, errp) ||
676                             !read_size_t(file, &ehrange->target, sizeof(uint32_t), subjbuf, errp) ||
677                             !read_size_t(file, &ehrange->slot,   sizeof(uint32_t), subjbuf, errp))
678                                 goto out;
679                 }
680         }
681 
682         /* read variable info */
683         if (flags & UC_FUNCTION_F_HAS_VARDBG) {
684                 snprintf(subjbuf, sizeof(subjbuf), "%s variable scopes count", subj);
685 
686                 if (!read_size_t(file, &chunk->debuginfo.variables.count, sizeof(uint32_t), subjbuf, errp))
687                         goto out;
688 
689                 chunk->debuginfo.variables.entries = xcalloc(
690                         sizeof(chunk->debuginfo.variables.entries[0]),
691                         chunk->debuginfo.variables.count);
692 
693                 for (i = 0; i < chunk->debuginfo.variables.count; i++) {
694                         snprintf(subjbuf, sizeof(subjbuf), "%s variable scope %zu of %zu offset",
695                                 subj, i, chunk->debuginfo.variables.count);
696 
697                         varrange = &chunk->debuginfo.variables.entries[i];
698 
699                         if (!read_size_t(file, &varrange->from,    sizeof(uint32_t), subjbuf, errp) ||
700                             !read_size_t(file, &varrange->to,      sizeof(uint32_t), subjbuf, errp) ||
701                             !read_size_t(file, &varrange->slot,    sizeof(uint32_t), subjbuf, errp) ||
702                             !read_size_t(file, &varrange->nameidx, sizeof(uint32_t), subjbuf, errp))
703                             goto out;
704 
705                         if (varrange->slot >= ((uint32_t)-1 / 2))
706                                 varrange->slot = ((size_t)-1 / 2) + (varrange->slot - ((uint32_t)-1 / 2));
707                 }
708 
709                 snprintf(subjbuf, sizeof(subjbuf), "%s variable names", subj);
710 
711                 if (!read_vallist(file, &chunk->debuginfo.varnames, subjbuf, errp))
712                         goto out;
713         }
714 
715         /* read offset info */
716         if (flags & UC_FUNCTION_F_HAS_OFFSETDBG) {
717                 snprintf(subjbuf, sizeof(subjbuf), "%s source offsets", subj);
718 
719                 if (!read_vector(file, &chunk->debuginfo.offsets, subjbuf, errp))
720                         goto out;
721         }
722 
723         return true;
724 
725 out:
726         uc_vallist_free(&chunk->debuginfo.varnames);
727 
728         free(chunk->entries);
729         free(chunk->ehranges.entries);
730         free(chunk->debuginfo.variables.entries);
731 
732         chunk->count = 0;
733         chunk->entries = NULL;
734 
735         chunk->ehranges.count = 0;
736         chunk->ehranges.entries = NULL;
737 
738         chunk->debuginfo.variables.count = 0;
739         chunk->debuginfo.variables.entries = NULL;
740 
741         return false;
742 }
743 
744 static bool
745 read_function(FILE *file, uc_program_t *program, size_t idx, char **errp)
746 {
747         size_t nargs, nupvals, srcidx, srcpos;
748         char subjbuf[64], *name = NULL;
749         uc_function_t *func = NULL;
750         uc_source_t *source;
751         uint32_t flags, u32;
752 
753         snprintf(subjbuf, sizeof(subjbuf), "function #%zu flags", idx);
754 
755         if (!read_u32(file, &flags, subjbuf, errp))
756                 goto out;
757 
758         if (flags & UC_FUNCTION_F_HAS_NAME) {
759                 snprintf(subjbuf, sizeof(subjbuf), "function #%zu name length", idx);
760 
761                 if (!read_u32(file, &u32, subjbuf, errp))
762                         goto out;
763 
764                 name = xalloc(u32);
765 
766                 snprintf(subjbuf, sizeof(subjbuf), "function #%zu name", idx);
767 
768                 if (!read_string(file, name, u32, subjbuf, errp))
769                         goto out;
770         }
771 
772         snprintf(subjbuf, sizeof(subjbuf), "function #%zu (%s) arg count and offset", idx, name ? name : "-");
773 
774         if (!read_size_t(file, &nargs,   sizeof(uint16_t), subjbuf, errp) ||
775             !read_size_t(file, &nupvals, sizeof(uint16_t), subjbuf, errp) ||
776             !read_size_t(file, &srcidx,  sizeof(uint32_t), subjbuf, errp) ||
777             !read_size_t(file, &srcpos,  sizeof(uint32_t), subjbuf, errp)) {
778                 goto out;
779         }
780 
781         // FIXME
782         if (srcidx < program->sources.count)
783                 source = program->sources.entries[srcidx];
784         else
785                 source = program->sources.entries[0];
786 
787         func = (uc_function_t *)uc_program_function_new(program, name, source, srcpos);
788         func->arrow   = (flags & UC_FUNCTION_F_IS_ARROW);
789         func->vararg  = (flags & UC_FUNCTION_F_IS_VARARG);
790         func->strict  = (flags & UC_FUNCTION_F_IS_STRICT);
791         func->module  = (flags & UC_FUNCTION_F_IS_MODULE);
792         func->nargs   = nargs;
793         func->nupvals = nupvals;
794 
795         snprintf(subjbuf, sizeof(subjbuf), "function #%zu (%s) body", idx, name ? name : "-");
796 
797         if (!read_chunk(file, &func->chunk, flags, subjbuf, errp))
798                 goto out;
799 
800         free(name);
801 
802         return true;
803 
804 out:
805         free(name);
806 
807         return false;
808 }
809 
810 uc_program_t *
811 uc_program_load(uc_source_t *input, char **errp)
812 {
813         uc_program_t *program = NULL;
814         uint32_t flags, nfuncs, i;
815 
816         if (!read_u32(input->fp, &i, "file magic", errp))
817                 goto out;
818 
819         if (i != UC_PRECOMPILED_BYTECODE_MAGIC) {
820                 xasprintf(errp, "Invalid file magic\n");
821                 goto out;
822         }
823 
824         if (!read_u32(input->fp, &flags, "program flags", errp))
825                 goto out;
826 
827         if ((flags >> 24) != UCODE_BYTECODE_VERSION) {
828                 xasprintf(errp, 
829                         "Bytecode version mismatch, got 0x%02x, expected 0x%02x\n",
830                         flags >> 24, UCODE_BYTECODE_VERSION);
831                 goto out;
832         }
833 
834         program = uc_program_new();
835 
836         if (!read_sourceinfo(input, flags, errp, program))
837                 goto out;
838 
839         if (!read_vallist(input->fp, &program->constants, "constants", errp))
840                 goto out;
841 
842         if (!read_u32(input->fp, &nfuncs, "function count", errp))
843                 goto out;
844 
845         for (i = 0; i < nfuncs; i++)
846                 if (!read_function(input->fp, program, i, errp))
847                         goto out;
848 
849         return program;
850 
851 out:
852         uc_program_put(program);
853 
854         return NULL;
855 }
856 
857 uc_function_t *
858 uc_program_entry(uc_program_t *program)
859 {
860         if (program->functions.prev == &program->functions)
861                 return NULL;
862 
863         return (uc_function_t *)program->functions.prev;
864 }
865 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt