10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51882Sjohnlev * Common Development and Distribution License (the "License"). 61882Sjohnlev * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 221882Sjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Routines for preparing tdata trees for conversion into CTF data, and 300Sstevel@tonic-gate * for placing the resulting data into an output file. 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <strings.h> 360Sstevel@tonic-gate #include <sys/types.h> 370Sstevel@tonic-gate #include <sys/stat.h> 380Sstevel@tonic-gate #include <fcntl.h> 390Sstevel@tonic-gate #include <libelf.h> 400Sstevel@tonic-gate #include <gelf.h> 410Sstevel@tonic-gate #include <unistd.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include "ctftools.h" 440Sstevel@tonic-gate #include "list.h" 450Sstevel@tonic-gate #include "memory.h" 460Sstevel@tonic-gate #include "traverse.h" 470Sstevel@tonic-gate #include "symbol.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate typedef struct iidesc_match { 500Sstevel@tonic-gate int iim_fuzzy; 510Sstevel@tonic-gate iidesc_t *iim_ret; 520Sstevel@tonic-gate char *iim_name; 530Sstevel@tonic-gate char *iim_file; 540Sstevel@tonic-gate uchar_t iim_bind; 550Sstevel@tonic-gate } iidesc_match_t; 560Sstevel@tonic-gate 570Sstevel@tonic-gate static int 580Sstevel@tonic-gate burst_iitypes(void *data, void *arg) 590Sstevel@tonic-gate { 600Sstevel@tonic-gate iidesc_t *ii = data; 610Sstevel@tonic-gate iiburst_t *iiburst = arg; 620Sstevel@tonic-gate 630Sstevel@tonic-gate switch (ii->ii_type) { 640Sstevel@tonic-gate case II_GFUN: 650Sstevel@tonic-gate case II_SFUN: 660Sstevel@tonic-gate case II_GVAR: 670Sstevel@tonic-gate case II_SVAR: 680Sstevel@tonic-gate if (!(ii->ii_flags & IIDESC_F_USED)) 690Sstevel@tonic-gate return (0); 700Sstevel@tonic-gate break; 710Sstevel@tonic-gate default: 720Sstevel@tonic-gate break; 730Sstevel@tonic-gate } 740Sstevel@tonic-gate 750Sstevel@tonic-gate ii->ii_dtype->t_flags |= TDESC_F_ISROOT; 760Sstevel@tonic-gate (void) iitraverse_td(ii, iiburst->iib_tdtd); 770Sstevel@tonic-gate return (1); 780Sstevel@tonic-gate } 790Sstevel@tonic-gate 800Sstevel@tonic-gate /*ARGSUSED1*/ 810Sstevel@tonic-gate static int 820Sstevel@tonic-gate save_type_by_id(tdesc_t *tdp, tdesc_t **tdpp, void *private) 830Sstevel@tonic-gate { 840Sstevel@tonic-gate iiburst_t *iiburst = private; 850Sstevel@tonic-gate 860Sstevel@tonic-gate /* 870Sstevel@tonic-gate * Doing this on every node is horribly inefficient, but given that 880Sstevel@tonic-gate * we may be suppressing some types, we can't trust nextid in the 890Sstevel@tonic-gate * tdata_t. 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate if (tdp->t_id > iiburst->iib_maxtypeid) 920Sstevel@tonic-gate iiburst->iib_maxtypeid = tdp->t_id; 930Sstevel@tonic-gate 940Sstevel@tonic-gate slist_add(&iiburst->iib_types, tdp, tdesc_idcmp); 950Sstevel@tonic-gate 960Sstevel@tonic-gate return (1); 970Sstevel@tonic-gate } 980Sstevel@tonic-gate 990Sstevel@tonic-gate static tdtrav_cb_f burst_types_cbs[] = { 1000Sstevel@tonic-gate NULL, 1010Sstevel@tonic-gate save_type_by_id, /* intrinsic */ 1020Sstevel@tonic-gate save_type_by_id, /* pointer */ 1030Sstevel@tonic-gate save_type_by_id, /* array */ 1040Sstevel@tonic-gate save_type_by_id, /* function */ 1050Sstevel@tonic-gate save_type_by_id, /* struct */ 1060Sstevel@tonic-gate save_type_by_id, /* union */ 1070Sstevel@tonic-gate save_type_by_id, /* enum */ 1080Sstevel@tonic-gate save_type_by_id, /* forward */ 1090Sstevel@tonic-gate save_type_by_id, /* typedef */ 1100Sstevel@tonic-gate tdtrav_assert, /* typedef_unres */ 1110Sstevel@tonic-gate save_type_by_id, /* volatile */ 1120Sstevel@tonic-gate save_type_by_id, /* const */ 1130Sstevel@tonic-gate save_type_by_id /* restrict */ 1140Sstevel@tonic-gate }; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate static iiburst_t * 1180Sstevel@tonic-gate iiburst_new(tdata_t *td, int max) 1190Sstevel@tonic-gate { 1200Sstevel@tonic-gate iiburst_t *iiburst = xcalloc(sizeof (iiburst_t)); 1210Sstevel@tonic-gate iiburst->iib_td = td; 1220Sstevel@tonic-gate iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max); 1230Sstevel@tonic-gate iiburst->iib_nfuncs = 0; 1240Sstevel@tonic-gate iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max); 1250Sstevel@tonic-gate iiburst->iib_nobjts = 0; 1260Sstevel@tonic-gate return (iiburst); 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate static void 1300Sstevel@tonic-gate iiburst_types(iiburst_t *iiburst) 1310Sstevel@tonic-gate { 1320Sstevel@tonic-gate tdtrav_data_t tdtd; 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs, 1350Sstevel@tonic-gate NULL, (void *)iiburst); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate iiburst->iib_tdtd = &tdtd; 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate (void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate static void 1430Sstevel@tonic-gate iiburst_free(iiburst_t *iiburst) 1440Sstevel@tonic-gate { 1450Sstevel@tonic-gate free(iiburst->iib_funcs); 1460Sstevel@tonic-gate free(iiburst->iib_objts); 1470Sstevel@tonic-gate list_free(iiburst->iib_types, NULL, NULL); 1480Sstevel@tonic-gate free(iiburst); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * See if this iidesc matches the ELF symbol data we pass in. 1530Sstevel@tonic-gate * 1540Sstevel@tonic-gate * A fuzzy match is where we have a local symbol matching the name of a 1550Sstevel@tonic-gate * global type description. This is common when a mapfile is used for a 1560Sstevel@tonic-gate * DSO, but we don't accept it by default. 1570Sstevel@tonic-gate * 1580Sstevel@tonic-gate * A weak fuzzy match is when a weak symbol was resolved and matched to 1590Sstevel@tonic-gate * a global type description. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate static int 1620Sstevel@tonic-gate matching_iidesc(iidesc_t *iidesc, iidesc_match_t *match) 1630Sstevel@tonic-gate { 1640Sstevel@tonic-gate if (streq(iidesc->ii_name, match->iim_name) == 0) 1650Sstevel@tonic-gate return (0); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate switch (iidesc->ii_type) { 1680Sstevel@tonic-gate case II_GFUN: 1690Sstevel@tonic-gate case II_GVAR: 1700Sstevel@tonic-gate if (match->iim_bind == STB_GLOBAL) { 1710Sstevel@tonic-gate match->iim_ret = iidesc; 1720Sstevel@tonic-gate return (-1); 1730Sstevel@tonic-gate } else if (match->iim_fuzzy && match->iim_ret == NULL) { 1740Sstevel@tonic-gate match->iim_ret = iidesc; 1750Sstevel@tonic-gate /* continue to look for strong match */ 1760Sstevel@tonic-gate return (0); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate break; 1790Sstevel@tonic-gate case II_SFUN: 1800Sstevel@tonic-gate case II_SVAR: 1810Sstevel@tonic-gate if (match->iim_bind == STB_LOCAL && 1820Sstevel@tonic-gate match->iim_file != NULL && 1830Sstevel@tonic-gate streq(iidesc->ii_owner, match->iim_file)) { 1840Sstevel@tonic-gate match->iim_ret = iidesc; 1850Sstevel@tonic-gate return (-1); 1860Sstevel@tonic-gate } 1870Sstevel@tonic-gate break; 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate return (0); 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate static iidesc_t * 1930Sstevel@tonic-gate find_iidesc(hash_t *hash, iidesc_match_t *match) 1940Sstevel@tonic-gate { 1950Sstevel@tonic-gate iidesc_t tmpdesc; 1960Sstevel@tonic-gate match->iim_ret = NULL; 1970Sstevel@tonic-gate bzero(&tmpdesc, sizeof (iidesc_t)); 1980Sstevel@tonic-gate tmpdesc.ii_name = match->iim_name; 1990Sstevel@tonic-gate (void) hash_match(hash, &tmpdesc, (int (*)())matching_iidesc, match); 2000Sstevel@tonic-gate return (match->iim_ret); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * If we have a weak symbol, attempt to find the strong symbol it will 2050Sstevel@tonic-gate * resolve to. Note: the code where this actually happens is in 2060Sstevel@tonic-gate * sym_process() in cmd/sgs/libld/common/syms.c 2070Sstevel@tonic-gate * 2080Sstevel@tonic-gate * Finding the matching symbol is unfortunately not trivial. For a 2090Sstevel@tonic-gate * symbol to be a candidate, it must: 2100Sstevel@tonic-gate * 2110Sstevel@tonic-gate * - have the same type (function, object) 2120Sstevel@tonic-gate * - have the same value (address) 2130Sstevel@tonic-gate * - have the same size 2140Sstevel@tonic-gate * - not be another weak symbol 2150Sstevel@tonic-gate * - belong to the same section (checked via section index) 2160Sstevel@tonic-gate * 2170Sstevel@tonic-gate * If such a candidate is global, then we assume we've found it. The 2180Sstevel@tonic-gate * linker generates the symbol table such that the curfile might be 2190Sstevel@tonic-gate * incorrect; this is OK for global symbols, since find_iidesc() doesn't 2200Sstevel@tonic-gate * need to check for the source file for the symbol. 2210Sstevel@tonic-gate * 2220Sstevel@tonic-gate * We might have found a strong local symbol, where the curfile is 2230Sstevel@tonic-gate * accurate and matches that of the weak symbol. We assume this is a 2240Sstevel@tonic-gate * reasonable match. 2250Sstevel@tonic-gate * 2260Sstevel@tonic-gate * If we've got a local symbol with a non-matching curfile, there are 2270Sstevel@tonic-gate * two possibilities. Either this is a completely different symbol, or 2280Sstevel@tonic-gate * it's a once-global symbol that was scoped to local via a mapfile. In 2290Sstevel@tonic-gate * the latter case, curfile is likely inaccurate since the linker does 2300Sstevel@tonic-gate * not preserve the needed curfile in the order of the symbol table (see 2310Sstevel@tonic-gate * the comments about locally scoped symbols in libld's update_osym()). 2320Sstevel@tonic-gate * As we can't tell this case from the former one, we use this symbol 2330Sstevel@tonic-gate * iff no other matching symbol is found. 2340Sstevel@tonic-gate * 2350Sstevel@tonic-gate * What we really need here is a SUNW section containing weak<->strong 2360Sstevel@tonic-gate * mappings that we can consume. 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate static int 2390Sstevel@tonic-gate check_for_weak(GElf_Sym *weak, char const *weakfile, 2400Sstevel@tonic-gate Elf_Data *data, int nent, Elf_Data *strdata, 2410Sstevel@tonic-gate GElf_Sym *retsym, char **curfilep) 2420Sstevel@tonic-gate { 2430Sstevel@tonic-gate char *curfile = NULL; 2440Sstevel@tonic-gate char *tmpfile; 2450Sstevel@tonic-gate GElf_Sym tmpsym; 2460Sstevel@tonic-gate int candidate = 0; 2470Sstevel@tonic-gate int i; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (GELF_ST_BIND(weak->st_info) != STB_WEAK) 2500Sstevel@tonic-gate return (0); 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate for (i = 0; i < nent; i++) { 2530Sstevel@tonic-gate GElf_Sym sym; 2540Sstevel@tonic-gate uchar_t type; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate if (gelf_getsym(data, i, &sym) == NULL) 2570Sstevel@tonic-gate continue; 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate type = GELF_ST_TYPE(sym.st_info); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate if (type == STT_FILE) 2620Sstevel@tonic-gate curfile = (char *)strdata->d_buf + sym.st_name; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if (GELF_ST_TYPE(weak->st_info) != type || 2650Sstevel@tonic-gate weak->st_value != sym.st_value) 2660Sstevel@tonic-gate continue; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate if (weak->st_size != sym.st_size) 2690Sstevel@tonic-gate continue; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate if (GELF_ST_BIND(sym.st_info) == STB_WEAK) 2720Sstevel@tonic-gate continue; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate if (sym.st_shndx != weak->st_shndx) 2750Sstevel@tonic-gate continue; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 2780Sstevel@tonic-gate (curfile == NULL || weakfile == NULL || 2790Sstevel@tonic-gate strcmp(curfile, weakfile) != 0)) { 2800Sstevel@tonic-gate candidate = 1; 2810Sstevel@tonic-gate tmpfile = curfile; 2820Sstevel@tonic-gate tmpsym = sym; 2830Sstevel@tonic-gate continue; 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate *curfilep = curfile; 2870Sstevel@tonic-gate *retsym = sym; 2880Sstevel@tonic-gate return (1); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate if (candidate) { 2920Sstevel@tonic-gate *curfilep = tmpfile; 2930Sstevel@tonic-gate *retsym = tmpsym; 2940Sstevel@tonic-gate return (1); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate return (0); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * When we've found the underlying symbol's type description 3020Sstevel@tonic-gate * for a weak symbol, we need to copy it and rename it to match 3030Sstevel@tonic-gate * the weak symbol. We also need to add it to the td so it's 3040Sstevel@tonic-gate * handled along with the others later. 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate static iidesc_t * 3070Sstevel@tonic-gate copy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc, 3080Sstevel@tonic-gate const char *weakname, const char *weakfile) 3090Sstevel@tonic-gate { 3100Sstevel@tonic-gate iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile); 3110Sstevel@tonic-gate uchar_t type = GELF_ST_TYPE(sym->st_info); 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate switch (type) { 3140Sstevel@tonic-gate case STT_OBJECT: 3150Sstevel@tonic-gate new->ii_type = II_GVAR; 3160Sstevel@tonic-gate break; 3170Sstevel@tonic-gate case STT_FUNC: 3180Sstevel@tonic-gate new->ii_type = II_GFUN; 3190Sstevel@tonic-gate break; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate hash_add(td->td_iihash, new); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate return (new); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate /* 3280Sstevel@tonic-gate * Process the symbol table of the output file, associating each symbol 3290Sstevel@tonic-gate * with a type description if possible, and sorting them into functions 3300Sstevel@tonic-gate * and data, maintaining symbol table order. 3310Sstevel@tonic-gate */ 3320Sstevel@tonic-gate static iiburst_t * 3330Sstevel@tonic-gate sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch, 3340Sstevel@tonic-gate int dynsym) 3350Sstevel@tonic-gate { 3360Sstevel@tonic-gate iiburst_t *iiburst; 3370Sstevel@tonic-gate Elf_Scn *scn; 3380Sstevel@tonic-gate GElf_Shdr shdr; 3390Sstevel@tonic-gate Elf_Data *data, *strdata; 3400Sstevel@tonic-gate int i, stidx; 3410Sstevel@tonic-gate int nent; 3420Sstevel@tonic-gate iidesc_match_t match; 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate match.iim_fuzzy = fuzzymatch; 3450Sstevel@tonic-gate match.iim_file = NULL; 3460Sstevel@tonic-gate 347*1951Sjohnlev if ((stidx = findelfsecidx(elf, file, 348*1951Sjohnlev dynsym ? ".dynsym" : ".symtab")) < 0) 3490Sstevel@tonic-gate terminate("%s: Can't open symbol table\n", file); 3500Sstevel@tonic-gate scn = elf_getscn(elf, stidx); 3510Sstevel@tonic-gate data = elf_getdata(scn, NULL); 3520Sstevel@tonic-gate gelf_getshdr(scn, &shdr); 3530Sstevel@tonic-gate nent = shdr.sh_size / shdr.sh_entsize; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate scn = elf_getscn(elf, shdr.sh_link); 3560Sstevel@tonic-gate strdata = elf_getdata(scn, NULL); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate iiburst = iiburst_new(td, nent); 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate for (i = 0; i < nent; i++) { 3610Sstevel@tonic-gate GElf_Sym sym; 3620Sstevel@tonic-gate iidesc_t **tolist; 3630Sstevel@tonic-gate GElf_Sym ssym; 3640Sstevel@tonic-gate iidesc_match_t smatch; 3650Sstevel@tonic-gate int *curr; 3660Sstevel@tonic-gate iidesc_t *iidesc; 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate if (gelf_getsym(data, i, &sym) == NULL) 3690Sstevel@tonic-gate elfterminate(file, "Couldn't read symbol %d", i); 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate match.iim_name = (char *)strdata->d_buf + sym.st_name; 3720Sstevel@tonic-gate match.iim_bind = GELF_ST_BIND(sym.st_info); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate switch (GELF_ST_TYPE(sym.st_info)) { 3750Sstevel@tonic-gate case STT_FILE: 3760Sstevel@tonic-gate match.iim_file = match.iim_name; 3770Sstevel@tonic-gate continue; 3780Sstevel@tonic-gate case STT_OBJECT: 3790Sstevel@tonic-gate tolist = iiburst->iib_objts; 3800Sstevel@tonic-gate curr = &iiburst->iib_nobjts; 3810Sstevel@tonic-gate break; 3820Sstevel@tonic-gate case STT_FUNC: 3830Sstevel@tonic-gate tolist = iiburst->iib_funcs; 3840Sstevel@tonic-gate curr = &iiburst->iib_nfuncs; 3850Sstevel@tonic-gate break; 3860Sstevel@tonic-gate default: 3870Sstevel@tonic-gate continue; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate if (ignore_symbol(&sym, match.iim_name)) 3910Sstevel@tonic-gate continue; 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate iidesc = find_iidesc(td->td_iihash, &match); 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate if (iidesc != NULL) { 3960Sstevel@tonic-gate tolist[*curr] = iidesc; 3970Sstevel@tonic-gate iidesc->ii_flags |= IIDESC_F_USED; 3980Sstevel@tonic-gate (*curr)++; 3990Sstevel@tonic-gate continue; 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if (!check_for_weak(&sym, match.iim_file, data, nent, strdata, 4030Sstevel@tonic-gate &ssym, &smatch.iim_file)) { 4040Sstevel@tonic-gate (*curr)++; 4050Sstevel@tonic-gate continue; 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate smatch.iim_fuzzy = fuzzymatch; 4090Sstevel@tonic-gate smatch.iim_name = (char *)strdata->d_buf + ssym.st_name; 4100Sstevel@tonic-gate smatch.iim_bind = GELF_ST_BIND(ssym.st_info); 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate debug(3, "Weak symbol %s resolved to %s\n", match.iim_name, 4130Sstevel@tonic-gate smatch.iim_name); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate iidesc = find_iidesc(td->td_iihash, &smatch); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate if (iidesc != NULL) { 4180Sstevel@tonic-gate tolist[*curr] = copy_from_strong(td, &sym, 4190Sstevel@tonic-gate iidesc, match.iim_name, match.iim_file); 4200Sstevel@tonic-gate tolist[*curr]->ii_flags |= IIDESC_F_USED; 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate (*curr)++; 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate /* 4270Sstevel@tonic-gate * Stabs are generated for every function declared in a given C source 4280Sstevel@tonic-gate * file. When converting an object file, we may encounter a stab that 4290Sstevel@tonic-gate * has no symbol table entry because the optimizer has decided to omit 4300Sstevel@tonic-gate * that item (for example, an unreferenced static function). We may 4310Sstevel@tonic-gate * see iidescs that do not have an associated symtab entry, and so 4320Sstevel@tonic-gate * we do not write records for those functions into the CTF data. 4330Sstevel@tonic-gate * All others get marked as a root by this function. 4340Sstevel@tonic-gate */ 4350Sstevel@tonic-gate iiburst_types(iiburst); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate /* 4380Sstevel@tonic-gate * By not adding some of the functions and/or objects, we may have 4390Sstevel@tonic-gate * caused some types that were referenced solely by those 4400Sstevel@tonic-gate * functions/objects to be suppressed. This could cause a label, 4410Sstevel@tonic-gate * generated prior to the evisceration, to be incorrect. Find the 4420Sstevel@tonic-gate * highest type index, and change the label indicies to be no higher 4430Sstevel@tonic-gate * than this value. 4440Sstevel@tonic-gate */ 4450Sstevel@tonic-gate tdata_label_newmax(td, iiburst->iib_maxtypeid); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate return (iiburst); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate static void 4510Sstevel@tonic-gate write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname, 4520Sstevel@tonic-gate caddr_t ctfdata, size_t ctfsize, int flags) 4530Sstevel@tonic-gate { 4540Sstevel@tonic-gate GElf_Ehdr sehdr, dehdr; 4550Sstevel@tonic-gate Elf_Scn *sscn, *dscn; 4560Sstevel@tonic-gate Elf_Data *sdata, *ddata; 4570Sstevel@tonic-gate GElf_Shdr shdr; 4580Sstevel@tonic-gate GElf_Word symtab_type; 4590Sstevel@tonic-gate int symtab_idx = -1; 4600Sstevel@tonic-gate off_t new_offset = 0; 4610Sstevel@tonic-gate off_t ctfnameoff = 0; 4620Sstevel@tonic-gate int dynsym = (flags & CTF_USE_DYNSYM); 4630Sstevel@tonic-gate int keep_stabs = (flags & CTF_KEEP_STABS); 4640Sstevel@tonic-gate int *secxlate; 4650Sstevel@tonic-gate int srcidx, dstidx; 4660Sstevel@tonic-gate int curnmoff = 0; 4670Sstevel@tonic-gate int changing = 0; 4680Sstevel@tonic-gate int pad; 4690Sstevel@tonic-gate int i; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate if (gelf_newehdr(dst, gelf_getclass(src)) == NULL) 4720Sstevel@tonic-gate elfterminate(dstname, "Cannot copy ehdr to temp file"); 4730Sstevel@tonic-gate gelf_getehdr(src, &sehdr); 4740Sstevel@tonic-gate memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr)); 4750Sstevel@tonic-gate gelf_update_ehdr(dst, &dehdr); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate /* 4800Sstevel@tonic-gate * Neither the existing stab sections nor the SUNW_ctf sections (new or 4810Sstevel@tonic-gate * existing) are SHF_ALLOC'd, so they won't be in areas referenced by 4820Sstevel@tonic-gate * program headers. As such, we can just blindly copy the program 4830Sstevel@tonic-gate * headers from the existing file to the new file. 4840Sstevel@tonic-gate */ 4850Sstevel@tonic-gate if (sehdr.e_phnum != 0) { 4860Sstevel@tonic-gate (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT); 4870Sstevel@tonic-gate if (gelf_newphdr(dst, sehdr.e_phnum) == NULL) 4880Sstevel@tonic-gate elfterminate(dstname, "Cannot make phdrs in temp file"); 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate for (i = 0; i < sehdr.e_phnum; i++) { 4910Sstevel@tonic-gate GElf_Phdr phdr; 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate gelf_getphdr(src, i, &phdr); 4940Sstevel@tonic-gate gelf_update_phdr(dst, i, &phdr); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate secxlate = xmalloc(sizeof (int) * sehdr.e_shnum); 4990Sstevel@tonic-gate for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) { 5000Sstevel@tonic-gate Elf_Scn *scn = elf_getscn(src, srcidx); 5010Sstevel@tonic-gate GElf_Shdr shdr; 5020Sstevel@tonic-gate char *sname; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate gelf_getshdr(scn, &shdr); 5050Sstevel@tonic-gate sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name); 5060Sstevel@tonic-gate if (sname == NULL) { 5070Sstevel@tonic-gate elfterminate(srcname, "Can't find string at %u", 5080Sstevel@tonic-gate shdr.sh_name); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) { 5120Sstevel@tonic-gate secxlate[srcidx] = -1; 5130Sstevel@tonic-gate } else if (!keep_stabs && 5140Sstevel@tonic-gate (strncmp(sname, ".stab", 5) == 0 || 5150Sstevel@tonic-gate strncmp(sname, ".debug", 6) == 0 || 5160Sstevel@tonic-gate strncmp(sname, ".rel.debug", 10) == 0 || 5170Sstevel@tonic-gate strncmp(sname, ".rela.debug", 11) == 0)) { 5180Sstevel@tonic-gate secxlate[srcidx] = -1; 5190Sstevel@tonic-gate } else if (dynsym && shdr.sh_type == SHT_SYMTAB) { 5200Sstevel@tonic-gate /* 5210Sstevel@tonic-gate * If we're building CTF against the dynsym, 5220Sstevel@tonic-gate * we'll rip out the symtab so debuggers aren't 5230Sstevel@tonic-gate * confused. 5240Sstevel@tonic-gate */ 5250Sstevel@tonic-gate secxlate[srcidx] = -1; 5260Sstevel@tonic-gate } else { 5270Sstevel@tonic-gate secxlate[srcidx] = dstidx++; 5280Sstevel@tonic-gate curnmoff += strlen(sname) + 1; 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate new_offset = (off_t)dehdr.e_phoff; 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) { 5350Sstevel@tonic-gate char *sname; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate sscn = elf_getscn(src, srcidx); 5380Sstevel@tonic-gate gelf_getshdr(sscn, &shdr); 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate if (secxlate[srcidx] == -1) { 5410Sstevel@tonic-gate changing = 1; 5420Sstevel@tonic-gate continue; 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate dscn = elf_newscn(dst); 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate * If this file has program headers, we need to explicitly lay 5490Sstevel@tonic-gate * out sections. If none of the sections prior to this one have 5500Sstevel@tonic-gate * been removed, then we can just use the existing location. If 5510Sstevel@tonic-gate * one or more sections have been changed, then we need to 5520Sstevel@tonic-gate * adjust this one to avoid holes. 5530Sstevel@tonic-gate */ 5540Sstevel@tonic-gate if (changing && sehdr.e_phnum != 0) { 5550Sstevel@tonic-gate pad = new_offset % shdr.sh_addralign; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate if (pad) 5580Sstevel@tonic-gate new_offset += shdr.sh_addralign - pad; 5590Sstevel@tonic-gate shdr.sh_offset = new_offset; 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate shdr.sh_link = secxlate[shdr.sh_link]; 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA) 5650Sstevel@tonic-gate shdr.sh_info = secxlate[shdr.sh_info]; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name); 5680Sstevel@tonic-gate if (sname == NULL) { 5690Sstevel@tonic-gate elfterminate(srcname, "Can't find string at %u", 5700Sstevel@tonic-gate shdr.sh_name); 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate if ((sdata = elf_getdata(sscn, NULL)) == NULL) 5730Sstevel@tonic-gate elfterminate(srcname, "Cannot get sect %s data", sname); 5740Sstevel@tonic-gate if ((ddata = elf_newdata(dscn)) == NULL) 5750Sstevel@tonic-gate elfterminate(dstname, "Can't make sect %s data", sname); 5760Sstevel@tonic-gate bcopy(sdata, ddata, sizeof (Elf_Data)); 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate if (srcidx == sehdr.e_shstrndx) { 5790Sstevel@tonic-gate char seclen = strlen(CTF_ELF_SCN_NAME); 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size + 5820Sstevel@tonic-gate seclen + 1); 5830Sstevel@tonic-gate bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 5840Sstevel@tonic-gate strcpy((caddr_t)ddata->d_buf + shdr.sh_size, 5850Sstevel@tonic-gate CTF_ELF_SCN_NAME); 5860Sstevel@tonic-gate ctfnameoff = (off_t)shdr.sh_size; 5870Sstevel@tonic-gate shdr.sh_size += seclen + 1; 5880Sstevel@tonic-gate ddata->d_size += seclen + 1; 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate if (sehdr.e_phnum != 0) 5910Sstevel@tonic-gate changing = 1; 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) { 5950Sstevel@tonic-gate int nsym = shdr.sh_size / shdr.sh_entsize; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate symtab_idx = secxlate[srcidx]; 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate ddata->d_buf = xmalloc(shdr.sh_size); 6000Sstevel@tonic-gate bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size); 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate for (i = 0; i < nsym; i++) { 6030Sstevel@tonic-gate GElf_Sym sym; 6040Sstevel@tonic-gate short newscn; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate (void) gelf_getsym(ddata, i, &sym); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate if (sym.st_shndx >= SHN_LORESERVE) 6090Sstevel@tonic-gate continue; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate if ((newscn = secxlate[sym.st_shndx]) != 6120Sstevel@tonic-gate sym.st_shndx) { 6130Sstevel@tonic-gate sym.st_shndx = 6140Sstevel@tonic-gate (newscn == -1 ? 1 : newscn); 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate gelf_update_sym(ddata, i, &sym); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate if (gelf_update_shdr(dscn, &shdr) == NULL) 6220Sstevel@tonic-gate elfterminate(dstname, "Cannot update sect %s", sname); 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate new_offset = (off_t)shdr.sh_offset; 6250Sstevel@tonic-gate if (shdr.sh_type != SHT_NOBITS) 6260Sstevel@tonic-gate new_offset += shdr.sh_size; 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate if (symtab_idx == -1) { 630*1951Sjohnlev terminate("%s: Cannot find %s section\n", srcname, 6310Sstevel@tonic-gate dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB"); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate /* Add the ctf section */ 6350Sstevel@tonic-gate dscn = elf_newscn(dst); 6360Sstevel@tonic-gate gelf_getshdr(dscn, &shdr); 6370Sstevel@tonic-gate shdr.sh_name = ctfnameoff; 6380Sstevel@tonic-gate shdr.sh_type = SHT_PROGBITS; 6390Sstevel@tonic-gate shdr.sh_size = ctfsize; 6400Sstevel@tonic-gate shdr.sh_link = symtab_idx; 6410Sstevel@tonic-gate shdr.sh_addralign = 4; 6420Sstevel@tonic-gate if (changing && sehdr.e_phnum != 0) { 6430Sstevel@tonic-gate pad = new_offset % shdr.sh_addralign; 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate if (pad) 6460Sstevel@tonic-gate new_offset += shdr.sh_addralign - pad; 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate shdr.sh_offset = new_offset; 6490Sstevel@tonic-gate new_offset += shdr.sh_size; 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate ddata = elf_newdata(dscn); 6530Sstevel@tonic-gate ddata->d_buf = ctfdata; 6540Sstevel@tonic-gate ddata->d_size = ctfsize; 6550Sstevel@tonic-gate ddata->d_align = shdr.sh_addralign; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate gelf_update_shdr(dscn, &shdr); 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate /* update the section header location */ 6600Sstevel@tonic-gate if (sehdr.e_phnum != 0) { 6610Sstevel@tonic-gate size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT); 6620Sstevel@tonic-gate size_t r = new_offset % align; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate if (r) 6650Sstevel@tonic-gate new_offset += align - r; 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate dehdr.e_shoff = new_offset; 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* commit to disk */ 6710Sstevel@tonic-gate dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx]; 6720Sstevel@tonic-gate gelf_update_ehdr(dst, &dehdr); 6730Sstevel@tonic-gate if (elf_update(dst, ELF_C_WRITE) < 0) 6740Sstevel@tonic-gate elfterminate(dstname, "Cannot finalize temp file"); 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate free(secxlate); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate static caddr_t 6800Sstevel@tonic-gate make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags) 6810Sstevel@tonic-gate { 6820Sstevel@tonic-gate iiburst_t *iiburst; 6830Sstevel@tonic-gate caddr_t data; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH, 6860Sstevel@tonic-gate flags & CTF_USE_DYNSYM); 6870Sstevel@tonic-gate data = ctf_gen(iiburst, lenp, flags & CTF_COMPRESS); 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate iiburst_free(iiburst); 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate return (data); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate void 6950Sstevel@tonic-gate write_ctf(tdata_t *td, const char *curname, const char *newname, int flags) 6960Sstevel@tonic-gate { 6970Sstevel@tonic-gate struct stat st; 6980Sstevel@tonic-gate Elf *elf = NULL; 6990Sstevel@tonic-gate Elf *telf = NULL; 7000Sstevel@tonic-gate caddr_t data; 7010Sstevel@tonic-gate size_t len; 7020Sstevel@tonic-gate int fd = -1; 7030Sstevel@tonic-gate int tfd = -1; 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate (void) elf_version(EV_CURRENT); 7060Sstevel@tonic-gate if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0) 7070Sstevel@tonic-gate terminate("%s: Cannot open for re-reading", curname); 7080Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 7090Sstevel@tonic-gate elfterminate(curname, "Cannot re-read"); 7100Sstevel@tonic-gate 7111882Sjohnlev if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) 7120Sstevel@tonic-gate terminate("Cannot open temp file %s for writing", newname); 7130Sstevel@tonic-gate if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL) 7140Sstevel@tonic-gate elfterminate(curname, "Cannot write"); 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate data = make_ctf_data(td, elf, curname, &len, flags); 7170Sstevel@tonic-gate write_file(elf, curname, telf, newname, data, len, flags); 7180Sstevel@tonic-gate free(data); 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate elf_end(telf); 7210Sstevel@tonic-gate elf_end(elf); 7220Sstevel@tonic-gate (void) close(fd); 7230Sstevel@tonic-gate (void) close(tfd); 7240Sstevel@tonic-gate } 725