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