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