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