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 retrieving CTF data from a .SUNW_ctf ELF section 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <gelf.h> 37 #include <strings.h> 38 #include <sys/types.h> 39 40 #include "ctftools.h" 41 #include "memory.h" 42 #include "symbol.h" 43 44 typedef int read_cb_f(tdata_t *, char *, void *); 45 46 /* 47 * Return the source types that the object was generated from. 48 */ 49 source_types_t 50 built_source_types(Elf *elf, char const *file) 51 { 52 source_types_t types = SOURCE_NONE; 53 symit_data_t *si; 54 55 if ((si = symit_new(elf, file)) == NULL) 56 return (SOURCE_NONE); 57 58 while (symit_next(si, STT_FILE) != NULL) { 59 char *name = symit_name(si); 60 size_t len = strlen(name); 61 if (len < 2 || name[len - 2] != '.') { 62 types |= SOURCE_UNKNOWN; 63 continue; 64 } 65 66 switch (name[len - 1]) { 67 case 'c': 68 types |= SOURCE_C; 69 break; 70 case 'h': 71 /* ignore */ 72 break; 73 case 's': 74 types |= SOURCE_S; 75 break; 76 default: 77 types |= SOURCE_UNKNOWN; 78 } 79 } 80 81 symit_free(si); 82 return (types); 83 } 84 85 static int 86 read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg, 87 int require_ctf) 88 { 89 Elf_Scn *ctfscn; 90 Elf_Data *ctfdata; 91 symit_data_t *si = NULL; 92 int ctfscnidx; 93 tdata_t *td; 94 95 if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { 96 if (require_ctf && 97 (built_source_types(elf, file) & SOURCE_C)) { 98 terminate("Input file %s was partially built from " 99 "C sources, but no CTF data was present\n", file); 100 } 101 return (0); 102 } 103 104 if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL || 105 (ctfdata = elf_getdata(ctfscn, NULL)) == NULL) 106 elfterminate(file, "Cannot read CTF section"); 107 108 /* Reconstruction of type tree */ 109 if ((si = symit_new(elf, file)) == NULL) { 110 warning("%s has no symbol table - skipping", file); 111 return (0); 112 } 113 114 td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label); 115 tdata_build_hashes(td); 116 117 symit_free(si); 118 119 if (td != NULL) { 120 if (func(td, file, arg) < 0) 121 return (-1); 122 else 123 return (1); 124 } 125 return (0); 126 } 127 128 static int 129 read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func, 130 void *arg, int require_ctf) 131 { 132 Elf *melf; 133 Elf_Cmd cmd = ELF_C_READ; 134 Elf_Arhdr *arh; 135 int secnum = 1, found = 0; 136 137 while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 138 int rc = 0; 139 140 if ((arh = elf_getarhdr(melf)) == NULL) { 141 elfterminate(file, "Can't get archive header for " 142 "member %d", secnum); 143 } 144 145 /* skip special sections - their names begin with "/" */ 146 if (*arh->ar_name != '/') { 147 size_t memlen = strlen(file) + 1 + 148 strlen(arh->ar_name) + 1 + 1; 149 char *memname = xmalloc(memlen); 150 151 snprintf(memname, memlen, "%s(%s)", file, arh->ar_name); 152 153 switch (elf_kind(melf)) { 154 case ELF_K_AR: 155 rc = read_archive(fd, melf, memname, label, 156 func, arg, require_ctf); 157 break; 158 case ELF_K_ELF: 159 rc = read_file(melf, memname, label, 160 func, arg, require_ctf); 161 break; 162 default: 163 terminate("%s: Unknown elf kind %d\n", 164 memname, elf_kind(melf)); 165 } 166 167 free(memname); 168 } 169 170 cmd = elf_next(melf); 171 (void) elf_end(melf); 172 secnum++; 173 174 if (rc < 0) 175 return (rc); 176 else 177 found += rc; 178 } 179 180 return (found); 181 } 182 183 static int 184 read_ctf_common(char *file, char *label, read_cb_f *func, void *arg, 185 int require_ctf) 186 { 187 Elf *elf; 188 int found = 0; 189 int fd; 190 191 debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE")); 192 193 (void) elf_version(EV_CURRENT); 194 195 if ((fd = open(file, O_RDONLY)) < 0) 196 terminate("%s: Cannot open for reading", file); 197 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 198 elfterminate(file, "Cannot read"); 199 200 switch (elf_kind(elf)) { 201 case ELF_K_AR: 202 found = read_archive(fd, elf, file, label, 203 func, arg, require_ctf); 204 break; 205 206 case ELF_K_ELF: 207 found = read_file(elf, file, label, 208 func, arg, require_ctf); 209 break; 210 211 default: 212 terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf)); 213 } 214 215 (void) elf_end(elf); 216 (void) close(fd); 217 218 return (found); 219 } 220 221 /*ARGSUSED*/ 222 int 223 read_ctf_save_cb(tdata_t *td, char *name, void *retp) 224 { 225 tdata_t **tdp = retp; 226 227 *tdp = td; 228 229 return (1); 230 } 231 232 int 233 read_ctf(char **files, int n, char *label, read_cb_f *func, void *private, 234 int require_ctf) 235 { 236 int found; 237 int i, rc; 238 239 for (i = 0, found = 0; i < n; i++) { 240 if ((rc = read_ctf_common(files[i], label, func, 241 private, require_ctf)) < 0) 242 return (rc); 243 found += rc; 244 } 245 246 return (found); 247 } 248 249 static int 250 count_archive(int fd, Elf *elf, char *file) 251 { 252 Elf *melf; 253 Elf_Cmd cmd = ELF_C_READ; 254 Elf_Arhdr *arh; 255 int nfiles = 0, err = 0; 256 257 while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 258 if ((arh = elf_getarhdr(melf)) == NULL) { 259 warning("Can't process input archive %s\n", 260 file); 261 err++; 262 } 263 264 if (*arh->ar_name != '/') 265 nfiles++; 266 267 cmd = elf_next(melf); 268 (void) elf_end(melf); 269 } 270 271 if (err > 0) 272 return (-1); 273 274 return (nfiles); 275 } 276 277 int 278 count_files(char **files, int n) 279 { 280 int nfiles = 0, err = 0; 281 Elf *elf; 282 int fd, rc, i; 283 284 (void) elf_version(EV_CURRENT); 285 286 for (i = 0; i < n; i++) { 287 char *file = files[i]; 288 289 if ((fd = open(file, O_RDONLY)) < 0) { 290 warning("Can't read input file %s", file); 291 err++; 292 continue; 293 } 294 295 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 296 warning("Can't open input file %s: %s\n", file, 297 elf_errmsg(-1)); 298 err++; 299 (void) close(fd); 300 continue; 301 } 302 303 switch (elf_kind(elf)) { 304 case ELF_K_AR: 305 if ((rc = count_archive(fd, elf, file)) < 0) 306 err++; 307 else 308 nfiles += rc; 309 break; 310 case ELF_K_ELF: 311 nfiles++; 312 break; 313 default: 314 warning("Input file %s is corrupt\n", file); 315 err++; 316 } 317 318 (void) elf_end(elf); 319 (void) close(fd); 320 } 321 322 if (err > 0) 323 return (-1); 324 325 debug(2, "Found %d files in %d input files\n", nfiles, n); 326 327 return (nfiles); 328 } 329 330 struct symit_data { 331 GElf_Shdr si_shdr; 332 Elf_Data *si_symd; 333 Elf_Data *si_strd; 334 GElf_Sym si_cursym; 335 char *si_curname; 336 char *si_curfile; 337 int si_nument; 338 int si_next; 339 }; 340 341 symit_data_t * 342 symit_new(Elf *elf, const char *file) 343 { 344 symit_data_t *si; 345 Elf_Scn *scn; 346 int symtabidx; 347 348 if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0) 349 return (NULL); 350 351 si = xcalloc(sizeof (symit_data_t)); 352 353 if ((scn = elf_getscn(elf, symtabidx)) == NULL || 354 gelf_getshdr(scn, &si->si_shdr) == NULL || 355 (si->si_symd = elf_getdata(scn, NULL)) == NULL) 356 elfterminate(file, "Cannot read .symtab"); 357 358 if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL || 359 (si->si_strd = elf_getdata(scn, NULL)) == NULL) 360 elfterminate(file, "Cannot read strings for .symtab"); 361 362 si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize; 363 364 return (si); 365 } 366 367 void 368 symit_free(symit_data_t *si) 369 { 370 free(si); 371 } 372 373 void 374 symit_reset(symit_data_t *si) 375 { 376 si->si_next = 0; 377 } 378 379 char * 380 symit_curfile(symit_data_t *si) 381 { 382 return (si->si_curfile); 383 } 384 385 GElf_Sym * 386 symit_next(symit_data_t *si, int type) 387 { 388 GElf_Sym sym; 389 int check_sym = (type == STT_OBJECT || type == STT_FUNC); 390 391 for (; si->si_next < si->si_nument; si->si_next++) { 392 gelf_getsym(si->si_symd, si->si_next, &si->si_cursym); 393 gelf_getsym(si->si_symd, si->si_next, &sym); 394 si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name; 395 396 if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 397 si->si_curfile = si->si_curname; 398 399 if (GELF_ST_TYPE(sym.st_info) != type || 400 sym.st_shndx == SHN_UNDEF) 401 continue; 402 403 if (check_sym && ignore_symbol(&sym, si->si_curname)) 404 continue; 405 406 si->si_next++; 407 408 return (&si->si_cursym); 409 } 410 411 return (NULL); 412 } 413 414 char * 415 symit_name(symit_data_t *si) 416 { 417 return (si->si_curname); 418 }