1327Sjkh/* 2379Sjkh * CDDL HEADER START 3327Sjkh * 4327Sjkh * The contents of this file are subject to the terms of the 5327Sjkh * Common Development and Distribution License (the "License"). 6327Sjkh * You may not use this file except in compliance with the License. 7327Sjkh * 8327Sjkh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9327Sjkh * or http://www.opensolaris.org/os/licensing. 10327Sjkh * See the License for the specific language governing permissions 11327Sjkh * and limitations under the License. 12327Sjkh * 13327Sjkh * When distributing Covered Code, include this CDDL HEADER in each 14327Sjkh * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15327Sjkh * If applicable, add the following below this CDDL HEADER, with the 16327Sjkh * fields enclosed by brackets "[]" replaced with your own identifying 17327Sjkh * information: Portions Copyright [yyyy] [name of copyright owner] 18327Sjkh * 19327Sjkh * CDDL HEADER END 20327Sjkh */ 21327Sjkh/* 22327Sjkh * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23327Sjkh * Use is subject to license terms. 24327Sjkh */ 25327Sjkh 26327Sjkh#pragma ident "%Z%%M% %I% %E% SMI" 27327Sjkh 28327Sjkh/* 29379Sjkh * Routines for retrieving CTF data from a .SUNW_ctf ELF section 30327Sjkh */ 31327Sjkh 32327Sjkh#include <stdio.h> 33379Sjkh#include <stdlib.h> 34383Sjkh#include <fcntl.h> 35327Sjkh#include <unistd.h> 36327Sjkh#include <gelf.h> 37327Sjkh#include <strings.h> 38327Sjkh#include <sys/types.h> 39327Sjkh 40327Sjkh#include "ctftools.h" 41327Sjkh#include "memory.h" 42327Sjkh#include "symbol.h" 43327Sjkh 44327Sjkhtypedef int read_cb_f(tdata_t *, char *, void *); 45327Sjkh 46327Sjkh/* 47327Sjkh * Return the source types that the object was generated from. 48327Sjkh */ 49327Sjkhsource_types_t 50327Sjkhbuilt_source_types(Elf *elf, char const *file) 51327Sjkh{ 52327Sjkh source_types_t types = SOURCE_NONE; 53327Sjkh symit_data_t *si; 54327Sjkh 55327Sjkh if ((si = symit_new(elf, file)) == NULL) 56327Sjkh return (SOURCE_NONE); 57327Sjkh 58327Sjkh while (symit_next(si, STT_FILE) != NULL) { 59327Sjkh char *name = symit_name(si); 60327Sjkh size_t len = strlen(name); 61327Sjkh if (len < 2 || name[len - 2] != '.') { 62327Sjkh types |= SOURCE_UNKNOWN; 63327Sjkh continue; 64327Sjkh } 65327Sjkh 66327Sjkh switch (name[len - 1]) { 67327Sjkh case 'c': 68327Sjkh types |= SOURCE_C; 69327Sjkh break; 70327Sjkh case 'h': 71327Sjkh /* ignore */ 72327Sjkh break; 73327Sjkh case 's': 74327Sjkh case 'S': 75327Sjkh types |= SOURCE_S; 76327Sjkh break; 77327Sjkh default: 78327Sjkh types |= SOURCE_UNKNOWN; 79327Sjkh } 80327Sjkh } 81327Sjkh 82327Sjkh symit_free(si); 83327Sjkh return (types); 84327Sjkh} 85327Sjkh 86327Sjkhstatic int 87327Sjkhread_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg, 88327Sjkh int require_ctf) 89379Sjkh{ 90379Sjkh Elf_Scn *ctfscn; 91379Sjkh Elf_Data *ctfdata = NULL; 92379Sjkh symit_data_t *si = NULL; 93383Sjkh int ctfscnidx; 94383Sjkh tdata_t *td; 95383Sjkh 96383Sjkh if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { 97327Sjkh if (require_ctf && 98327Sjkh (built_source_types(elf, file) & SOURCE_C)) { 99327Sjkh terminate("Input file %s was partially built from " 100327Sjkh "C sources, but no CTF data was present\n", file); 101327Sjkh } 102327Sjkh return (0); 103327Sjkh } 104327Sjkh 105327Sjkh if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL || 106327Sjkh (ctfdata = elf_getdata(ctfscn, NULL)) == NULL) 107327Sjkh elfterminate(file, "Cannot read CTF section"); 108327Sjkh 109327Sjkh /* Reconstruction of type tree */ 110327Sjkh if ((si = symit_new(elf, file)) == NULL) { 111327Sjkh warning("%s has no symbol table - skipping", file); 112327Sjkh return (0); 113327Sjkh } 114327Sjkh 115327Sjkh td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label); 116327Sjkh tdata_build_hashes(td); 117327Sjkh 118327Sjkh symit_free(si); 119327Sjkh 120327Sjkh if (td != NULL) { 121327Sjkh if (func(td, file, arg) < 0) 122327Sjkh return (-1); 123327Sjkh else 124327Sjkh return (1); 125327Sjkh } 126327Sjkh return (0); 127327Sjkh} 128327Sjkh 129327Sjkhstatic int 130327Sjkhread_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func, 131327Sjkh void *arg, int require_ctf) 132327Sjkh{ 133327Sjkh Elf *melf; 134327Sjkh Elf_Cmd cmd = ELF_C_READ; 135327Sjkh Elf_Arhdr *arh; 136327Sjkh int secnum = 1, found = 0; 137327Sjkh 138327Sjkh while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 139327Sjkh int rc = 0; 140327Sjkh 141327Sjkh if ((arh = elf_getarhdr(melf)) == NULL) { 142327Sjkh elfterminate(file, "Can't get archive header for " 143327Sjkh "member %d", secnum); 144327Sjkh } 145379Sjkh 146327Sjkh /* skip special sections - their names begin with "/" */ 147383Sjkh if (*arh->ar_name != '/') { 148327Sjkh size_t memlen = strlen(file) + 1 + 149327Sjkh strlen(arh->ar_name) + 1 + 1; 150327Sjkh 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 char *bname; 391 int check_sym = (type == STT_OBJECT || type == STT_FUNC); 392 393 for (; si->si_next < si->si_nument; si->si_next++) { 394 gelf_getsym(si->si_symd, si->si_next, &si->si_cursym); 395 gelf_getsym(si->si_symd, si->si_next, &sym); 396 si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name; 397 398 if (GELF_ST_TYPE(sym.st_info) == STT_FILE) { 399 bname = strrchr(si->si_curname, '/'); 400 si->si_curfile = bname == NULL ? si->si_curname : bname + 1; 401 } 402 403 if (GELF_ST_TYPE(sym.st_info) != type || 404 sym.st_shndx == SHN_UNDEF) 405 continue; 406 407 if (check_sym && ignore_symbol(&sym, si->si_curname)) 408 continue; 409 410 si->si_next++; 411 412 return (&si->si_cursym); 413 } 414 415 return (NULL); 416} 417 418char * 419symit_name(symit_data_t *si) 420{ 421 return (si->si_curname); 422} 423