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