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