1 /*- 2 * Copyright (c) 2007-2011 Kai Wang 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <sys/param.h> 29 #include <sys/stat.h> 30 #include <err.h> 31 #include <libgen.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "elfcopy.h" 37 38 ELFTC_VCSID("$Id: sections.c 2358 2011-12-19 18:22:32Z kaiwang27 $"); 39 40 static void add_gnu_debuglink(struct elfcopy *ecp); 41 static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc); 42 static void check_section_rename(struct elfcopy *ecp, struct section *s); 43 static void filter_reloc(struct elfcopy *ecp, struct section *s); 44 static int get_section_flags(struct elfcopy *ecp, const char *name); 45 static void insert_sections(struct elfcopy *ecp); 46 static void insert_to_strtab(struct section *t, const char *s); 47 static int is_append_section(struct elfcopy *ecp, const char *name); 48 static int is_compress_section(struct elfcopy *ecp, const char *name); 49 static int is_debug_section(const char *name); 50 static int is_modify_section(struct elfcopy *ecp, const char *name); 51 static int is_print_section(struct elfcopy *ecp, const char *name); 52 static int lookup_string(struct section *t, const char *s); 53 static void modify_section(struct elfcopy *ecp, struct section *s); 54 static void pad_section(struct elfcopy *ecp, struct section *s); 55 static void print_data(const char *d, size_t sz); 56 static void print_section(struct section *s); 57 static void *read_section(struct section *s, size_t *size); 58 static void update_reloc(struct elfcopy *ecp, struct section *s); 59 60 int 61 is_remove_section(struct elfcopy *ecp, const char *name) 62 { 63 64 /* Always keep section name table */ 65 if (strcmp(name, ".shstrtab") == 0) 66 return 0; 67 if (strcmp(name, ".symtab") == 0 || 68 strcmp(name, ".strtab") == 0) { 69 if (ecp->strip == STRIP_ALL && lookup_symop_list( 70 ecp, NULL, SYMOP_KEEP) == NULL) 71 return (1); 72 else 73 return (0); 74 } 75 76 if (is_debug_section(name)) { 77 if (ecp->strip == STRIP_ALL || 78 ecp->strip == STRIP_DEBUG || 79 ecp->strip == STRIP_UNNEEDED || 80 (ecp->flags & DISCARD_LOCAL)) 81 return (1); 82 if (ecp->strip == STRIP_NONDEBUG) 83 return (0); 84 } 85 86 if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) { 87 struct sec_action *sac; 88 89 sac = lookup_sec_act(ecp, name, 0); 90 if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove) 91 return (1); 92 if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy)) 93 return (1); 94 } 95 96 return (0); 97 } 98 99 /* 100 * Relocation section needs to be removed if the section it applies to 101 * will be removed. 102 */ 103 int 104 is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info) 105 { 106 const char *name; 107 GElf_Shdr ish; 108 Elf_Scn *is; 109 size_t indx; 110 int elferr; 111 112 if (elf_getshstrndx(ecp->ein, &indx) == 0) 113 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", 114 elf_errmsg(-1)); 115 116 is = NULL; 117 while ((is = elf_nextscn(ecp->ein, is)) != NULL) { 118 if (sh_info == elf_ndxscn(is)) { 119 if (gelf_getshdr(is, &ish) == NULL) 120 errx(EXIT_FAILURE, "gelf_getshdr failed: %s", 121 elf_errmsg(-1)); 122 if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == 123 NULL) 124 errx(EXIT_FAILURE, "elf_strptr failed: %s", 125 elf_errmsg(-1)); 126 if (is_remove_section(ecp, name)) 127 return (1); 128 else 129 return (0); 130 } 131 } 132 elferr = elf_errno(); 133 if (elferr != 0) 134 errx(EXIT_FAILURE, "elf_nextscn failed: %s", 135 elf_errmsg(elferr)); 136 137 /* Remove reloc section if we can't find the target section. */ 138 return (1); 139 } 140 141 static int 142 is_append_section(struct elfcopy *ecp, const char *name) 143 { 144 struct sec_action *sac; 145 146 sac = lookup_sec_act(ecp, name, 0); 147 if (sac != NULL && sac->append != 0 && sac->string != NULL) 148 return (1); 149 150 return (0); 151 } 152 153 static int 154 is_compress_section(struct elfcopy *ecp, const char *name) 155 { 156 struct sec_action *sac; 157 158 sac = lookup_sec_act(ecp, name, 0); 159 if (sac != NULL && sac->compress != 0) 160 return (1); 161 162 return (0); 163 } 164 165 static void 166 check_section_rename(struct elfcopy *ecp, struct section *s) 167 { 168 struct sec_action *sac; 169 char *prefix; 170 size_t namelen; 171 172 if (s->pseudo) 173 return; 174 175 sac = lookup_sec_act(ecp, s->name, 0); 176 if (sac != NULL && sac->rename) 177 s->name = sac->newname; 178 179 if (!strcmp(s->name, ".symtab") || 180 !strcmp(s->name, ".strtab") || 181 !strcmp(s->name, ".shstrtab")) 182 return; 183 184 prefix = NULL; 185 if (s->loadable && ecp->prefix_alloc != NULL) 186 prefix = ecp->prefix_alloc; 187 else if (ecp->prefix_sec != NULL) 188 prefix = ecp->prefix_sec; 189 190 if (prefix != NULL) { 191 namelen = strlen(s->name) + strlen(prefix) + 1; 192 if ((s->newname = malloc(namelen)) == NULL) 193 err(EXIT_FAILURE, "malloc failed"); 194 snprintf(s->newname, namelen, "%s%s", prefix, s->name); 195 s->name = s->newname; 196 } 197 } 198 199 static int 200 get_section_flags(struct elfcopy *ecp, const char *name) 201 { 202 struct sec_action *sac; 203 204 sac = lookup_sec_act(ecp, name, 0); 205 if (sac != NULL && sac->flags) 206 return sac->flags; 207 208 return (0); 209 } 210 211 /* 212 * Determine whether the section are debugging section. 213 * According to libbfd, debugging sections are recognized 214 * only by name. 215 */ 216 static int 217 is_debug_section(const char *name) 218 { 219 const char *dbg_sec[] = { 220 ".debug", 221 ".gnu.linkonce.wi.", 222 ".line", 223 ".stab", 224 NULL 225 }; 226 const char **p; 227 228 for(p = dbg_sec; *p; p++) { 229 if (strncmp(name, *p, strlen(*p)) == 0) 230 return (1); 231 } 232 233 return (0); 234 } 235 236 static int 237 is_print_section(struct elfcopy *ecp, const char *name) 238 { 239 struct sec_action *sac; 240 241 sac = lookup_sec_act(ecp, name, 0); 242 if (sac != NULL && sac->print != 0) 243 return (1); 244 245 return (0); 246 } 247 248 static int 249 is_modify_section(struct elfcopy *ecp, const char *name) 250 { 251 252 if (is_append_section(ecp, name) || 253 is_compress_section(ecp, name)) 254 return (1); 255 256 return (0); 257 } 258 259 struct sec_action* 260 lookup_sec_act(struct elfcopy *ecp, const char *name, int add) 261 { 262 struct sec_action *sac; 263 264 if (name == NULL) 265 return NULL; 266 267 STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) { 268 if (strcmp(name, sac->name) == 0) 269 return sac; 270 } 271 272 if (add == 0) 273 return NULL; 274 275 if ((sac = malloc(sizeof(*sac))) == NULL) 276 errx(EXIT_FAILURE, "not enough memory"); 277 memset(sac, 0, sizeof(*sac)); 278 sac->name = name; 279 STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list); 280 281 return (sac); 282 } 283 284 void 285 free_sec_act(struct elfcopy *ecp) 286 { 287 struct sec_action *sac, *sac_temp; 288 289 STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) { 290 STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list); 291 free(sac); 292 } 293 } 294 295 void 296 insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail) 297 { 298 struct section *s; 299 300 if (!tail) { 301 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 302 if (sec->off < s->off) { 303 TAILQ_INSERT_BEFORE(s, sec, sec_list); 304 goto inc_nos; 305 } 306 } 307 } 308 309 TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list); 310 311 inc_nos: 312 if (sec->pseudo == 0) 313 ecp->nos++; 314 } 315 316 /* 317 * First step of section creation: create scn and internal section 318 * structure, discard sections to be removed. 319 */ 320 void 321 create_scn(struct elfcopy *ecp) 322 { 323 struct section *s; 324 const char *name; 325 Elf_Scn *is; 326 GElf_Shdr ish; 327 size_t indx; 328 uint64_t oldndx, newndx; 329 int elferr, sec_flags; 330 331 /* 332 * Insert a pseudo section that contains the ELF header 333 * and program header. Used as reference for section offset 334 * or load address adjustment. 335 */ 336 if ((s = calloc(1, sizeof(*s))) == NULL) 337 err(EXIT_FAILURE, "calloc failed"); 338 s->off = 0; 339 s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) + 340 gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT); 341 s->align = 1; 342 s->pseudo = 1; 343 s->loadable = add_to_inseg_list(ecp, s); 344 insert_to_sec_list(ecp, s, 0); 345 346 /* Create internal .shstrtab section. */ 347 init_shstrtab(ecp); 348 349 if (elf_getshstrndx(ecp->ein, &indx) == 0) 350 errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", 351 elf_errmsg(-1)); 352 353 is = NULL; 354 while ((is = elf_nextscn(ecp->ein, is)) != NULL) { 355 if (gelf_getshdr(is, &ish) == NULL) 356 errx(EXIT_FAILURE, "219 gelf_getshdr failed: %s", 357 elf_errmsg(-1)); 358 if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL) 359 errx(EXIT_FAILURE, "elf_strptr failed: %s", 360 elf_errmsg(-1)); 361 362 /* Skip sections to be removed. */ 363 if (is_remove_section(ecp, name)) 364 continue; 365 366 /* 367 * Relocation section need to be remove if the section 368 * it applies will be removed. 369 */ 370 if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) 371 if (ish.sh_info != 0 && 372 is_remove_reloc_sec(ecp, ish.sh_info)) 373 continue; 374 375 /* Get section flags set by user. */ 376 sec_flags = get_section_flags(ecp, name); 377 378 /* Create internal section object. */ 379 if (strcmp(name, ".shstrtab") != 0) { 380 if ((s = calloc(1, sizeof(*s))) == NULL) 381 err(EXIT_FAILURE, "calloc failed"); 382 s->name = name; 383 s->is = is; 384 s->off = ish.sh_offset; 385 s->sz = ish.sh_size; 386 s->align = ish.sh_addralign; 387 s->type = ish.sh_type; 388 s->vma = ish.sh_addr; 389 390 /* 391 * Search program headers to determine whether section 392 * is loadable, but if user explicitly set section flags 393 * while neither "load" nor "alloc" is set, we make the 394 * section unloadable. 395 */ 396 if (sec_flags && 397 (sec_flags & (SF_LOAD | SF_ALLOC)) == 0) 398 s->loadable = 0; 399 else 400 s->loadable = add_to_inseg_list(ecp, s); 401 } else { 402 /* Assuming .shstrtab is "unloadable". */ 403 s = ecp->shstrtab; 404 s->off = ish.sh_offset; 405 } 406 407 oldndx = newndx = SHN_UNDEF; 408 if (strcmp(name, ".symtab") != 0 && 409 strcmp(name, ".strtab") != 0) { 410 if (!strcmp(name, ".shstrtab")) { 411 /* 412 * Add sections specified by --add-section and 413 * gnu debuglink. we want these sections have 414 * smaller index than .shstrtab section. 415 */ 416 if (ecp->debuglink != NULL) 417 add_gnu_debuglink(ecp); 418 if (ecp->flags & SEC_ADD) 419 insert_sections(ecp); 420 } 421 if ((s->os = elf_newscn(ecp->eout)) == NULL) 422 errx(EXIT_FAILURE, "elf_newscn failed: %s", 423 elf_errmsg(-1)); 424 if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF) 425 errx(EXIT_FAILURE, "elf_ndxscn failed: %s", 426 elf_errmsg(-1)); 427 } 428 if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF) 429 errx(EXIT_FAILURE, "elf_ndxscn failed: %s", 430 elf_errmsg(-1)); 431 if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF) 432 ecp->secndx[oldndx] = newndx; 433 434 /* 435 * If strip action is STRIP_NONDEBUG(only keep debug), 436 * change sections flags of loadable sections to SHF_NOBITS, 437 * and the content of those sections will be ignored. 438 */ 439 if (ecp->strip == STRIP_NONDEBUG && (ish.sh_flags & SHF_ALLOC)) 440 s->type = SHT_NOBITS; 441 442 check_section_rename(ecp, s); 443 444 /* create section header based on input object. */ 445 if (strcmp(name, ".symtab") != 0 && 446 strcmp(name, ".strtab") != 0 && 447 strcmp(name, ".shstrtab") != 0) 448 copy_shdr(ecp, s, NULL, 0, sec_flags); 449 450 if (strcmp(name, ".symtab") == 0) { 451 ecp->flags |= SYMTAB_EXIST; 452 ecp->symtab = s; 453 } 454 if (strcmp(name, ".strtab") == 0) 455 ecp->strtab = s; 456 457 insert_to_sec_list(ecp, s, 0); 458 } 459 elferr = elf_errno(); 460 if (elferr != 0) 461 errx(EXIT_FAILURE, "elf_nextscn failed: %s", 462 elf_errmsg(elferr)); 463 } 464 465 struct section * 466 insert_shtab(struct elfcopy *ecp, int tail) 467 { 468 struct section *s, *shtab; 469 GElf_Ehdr ieh; 470 int nsecs; 471 472 /* 473 * Treat section header table as a "pseudo" section, insert it 474 * into section list, so later it will get sorted and resynced 475 * just as normal sections. 476 */ 477 if ((shtab = calloc(1, sizeof(*shtab))) == NULL) 478 errx(EXIT_FAILURE, "calloc failed"); 479 if (!tail) { 480 /* shoff of input object is used as a hint. */ 481 if (gelf_getehdr(ecp->ein, &ieh) == NULL) 482 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", 483 elf_errmsg(-1)); 484 shtab->off = ieh.e_shoff; 485 } else 486 shtab->off = 0; 487 /* Calculate number of sections in the output object. */ 488 nsecs = 0; 489 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 490 if (!s->pseudo) 491 nsecs++; 492 } 493 /* Remember there is always a null section, so we +1 here. */ 494 shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT); 495 if (shtab->sz == 0) 496 errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1)); 497 shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8); 498 shtab->loadable = 0; 499 shtab->pseudo = 1; 500 insert_to_sec_list(ecp, shtab, tail); 501 502 return (shtab); 503 } 504 505 void 506 copy_content(struct elfcopy *ecp) 507 { 508 struct section *s; 509 510 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 511 /* Skip pseudo section. */ 512 if (s->pseudo) 513 continue; 514 515 /* Skip special sections. */ 516 if (strcmp(s->name, ".symtab") == 0 || 517 strcmp(s->name, ".strtab") == 0 || 518 strcmp(s->name, ".shstrtab") == 0) 519 continue; 520 521 /* 522 * If strip action is STRIP_ALL, relocation info need 523 * to be stripped. Skip filtering otherwisw. 524 */ 525 if (ecp->strip == STRIP_ALL && 526 (s->type == SHT_REL || s->type == SHT_RELA)) 527 filter_reloc(ecp, s); 528 529 if (is_modify_section(ecp, s->name)) 530 modify_section(ecp, s); 531 532 copy_data(s); 533 534 /* 535 * If symbol table is modified, relocation info might 536 * need update, as symbol index may have changed. 537 */ 538 if ((ecp->flags & SYMTAB_INTACT) == 0 && 539 (ecp->flags & SYMTAB_EXIST) && 540 (s->type == SHT_REL || s->type == SHT_RELA)) 541 update_reloc(ecp, s); 542 543 if (is_print_section(ecp, s->name)) 544 print_section(s); 545 } 546 } 547 548 /* 549 * Filter relocation entries, only keep those entries whose 550 * symbol is in the keep list. 551 */ 552 static void 553 filter_reloc(struct elfcopy *ecp, struct section *s) 554 { 555 const char *name; 556 GElf_Shdr ish; 557 GElf_Rel rel; 558 GElf_Rela rela; 559 Elf32_Rel *rel32; 560 Elf64_Rel *rel64; 561 Elf32_Rela *rela32; 562 Elf64_Rela *rela64; 563 Elf_Data *id; 564 uint64_t cap, n, nrels; 565 int elferr, i; 566 567 if (gelf_getshdr(s->is, &ish) == NULL) 568 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", 569 elf_errmsg(-1)); 570 571 /* We don't want to touch relocation info for dynamic symbols. */ 572 if ((ecp->flags & SYMTAB_EXIST) == 0) { 573 if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0) { 574 /* 575 * This reloc section applies to the symbol table 576 * that was stripped, so discard whole section. 577 */ 578 s->nocopy = 1; 579 s->sz = 0; 580 } 581 return; 582 } else { 583 /* Symbol table exist, check if index equals. */ 584 if (ish.sh_link != elf_ndxscn(ecp->symtab->is)) 585 return; 586 } 587 588 #define COPYREL(REL, SZ) do { \ 589 if (nrels == 0) { \ 590 if ((REL##SZ = malloc(cap * \ 591 sizeof(Elf##SZ##_Rel))) == NULL) \ 592 err(EXIT_FAILURE, "malloc failed"); \ 593 } \ 594 if (nrels >= cap) { \ 595 cap *= 2; \ 596 if ((REL##SZ = realloc(REL##SZ, cap * \ 597 sizeof(Elf##SZ##_Rel))) == NULL) \ 598 err(EXIT_FAILURE, "realloc failed"); \ 599 } \ 600 REL##SZ[nrels].r_offset = REL.r_offset; \ 601 REL##SZ[nrels].r_info = REL.r_info; \ 602 if (s->type == SHT_RELA) \ 603 rela##SZ[nrels].r_addend = rela.r_addend; \ 604 nrels++; \ 605 } while (0) 606 607 nrels = 0; 608 cap = 4; /* keep list is usually small. */ 609 rel32 = NULL; 610 rel64 = NULL; 611 rela32 = NULL; 612 rela64 = NULL; 613 if ((id = elf_getdata(s->is, NULL)) == NULL) 614 errx(EXIT_FAILURE, "elf_getdata() failed: %s", 615 elf_errmsg(-1)); 616 n = ish.sh_size / ish.sh_entsize; 617 for(i = 0; (uint64_t)i < n; i++) { 618 if (s->type == SHT_REL) { 619 if (gelf_getrel(id, i, &rel) != &rel) 620 errx(EXIT_FAILURE, "gelf_getrel failed: %s", 621 elf_errmsg(-1)); 622 } else { 623 if (gelf_getrela(id, i, &rela) != &rela) 624 errx(EXIT_FAILURE, "gelf_getrel failed: %s", 625 elf_errmsg(-1)); 626 } 627 name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is), 628 GELF_R_SYM(rel.r_info)); 629 if (name == NULL) 630 errx(EXIT_FAILURE, "elf_strptr failed: %s", 631 elf_errmsg(-1)); 632 if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) { 633 if (ecp->oec == ELFCLASS32) { 634 if (s->type == SHT_REL) 635 COPYREL(rel, 32); 636 else 637 COPYREL(rela, 32); 638 } else { 639 if (s->type == SHT_REL) 640 COPYREL(rel, 64); 641 else 642 COPYREL(rela, 64); 643 } 644 } 645 } 646 elferr = elf_errno(); 647 if (elferr != 0) 648 errx(EXIT_FAILURE, "elf_getdata() failed: %s", 649 elf_errmsg(elferr)); 650 651 if (ecp->oec == ELFCLASS32) { 652 if (s->type == SHT_REL) 653 s->buf = rel32; 654 else 655 s->buf = rela32; 656 } else { 657 if (s->type == SHT_REL) 658 s->buf = rel64; 659 else 660 s->buf = rela64; 661 } 662 s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL : 663 ELF_T_RELA), nrels, EV_CURRENT); 664 s->nocopy = 1; 665 } 666 667 static void 668 update_reloc(struct elfcopy *ecp, struct section *s) 669 { 670 GElf_Shdr osh; 671 GElf_Rel rel; 672 GElf_Rela rela; 673 Elf_Data *od; 674 uint64_t n; 675 int i; 676 677 #define UPDATEREL(REL) do { \ 678 if (gelf_get##REL(od, i, &REL) != &REL) \ 679 errx(EXIT_FAILURE, "gelf_get##REL failed: %s", \ 680 elf_errmsg(-1)); \ 681 REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)], \ 682 GELF_R_TYPE(REL.r_info)); \ 683 if (!gelf_update_##REL(od, i, &REL)) \ 684 errx(EXIT_FAILURE, "gelf_update_##REL failed: %s", \ 685 elf_errmsg(-1)); \ 686 } while(0) 687 688 if (s->sz == 0) 689 return; 690 if (gelf_getshdr(s->os, &osh) == NULL) 691 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", 692 elf_errmsg(-1)); 693 /* Only process .symtab reloc info. */ 694 if (osh.sh_link != elf_ndxscn(ecp->symtab->is)) 695 return; 696 if ((od = elf_getdata(s->os, NULL)) == NULL) 697 errx(EXIT_FAILURE, "elf_getdata() failed: %s", 698 elf_errmsg(-1)); 699 n = osh.sh_size / osh.sh_entsize; 700 for(i = 0; (uint64_t)i < n; i++) { 701 if (s->type == SHT_REL) 702 UPDATEREL(rel); 703 else 704 UPDATEREL(rela); 705 } 706 } 707 708 static void 709 pad_section(struct elfcopy *ecp, struct section *s) 710 { 711 GElf_Shdr osh; 712 Elf_Data *od; 713 714 if (s == NULL || s->pad_sz == 0) 715 return; 716 717 if ((s->pad = malloc(s->pad_sz)) == NULL) 718 err(EXIT_FAILURE, "malloc failed"); 719 memset(s->pad, ecp->fill, s->pad_sz); 720 721 /* Create a new Elf_Data to contain the padding bytes. */ 722 if ((od = elf_newdata(s->os)) == NULL) 723 errx(EXIT_FAILURE, "elf_newdata() failed: %s", 724 elf_errmsg(-1)); 725 od->d_align = 1; 726 od->d_off = s->sz; 727 od->d_buf = s->pad; 728 od->d_type = ELF_T_BYTE; 729 od->d_size = s->pad_sz; 730 od->d_version = EV_CURRENT; 731 732 /* Update section header. */ 733 if (gelf_getshdr(s->os, &osh) == NULL) 734 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 735 elf_errmsg(-1)); 736 osh.sh_size = s->sz + s->pad_sz; 737 if (!gelf_update_shdr(s->os, &osh)) 738 errx(EXIT_FAILURE, "elf_update_shdr failed: %s", 739 elf_errmsg(-1)); 740 } 741 742 void 743 resync_sections(struct elfcopy *ecp) 744 { 745 struct section *s, *ps; 746 GElf_Shdr osh; 747 uint64_t off; 748 int first; 749 750 ps = NULL; 751 first = 1; 752 off = 0; 753 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 754 if (first) { 755 off = s->off; 756 first = 0; 757 } 758 759 /* Align section offset. */ 760 if (off <= s->off) { 761 if (!s->loadable) 762 s->off = roundup(off, s->align); 763 } else { 764 if (s->loadable) 765 warnx("moving loadable section %s, " 766 "is this intentional?", s->name); 767 s->off = roundup(off, s->align); 768 } 769 770 /* Calculate next section offset. */ 771 off = s->off; 772 if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL)) 773 off += s->sz; 774 775 if (s->pseudo) { 776 ps = NULL; 777 continue; 778 } 779 780 /* Count padding bytes added through --pad-to. */ 781 if (s->pad_sz > 0) 782 off += s->pad_sz; 783 784 /* Update section header accordingly. */ 785 if (gelf_getshdr(s->os, &osh) == NULL) 786 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 787 elf_errmsg(-1)); 788 osh.sh_addr = s->vma; 789 osh.sh_offset = s->off; 790 osh.sh_size = s->sz; 791 if (!gelf_update_shdr(s->os, &osh)) 792 errx(EXIT_FAILURE, "elf_update_shdr failed: %s", 793 elf_errmsg(-1)); 794 795 /* Add padding for previous section, if need. */ 796 if (ps != NULL) { 797 if (ps->pad_sz > 0) { 798 /* Apply padding added by --pad-to. */ 799 pad_section(ecp, ps); 800 } else if ((ecp->flags & GAP_FILL) && 801 (ps->off + ps->sz < s->off)) { 802 /* 803 * Fill the gap between sections by padding 804 * the section with lower address. 805 */ 806 ps->pad_sz = s->off - (ps->off + ps->sz); 807 pad_section(ecp, ps); 808 } 809 } 810 811 ps = s; 812 } 813 814 /* Pad the last section, if need. */ 815 if (ps != NULL && ps->pad_sz > 0) 816 pad_section(ecp, ps); 817 } 818 819 static void 820 modify_section(struct elfcopy *ecp, struct section *s) 821 { 822 struct sec_action *sac; 823 size_t srcsz, dstsz, p, len; 824 char *b, *c, *d, *src, *end; 825 int dupe; 826 827 src = read_section(s, &srcsz); 828 if (src == NULL || srcsz == 0) { 829 /* For empty section, we proceed if we need to append. */ 830 if (!is_append_section(ecp, s->name)) 831 return; 832 } 833 834 /* Allocate buffer needed for new section data. */ 835 dstsz = srcsz; 836 if (is_append_section(ecp, s->name)) { 837 sac = lookup_sec_act(ecp, s->name, 0); 838 dstsz += strlen(sac->string) + 1; 839 } 840 if ((b = malloc(dstsz)) == NULL) 841 err(EXIT_FAILURE, "malloc failed"); 842 s->buf = b; 843 844 /* Compress section. */ 845 p = 0; 846 if (is_compress_section(ecp, s->name)) { 847 end = src + srcsz; 848 for(c = src; c < end;) { 849 len = 0; 850 while(c + len < end && c[len] != '\0') 851 len++; 852 if (c + len == end) { 853 /* XXX should we warn here? */ 854 strncpy(&b[p], c, len); 855 p += len; 856 break; 857 } 858 dupe = 0; 859 for (d = b; d < b + p; ) { 860 if (strcmp(d, c) == 0) { 861 dupe = 1; 862 break; 863 } 864 d += strlen(d) + 1; 865 } 866 if (!dupe) { 867 strncpy(&b[p], c, len); 868 b[p + len] = '\0'; 869 p += len + 1; 870 } 871 c += len + 1; 872 } 873 } else { 874 memcpy(b, src, srcsz); 875 p += srcsz; 876 } 877 878 /* Append section. */ 879 if (is_append_section(ecp, s->name)) { 880 sac = lookup_sec_act(ecp, s->name, 0); 881 len = strlen(sac->string); 882 strncpy(&b[p], sac->string, len); 883 b[p + len] = '\0'; 884 p += len + 1; 885 } 886 887 s->sz = p; 888 s->nocopy = 1; 889 } 890 891 static void 892 print_data(const char *d, size_t sz) 893 { 894 const char *c; 895 896 for (c = d; c < d + sz; c++) { 897 if (*c == '\0') 898 putchar('\n'); 899 else 900 putchar(*c); 901 } 902 } 903 904 static void 905 print_section(struct section *s) 906 { 907 Elf_Data *id; 908 int elferr; 909 910 if (s->buf != NULL && s->sz > 0) { 911 print_data(s->buf, s->sz); 912 } else { 913 id = NULL; 914 while ((id = elf_getdata(s->is, id)) != NULL) 915 print_data(id->d_buf, id->d_size); 916 elferr = elf_errno(); 917 if (elferr != 0) 918 errx(EXIT_FAILURE, "elf_getdata() failed: %s", 919 elf_errmsg(elferr)); 920 } 921 putchar('\n'); 922 } 923 924 static void * 925 read_section(struct section *s, size_t *size) 926 { 927 Elf_Data *id; 928 char *b; 929 size_t sz; 930 int elferr; 931 932 sz = 0; 933 b = NULL; 934 id = NULL; 935 while ((id = elf_getdata(s->is, id)) != NULL) { 936 if (b == NULL) 937 b = malloc(id->d_size); 938 else 939 b = malloc(sz + id->d_size); 940 if (b == NULL) 941 err(EXIT_FAILURE, "malloc or realloc failed"); 942 943 memcpy(&b[sz], id->d_buf, id->d_size); 944 sz += id->d_size; 945 } 946 elferr = elf_errno(); 947 if (elferr != 0) 948 errx(EXIT_FAILURE, "elf_getdata() failed: %s", 949 elf_errmsg(elferr)); 950 951 *size = sz; 952 953 return (b); 954 } 955 956 void 957 copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, 958 int sec_flags) 959 { 960 GElf_Shdr ish, osh; 961 962 if (gelf_getshdr(s->is, &ish) == NULL) 963 errx(EXIT_FAILURE, "526 gelf_getshdr() failed: %s", 964 elf_errmsg(-1)); 965 if (gelf_getshdr(s->os, &osh) == NULL) 966 errx(EXIT_FAILURE, "529 gelf_getshdr() failed: %s", 967 elf_errmsg(-1)); 968 969 if (copy) 970 (void) memcpy(&osh, &ish, sizeof(ish)); 971 else { 972 osh.sh_type = s->type; 973 osh.sh_addr = s->vma; 974 osh.sh_offset = s->off; 975 osh.sh_size = s->sz; 976 osh.sh_link = ish.sh_link; 977 osh.sh_info = ish.sh_info; 978 osh.sh_addralign = s->align; 979 osh.sh_entsize = ish.sh_entsize; 980 981 if (sec_flags) { 982 osh.sh_flags = 0; 983 if (sec_flags & SF_ALLOC) { 984 osh.sh_flags |= SHF_ALLOC; 985 if (!s->loadable) 986 warnx("set SHF_ALLOC flag for " 987 "unloadable section %s", 988 s->name); 989 } 990 if ((sec_flags & SF_READONLY) == 0) 991 osh.sh_flags |= SHF_WRITE; 992 if (sec_flags & SF_CODE) 993 osh.sh_flags |= SHF_EXECINSTR; 994 } else 995 osh.sh_flags = ish.sh_flags; 996 } 997 998 if (name == NULL) 999 add_to_shstrtab(ecp, s->name); 1000 else 1001 add_to_shstrtab(ecp, name); 1002 1003 if (!gelf_update_shdr(s->os, &osh)) 1004 errx(EXIT_FAILURE, "elf_update_shdr failed: %s", 1005 elf_errmsg(-1)); 1006 } 1007 1008 void 1009 copy_data(struct section *s) 1010 { 1011 Elf_Data *id, *od; 1012 int elferr; 1013 1014 if (s->nocopy && s->buf == NULL) 1015 return; 1016 1017 if ((id = elf_getdata(s->is, NULL)) == NULL) { 1018 elferr = elf_errno(); 1019 if (elferr != 0) 1020 errx(EXIT_FAILURE, "elf_getdata() failed: %s", 1021 elf_errmsg(elferr)); 1022 return; 1023 } 1024 1025 if ((od = elf_newdata(s->os)) == NULL) 1026 errx(EXIT_FAILURE, "elf_newdata() failed: %s", 1027 elf_errmsg(-1)); 1028 1029 if (s->nocopy) { 1030 /* Use s->buf as content if s->nocopy is set. */ 1031 od->d_align = id->d_align; 1032 od->d_off = 0; 1033 od->d_buf = s->buf; 1034 od->d_type = id->d_type; 1035 od->d_size = s->sz; 1036 od->d_version = id->d_version; 1037 } else { 1038 od->d_align = id->d_align; 1039 od->d_off = id->d_off; 1040 od->d_buf = id->d_buf; 1041 od->d_type = id->d_type; 1042 od->d_size = id->d_size; 1043 od->d_version = id->d_version; 1044 } 1045 } 1046 1047 struct section * 1048 create_external_section(struct elfcopy *ecp, const char *name, char *newname, 1049 void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype, 1050 uint64_t flags, uint64_t align, uint64_t vma, int loadable) 1051 { 1052 struct section *s; 1053 Elf_Scn *os; 1054 Elf_Data *od; 1055 GElf_Shdr osh; 1056 1057 if ((os = elf_newscn(ecp->eout)) == NULL) 1058 errx(EXIT_FAILURE, "elf_newscn() failed: %s", 1059 elf_errmsg(-1)); 1060 if ((s = calloc(1, sizeof(*s))) == NULL) 1061 err(EXIT_FAILURE, "calloc failed"); 1062 s->name = name; 1063 s->newname = newname; /* needs to be free()'ed */ 1064 s->off = off; 1065 s->sz = size; 1066 s->vma = vma; 1067 s->align = align; 1068 s->loadable = loadable; 1069 s->is = NULL; 1070 s->os = os; 1071 s->type = stype; 1072 s->nocopy = 1; 1073 insert_to_sec_list(ecp, s, 1); 1074 1075 if (gelf_getshdr(os, &osh) == NULL) 1076 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", 1077 elf_errmsg(-1)); 1078 osh.sh_flags = flags; 1079 osh.sh_type = s->type; 1080 osh.sh_addr = s->vma; 1081 osh.sh_addralign = s->align; 1082 if (!gelf_update_shdr(os, &osh)) 1083 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 1084 elf_errmsg(-1)); 1085 add_to_shstrtab(ecp, name); 1086 1087 if (buf != NULL && size != 0) { 1088 if ((od = elf_newdata(os)) == NULL) 1089 errx(EXIT_FAILURE, "elf_newdata() failed: %s", 1090 elf_errmsg(-1)); 1091 od->d_align = align; 1092 od->d_off = 0; 1093 od->d_buf = buf; 1094 od->d_size = size; 1095 od->d_type = dtype; 1096 od->d_version = EV_CURRENT; 1097 } 1098 1099 /* 1100 * Clear SYMTAB_INTACT, as we probably need to update/add new 1101 * STT_SECTION symbols into the symbol table. 1102 */ 1103 ecp->flags &= ~SYMTAB_INTACT; 1104 1105 return (s); 1106 } 1107 1108 /* 1109 * Insert sections specified by --add-section to the end of section list. 1110 */ 1111 static void 1112 insert_sections(struct elfcopy *ecp) 1113 { 1114 struct sec_add *sa; 1115 struct section *s; 1116 size_t off; 1117 1118 /* Put these sections in the end of current list. */ 1119 off = 0; 1120 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 1121 if (s->type != SHT_NOBITS && s->type != SHT_NULL) 1122 off = s->off + s->sz; 1123 else 1124 off = s->off; 1125 } 1126 1127 STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) { 1128 1129 /* TODO: Add section header vma/lma, flag changes here */ 1130 1131 (void) create_external_section(ecp, sa->name, NULL, sa->content, 1132 sa->size, off, SHT_PROGBITS, ELF_T_BYTE, 0, 1, 0, 0); 1133 } 1134 } 1135 1136 void 1137 add_to_shstrtab(struct elfcopy *ecp, const char *name) 1138 { 1139 struct section *s; 1140 1141 s = ecp->shstrtab; 1142 insert_to_strtab(s, name); 1143 } 1144 1145 void 1146 update_shdr(struct elfcopy *ecp, int update_link) 1147 { 1148 struct section *s; 1149 GElf_Shdr osh; 1150 int elferr; 1151 1152 TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { 1153 if (s->pseudo) 1154 continue; 1155 1156 if (gelf_getshdr(s->os, &osh) == NULL) 1157 errx(EXIT_FAILURE, "668 gelf_getshdr failed: %s", 1158 elf_errmsg(-1)); 1159 1160 /* Find section name in string table and set sh_name. */ 1161 osh.sh_name = lookup_string(ecp->shstrtab, s->name); 1162 1163 /* 1164 * sh_link needs to be updated, since the index of the 1165 * linked section might have changed. 1166 */ 1167 if (update_link && osh.sh_link != 0) 1168 osh.sh_link = ecp->secndx[osh.sh_link]; 1169 1170 /* 1171 * sh_info of relocation section links to the section to which 1172 * its relocation info applies. So it may need update as well. 1173 */ 1174 if ((s->type == SHT_REL || s->type == SHT_RELA) && 1175 osh.sh_info != 0) 1176 osh.sh_info = ecp->secndx[osh.sh_info]; 1177 1178 if (!gelf_update_shdr(s->os, &osh)) 1179 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 1180 elf_errmsg(-1)); 1181 } 1182 elferr = elf_errno(); 1183 if (elferr != 0) 1184 errx(EXIT_FAILURE, "elf_nextscn failed: %s", 1185 elf_errmsg(elferr)); 1186 } 1187 1188 void 1189 init_shstrtab(struct elfcopy *ecp) 1190 { 1191 struct section *s; 1192 1193 if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL) 1194 err(EXIT_FAILURE, "calloc failed"); 1195 s = ecp->shstrtab; 1196 s->name = ".shstrtab"; 1197 s->is = NULL; 1198 s->sz = 0; 1199 s->align = 1; 1200 s->loadable = 0; 1201 s->type = SHT_STRTAB; 1202 s->vma = 0; 1203 1204 insert_to_strtab(s, ""); 1205 insert_to_strtab(s, ".symtab"); 1206 insert_to_strtab(s, ".strtab"); 1207 insert_to_strtab(s, ".shstrtab"); 1208 } 1209 1210 void 1211 set_shstrtab(struct elfcopy *ecp) 1212 { 1213 struct section *s; 1214 Elf_Data *data; 1215 GElf_Shdr sh; 1216 1217 s = ecp->shstrtab; 1218 1219 if (gelf_getshdr(s->os, &sh) == NULL) 1220 errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s", 1221 elf_errmsg(-1)); 1222 sh.sh_addr = 0; 1223 sh.sh_addralign = 1; 1224 sh.sh_offset = s->off; 1225 sh.sh_type = SHT_STRTAB; 1226 sh.sh_flags = 0; 1227 sh.sh_entsize = 0; 1228 sh.sh_info = 0; 1229 sh.sh_link = 0; 1230 1231 if ((data = elf_newdata(s->os)) == NULL) 1232 errx(EXIT_FAILURE, "elf_newdata() failed: %s", 1233 elf_errmsg(-1)); 1234 1235 /* 1236 * If we don't have a symbol table, skip those a few bytes 1237 * which are reserved for this in the beginning of shstrtab. 1238 */ 1239 if (!(ecp->flags & SYMTAB_EXIST)) { 1240 s->sz -= sizeof(".symtab\0.strtab"); 1241 memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"), 1242 s->sz); 1243 } 1244 1245 sh.sh_size = s->sz; 1246 if (!gelf_update_shdr(s->os, &sh)) 1247 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s", 1248 elf_errmsg(-1)); 1249 1250 data->d_align = 1; 1251 data->d_buf = s->buf; 1252 data->d_size = s->sz; 1253 data->d_off = 0; 1254 data->d_type = ELF_T_BYTE; 1255 data->d_version = EV_CURRENT; 1256 1257 if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os))) 1258 errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s", 1259 elf_errmsg(-1)); 1260 } 1261 1262 void 1263 add_section(struct elfcopy *ecp, const char *arg) 1264 { 1265 struct sec_add *sa; 1266 struct stat sb; 1267 const char *s, *fn; 1268 FILE *fp; 1269 int len; 1270 1271 if ((s = strchr(arg, '=')) == NULL) 1272 errx(EXIT_FAILURE, 1273 "illegal format for --add-section option"); 1274 if ((sa = malloc(sizeof(*sa))) == NULL) 1275 err(EXIT_FAILURE, "malloc failed"); 1276 1277 len = s - arg; 1278 if ((sa->name = malloc(len + 1)) == NULL) 1279 err(EXIT_FAILURE, "malloc failed"); 1280 strncpy(sa->name, arg, len); 1281 sa->name[len] = '\0'; 1282 1283 fn = s + 1; 1284 if (stat(fn, &sb) == -1) 1285 err(EXIT_FAILURE, "stat failed"); 1286 sa->size = sb.st_size; 1287 if ((sa->content = malloc(sa->size)) == NULL) 1288 err(EXIT_FAILURE, "malloc failed"); 1289 if ((fp = fopen(fn, "r")) == NULL) 1290 err(EXIT_FAILURE, "can not open %s", fn); 1291 if (fread(sa->content, 1, sa->size, fp) == 0 || 1292 ferror(fp)) 1293 err(EXIT_FAILURE, "fread failed"); 1294 fclose(fp); 1295 1296 STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); 1297 ecp->flags |= SEC_ADD; 1298 } 1299 1300 void 1301 free_sec_add(struct elfcopy *ecp) 1302 { 1303 struct sec_add *sa, *sa_temp; 1304 1305 STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) { 1306 STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list); 1307 free(sa->name); 1308 free(sa->content); 1309 free(sa); 1310 } 1311 } 1312 1313 static void 1314 add_gnu_debuglink(struct elfcopy *ecp) 1315 { 1316 struct sec_add *sa; 1317 struct stat sb; 1318 FILE *fp; 1319 char *fnbase, *buf; 1320 int crc_off; 1321 int crc; 1322 1323 if (ecp->debuglink == NULL) 1324 return; 1325 1326 /* Read debug file content. */ 1327 if ((sa = malloc(sizeof(*sa))) == NULL) 1328 err(EXIT_FAILURE, "malloc failed"); 1329 if ((sa->name = strdup(".gnu_debuglink")) == NULL) 1330 err(EXIT_FAILURE, "strdup failed"); 1331 if (stat(ecp->debuglink, &sb) == -1) 1332 err(EXIT_FAILURE, "stat failed"); 1333 if ((buf = malloc(sb.st_size)) == NULL) 1334 err(EXIT_FAILURE, "malloc failed"); 1335 if ((fp = fopen(ecp->debuglink, "r")) == NULL) 1336 err(EXIT_FAILURE, "can not open %s", ecp->debuglink); 1337 if (fread(buf, 1, sb.st_size, fp) == 0 || 1338 ferror(fp)) 1339 err(EXIT_FAILURE, "fread failed"); 1340 fclose(fp); 1341 1342 /* Calculate crc checksum. */ 1343 crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF); 1344 free(buf); 1345 1346 /* Calculate section size and the offset to store crc checksum. */ 1347 if ((fnbase = basename(ecp->debuglink)) == NULL) 1348 err(EXIT_FAILURE, "basename failed"); 1349 crc_off = roundup(strlen(fnbase) + 1, 4); 1350 sa->size = crc_off + 4; 1351 1352 /* Section content. */ 1353 if ((sa->content = calloc(1, sa->size)) == NULL) 1354 err(EXIT_FAILURE, "malloc failed"); 1355 strncpy(sa->content, fnbase, strlen(fnbase)); 1356 if (ecp->oed == ELFDATA2LSB) { 1357 sa->content[crc_off] = crc & 0xFF; 1358 sa->content[crc_off + 1] = (crc >> 8) & 0xFF; 1359 sa->content[crc_off + 2] = (crc >> 16) & 0xFF; 1360 sa->content[crc_off + 3] = crc >> 24; 1361 } else { 1362 sa->content[crc_off] = crc >> 24; 1363 sa->content[crc_off + 1] = (crc >> 16) & 0xFF; 1364 sa->content[crc_off + 2] = (crc >> 8) & 0xFF; 1365 sa->content[crc_off + 3] = crc & 0xFF; 1366 } 1367 1368 STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); 1369 ecp->flags |= SEC_ADD; 1370 } 1371 1372 static void 1373 insert_to_strtab(struct section *t, const char *s) 1374 { 1375 const char *r; 1376 char *b, *c; 1377 size_t len, slen; 1378 int append; 1379 1380 if (t->sz == 0) { 1381 t->cap = 512; 1382 if ((t->buf = malloc(t->cap)) == NULL) 1383 err(EXIT_FAILURE, "malloc failed"); 1384 } 1385 1386 slen = strlen(s); 1387 append = 0; 1388 b = t->buf; 1389 for (c = b; c < b + t->sz;) { 1390 len = strlen(c); 1391 if (!append && len >= slen) { 1392 r = c + (len - slen); 1393 if (strcmp(r, s) == 0) 1394 return; 1395 } else if (len < slen && len != 0) { 1396 r = s + (slen - len); 1397 if (strcmp(c, r) == 0) { 1398 t->sz -= len + 1; 1399 memmove(c, c + len + 1, t->sz - (c - b)); 1400 append = 1; 1401 continue; 1402 } 1403 } 1404 c += len + 1; 1405 } 1406 1407 while (t->sz + slen + 1 >= t->cap) { 1408 t->cap *= 2; 1409 if ((t->buf = realloc(t->buf, t->cap)) == NULL) 1410 err(EXIT_FAILURE, "realloc failed"); 1411 } 1412 b = t->buf; 1413 strncpy(&b[t->sz], s, slen); 1414 b[t->sz + slen] = '\0'; 1415 t->sz += slen + 1; 1416 } 1417 1418 static int 1419 lookup_string(struct section *t, const char *s) 1420 { 1421 const char *b, *c, *r; 1422 size_t len, slen; 1423 1424 slen = strlen(s); 1425 b = t->buf; 1426 for (c = b; c < b + t->sz;) { 1427 len = strlen(c); 1428 if (len >= slen) { 1429 r = c + (len - slen); 1430 if (strcmp(r, s) == 0) 1431 return (r - b); 1432 } 1433 c += len + 1; 1434 } 1435 1436 return (-1); 1437 } 1438 1439 static uint32_t crctable[256] = 1440 { 1441 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 1442 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 1443 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, 1444 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, 1445 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, 1446 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 1447 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 1448 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, 1449 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, 1450 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, 1451 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 1452 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 1453 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 1454 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, 1455 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, 1456 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 1457 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 1458 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, 1459 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 1460 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, 1461 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 1462 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 1463 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, 1464 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, 1465 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 1466 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 1467 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 1468 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, 1469 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, 1470 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, 1471 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 1472 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 1473 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, 1474 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, 1475 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, 1476 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 1477 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 1478 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, 1479 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, 1480 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, 1481 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 1482 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 1483 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 1484 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, 1485 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, 1486 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 1487 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 1488 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, 1489 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 1490 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, 1491 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 1492 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 1493 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, 1494 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, 1495 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 1496 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 1497 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 1498 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, 1499 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, 1500 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, 1501 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 1502 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 1503 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 1504 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL 1505 }; 1506 1507 static uint32_t 1508 calc_crc32(const char *p, size_t len, uint32_t crc) 1509 { 1510 uint32_t i; 1511 1512 for (i = 0; i < len; i++) { 1513 crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8); 1514 } 1515 1516 return (crc ^ 0xFFFFFFFF); 1517 } 1518