input.c revision 178481
150476Speter/* 247831Sfoxfair * CDDL HEADER START 347831Sfoxfair * 447831Sfoxfair * The contents of this file are subject to the terms of the 547831Sfoxfair * Common Development and Distribution License (the "License"). 647831Sfoxfair * You may not use this file except in compliance with the License. 747831Sfoxfair * 847831Sfoxfair * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 947831Sfoxfair * or http://www.opensolaris.org/os/licensing. 1047831Sfoxfair * See the License for the specific language governing permissions 1147831Sfoxfair * and limitations under the License. 1247831Sfoxfair * 1347831Sfoxfair * When distributing Covered Code, include this CDDL HEADER in each 1447831Sfoxfair * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1547831Sfoxfair * If applicable, add the following below this CDDL HEADER, with the 1647831Sfoxfair * fields enclosed by brackets "[]" replaced with your own identifying 1747831Sfoxfair * information: Portions Copyright [yyyy] [name of copyright owner] 1847831Sfoxfair * 1947831Sfoxfair * CDDL HEADER END 2047831Sfoxfair */ 2147831Sfoxfair/* 2247831Sfoxfair * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2347831Sfoxfair * Use is subject to license terms. 2447831Sfoxfair */ 2547831Sfoxfair 2647831Sfoxfair#pragma ident "%Z%%M% %I% %E% SMI" 2747831Sfoxfair 2847831Sfoxfair/* 2947831Sfoxfair * Routines for retrieving CTF data from a .SUNW_ctf ELF section 3047831Sfoxfair */ 3147831Sfoxfair 3247831Sfoxfair#include <stdio.h> 3347831Sfoxfair#include <stdlib.h> 3447831Sfoxfair#include <fcntl.h> 3547831Sfoxfair#include <unistd.h> 3647831Sfoxfair#include <gelf.h> 3747831Sfoxfair#include <strings.h> 3847831Sfoxfair#include <sys/types.h> 3947831Sfoxfair 4047831Sfoxfair#include "ctftools.h" 4147831Sfoxfair#include "memory.h" 4247831Sfoxfair#include "symbol.h" 4347831Sfoxfair 4447831Sfoxfairtypedef int read_cb_f(tdata_t *, char *, void *); 4547831Sfoxfair 4647831Sfoxfair/* 4747831Sfoxfair * Return the source types that the object was generated from. 4847831Sfoxfair */ 4947831Sfoxfairsource_types_t 5047831Sfoxfairbuilt_source_types(Elf *elf, char const *file) 5147831Sfoxfair{ 5247831Sfoxfair source_types_t types = SOURCE_NONE; 5347831Sfoxfair symit_data_t *si; 5447831Sfoxfair 5547831Sfoxfair if ((si = symit_new(elf, file)) == NULL) 5647831Sfoxfair return (SOURCE_NONE); 5747831Sfoxfair 5847831Sfoxfair while (symit_next(si, STT_FILE) != NULL) { 5947831Sfoxfair char *name = symit_name(si); 6047831Sfoxfair size_t len = strlen(name); 6147831Sfoxfair if (len < 2 || name[len - 2] != '.') { 6247831Sfoxfair types |= SOURCE_UNKNOWN; 6347831Sfoxfair continue; 6447831Sfoxfair } 6547831Sfoxfair 6653943Sache switch (name[len - 1]) { 6747831Sfoxfair case 'c': 6847831Sfoxfair types |= SOURCE_C; 6947831Sfoxfair break; 7047831Sfoxfair case 'h': 7147831Sfoxfair /* ignore */ 7247831Sfoxfair break; 7347831Sfoxfair case 's': 7447831Sfoxfair case 'S': 7547831Sfoxfair types |= SOURCE_S; 7647831Sfoxfair break; 7747831Sfoxfair default: 7847831Sfoxfair types |= SOURCE_UNKNOWN; 7953943Sache } 8053943Sache } 8153943Sache 8253943Sache symit_free(si); 8353943Sache return (types); 8453943Sache} 8553943Sache 8653943Sachestatic int 8753943Sacheread_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg, 8853943Sache int require_ctf) 8953943Sache{ 9053943Sache Elf_Scn *ctfscn; 9153943Sache Elf_Data *ctfdata = NULL; 9253943Sache symit_data_t *si = NULL; 9353943Sache int ctfscnidx; 9453943Sache tdata_t *td; 9553943Sache 9653943Sache if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { 9753943Sache 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 129static int 130read_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 184static int 185read_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*/ 223int 224read_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 233int 234read_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 250static int 251count_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 278int 279count_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 331struct 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 342symit_data_t * 343symit_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 368void 369symit_free(symit_data_t *si) 370{ 371 free(si); 372} 373 374void 375symit_reset(symit_data_t *si) 376{ 377 si->si_next = 0; 378} 379 380char * 381symit_curfile(symit_data_t *si) 382{ 383 return (si->si_curfile); 384} 385 386GElf_Sym * 387symit_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 415char * 416symit_name(symit_data_t *si) 417{ 418 return (si->si_curname); 419} 420