1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Routines for preparing tdata trees for conversion into CTF data, and 30 * for placing the resulting data into an output file. 31 */ 32 33 #if HAVE_NBTOOL_CONFIG_H 34 # include "nbtool_config.h" 35 #endif 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <strings.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <fcntl.h> 43 #include <libelf.h> 44 #include <gelf.h> 45 #include <unistd.h> 46 47 #include "ctftools.h" 48 #include "list.h" 49 #include "memory.h" 50 #include "traverse.h" 51 #include "symbol.h" 52 53 typedef struct iidesc_match { 54 int iim_fuzzy; 55 iidesc_t *iim_ret; 56 char *iim_name; 57 char *iim_file; 58 uchar_t iim_bind; 59 } iidesc_match_t; 60 61 static int 62 burst_iitypes(void *data, void *arg) 63 { 64 iidesc_t *ii = data; 65 iiburst_t *iiburst = arg; 66 67 switch (ii->ii_type) { 68 case II_GFUN: 69 case II_SFUN: 70 case II_GVAR: 71 case II_SVAR: 72 if (!(ii->ii_flags & IIDESC_F_USED)) 73 return (0); 74 break; 75 default: 76 break; 77 } 78 79 ii->ii_dtype->t_flags |= TDESC_F_ISROOT; 80 (void) iitraverse_td(ii, iiburst->iib_tdtd); 81 return (1); 82 } 83 84 /*ARGSUSED1*/ 85 static int 86 save_type_by_id(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private) 87 { 88 iiburst_t *iiburst = private; 89 90 /* 91 * Doing this on every node is horribly inefficient, but given that 92 * we may be suppressing some types, we can't trust nextid in the 93 * tdata_t. 94 */ 95 if (tdp->t_id > iiburst->iib_maxtypeid) 96 iiburst->iib_maxtypeid = tdp->t_id; 97 98 slist_add(&iiburst->iib_types, tdp, tdesc_idcmp); 99 100 return (1); 101 } 102 103 static tdtrav_cb_f burst_types_cbs[] = { 104 NULL, 105 save_type_by_id, /* intrinsic */ 106 save_type_by_id, /* pointer */ 107 save_type_by_id, /* array */ 108 save_type_by_id, /* function */ 109 save_type_by_id, /* struct */ 110 save_type_by_id, /* union */ 111 save_type_by_id, /* enum */ 112 save_type_by_id, /* forward */ 113 save_type_by_id, /* typedef */ 114 tdtrav_assert, /* typedef_unres */ 115 save_type_by_id, /* volatile */ 116 save_type_by_id, /* const */ 117 save_type_by_id /* restrict */ 118 }; 119 120 121 static iiburst_t * 122 iiburst_new(tdata_t *td, int max) 123 { 124 iiburst_t *iiburst = xcalloc(sizeof (iiburst_t)); 125 iiburst->iib_td = td; 126 iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max); 127 iiburst->iib_nfuncs = 0; 128 iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max); 129 iiburst->iib_nobjts = 0; 130 return (iiburst); 131 } 132 133 static void 134 iiburst_types(iiburst_t *iiburst) 135 { 136 tdtrav_data_t tdtd; 137 138 tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs, 139 NULL, (void *)iiburst); 140 141 iiburst->iib_tdtd = &tdtd; 142 143 (void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst); 144 } 145 146 static void 147 iiburst_free(iiburst_t *iiburst) 148 { 149 free(iiburst->iib_funcs); 150 free(iiburst->iib_objts); 151 list_free(iiburst->iib_types, NULL, NULL); 152 free(iiburst); 153 } 154 155 /* 156 * See if this iidesc matches the ELF symbol data we pass in. 157 * 158 * A fuzzy match is where we have a local symbol matching the name of a 159 * global type description. This is common when a mapfile is used for a 160 * DSO, but we don't accept it by default. 161 * 162 * A weak fuzzy match is when a weak symbol was resolved and matched to 163 * a global type description. 164 */ 165 static int 166 matching_iidesc(void *arg1, void *arg2) 167 { 168 iidesc_t *iidesc = arg1; 169 iidesc_match_t *match = arg2; 170 if (streq(iidesc->ii_name, match->iim_name) == 0) 171 return (0); 172 173 switch (iidesc->ii_type) { 174 case II_GFUN: 175 case II_GVAR: 176 if (match->iim_bind == STB_GLOBAL) { 177 match->iim_ret = iidesc; 178 return (-1); 179 } else if (match->iim_fuzzy && match->iim_ret == NULL) { 180 match->iim_ret = iidesc; 181 /* continue to look for strong match */ 182 return (0); 183 } 184 break; 185 case II_SFUN: 186 case II_SVAR: 187 if (match->iim_bind == STB_LOCAL && 188 match->iim_file != NULL && 189 streq(iidesc->ii_owner, match->iim_file)) { 190 match->iim_ret = iidesc; 191 return (-1); 192 } 193 break; 194 default: 195 break; 196 } 197 return (0); 198 } 199 200 static iidesc_t * 201 find_iidesc(tdata_t *td, iidesc_match_t *match) 202 { 203 match->iim_ret = NULL; 204 iter_iidescs_by_name(td, match->iim_name, 205 matching_iidesc, match); 206 return (match->iim_ret); 207 } 208 209 /* 210 * If we have a weak symbol, attempt to find the strong symbol it will 211 * resolve to. Note: the code where this actually happens is in 212 * sym_process() in cmd/sgs/libld/common/syms.c 213 * 214 * Finding the matching symbol is unfortunately not trivial. For a 215 * symbol to be a candidate, it must: 216 * 217 * - have the same type (function, object) 218 * - have the same value (address) 219 * - have the same size 220 * - not be another weak symbol 221 * - belong to the same section (checked via section index) 222 * 223 * If such a candidate is global, then we assume we've found it. The 224 * linker generates the symbol table such that the curfile might be 225 * incorrect; this is OK for global symbols, since find_iidesc() doesn't 226 * need to check for the source file for the symbol. 227 * 228 * We might have found a strong local symbol, where the curfile is 229 * accurate and matches that of the weak symbol. We assume this is a 230 * reasonable match. 231 * 232 * If we've got a local symbol with a non-matching curfile, there are 233 * two possibilities. Either this is a completely different symbol, or 234 * it's a once-global symbol that was scoped to local via a mapfile. In 235 * the latter case, curfile is likely inaccurate since the linker does 236 * not preserve the needed curfile in the order of the symbol table (see 237 * the comments about locally scoped symbols in libld's update_osym()). 238 * As we can't tell this case from the former one, we use this symbol 239 * iff no other matching symbol is found. 240 * 241 * What we really need here is a SUNW section containing weak<->strong 242 * mappings that we can consume. 243 */ 244 static int 245 check_for_weak(GElf_Sym *weak, char const *weakfile, 246 Elf_Data *data, int nent, Elf_Data *strdata, 247 GElf_Sym *retsym, char **curfilep) 248 { 249 char *curfile = NULL; 250 char *tmpfile1 = NULL; 251 GElf_Sym tmpsym; 252 int candidate = 0; 253 int i; 254 tmpsym.st_info = 0; 255 tmpsym.st_name = 0; 256 257 if (GELF_ST_BIND(weak->st_info) != STB_WEAK) 258 return (0); 259 260 for (i = 0; i < nent; i++) { 261 GElf_Sym sym; 262 uchar_t type; 263 264 if (gelf_getsym(data, i, &sym) == NULL) 265 continue; 266 267 type = GELF_ST_TYPE(sym.st_info); 268 269 if (type == STT_FILE) 270 curfile = (char *)strdata->d_buf + sym.st_name; 271 272 if (GELF_ST_TYPE(weak->st_info) != type || 273 weak->st_value != sym.st_value) 274 continue; 275 276 if (weak->st_size != sym.st_size) 277 continue; 278 279 if (GELF_ST_BIND(sym.st_info) == STB_WEAK) 280 continue; 281 282 if (sym.st_shndx != weak->st_shndx) 283 continue; 284 285 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 286 (curfile == NULL || weakfile == NULL || 287 strcmp(curfile, weakfile) != 0)) { 288 candidate = 1; 289 tmpfile1 = curfile; 290 tmpsym = sym; 291 continue; 292 } 293 294 *curfilep = curfile; 295 *retsym = sym; 296 return (1); 297 } 298 299 if (candidate) { 300 *curfilep = tmpfile1; 301 *retsym = tmpsym; 302 return (1); 303 } 304 305 return (0); 306 } 307 308 /* 309 * When we've found the underlying symbol's type description 310 * for a weak symbol, we need to copy it and rename it to match 311 * the weak symbol. We also need to add it to the td so it's 312 * handled along with the others later. 313 */ 314 static iidesc_t * 315 copy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc, 316 const char *weakname, const char *weakfile) 317 { 318 iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile); 319 uchar_t type = GELF_ST_TYPE(sym->st_info); 320 321 switch (type) { 322 case STT_OBJECT: 323 new->ii_type = II_GVAR; 324 break; 325 case STT_FUNC: 326 new->ii_type = II_GFUN; 327 break; 328 } 329 330 hash_add(td->td_iihash, new); 331 332 return (new); 333 } 334 335 /* 336 * Process the symbol table of the output file, associating each symbol 337 * with a type description if possible, and sorting them into functions 338 * and data, maintaining symbol table order. 339 */ 340 static iiburst_t * 341 sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch, 342 int dynsym) 343 { 344 iiburst_t *iiburst; 345 Elf_Scn *scn; 346 GElf_Shdr shdr; 347 Elf_Data *data, *strdata; 348 int i, stidx; 349 int nent; 350 iidesc_match_t match; 351 352 match.iim_fuzzy = fuzzymatch; 353 match.iim_file = NULL; 354 355 if ((stidx = findelfsecidx(elf, file, 356 dynsym ? ".dynsym" : ".symtab")) < 0) 357 terminate("%s: Can't open symbol table\n", file); 358 scn = elf_getscn(elf, stidx); 359 data = elf_getdata(scn, NULL); 360 gelf_getshdr(scn, &shdr); 361 nent = shdr.sh_size / shdr.sh_entsize; 362 363 scn = elf_getscn(elf, shdr.sh_link); 364 strdata = elf_getdata(scn, NULL); 365 366 iiburst = iiburst_new(td, nent); 367 368 for (i = 0; i < nent; i++) { 369 GElf_Sym sym; 370 char *bname; 371 iidesc_t **tolist; 372 GElf_Sym ssym; 373 iidesc_match_t smatch; 374 int *curr; 375 iidesc_t *iidesc; 376 377 if (gelf_getsym(data, i, &sym) == NULL) 378 elfterminate(file, "Couldn't read symbol %d", i); 379 380 match.iim_name = (char *)strdata->d_buf + sym.st_name; 381 match.iim_bind = GELF_ST_BIND(sym.st_info); 382 383 switch (GELF_ST_TYPE(sym.st_info)) { 384 case STT_FILE: 385 bname = strrchr(match.iim_name, '/'); 386 match.iim_file = bname == NULL ? match.iim_name : bname + 1; 387 continue; 388 case STT_OBJECT: 389 tolist = iiburst->iib_objts; 390 curr = &iiburst->iib_nobjts; 391 break; 392 case STT_FUNC: 393 tolist = iiburst->iib_funcs; 394 curr = &iiburst->iib_nfuncs; 395 break; 396 default: 397 continue; 398 } 399 400 if (ignore_symbol(&sym, match.iim_name)) 401 continue; 402 403 iidesc = find_iidesc(td, &match); 404 405 if (iidesc != NULL) { 406 tolist[*curr] = iidesc; 407 iidesc->ii_flags |= IIDESC_F_USED; 408 (*curr)++; 409 continue; 410 } 411 412 if (!check_for_weak(&sym, match.iim_file, data, nent, strdata, 413 &ssym, &smatch.iim_file)) { 414 (*curr)++; 415 continue; 416 } 417 418 smatch.iim_fuzzy = fuzzymatch; 419 smatch.iim_name = (char *)strdata->d_buf + ssym.st_name; 420 smatch.iim_bind = GELF_ST_BIND(ssym.st_info); 421 422 debug(3, "Weak symbol %s resolved to %s\n", match.iim_name, 423 smatch.iim_name); 424 425 iidesc = find_iidesc(td, &smatch); 426 427 if (iidesc != NULL) { 428 tolist[*curr] = copy_from_strong(td, &sym, 429 iidesc, match.iim_name, match.iim_file); 430 tolist[*curr]->ii_flags |= IIDESC_F_USED; 431 } 432 433 (*curr)++; 434 } 435 436 /* 437 * Stabs are generated for every function declared in a given C source 438 * file. When converting an object file, we may encounter a stab that 439 * has no symbol table entry because the optimizer has decided to omit 440 * that item (for example, an unreferenced static function). We may 441 * see iidescs that do not have an associated symtab entry, and so 442 * we do not write records for those functions into the CTF data. 443 * All others get marked as a root by this function. 444 */ 445 iiburst_types(iiburst); 446 447 /* 448 * By not adding some of the functions and/or objects, we may have 449 * caused some types that were referenced solely by those 450 * functions/objects to be suppressed. This could cause a label, 451 * generated prior to the evisceration, to be incorrect. Find the 452 * highest type index, and change the label indicies to be no higher 453 * than this value. 454 */ 455 tdata_label_newmax(td, iiburst->iib_maxtypeid); 456 457 return (iiburst); 458 } 459 460 static void 461 write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname, 462 caddr_t ctfdata, size_t ctfsize, int flags) 463 { 464 GElf_Ehdr sehdr, dehdr; 465 Elf_Scn *sscn, *dscn; 466 Elf_Data *sdata, *ddata; 467 GElf_Shdr shdr; 468 GElf_Word symtab_type; 469 int symtab_idx = -1; 470 off_t new_offset = 0; 471 off_t ctfnameoff = 0; 472 int dynsym = (flags & CTF_USE_DYNSYM); 473 int keep_stabs = (flags & CTF_KEEP_STABS); 474 int *secxlate; 475 int srcidx, dstidx; 476 int curnmoff = 0; 477 int changing = 0; 478 int pad; 479 int i; 480 481 if (gelf_newehdr(dst, gelf_getclass(src)) == NULL) 482 elfterminate(dstname, "Cannot copy ehdr to temp file"); 483 gelf_getehdr(src, &sehdr); 484 memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr)); 485 gelf_update_ehdr(dst, &dehdr); 486 487 symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB; 488 489 /* 490 * Neither the existing stab sections nor the SUNW_ctf sections (new or 491 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by 492 * program headers. As such, we can just blindly copy the program 493 * headers from the existing file to the new file. 494 */ 495 if (sehdr.e_phnum != 0) { 496 (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT); 497 if (gelf_newphdr(dst, sehdr.e_phnum) == NULL) 498 elfterminate(dstname, "Cannot make phdrs in temp file"); 499 500 for (i = 0; i < sehdr.e_phnum; i++) { 501 GElf_Phdr phdr; 502 503 gelf_getphdr(src, i, &phdr); 504 gelf_update_phdr(dst, i, &phdr); 505 } 506 } 507 508 secxlate = xmalloc(sizeof (int) * sehdr.e_shnum); 509 for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) { 510 Elf_Scn *scn = elf_getscn(src, srcidx); 511 GElf_Shdr shdr1; 512 char *sname; 513 514 gelf_getshdr(scn, &shdr1); 515 sname = elf_strptr(src, sehdr.e_shstrndx, shdr1.sh_name); 516 if (sname == NULL) { 517 elfterminate(srcname, "Can't find string at %u", 518 shdr1.sh_name); 519 } 520 521 if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) { 522 secxlate[srcidx] = -1; 523 } else if (!keep_stabs && 524 (strncmp(sname, ".stab", 5) == 0 || 525 strncmp(sname, ".debug", 6) == 0 || 526 strncmp(sname, ".rel.debug", 10) == 0 || 527 strncmp(sname, ".rela.debug", 11) == 0)) { 528 secxlate[srcidx] = -1; 529 } else if (dynsym && shdr1.sh_type == SHT_SYMTAB) { 530 /* 531 * If we're building CTF against the dynsym, 532 * we'll rip out the symtab so debuggers aren't 533 * confused. 534 */ 535 secxlate[srcidx] = -1; 536 } else { 537 secxlate[srcidx] = dstidx++; 538 curnmoff += strlen(sname) + 1; 539 } 540 541 new_offset = (off_t)dehdr.e_phoff; 542 } 543 544 for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) { 545 char *sname; 546 547 sscn = elf_getscn(src, srcidx); 548 gelf_getshdr(sscn, &shdr); 549 550 if (secxlate[srcidx] == -1) { 551 changing = 1; 552 continue; 553 } 554 555 dscn = elf_newscn(dst); 556 557 /* 558 * If this file has program headers, we need to explicitly lay 559 * out sections. If none of the sections prior to this one have 560 * been removed, then we can just use the existing location. If 561 * one or more sections have been changed, then we need to 562 * adjust this one to avoid holes. 563 */ 564 if (changing && sehdr.e_phnum != 0) { 565 pad = new_offset % shdr.sh_addralign; 566 567 if (pad) 568 new_offset += shdr.sh_addralign - pad; 569 shdr.sh_offset = new_offset; 570 } 571 572 shdr.sh_link = secxlate[shdr.sh_link]; 573 574 if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA) 575 shdr.sh_info = secxlate[shdr.sh_info]; 576 577 sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name); 578 if (sname == NULL) { 579 elfterminate(srcname, "Can't find string at %u", 580 shdr.sh_name); 581 } 582 583 #if !defined(sun) 584 if (gelf_update_shdr(dscn, &shdr) == 0) 585 elfterminate(dstname, "Cannot update sect %s", sname); 586 #endif 587 588 if ((sdata = elf_getdata(sscn, NULL)) == NULL) 589 elfterminate(srcname, "Cannot get sect %s data", sname); 590 if ((ddata = elf_newdata(dscn)) == NULL) 591 elfterminate(dstname, "Can't make sect %s data", sname); 592 #if defined(sun) 593 bcopy(sdata, ddata, sizeof (Elf_Data)); 594 #else 595 /* 596 * FreeBSD's Elf_Data has private fields which the 597 * elf_* routines manage. Simply copying the 598 * entire structure corrupts the data. So we need 599 * to copy the public fields explictly. 600 */ 601 ddata->d_align = sdata->d_align; 602 ddata->d_off = sdata->d_off; 603 ddata->d_size = sdata->d_size; 604 ddata->d_type = sdata->d_type; 605 ddata->d_version = sdata->d_version; 606 #endif 607 608 if (srcidx == sehdr.e_shstrndx) { 609 char seclen = strlen(CTF_ELF_SCN_NAME); 610 611 ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size + 612 seclen + 1); 613 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 614 strcpy((caddr_t)ddata->d_buf + shdr.sh_size, 615 CTF_ELF_SCN_NAME); 616 ctfnameoff = (off_t)shdr.sh_size; 617 shdr.sh_size += seclen + 1; 618 ddata->d_size += seclen + 1; 619 620 if (sehdr.e_phnum != 0) 621 changing = 1; 622 } 623 624 if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) { 625 int nsym = shdr.sh_size / shdr.sh_entsize; 626 627 symtab_idx = secxlate[srcidx]; 628 629 ddata->d_buf = xmalloc(shdr.sh_size); 630 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 631 632 for (i = 0; i < nsym; i++) { 633 GElf_Sym sym; 634 short newscn; 635 636 if (gelf_getsym(ddata, i, &sym) == NULL) 637 printf("Could not get symbol %d\n",i); 638 639 if (sym.st_shndx >= SHN_LORESERVE) 640 continue; 641 642 if ((newscn = secxlate[sym.st_shndx]) != 643 sym.st_shndx) { 644 sym.st_shndx = 645 (newscn == -1 ? 1 : newscn); 646 647 gelf_update_sym(ddata, i, &sym); 648 } 649 } 650 } 651 652 #if !defined(sun) 653 if (ddata->d_buf == NULL && sdata->d_buf != NULL) { 654 ddata->d_buf = xmalloc(shdr.sh_size); 655 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 656 } 657 #endif 658 659 if (gelf_update_shdr(dscn, &shdr) == 0) 660 elfterminate(dstname, "Cannot update sect %s", sname); 661 662 new_offset = (off_t)shdr.sh_offset; 663 if (shdr.sh_type != SHT_NOBITS) 664 new_offset += shdr.sh_size; 665 } 666 667 if (symtab_idx == -1) { 668 terminate("%s: Cannot find %s section\n", srcname, 669 dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB"); 670 } 671 672 /* Add the ctf section */ 673 dscn = elf_newscn(dst); 674 gelf_getshdr(dscn, &shdr); 675 shdr.sh_name = ctfnameoff; 676 shdr.sh_type = SHT_PROGBITS; 677 shdr.sh_size = ctfsize; 678 shdr.sh_link = symtab_idx; 679 shdr.sh_addralign = 4; 680 if (changing && sehdr.e_phnum != 0) { 681 pad = new_offset % shdr.sh_addralign; 682 683 if (pad) 684 new_offset += shdr.sh_addralign - pad; 685 686 shdr.sh_offset = new_offset; 687 new_offset += shdr.sh_size; 688 } 689 690 ddata = elf_newdata(dscn); 691 ddata->d_buf = ctfdata; 692 ddata->d_size = ctfsize; 693 ddata->d_align = shdr.sh_addralign; 694 ddata->d_off = 0; 695 696 gelf_update_shdr(dscn, &shdr); 697 698 /* update the section header location */ 699 if (sehdr.e_phnum != 0) { 700 size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT); 701 size_t r = new_offset % align; 702 703 if (r) 704 new_offset += align - r; 705 706 dehdr.e_shoff = new_offset; 707 } 708 709 /* commit to disk */ 710 dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx]; 711 gelf_update_ehdr(dst, &dehdr); 712 if (elf_update(dst, ELF_C_WRITE) < 0) 713 elfterminate(dstname, "Cannot finalize temp file"); 714 715 free(secxlate); 716 } 717 718 static caddr_t 719 make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags) 720 { 721 iiburst_t *iiburst; 722 caddr_t data; 723 724 iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH, 725 flags & CTF_USE_DYNSYM); 726 data = ctf_gen(iiburst, lenp, flags & (CTF_COMPRESS | CTF_SWAP_BYTES)); 727 728 iiburst_free(iiburst); 729 730 return (data); 731 } 732 733 void 734 write_ctf(tdata_t *td, const char *curname, const char *newname, int flags) 735 { 736 struct stat st; 737 Elf *elf = NULL; 738 Elf *telf = NULL; 739 GElf_Ehdr ehdr; 740 caddr_t data; 741 size_t len; 742 int fd = -1; 743 int tfd = -1; 744 int byteorder; 745 746 (void) elf_version(EV_CURRENT); 747 if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0) 748 terminate("%s: Cannot open for re-reading", curname); 749 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 750 elfterminate(curname, "Cannot re-read"); 751 752 if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) 753 terminate("Cannot open temp file %s for writing", newname); 754 if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL) 755 elfterminate(curname, "Cannot write"); 756 757 if (gelf_getehdr(elf, &ehdr)) { 758 #if BYTE_ORDER == _BIG_ENDIAN 759 byteorder = ELFDATA2MSB; 760 #else 761 byteorder = ELFDATA2LSB; 762 #endif 763 /* 764 * If target and host has the same byte order 765 * clear byte swapping request 766 */ 767 if (ehdr.e_ident[EI_DATA] == byteorder) 768 flags &= ~CTF_SWAP_BYTES; 769 } 770 else 771 elfterminate(curname, "Failed to get EHDR"); 772 773 data = make_ctf_data(td, elf, curname, &len, flags); 774 write_file(elf, curname, telf, newname, data, len, flags); 775 free(data); 776 777 elf_end(telf); 778 elf_end(elf); 779 (void) close(fd); 780 (void) close(tfd); 781 } 782