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 iidesc_t **tolist; 371 GElf_Sym ssym; 372 iidesc_match_t smatch; 373 int *curr; 374 iidesc_t *iidesc; 375 376 if (gelf_getsym(data, i, &sym) == NULL) 377 elfterminate(file, "Couldn't read symbol %d", i); 378 379 match.iim_name = (char *)strdata->d_buf + sym.st_name; 380 match.iim_bind = GELF_ST_BIND(sym.st_info); 381 382 switch (GELF_ST_TYPE(sym.st_info)) { 383 case STT_FILE: 384 match.iim_file = match.iim_name; 385 continue; 386 case STT_OBJECT: 387 tolist = iiburst->iib_objts; 388 curr = &iiburst->iib_nobjts; 389 break; 390 case STT_FUNC: 391 tolist = iiburst->iib_funcs; 392 curr = &iiburst->iib_nfuncs; 393 break; 394 default: 395 continue; 396 } 397 398 if (ignore_symbol(&sym, match.iim_name)) 399 continue; 400 401 iidesc = find_iidesc(td, &match); 402 403 if (iidesc != NULL) { 404 tolist[*curr] = iidesc; 405 iidesc->ii_flags |= IIDESC_F_USED; 406 (*curr)++; 407 continue; 408 } 409 410 if (!check_for_weak(&sym, match.iim_file, data, nent, strdata, 411 &ssym, &smatch.iim_file)) { 412 (*curr)++; 413 continue; 414 } 415 416 smatch.iim_fuzzy = fuzzymatch; 417 smatch.iim_name = (char *)strdata->d_buf + ssym.st_name; 418 smatch.iim_bind = GELF_ST_BIND(ssym.st_info); 419 420 debug(3, "Weak symbol %s resolved to %s\n", match.iim_name, 421 smatch.iim_name); 422 423 iidesc = find_iidesc(td, &smatch); 424 425 if (iidesc != NULL) { 426 tolist[*curr] = copy_from_strong(td, &sym, 427 iidesc, match.iim_name, match.iim_file); 428 tolist[*curr]->ii_flags |= IIDESC_F_USED; 429 } 430 431 (*curr)++; 432 } 433 434 /* 435 * Stabs are generated for every function declared in a given C source 436 * file. When converting an object file, we may encounter a stab that 437 * has no symbol table entry because the optimizer has decided to omit 438 * that item (for example, an unreferenced static function). We may 439 * see iidescs that do not have an associated symtab entry, and so 440 * we do not write records for those functions into the CTF data. 441 * All others get marked as a root by this function. 442 */ 443 iiburst_types(iiburst); 444 445 /* 446 * By not adding some of the functions and/or objects, we may have 447 * caused some types that were referenced solely by those 448 * functions/objects to be suppressed. This could cause a label, 449 * generated prior to the evisceration, to be incorrect. Find the 450 * highest type index, and change the label indicies to be no higher 451 * than this value. 452 */ 453 tdata_label_newmax(td, iiburst->iib_maxtypeid); 454 455 return (iiburst); 456 } 457 458 static void 459 write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname, 460 caddr_t ctfdata, size_t ctfsize, int flags) 461 { 462 GElf_Ehdr sehdr, dehdr; 463 Elf_Scn *sscn, *dscn; 464 Elf_Data *sdata, *ddata; 465 GElf_Shdr shdr; 466 GElf_Word symtab_type; 467 int symtab_idx = -1; 468 off_t new_offset = 0; 469 off_t ctfnameoff = 0; 470 int dynsym = (flags & CTF_USE_DYNSYM); 471 int keep_stabs = (flags & CTF_KEEP_STABS); 472 int *secxlate; 473 int srcidx, dstidx; 474 int curnmoff = 0; 475 int changing = 0; 476 int pad; 477 int i; 478 479 if (gelf_newehdr(dst, gelf_getclass(src)) == 0) 480 elfterminate(dstname, "Cannot copy ehdr to temp file"); 481 gelf_getehdr(src, &sehdr); 482 memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr)); 483 gelf_update_ehdr(dst, &dehdr); 484 485 symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB; 486 487 /* 488 * Neither the existing stab sections nor the SUNW_ctf sections (new or 489 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by 490 * program headers. As such, we can just blindly copy the program 491 * headers from the existing file to the new file. 492 */ 493 if (sehdr.e_phnum != 0) { 494 (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT); 495 if (gelf_newphdr(dst, sehdr.e_phnum) == 0) 496 elfterminate(dstname, "Cannot make phdrs in temp file"); 497 498 for (i = 0; i < sehdr.e_phnum; i++) { 499 GElf_Phdr phdr; 500 501 gelf_getphdr(src, i, &phdr); 502 gelf_update_phdr(dst, i, &phdr); 503 } 504 } 505 506 secxlate = xmalloc(sizeof (int) * sehdr.e_shnum); 507 for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) { 508 Elf_Scn *scn = elf_getscn(src, srcidx); 509 GElf_Shdr shdr1; 510 char *sname; 511 512 gelf_getshdr(scn, &shdr1); 513 sname = elf_strptr(src, sehdr.e_shstrndx, shdr1.sh_name); 514 if (sname == NULL) { 515 elfterminate(srcname, "Can't find string at %u", 516 shdr1.sh_name); 517 } 518 519 if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) { 520 secxlate[srcidx] = -1; 521 } else if (!keep_stabs && 522 (strncmp(sname, ".stab", 5) == 0 || 523 strncmp(sname, ".debug", 6) == 0 || 524 strncmp(sname, ".rel.debug", 10) == 0 || 525 strncmp(sname, ".rela.debug", 11) == 0)) { 526 secxlate[srcidx] = -1; 527 } else if (dynsym && shdr1.sh_type == SHT_SYMTAB) { 528 /* 529 * If we're building CTF against the dynsym, 530 * we'll rip out the symtab so debuggers aren't 531 * confused. 532 */ 533 secxlate[srcidx] = -1; 534 } else { 535 secxlate[srcidx] = dstidx++; 536 curnmoff += strlen(sname) + 1; 537 } 538 539 new_offset = (off_t)dehdr.e_phoff; 540 } 541 542 for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) { 543 char *sname; 544 545 sscn = elf_getscn(src, srcidx); 546 gelf_getshdr(sscn, &shdr); 547 548 if (secxlate[srcidx] == -1) { 549 changing = 1; 550 continue; 551 } 552 553 dscn = elf_newscn(dst); 554 555 /* 556 * If this file has program headers, we need to explicitly lay 557 * out sections. If none of the sections prior to this one have 558 * been removed, then we can just use the existing location. If 559 * one or more sections have been changed, then we need to 560 * adjust this one to avoid holes. 561 */ 562 if (changing && sehdr.e_phnum != 0) { 563 pad = new_offset % shdr.sh_addralign; 564 565 if (pad) 566 new_offset += shdr.sh_addralign - pad; 567 shdr.sh_offset = new_offset; 568 } 569 570 shdr.sh_link = secxlate[shdr.sh_link]; 571 572 if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA) 573 shdr.sh_info = secxlate[shdr.sh_info]; 574 575 sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name); 576 if (sname == NULL) { 577 elfterminate(srcname, "Can't find string at %u", 578 shdr.sh_name); 579 } 580 581 #if !defined(sun) 582 if (gelf_update_shdr(dscn, &shdr) == 0) 583 elfterminate(dstname, "Cannot update sect %s", sname); 584 #endif 585 586 if ((sdata = elf_getdata(sscn, NULL)) == NULL) { 587 elfterminate(srcname, "Cannot get sect %s data", sname); 588 } 589 if ((ddata = elf_newdata(dscn)) == NULL) 590 elfterminate(dstname, "Can't make sect %s data", sname); 591 #if defined(sun) 592 bcopy(sdata, ddata, sizeof (Elf_Data)); 593 #else 594 /* 595 * FreeBSD's Elf_Data has private fields which the 596 * elf_* routines manage. Simply copying the 597 * entire structure corrupts the data. So we need 598 * to copy the public fields explictly. 599 */ 600 ddata->d_align = sdata->d_align; 601 ddata->d_off = sdata->d_off; 602 ddata->d_size = sdata->d_size; 603 ddata->d_type = sdata->d_type; 604 ddata->d_version = sdata->d_version; 605 #endif 606 607 if (srcidx == sehdr.e_shstrndx) { 608 char seclen = strlen(CTF_ELF_SCN_NAME); 609 610 ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size + 611 seclen + 1); 612 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 613 strcpy((caddr_t)ddata->d_buf + shdr.sh_size, 614 CTF_ELF_SCN_NAME); 615 ctfnameoff = (off_t)shdr.sh_size; 616 shdr.sh_size += seclen + 1; 617 ddata->d_size += seclen + 1; 618 619 if (sehdr.e_phnum != 0) 620 changing = 1; 621 } 622 623 if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) { 624 int nsym = shdr.sh_size / shdr.sh_entsize; 625 626 symtab_idx = secxlate[srcidx]; 627 628 ddata->d_buf = xmalloc(shdr.sh_size); 629 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 630 631 for (i = 0; i < nsym; i++) { 632 GElf_Sym sym; 633 short newscn; 634 635 if (gelf_getsym(ddata, i, &sym) == NULL) 636 printf("Could not get symbol %d\n",i); 637 638 if (sym.st_shndx >= SHN_LORESERVE) 639 continue; 640 641 if ((newscn = secxlate[sym.st_shndx]) != 642 sym.st_shndx) { 643 sym.st_shndx = 644 (newscn == -1 ? 1 : newscn); 645 646 gelf_update_sym(ddata, i, &sym); 647 } 648 } 649 } 650 651 #if !defined(sun) 652 if ((ddata->d_buf == NULL) && (sdata->d_buf != NULL)) { 653 ddata->d_buf = xmalloc(shdr.sh_size); 654 bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 655 } 656 #endif 657 658 if (gelf_update_shdr(dscn, &shdr) == 0) 659 elfterminate(dstname, "Cannot update sect %s", sname); 660 661 new_offset = (off_t)shdr.sh_offset; 662 if (shdr.sh_type != SHT_NOBITS) 663 new_offset += shdr.sh_size; 664 } 665 666 if (symtab_idx == -1) { 667 terminate("%s: Cannot find %s section\n", srcname, 668 dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB"); 669 } 670 671 /* Add the ctf section */ 672 dscn = elf_newscn(dst); 673 gelf_getshdr(dscn, &shdr); 674 shdr.sh_name = ctfnameoff; 675 shdr.sh_type = SHT_PROGBITS; 676 shdr.sh_size = ctfsize; 677 shdr.sh_link = symtab_idx; 678 shdr.sh_addralign = 4; 679 if (changing && sehdr.e_phnum != 0) { 680 pad = new_offset % shdr.sh_addralign; 681 682 if (pad) 683 new_offset += shdr.sh_addralign - pad; 684 685 shdr.sh_offset = new_offset; 686 new_offset += shdr.sh_size; 687 } 688 689 ddata = elf_newdata(dscn); 690 ddata->d_buf = ctfdata; 691 ddata->d_size = ctfsize; 692 ddata->d_align = shdr.sh_addralign; 693 ddata->d_off = 0; 694 695 gelf_update_shdr(dscn, &shdr); 696 697 /* update the section header location */ 698 if (sehdr.e_phnum != 0) { 699 size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT); 700 size_t r = new_offset % align; 701 702 if (r) 703 new_offset += align - r; 704 705 dehdr.e_shoff = new_offset; 706 } 707 708 /* commit to disk */ 709 dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx]; 710 gelf_update_ehdr(dst, &dehdr); 711 if (elf_update(dst, ELF_C_WRITE) < 0) 712 elfterminate(dstname, "Cannot finalize temp file"); 713 714 free(secxlate); 715 } 716 717 static caddr_t 718 make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags) 719 { 720 iiburst_t *iiburst; 721 caddr_t data; 722 723 iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH, 724 flags & CTF_USE_DYNSYM); 725 data = ctf_gen(iiburst, lenp, flags & CTF_COMPRESS); 726 727 iiburst_free(iiburst); 728 729 return (data); 730 } 731 732 void 733 write_ctf(tdata_t *td, const char *curname, const char *newname, int flags) 734 { 735 struct stat st; 736 Elf *elf = NULL; 737 Elf *telf = NULL; 738 caddr_t data; 739 size_t len; 740 int fd = -1; 741 int tfd = -1; 742 743 (void) elf_version(EV_CURRENT); 744 if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0) 745 terminate("%s: Cannot open for re-reading", curname); 746 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 747 elfterminate(curname, "Cannot re-read"); 748 749 if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) 750 terminate("Cannot open temp file %s for writing", newname); 751 if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL) 752 elfterminate(curname, "Cannot write"); 753 754 data = make_ctf_data(td, elf, curname, &len, flags); 755 write_file(elf, curname, telf, newname, data, len, flags); 756 free(data); 757 758 elf_end(telf); 759 elf_end(elf); 760 (void) close(fd); 761 (void) close(tfd); 762 } 763