11673e404SJohn Birrell /* 21673e404SJohn Birrell * CDDL HEADER START 31673e404SJohn Birrell * 41673e404SJohn Birrell * The contents of this file are subject to the terms of the 51673e404SJohn Birrell * Common Development and Distribution License (the "License"). 61673e404SJohn Birrell * You may not use this file except in compliance with the License. 71673e404SJohn Birrell * 81673e404SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91673e404SJohn Birrell * or http://www.opensolaris.org/os/licensing. 101673e404SJohn Birrell * See the License for the specific language governing permissions 111673e404SJohn Birrell * and limitations under the License. 121673e404SJohn Birrell * 131673e404SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 141673e404SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151673e404SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 161673e404SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 171673e404SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 181673e404SJohn Birrell * 191673e404SJohn Birrell * CDDL HEADER END 201673e404SJohn Birrell */ 211673e404SJohn Birrell /* 221673e404SJohn Birrell * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 231673e404SJohn Birrell * Use is subject to license terms. 241673e404SJohn Birrell */ 251673e404SJohn Birrell 261673e404SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 271673e404SJohn Birrell 281673e404SJohn Birrell /* 291673e404SJohn Birrell * Routines for retrieving CTF data from a .SUNW_ctf ELF section 301673e404SJohn Birrell */ 311673e404SJohn Birrell 321673e404SJohn Birrell #include <stdio.h> 331673e404SJohn Birrell #include <stdlib.h> 341673e404SJohn Birrell #include <fcntl.h> 351673e404SJohn Birrell #include <unistd.h> 361673e404SJohn Birrell #include <gelf.h> 371673e404SJohn Birrell #include <strings.h> 381673e404SJohn Birrell #include <sys/types.h> 391673e404SJohn Birrell 401673e404SJohn Birrell #include "ctftools.h" 411673e404SJohn Birrell #include "memory.h" 421673e404SJohn Birrell #include "symbol.h" 431673e404SJohn Birrell 441673e404SJohn Birrell typedef int read_cb_f(tdata_t *, char *, void *); 451673e404SJohn Birrell 461673e404SJohn Birrell /* 471673e404SJohn Birrell * Return the source types that the object was generated from. 481673e404SJohn Birrell */ 491673e404SJohn Birrell source_types_t 501673e404SJohn Birrell built_source_types(Elf *elf, char const *file) 511673e404SJohn Birrell { 521673e404SJohn Birrell source_types_t types = SOURCE_NONE; 531673e404SJohn Birrell symit_data_t *si; 541673e404SJohn Birrell 551673e404SJohn Birrell if ((si = symit_new(elf, file)) == NULL) 561673e404SJohn Birrell return (SOURCE_NONE); 571673e404SJohn Birrell 581673e404SJohn Birrell while (symit_next(si, STT_FILE) != NULL) { 591673e404SJohn Birrell char *name = symit_name(si); 601673e404SJohn Birrell size_t len = strlen(name); 611673e404SJohn Birrell if (len < 2 || name[len - 2] != '.') { 621673e404SJohn Birrell types |= SOURCE_UNKNOWN; 631673e404SJohn Birrell continue; 641673e404SJohn Birrell } 651673e404SJohn Birrell 661673e404SJohn Birrell switch (name[len - 1]) { 671673e404SJohn Birrell case 'c': 681673e404SJohn Birrell types |= SOURCE_C; 691673e404SJohn Birrell break; 701673e404SJohn Birrell case 'h': 711673e404SJohn Birrell /* ignore */ 721673e404SJohn Birrell break; 731673e404SJohn Birrell case 's': 741673e404SJohn Birrell case 'S': 751673e404SJohn Birrell types |= SOURCE_S; 761673e404SJohn Birrell break; 771673e404SJohn Birrell default: 781673e404SJohn Birrell types |= SOURCE_UNKNOWN; 791673e404SJohn Birrell } 801673e404SJohn Birrell } 811673e404SJohn Birrell 821673e404SJohn Birrell symit_free(si); 831673e404SJohn Birrell return (types); 841673e404SJohn Birrell } 851673e404SJohn Birrell 861673e404SJohn Birrell static int 871673e404SJohn Birrell read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg, 881673e404SJohn Birrell int require_ctf) 891673e404SJohn Birrell { 901673e404SJohn Birrell Elf_Scn *ctfscn; 911673e404SJohn Birrell Elf_Data *ctfdata = NULL; 921673e404SJohn Birrell symit_data_t *si = NULL; 931673e404SJohn Birrell int ctfscnidx; 941673e404SJohn Birrell tdata_t *td; 951673e404SJohn Birrell 961673e404SJohn Birrell if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { 971673e404SJohn Birrell if (require_ctf && 981673e404SJohn Birrell (built_source_types(elf, file) & SOURCE_C)) { 991673e404SJohn Birrell terminate("Input file %s was partially built from " 1001673e404SJohn Birrell "C sources, but no CTF data was present\n", file); 1011673e404SJohn Birrell } 1021673e404SJohn Birrell return (0); 1031673e404SJohn Birrell } 1041673e404SJohn Birrell 1051673e404SJohn Birrell if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL || 1061673e404SJohn Birrell (ctfdata = elf_getdata(ctfscn, NULL)) == NULL) 1071673e404SJohn Birrell elfterminate(file, "Cannot read CTF section"); 1081673e404SJohn Birrell 1091673e404SJohn Birrell /* Reconstruction of type tree */ 1101673e404SJohn Birrell if ((si = symit_new(elf, file)) == NULL) { 1111673e404SJohn Birrell warning("%s has no symbol table - skipping", file); 1121673e404SJohn Birrell return (0); 1131673e404SJohn Birrell } 1141673e404SJohn Birrell 1151673e404SJohn Birrell td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label); 1161673e404SJohn Birrell tdata_build_hashes(td); 1171673e404SJohn Birrell 1181673e404SJohn Birrell symit_free(si); 1191673e404SJohn Birrell 1201673e404SJohn Birrell if (td != NULL) { 1211673e404SJohn Birrell if (func(td, file, arg) < 0) 1221673e404SJohn Birrell return (-1); 1231673e404SJohn Birrell else 1241673e404SJohn Birrell return (1); 1251673e404SJohn Birrell } 1261673e404SJohn Birrell return (0); 1271673e404SJohn Birrell } 1281673e404SJohn Birrell 1291673e404SJohn Birrell static int 1301673e404SJohn Birrell read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func, 1311673e404SJohn Birrell void *arg, int require_ctf) 1321673e404SJohn Birrell { 1331673e404SJohn Birrell Elf *melf; 1341673e404SJohn Birrell Elf_Cmd cmd = ELF_C_READ; 1351673e404SJohn Birrell Elf_Arhdr *arh; 1361673e404SJohn Birrell int secnum = 1, found = 0; 1371673e404SJohn Birrell 1381673e404SJohn Birrell while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 1391673e404SJohn Birrell int rc = 0; 1401673e404SJohn Birrell 1411673e404SJohn Birrell if ((arh = elf_getarhdr(melf)) == NULL) { 1421673e404SJohn Birrell elfterminate(file, "Can't get archive header for " 1431673e404SJohn Birrell "member %d", secnum); 1441673e404SJohn Birrell } 1451673e404SJohn Birrell 1461673e404SJohn Birrell /* skip special sections - their names begin with "/" */ 1471673e404SJohn Birrell if (*arh->ar_name != '/') { 1481673e404SJohn Birrell size_t memlen = strlen(file) + 1 + 1491673e404SJohn Birrell strlen(arh->ar_name) + 1 + 1; 1501673e404SJohn Birrell char *memname = xmalloc(memlen); 1511673e404SJohn Birrell 1521673e404SJohn Birrell snprintf(memname, memlen, "%s(%s)", file, arh->ar_name); 1531673e404SJohn Birrell 1541673e404SJohn Birrell switch (elf_kind(melf)) { 1551673e404SJohn Birrell case ELF_K_AR: 1561673e404SJohn Birrell rc = read_archive(fd, melf, memname, label, 1571673e404SJohn Birrell func, arg, require_ctf); 1581673e404SJohn Birrell break; 1591673e404SJohn Birrell case ELF_K_ELF: 1601673e404SJohn Birrell rc = read_file(melf, memname, label, 1611673e404SJohn Birrell func, arg, require_ctf); 1621673e404SJohn Birrell break; 1631673e404SJohn Birrell default: 1641673e404SJohn Birrell terminate("%s: Unknown elf kind %d\n", 1651673e404SJohn Birrell memname, elf_kind(melf)); 1661673e404SJohn Birrell } 1671673e404SJohn Birrell 1681673e404SJohn Birrell free(memname); 1691673e404SJohn Birrell } 1701673e404SJohn Birrell 1711673e404SJohn Birrell cmd = elf_next(melf); 1721673e404SJohn Birrell (void) elf_end(melf); 1731673e404SJohn Birrell secnum++; 1741673e404SJohn Birrell 1751673e404SJohn Birrell if (rc < 0) 1761673e404SJohn Birrell return (rc); 1771673e404SJohn Birrell else 1781673e404SJohn Birrell found += rc; 1791673e404SJohn Birrell } 1801673e404SJohn Birrell 1811673e404SJohn Birrell return (found); 1821673e404SJohn Birrell } 1831673e404SJohn Birrell 1841673e404SJohn Birrell static int 1851673e404SJohn Birrell read_ctf_common(char *file, char *label, read_cb_f *func, void *arg, 1861673e404SJohn Birrell int require_ctf) 1871673e404SJohn Birrell { 1881673e404SJohn Birrell Elf *elf; 1891673e404SJohn Birrell int found = 0; 1901673e404SJohn Birrell int fd; 1911673e404SJohn Birrell 1921673e404SJohn Birrell debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE")); 1931673e404SJohn Birrell 1941673e404SJohn Birrell (void) elf_version(EV_CURRENT); 1951673e404SJohn Birrell 1961673e404SJohn Birrell if ((fd = open(file, O_RDONLY)) < 0) 1971673e404SJohn Birrell terminate("%s: Cannot open for reading", file); 1981673e404SJohn Birrell if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 1991673e404SJohn Birrell elfterminate(file, "Cannot read"); 2001673e404SJohn Birrell 2011673e404SJohn Birrell switch (elf_kind(elf)) { 2021673e404SJohn Birrell case ELF_K_AR: 2031673e404SJohn Birrell found = read_archive(fd, elf, file, label, 2041673e404SJohn Birrell func, arg, require_ctf); 2051673e404SJohn Birrell break; 2061673e404SJohn Birrell 2071673e404SJohn Birrell case ELF_K_ELF: 2081673e404SJohn Birrell found = read_file(elf, file, label, 2091673e404SJohn Birrell func, arg, require_ctf); 2101673e404SJohn Birrell break; 2111673e404SJohn Birrell 2121673e404SJohn Birrell default: 2131673e404SJohn Birrell terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf)); 2141673e404SJohn Birrell } 2151673e404SJohn Birrell 2161673e404SJohn Birrell (void) elf_end(elf); 2171673e404SJohn Birrell (void) close(fd); 2181673e404SJohn Birrell 2191673e404SJohn Birrell return (found); 2201673e404SJohn Birrell } 2211673e404SJohn Birrell 2221673e404SJohn Birrell /*ARGSUSED*/ 2231673e404SJohn Birrell int 2241673e404SJohn Birrell read_ctf_save_cb(tdata_t *td, char *name __unused, void *retp) 2251673e404SJohn Birrell { 2261673e404SJohn Birrell tdata_t **tdp = retp; 2271673e404SJohn Birrell 2281673e404SJohn Birrell *tdp = td; 2291673e404SJohn Birrell 2301673e404SJohn Birrell return (1); 2311673e404SJohn Birrell } 2321673e404SJohn Birrell 2331673e404SJohn Birrell int 2341673e404SJohn Birrell read_ctf(char **files, int n, char *label, read_cb_f *func, void *private, 2351673e404SJohn Birrell int require_ctf) 2361673e404SJohn Birrell { 2371673e404SJohn Birrell int found; 2381673e404SJohn Birrell int i, rc; 2391673e404SJohn Birrell 2401673e404SJohn Birrell for (i = 0, found = 0; i < n; i++) { 2411673e404SJohn Birrell if ((rc = read_ctf_common(files[i], label, func, 2421673e404SJohn Birrell private, require_ctf)) < 0) 2431673e404SJohn Birrell return (rc); 2441673e404SJohn Birrell found += rc; 2451673e404SJohn Birrell } 2461673e404SJohn Birrell 2471673e404SJohn Birrell return (found); 2481673e404SJohn Birrell } 2491673e404SJohn Birrell 2501673e404SJohn Birrell static int 2511673e404SJohn Birrell count_archive(int fd, Elf *elf, char *file) 2521673e404SJohn Birrell { 2531673e404SJohn Birrell Elf *melf; 2541673e404SJohn Birrell Elf_Cmd cmd = ELF_C_READ; 2551673e404SJohn Birrell Elf_Arhdr *arh; 2561673e404SJohn Birrell int nfiles = 0, err = 0; 2571673e404SJohn Birrell 2581673e404SJohn Birrell while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 2591673e404SJohn Birrell if ((arh = elf_getarhdr(melf)) == NULL) { 2601673e404SJohn Birrell warning("Can't process input archive %s\n", 2611673e404SJohn Birrell file); 2621673e404SJohn Birrell err++; 2631673e404SJohn Birrell } 2641673e404SJohn Birrell 2651673e404SJohn Birrell if (*arh->ar_name != '/') 2661673e404SJohn Birrell nfiles++; 2671673e404SJohn Birrell 2681673e404SJohn Birrell cmd = elf_next(melf); 2691673e404SJohn Birrell (void) elf_end(melf); 2701673e404SJohn Birrell } 2711673e404SJohn Birrell 2721673e404SJohn Birrell if (err > 0) 2731673e404SJohn Birrell return (-1); 2741673e404SJohn Birrell 2751673e404SJohn Birrell return (nfiles); 2761673e404SJohn Birrell } 2771673e404SJohn Birrell 2781673e404SJohn Birrell int 2791673e404SJohn Birrell count_files(char **files, int n) 2801673e404SJohn Birrell { 2811673e404SJohn Birrell int nfiles = 0, err = 0; 2821673e404SJohn Birrell Elf *elf; 2831673e404SJohn Birrell int fd, rc, i; 2841673e404SJohn Birrell 2851673e404SJohn Birrell (void) elf_version(EV_CURRENT); 2861673e404SJohn Birrell 2871673e404SJohn Birrell for (i = 0; i < n; i++) { 2881673e404SJohn Birrell char *file = files[i]; 2891673e404SJohn Birrell 2901673e404SJohn Birrell if ((fd = open(file, O_RDONLY)) < 0) { 2911673e404SJohn Birrell warning("Can't read input file %s", file); 2921673e404SJohn Birrell err++; 2931673e404SJohn Birrell continue; 2941673e404SJohn Birrell } 2951673e404SJohn Birrell 2961673e404SJohn Birrell if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 2971673e404SJohn Birrell warning("Can't open input file %s: %s\n", file, 2981673e404SJohn Birrell elf_errmsg(-1)); 2991673e404SJohn Birrell err++; 3001673e404SJohn Birrell (void) close(fd); 3011673e404SJohn Birrell continue; 3021673e404SJohn Birrell } 3031673e404SJohn Birrell 3041673e404SJohn Birrell switch (elf_kind(elf)) { 3051673e404SJohn Birrell case ELF_K_AR: 3061673e404SJohn Birrell if ((rc = count_archive(fd, elf, file)) < 0) 3071673e404SJohn Birrell err++; 3081673e404SJohn Birrell else 3091673e404SJohn Birrell nfiles += rc; 3101673e404SJohn Birrell break; 3111673e404SJohn Birrell case ELF_K_ELF: 3121673e404SJohn Birrell nfiles++; 3131673e404SJohn Birrell break; 3141673e404SJohn Birrell default: 3151673e404SJohn Birrell warning("Input file %s is corrupt\n", file); 3161673e404SJohn Birrell err++; 3171673e404SJohn Birrell } 3181673e404SJohn Birrell 3191673e404SJohn Birrell (void) elf_end(elf); 3201673e404SJohn Birrell (void) close(fd); 3211673e404SJohn Birrell } 3221673e404SJohn Birrell 3231673e404SJohn Birrell if (err > 0) 3241673e404SJohn Birrell return (-1); 3251673e404SJohn Birrell 3261673e404SJohn Birrell debug(2, "Found %d files in %d input files\n", nfiles, n); 3271673e404SJohn Birrell 3281673e404SJohn Birrell return (nfiles); 3291673e404SJohn Birrell } 3301673e404SJohn Birrell 3311673e404SJohn Birrell struct symit_data { 3321673e404SJohn Birrell GElf_Shdr si_shdr; 3331673e404SJohn Birrell Elf_Data *si_symd; 3341673e404SJohn Birrell Elf_Data *si_strd; 3351673e404SJohn Birrell GElf_Sym si_cursym; 3361673e404SJohn Birrell char *si_curname; 3371673e404SJohn Birrell char *si_curfile; 3381673e404SJohn Birrell int si_nument; 3391673e404SJohn Birrell int si_next; 3401673e404SJohn Birrell }; 3411673e404SJohn Birrell 3421673e404SJohn Birrell symit_data_t * 3431673e404SJohn Birrell symit_new(Elf *elf, const char *file) 3441673e404SJohn Birrell { 3451673e404SJohn Birrell symit_data_t *si; 3461673e404SJohn Birrell Elf_Scn *scn; 3471673e404SJohn Birrell int symtabidx; 3481673e404SJohn Birrell 3491673e404SJohn Birrell if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0) 3501673e404SJohn Birrell return (NULL); 3511673e404SJohn Birrell 3521673e404SJohn Birrell si = xcalloc(sizeof (symit_data_t)); 3531673e404SJohn Birrell 3541673e404SJohn Birrell if ((scn = elf_getscn(elf, symtabidx)) == NULL || 3551673e404SJohn Birrell gelf_getshdr(scn, &si->si_shdr) == NULL || 3561673e404SJohn Birrell (si->si_symd = elf_getdata(scn, NULL)) == NULL) 3571673e404SJohn Birrell elfterminate(file, "Cannot read .symtab"); 3581673e404SJohn Birrell 3591673e404SJohn Birrell if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL || 3601673e404SJohn Birrell (si->si_strd = elf_getdata(scn, NULL)) == NULL) 3611673e404SJohn Birrell elfterminate(file, "Cannot read strings for .symtab"); 3621673e404SJohn Birrell 3631673e404SJohn Birrell si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize; 3641673e404SJohn Birrell 3651673e404SJohn Birrell return (si); 3661673e404SJohn Birrell } 3671673e404SJohn Birrell 3681673e404SJohn Birrell void 3691673e404SJohn Birrell symit_free(symit_data_t *si) 3701673e404SJohn Birrell { 3711673e404SJohn Birrell free(si); 3721673e404SJohn Birrell } 3731673e404SJohn Birrell 3741673e404SJohn Birrell void 3751673e404SJohn Birrell symit_reset(symit_data_t *si) 3761673e404SJohn Birrell { 3771673e404SJohn Birrell si->si_next = 0; 3781673e404SJohn Birrell } 3791673e404SJohn Birrell 3801673e404SJohn Birrell char * 3811673e404SJohn Birrell symit_curfile(symit_data_t *si) 3821673e404SJohn Birrell { 3831673e404SJohn Birrell return (si->si_curfile); 3841673e404SJohn Birrell } 3851673e404SJohn Birrell 3861673e404SJohn Birrell GElf_Sym * 3871673e404SJohn Birrell symit_next(symit_data_t *si, int type) 3881673e404SJohn Birrell { 3891673e404SJohn Birrell GElf_Sym sym; 3901673e404SJohn Birrell int check_sym = (type == STT_OBJECT || type == STT_FUNC); 3911673e404SJohn Birrell 3921673e404SJohn Birrell for (; si->si_next < si->si_nument; si->si_next++) { 3931673e404SJohn Birrell gelf_getsym(si->si_symd, si->si_next, &si->si_cursym); 3941673e404SJohn Birrell gelf_getsym(si->si_symd, si->si_next, &sym); 3951673e404SJohn Birrell si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name; 3961673e404SJohn Birrell 3971673e404SJohn Birrell if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 3981673e404SJohn Birrell si->si_curfile = si->si_curname; 3991673e404SJohn Birrell 4001673e404SJohn Birrell if (GELF_ST_TYPE(sym.st_info) != type || 4011673e404SJohn Birrell sym.st_shndx == SHN_UNDEF) 4021673e404SJohn Birrell continue; 4031673e404SJohn Birrell 4041673e404SJohn Birrell if (check_sym && ignore_symbol(&sym, si->si_curname)) 4051673e404SJohn Birrell continue; 4061673e404SJohn Birrell 4071673e404SJohn Birrell si->si_next++; 4081673e404SJohn Birrell 4091673e404SJohn Birrell return (&si->si_cursym); 4101673e404SJohn Birrell } 4111673e404SJohn Birrell 4121673e404SJohn Birrell return (NULL); 4131673e404SJohn Birrell } 4141673e404SJohn Birrell 4151673e404SJohn Birrell char * 4161673e404SJohn Birrell symit_name(symit_data_t *si) 4171673e404SJohn Birrell { 4181673e404SJohn Birrell return (si->si_curname); 4191673e404SJohn Birrell } 420