10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51882Sjohnlev * Common Development and Distribution License (the "License").
61882Sjohnlev * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
221882Sjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * Routines for retrieving CTF data from a .SUNW_ctf ELF section
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <fcntl.h>
350Sstevel@tonic-gate #include <unistd.h>
360Sstevel@tonic-gate #include <gelf.h>
370Sstevel@tonic-gate #include <strings.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include "ctftools.h"
410Sstevel@tonic-gate #include "memory.h"
421882Sjohnlev #include "symbol.h"
430Sstevel@tonic-gate
440Sstevel@tonic-gate typedef int read_cb_f(tdata_t *, char *, void *);
450Sstevel@tonic-gate
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate * Return the source types that the object was generated from.
480Sstevel@tonic-gate */
490Sstevel@tonic-gate source_types_t
built_source_types(Elf * elf,char const * file)500Sstevel@tonic-gate built_source_types(Elf *elf, char const *file)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate source_types_t types = SOURCE_NONE;
530Sstevel@tonic-gate symit_data_t *si;
540Sstevel@tonic-gate
550Sstevel@tonic-gate if ((si = symit_new(elf, file)) == NULL)
560Sstevel@tonic-gate return (SOURCE_NONE);
570Sstevel@tonic-gate
580Sstevel@tonic-gate while (symit_next(si, STT_FILE) != NULL) {
590Sstevel@tonic-gate char *name = symit_name(si);
600Sstevel@tonic-gate size_t len = strlen(name);
610Sstevel@tonic-gate if (len < 2 || name[len - 2] != '.') {
620Sstevel@tonic-gate types |= SOURCE_UNKNOWN;
630Sstevel@tonic-gate continue;
640Sstevel@tonic-gate }
650Sstevel@tonic-gate
660Sstevel@tonic-gate switch (name[len - 1]) {
670Sstevel@tonic-gate case 'c':
680Sstevel@tonic-gate types |= SOURCE_C;
690Sstevel@tonic-gate break;
700Sstevel@tonic-gate case 'h':
710Sstevel@tonic-gate /* ignore */
720Sstevel@tonic-gate break;
730Sstevel@tonic-gate case 's':
740Sstevel@tonic-gate types |= SOURCE_S;
750Sstevel@tonic-gate break;
760Sstevel@tonic-gate default:
770Sstevel@tonic-gate types |= SOURCE_UNKNOWN;
780Sstevel@tonic-gate }
790Sstevel@tonic-gate }
800Sstevel@tonic-gate
810Sstevel@tonic-gate symit_free(si);
820Sstevel@tonic-gate return (types);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate
850Sstevel@tonic-gate static int
read_file(Elf * elf,char * file,char * label,read_cb_f * func,void * arg,int require_ctf)860Sstevel@tonic-gate read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg,
870Sstevel@tonic-gate int require_ctf)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate Elf_Scn *ctfscn;
900Sstevel@tonic-gate Elf_Data *ctfdata;
910Sstevel@tonic-gate symit_data_t *si = NULL;
920Sstevel@tonic-gate int ctfscnidx;
930Sstevel@tonic-gate tdata_t *td;
940Sstevel@tonic-gate
95*1951Sjohnlev if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) {
960Sstevel@tonic-gate if (require_ctf &&
970Sstevel@tonic-gate (built_source_types(elf, file) & SOURCE_C)) {
980Sstevel@tonic-gate terminate("Input file %s was partially built from "
990Sstevel@tonic-gate "C sources, but no CTF data was present\n", file);
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate return (0);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL ||
1050Sstevel@tonic-gate (ctfdata = elf_getdata(ctfscn, NULL)) == NULL)
1060Sstevel@tonic-gate elfterminate(file, "Cannot read CTF section");
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate /* Reconstruction of type tree */
1090Sstevel@tonic-gate if ((si = symit_new(elf, file)) == NULL) {
1100Sstevel@tonic-gate warning("%s has no symbol table - skipping", file);
1110Sstevel@tonic-gate return (0);
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label);
1150Sstevel@tonic-gate tdata_build_hashes(td);
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate symit_free(si);
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate if (td != NULL) {
1200Sstevel@tonic-gate if (func(td, file, arg) < 0)
1210Sstevel@tonic-gate return (-1);
1220Sstevel@tonic-gate else
1230Sstevel@tonic-gate return (1);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate return (0);
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate static int
read_archive(int fd,Elf * elf,char * file,char * label,read_cb_f * func,void * arg,int require_ctf)1290Sstevel@tonic-gate read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func,
1300Sstevel@tonic-gate void *arg, int require_ctf)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate Elf *melf;
1330Sstevel@tonic-gate Elf_Cmd cmd = ELF_C_READ;
1340Sstevel@tonic-gate Elf_Arhdr *arh;
1350Sstevel@tonic-gate int secnum = 1, found = 0;
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
1380Sstevel@tonic-gate int rc = 0;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate if ((arh = elf_getarhdr(melf)) == NULL) {
1410Sstevel@tonic-gate elfterminate(file, "Can't get archive header for "
1420Sstevel@tonic-gate "member %d", secnum);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate /* skip special sections - their names begin with "/" */
1460Sstevel@tonic-gate if (*arh->ar_name != '/') {
1470Sstevel@tonic-gate size_t memlen = strlen(file) + 1 +
1480Sstevel@tonic-gate strlen(arh->ar_name) + 1 + 1;
1490Sstevel@tonic-gate char *memname = xmalloc(memlen);
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate snprintf(memname, memlen, "%s(%s)", file, arh->ar_name);
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate switch (elf_kind(melf)) {
1540Sstevel@tonic-gate case ELF_K_AR:
1550Sstevel@tonic-gate rc = read_archive(fd, melf, memname, label,
1560Sstevel@tonic-gate func, arg, require_ctf);
1570Sstevel@tonic-gate break;
1580Sstevel@tonic-gate case ELF_K_ELF:
1590Sstevel@tonic-gate rc = read_file(melf, memname, label,
1600Sstevel@tonic-gate func, arg, require_ctf);
1610Sstevel@tonic-gate break;
1620Sstevel@tonic-gate default:
1630Sstevel@tonic-gate terminate("%s: Unknown elf kind %d\n",
1640Sstevel@tonic-gate memname, elf_kind(melf));
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate free(memname);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate cmd = elf_next(melf);
1710Sstevel@tonic-gate (void) elf_end(melf);
1720Sstevel@tonic-gate secnum++;
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate if (rc < 0)
1750Sstevel@tonic-gate return (rc);
1760Sstevel@tonic-gate else
1770Sstevel@tonic-gate found += rc;
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate return (found);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate static int
read_ctf_common(char * file,char * label,read_cb_f * func,void * arg,int require_ctf)1840Sstevel@tonic-gate read_ctf_common(char *file, char *label, read_cb_f *func, void *arg,
1850Sstevel@tonic-gate int require_ctf)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate Elf *elf;
1880Sstevel@tonic-gate int found = 0;
1890Sstevel@tonic-gate int fd;
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE"));
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate (void) elf_version(EV_CURRENT);
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate if ((fd = open(file, O_RDONLY)) < 0)
1960Sstevel@tonic-gate terminate("%s: Cannot open for reading", file);
1970Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
1980Sstevel@tonic-gate elfterminate(file, "Cannot read");
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate switch (elf_kind(elf)) {
2010Sstevel@tonic-gate case ELF_K_AR:
2020Sstevel@tonic-gate found = read_archive(fd, elf, file, label,
2030Sstevel@tonic-gate func, arg, require_ctf);
2040Sstevel@tonic-gate break;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate case ELF_K_ELF:
2070Sstevel@tonic-gate found = read_file(elf, file, label,
2080Sstevel@tonic-gate func, arg, require_ctf);
2090Sstevel@tonic-gate break;
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate default:
2120Sstevel@tonic-gate terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf));
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate (void) elf_end(elf);
2160Sstevel@tonic-gate (void) close(fd);
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate return (found);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate /*ARGSUSED*/
2220Sstevel@tonic-gate int
read_ctf_save_cb(tdata_t * td,char * name,void * retp)2230Sstevel@tonic-gate read_ctf_save_cb(tdata_t *td, char *name, void *retp)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate tdata_t **tdp = retp;
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate *tdp = td;
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate return (1);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate int
read_ctf(char ** files,int n,char * label,read_cb_f * func,void * private,int require_ctf)2330Sstevel@tonic-gate read_ctf(char **files, int n, char *label, read_cb_f *func, void *private,
2340Sstevel@tonic-gate int require_ctf)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate int found;
2370Sstevel@tonic-gate int i, rc;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate for (i = 0, found = 0; i < n; i++) {
2400Sstevel@tonic-gate if ((rc = read_ctf_common(files[i], label, func,
2410Sstevel@tonic-gate private, require_ctf)) < 0)
2420Sstevel@tonic-gate return (rc);
2430Sstevel@tonic-gate found += rc;
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate return (found);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate static int
count_archive(int fd,Elf * elf,char * file)2500Sstevel@tonic-gate count_archive(int fd, Elf *elf, char *file)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate Elf *melf;
2530Sstevel@tonic-gate Elf_Cmd cmd = ELF_C_READ;
2540Sstevel@tonic-gate Elf_Arhdr *arh;
2550Sstevel@tonic-gate int nfiles = 0, err = 0;
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
2580Sstevel@tonic-gate if ((arh = elf_getarhdr(melf)) == NULL) {
2590Sstevel@tonic-gate warning("Can't process input archive %s\n",
2600Sstevel@tonic-gate file);
2610Sstevel@tonic-gate err++;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if (*arh->ar_name != '/')
2650Sstevel@tonic-gate nfiles++;
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate cmd = elf_next(melf);
2680Sstevel@tonic-gate (void) elf_end(melf);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate if (err > 0)
2720Sstevel@tonic-gate return (-1);
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate return (nfiles);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate int
count_files(char ** files,int n)2780Sstevel@tonic-gate count_files(char **files, int n)
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate int nfiles = 0, err = 0;
2810Sstevel@tonic-gate Elf *elf;
2820Sstevel@tonic-gate int fd, rc, i;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate (void) elf_version(EV_CURRENT);
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate for (i = 0; i < n; i++) {
2870Sstevel@tonic-gate char *file = files[i];
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate if ((fd = open(file, O_RDONLY)) < 0) {
2900Sstevel@tonic-gate warning("Can't read input file %s", file);
2910Sstevel@tonic-gate err++;
2920Sstevel@tonic-gate continue;
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
2960Sstevel@tonic-gate warning("Can't open input file %s: %s\n", file,
297*1951Sjohnlev elf_errmsg(-1));
2980Sstevel@tonic-gate err++;
2990Sstevel@tonic-gate (void) close(fd);
3000Sstevel@tonic-gate continue;
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate switch (elf_kind(elf)) {
3040Sstevel@tonic-gate case ELF_K_AR:
3050Sstevel@tonic-gate if ((rc = count_archive(fd, elf, file)) < 0)
3060Sstevel@tonic-gate err++;
3070Sstevel@tonic-gate else
3080Sstevel@tonic-gate nfiles += rc;
3090Sstevel@tonic-gate break;
3100Sstevel@tonic-gate case ELF_K_ELF:
3110Sstevel@tonic-gate nfiles++;
3120Sstevel@tonic-gate break;
3130Sstevel@tonic-gate default:
3140Sstevel@tonic-gate warning("Input file %s is corrupt\n", file);
3150Sstevel@tonic-gate err++;
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate (void) elf_end(elf);
3190Sstevel@tonic-gate (void) close(fd);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate if (err > 0)
3230Sstevel@tonic-gate return (-1);
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate debug(2, "Found %d files in %d input files\n", nfiles, n);
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate return (nfiles);
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate struct symit_data {
3310Sstevel@tonic-gate GElf_Shdr si_shdr;
3320Sstevel@tonic-gate Elf_Data *si_symd;
3330Sstevel@tonic-gate Elf_Data *si_strd;
3340Sstevel@tonic-gate GElf_Sym si_cursym;
3350Sstevel@tonic-gate char *si_curname;
3360Sstevel@tonic-gate char *si_curfile;
3370Sstevel@tonic-gate int si_nument;
3380Sstevel@tonic-gate int si_next;
3390Sstevel@tonic-gate };
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate symit_data_t *
symit_new(Elf * elf,const char * file)3420Sstevel@tonic-gate symit_new(Elf *elf, const char *file)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate symit_data_t *si;
3450Sstevel@tonic-gate Elf_Scn *scn;
3460Sstevel@tonic-gate int symtabidx;
3470Sstevel@tonic-gate
348*1951Sjohnlev if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0)
3490Sstevel@tonic-gate return (NULL);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate si = xcalloc(sizeof (symit_data_t));
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate if ((scn = elf_getscn(elf, symtabidx)) == NULL ||
3540Sstevel@tonic-gate gelf_getshdr(scn, &si->si_shdr) == NULL ||
3550Sstevel@tonic-gate (si->si_symd = elf_getdata(scn, NULL)) == NULL)
3560Sstevel@tonic-gate elfterminate(file, "Cannot read .symtab");
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL ||
3590Sstevel@tonic-gate (si->si_strd = elf_getdata(scn, NULL)) == NULL)
3600Sstevel@tonic-gate elfterminate(file, "Cannot read strings for .symtab");
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize;
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate return (si);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate void
symit_free(symit_data_t * si)3680Sstevel@tonic-gate symit_free(symit_data_t *si)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate free(si);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate void
symit_reset(symit_data_t * si)3740Sstevel@tonic-gate symit_reset(symit_data_t *si)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate si->si_next = 0;
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate char *
symit_curfile(symit_data_t * si)3800Sstevel@tonic-gate symit_curfile(symit_data_t *si)
3810Sstevel@tonic-gate {
3820Sstevel@tonic-gate return (si->si_curfile);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate GElf_Sym *
symit_next(symit_data_t * si,int type)3860Sstevel@tonic-gate symit_next(symit_data_t *si, int type)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate GElf_Sym sym;
3891882Sjohnlev int check_sym = (type == STT_OBJECT || type == STT_FUNC);
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate for (; si->si_next < si->si_nument; si->si_next++) {
3920Sstevel@tonic-gate gelf_getsym(si->si_symd, si->si_next, &si->si_cursym);
3930Sstevel@tonic-gate gelf_getsym(si->si_symd, si->si_next, &sym);
3940Sstevel@tonic-gate si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name;
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_FILE)
3970Sstevel@tonic-gate si->si_curfile = si->si_curname;
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != type ||
4000Sstevel@tonic-gate sym.st_shndx == SHN_UNDEF)
4010Sstevel@tonic-gate continue;
4020Sstevel@tonic-gate
4031882Sjohnlev if (check_sym && ignore_symbol(&sym, si->si_curname))
4041882Sjohnlev continue;
4051882Sjohnlev
4060Sstevel@tonic-gate si->si_next++;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate return (&si->si_cursym);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate return (NULL);
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate char *
symit_name(symit_data_t * si)4150Sstevel@tonic-gate symit_name(symit_data_t *si)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate return (si->si_curname);
4180Sstevel@tonic-gate }
419