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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt