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