• 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 #include <endian.h>
 20 
 21 #include "ucode/program.h"
 22 #include "ucode/source.h"
 23 #include "ucode/vallist.h"
 24 #include "ucode/chunk.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                                 return NULL;
592 
593                         if (len > 0) {
594                                 code = xalloc(len);
595 
596                                 if (!read_string(input->fp, code, len, "sourceinfo code buffer data", errp)) {
597                                         free(code);
598                                         free(path);
599 
600                                         return NULL;
601                                 }
602 
603                                 source = uc_source_new_buffer(path, code, len);
604                         }
605                         else {
606                                 source = uc_source_new_file(path);
607 
608                                 if (!source) {
609                                         fprintf(stderr, "Unable to open source file %s: %s\n", path, strerror(errno));
610                                         source = uc_source_new_buffer(path, xstrdup(""), 0);
611                                 }
612                         }
613 
614                         if (!read_vector(input->fp, &source->lineinfo, "sourceinfo lineinfo", errp)) {
615                                 uc_source_put(source);
616                                 free(path);
617 
618                                 return NULL;
619                         }
620 
621                         uc_source_runpath_set(source, input->runpath);
622                         uc_vector_push(&program->sources, source);
623 
624                         free(path);
625 
626                         count--;
627                 }
628         }
629         else {
630                 source = uc_source_new_buffer("[no source]", xstrdup(""), 0);
631 
632                 uc_source_runpath_set(source, input->runpath);
633                 uc_vector_push(&program->sources, source);
634         }
635 
636         return source;
637 }
638 
639 static bool
640 read_chunk(FILE *file, uc_chunk_t *chunk, uint32_t flags, const char *subj, char **errp)
641 {
642         uc_varrange_t *varrange;
643         uc_ehrange_t *ehrange;
644         char subjbuf[192];
645         size_t i;
646 
647         /* read bytecode data */
648         snprintf(subjbuf, sizeof(subjbuf), "%s byte code", subj);
649 
650         if (!read_vector(file, chunk, subjbuf, errp))
651                 goto out;
652 
653         /* read exception ranges */
654         if (flags & UC_FUNCTION_F_HAS_EXCEPTIONS) {
655                 snprintf(subjbuf, sizeof(subjbuf), "%s exception ranges count", subj);
656 
657                 if (!read_size_t(file, &chunk->ehranges.count, sizeof(uint32_t), subjbuf, errp))
658                         goto out;
659 
660                 chunk->ehranges.entries = xcalloc(
661                         sizeof(chunk->ehranges.entries[0]),
662                         chunk->ehranges.count);
663 
664                 for (i = 0; i < chunk->ehranges.count; i++) {
665                         snprintf(subjbuf, sizeof(subjbuf), "%s exception range %zu of %zu offset",
666                                 subj, i, chunk->ehranges.count);
667 
668                         ehrange = &chunk->ehranges.entries[i];
669 
670                         if (!read_size_t(file, &ehrange->from,   sizeof(uint32_t), subjbuf, errp) ||
671                             !read_size_t(file, &ehrange->to,     sizeof(uint32_t), subjbuf, errp) ||
672                             !read_size_t(file, &ehrange->target, sizeof(uint32_t), subjbuf, errp) ||
673                             !read_size_t(file, &ehrange->slot,   sizeof(uint32_t), subjbuf, errp))
674                                 goto out;
675                 }
676         }
677 
678         /* read variable info */
679         if (flags & UC_FUNCTION_F_HAS_VARDBG) {
680                 snprintf(subjbuf, sizeof(subjbuf), "%s variable scopes count", subj);
681 
682                 if (!read_size_t(file, &chunk->debuginfo.variables.count, sizeof(uint32_t), subjbuf, errp))
683                         goto out;
684 
685                 chunk->debuginfo.variables.entries = xcalloc(
686                         sizeof(chunk->debuginfo.variables.entries[0]),
687                         chunk->debuginfo.variables.count);
688 
689                 for (i = 0; i < chunk->debuginfo.variables.count; i++) {
690                         snprintf(subjbuf, sizeof(subjbuf), "%s variable scope %zu of %zu offset",
691                                 subj, i, chunk->debuginfo.variables.count);
692 
693                         varrange = &chunk->debuginfo.variables.entries[i];
694 
695                         if (!read_size_t(file, &varrange->from,    sizeof(uint32_t), subjbuf, errp) ||
696                             !read_size_t(file, &varrange->to,      sizeof(uint32_t), subjbuf, errp) ||
697                             !read_size_t(file, &varrange->slot,    sizeof(uint32_t), subjbuf, errp) ||
698                             !read_size_t(file, &varrange->nameidx, sizeof(uint32_t), subjbuf, errp))
699                             goto out;
700 
701                         if (varrange->slot >= ((uint32_t)-1 / 2))
702                                 varrange->slot = ((size_t)-1 / 2) + (varrange->slot - ((uint32_t)-1 / 2));
703                 }
704 
705                 snprintf(subjbuf, sizeof(subjbuf), "%s variable names", subj);
706 
707                 if (!read_vallist(file, &chunk->debuginfo.varnames, subjbuf, errp))
708                         goto out;
709         }
710 
711         /* read offset info */
712         if (flags & UC_FUNCTION_F_HAS_OFFSETDBG) {
713                 snprintf(subjbuf, sizeof(subjbuf), "%s source offsets", subj);
714 
715                 if (!read_vector(file, &chunk->debuginfo.offsets, subjbuf, errp))
716                         goto out;
717         }
718 
719         return true;
720 
721 out:
722         uc_vallist_free(&chunk->debuginfo.varnames);
723 
724         free(chunk->entries);
725         free(chunk->ehranges.entries);
726         free(chunk->debuginfo.variables.entries);
727 
728         chunk->count = 0;
729         chunk->entries = NULL;
730 
731         chunk->ehranges.count = 0;
732         chunk->ehranges.entries = NULL;
733 
734         chunk->debuginfo.variables.count = 0;
735         chunk->debuginfo.variables.entries = NULL;
736 
737         return false;
738 }
739 
740 static bool
741 read_function(FILE *file, uc_program_t *program, size_t idx, char **errp)
742 {
743         size_t nargs, nupvals, srcidx, srcpos;
744         char subjbuf[64], *name = NULL;
745         uc_function_t *func = NULL;
746         uc_source_t *source;
747         uint32_t flags, u32;
748 
749         snprintf(subjbuf, sizeof(subjbuf), "function #%zu flags", idx);
750 
751         if (!read_u32(file, &flags, subjbuf, errp))
752                 goto out;
753 
754         if (flags & UC_FUNCTION_F_HAS_NAME) {
755                 snprintf(subjbuf, sizeof(subjbuf), "function #%zu name length", idx);
756 
757                 if (!read_u32(file, &u32, subjbuf, errp))
758                         goto out;
759 
760                 name = xalloc(u32);
761 
762                 snprintf(subjbuf, sizeof(subjbuf), "function #%zu name", idx);
763 
764                 if (!read_string(file, name, u32, subjbuf, errp))
765                         goto out;
766         }
767 
768         snprintf(subjbuf, sizeof(subjbuf), "function #%zu (%s) arg count and offset", idx, name ? name : "-");
769 
770         if (!read_size_t(file, &nargs,   sizeof(uint16_t), subjbuf, errp) ||
771             !read_size_t(file, &nupvals, sizeof(uint16_t), subjbuf, errp) ||
772             !read_size_t(file, &srcidx,  sizeof(uint32_t), subjbuf, errp) ||
773             !read_size_t(file, &srcpos,  sizeof(uint32_t), subjbuf, errp)) {
774                 goto out;
775         }
776 
777         // FIXME
778         if (srcidx < program->sources.count)
779                 source = program->sources.entries[srcidx];
780         else
781                 source = program->sources.entries[0];
782 
783         func = (uc_function_t *)uc_program_function_new(program, name, source, srcpos);
784         func->arrow   = (flags & UC_FUNCTION_F_IS_ARROW);
785         func->vararg  = (flags & UC_FUNCTION_F_IS_VARARG);
786         func->strict  = (flags & UC_FUNCTION_F_IS_STRICT);
787         func->module  = (flags & UC_FUNCTION_F_IS_MODULE);
788         func->nargs   = nargs;
789         func->nupvals = nupvals;
790 
791         snprintf(subjbuf, sizeof(subjbuf), "function #%zu (%s) body", idx, name ? name : "-");
792 
793         if (!read_chunk(file, &func->chunk, flags, subjbuf, errp))
794                 goto out;
795 
796         free(name);
797 
798         return true;
799 
800 out:
801         free(name);
802 
803         return false;
804 }
805 
806 uc_program_t *
807 uc_program_load(uc_source_t *input, char **errp)
808 {
809         uc_program_t *program = NULL;
810         uint32_t flags, nfuncs, i;
811 
812         if (!read_u32(input->fp, &i, "file magic", errp))
813                 goto out;
814 
815         if (i != UC_PRECOMPILED_BYTECODE_MAGIC) {
816                 xasprintf(errp, "Invalid file magic\n");
817                 goto out;
818         }
819 
820         if (!read_u32(input->fp, &flags, "program flags", errp))
821                 goto out;
822 
823         program = uc_program_new();
824 
825         if (!read_sourceinfo(input, flags, errp, program))
826                 goto out;
827 
828         if (!read_vallist(input->fp, &program->constants, "constants", errp))
829                 goto out;
830 
831         if (!read_u32(input->fp, &nfuncs, "function count", errp))
832                 goto out;
833 
834         for (i = 0; i < nfuncs; i++)
835                 if (!read_function(input->fp, program, i, errp))
836                         goto out;
837 
838         return program;
839 
840 out:
841         uc_program_put(program);
842 
843         return NULL;
844 }
845 
846 uc_function_t *
847 uc_program_entry(uc_program_t *program)
848 {
849         if (program->functions.prev == &program->functions)
850                 return NULL;
851 
852         return (uc_function_t *)program->functions.prev;
853 }
854 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt