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