Path: blob/main/cddl/contrib/opensolaris/tools/ctf/cvt/input.c
39586 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/20/*21* Copyright 2006 Sun Microsystems, Inc. All rights reserved.22* Use is subject to license terms.23*/2425#pragma ident "%Z%%M% %I% %E% SMI"2627/*28* Routines for retrieving CTF data from a .SUNW_ctf ELF section29*/3031#include <stdio.h>32#include <stdlib.h>33#include <fcntl.h>34#include <unistd.h>35#include <gelf.h>36#include <strings.h>37#include <sys/types.h>3839#include "ctftools.h"40#include "memory.h"41#include "symbol.h"4243typedef int read_cb_f(tdata_t *, char *, void *);4445/*46* Return the source types that the object was generated from.47*/48source_types_t49built_source_types(Elf *elf, char const *file)50{51source_types_t types = SOURCE_NONE;52symit_data_t *si;5354if ((si = symit_new(elf, file)) == NULL)55return (SOURCE_NONE);5657while (symit_next(si, STT_FILE) != NULL) {58char *name = symit_name(si);59size_t len = strlen(name);60if (len < 2 || name[len - 2] != '.') {61types |= SOURCE_UNKNOWN;62continue;63}6465switch (name[len - 1]) {66case 'c':67types |= SOURCE_C;68break;69case 'h':70/* ignore */71break;72case 's':73case 'S':74types |= SOURCE_S;75break;76default:77types |= SOURCE_UNKNOWN;78}79}8081symit_free(si);82return (types);83}8485static int86read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg,87int require_ctf)88{89Elf_Scn *ctfscn;90Elf_Data *ctfdata = NULL;91symit_data_t *si = NULL;92int ctfscnidx;93tdata_t *td;9495if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) {96if (require_ctf &&97(built_source_types(elf, file) & SOURCE_C)) {98terminate("Input file %s was partially built from "99"C sources, but no CTF data was present\n", file);100}101return (0);102}103104if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL ||105(ctfdata = elf_getdata(ctfscn, NULL)) == NULL)106elfterminate(file, "Cannot read CTF section");107108/* Reconstruction of type tree */109if ((si = symit_new(elf, file)) == NULL) {110warning("%s has no symbol table - skipping", file);111return (0);112}113114td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label);115tdata_build_hashes(td);116117symit_free(si);118119if (td != NULL) {120if (func(td, file, arg) < 0)121return (-1);122else123return (1);124}125return (0);126}127128static int129read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func,130void *arg, int require_ctf)131{132Elf *melf;133Elf_Cmd cmd = ELF_C_READ;134Elf_Arhdr *arh;135int secnum = 1, found = 0;136137while ((melf = elf_begin(fd, cmd, elf)) != NULL) {138int rc = 0;139140if ((arh = elf_getarhdr(melf)) == NULL) {141elfterminate(file, "Can't get archive header for "142"member %d", secnum);143}144145/* skip special sections - their names begin with "/" */146if (*arh->ar_name != '/') {147size_t memlen = strlen(file) + 1 +148strlen(arh->ar_name) + 1 + 1;149char *memname = xmalloc(memlen);150151snprintf(memname, memlen, "%s(%s)", file, arh->ar_name);152153switch (elf_kind(melf)) {154case ELF_K_AR:155rc = read_archive(fd, melf, memname, label,156func, arg, require_ctf);157break;158case ELF_K_ELF:159rc = read_file(melf, memname, label,160func, arg, require_ctf);161break;162default:163terminate("%s: Unknown elf kind %d\n",164memname, elf_kind(melf));165}166167free(memname);168}169170cmd = elf_next(melf);171(void) elf_end(melf);172secnum++;173174if (rc < 0)175return (rc);176else177found += rc;178}179180return (found);181}182183static int184read_ctf_common(char *file, char *label, read_cb_f *func, void *arg,185int require_ctf)186{187Elf *elf;188int found = 0;189int fd;190191debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE"));192193(void) elf_version(EV_CURRENT);194195if ((fd = open(file, O_RDONLY)) < 0)196terminate("%s: Cannot open for reading", file);197if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)198elfterminate(file, "Cannot read");199200switch (elf_kind(elf)) {201case ELF_K_AR:202found = read_archive(fd, elf, file, label,203func, arg, require_ctf);204break;205206case ELF_K_ELF:207found = read_file(elf, file, label,208func, arg, require_ctf);209break;210211default:212terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf));213}214215(void) elf_end(elf);216(void) close(fd);217218return (found);219}220221/*ARGSUSED*/222int223read_ctf_save_cb(tdata_t *td, char *name __unused, void *retp)224{225tdata_t **tdp = retp;226227*tdp = td;228229return (1);230}231232int233read_ctf(char **files, int n, char *label, read_cb_f *func, void *private,234int require_ctf)235{236int found;237int i, rc;238239for (i = 0, found = 0; i < n; i++) {240if ((rc = read_ctf_common(files[i], label, func,241private, require_ctf)) < 0)242return (rc);243found += rc;244}245246return (found);247}248249static int250count_archive(int fd, Elf *elf, char *file)251{252Elf *melf;253Elf_Cmd cmd = ELF_C_READ;254Elf_Arhdr *arh;255int nfiles = 0, err = 0;256257while ((melf = elf_begin(fd, cmd, elf)) != NULL) {258if ((arh = elf_getarhdr(melf)) == NULL) {259warning("Can't process input archive %s\n",260file);261err++;262}263264if (*arh->ar_name != '/')265nfiles++;266267cmd = elf_next(melf);268(void) elf_end(melf);269}270271if (err > 0)272return (-1);273274return (nfiles);275}276277int278count_files(char **files, int n)279{280int nfiles = 0, err = 0;281Elf *elf;282int fd, rc, i;283284(void) elf_version(EV_CURRENT);285286for (i = 0; i < n; i++) {287char *file = files[i];288289if ((fd = open(file, O_RDONLY)) < 0) {290warning("Can't read input file %s", file);291err++;292continue;293}294295if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {296warning("Can't open input file %s: %s\n", file,297elf_errmsg(-1));298err++;299(void) close(fd);300continue;301}302303switch (elf_kind(elf)) {304case ELF_K_AR:305if ((rc = count_archive(fd, elf, file)) < 0)306err++;307else308nfiles += rc;309break;310case ELF_K_ELF:311nfiles++;312break;313default:314warning("Input file %s is corrupt\n", file);315err++;316}317318(void) elf_end(elf);319(void) close(fd);320}321322if (err > 0)323return (-1);324325debug(2, "Found %d files in %d input files\n", nfiles, n);326327return (nfiles);328}329330struct symit_data {331GElf_Shdr si_shdr;332Elf_Data *si_symd;333Elf_Data *si_strd;334GElf_Sym si_cursym;335char *si_curname;336char *si_curfile;337int si_nument;338int si_next;339};340341symit_data_t *342symit_new(Elf *elf, const char *file)343{344symit_data_t *si;345Elf_Scn *scn;346int symtabidx;347348if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0)349return (NULL);350351si = xcalloc(sizeof (symit_data_t));352353if ((scn = elf_getscn(elf, symtabidx)) == NULL ||354gelf_getshdr(scn, &si->si_shdr) == NULL ||355(si->si_symd = elf_getdata(scn, NULL)) == NULL)356elfterminate(file, "Cannot read .symtab");357358if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL ||359(si->si_strd = elf_getdata(scn, NULL)) == NULL)360elfterminate(file, "Cannot read strings for .symtab");361362si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize;363364return (si);365}366367void368symit_free(symit_data_t *si)369{370free(si);371}372373void374symit_reset(symit_data_t *si)375{376si->si_next = 0;377}378379char *380symit_curfile(symit_data_t *si)381{382return (si->si_curfile);383}384385GElf_Sym *386symit_next(symit_data_t *si, int type)387{388GElf_Sym sym;389char *bname;390int check_sym = (type == STT_OBJECT || type == STT_FUNC);391392for (; si->si_next < si->si_nument; si->si_next++) {393gelf_getsym(si->si_symd, si->si_next, &si->si_cursym);394gelf_getsym(si->si_symd, si->si_next, &sym);395si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name;396397if (GELF_ST_TYPE(sym.st_info) == STT_FILE) {398bname = strrchr(si->si_curname, '/');399si->si_curfile = bname == NULL ? si->si_curname : bname + 1;400}401402if (GELF_ST_TYPE(sym.st_info) != type ||403sym.st_shndx == SHN_UNDEF)404continue;405406if (check_sym && ignore_symbol(&sym, si->si_curname))407continue;408409si->si_next++;410411return (&si->si_cursym);412}413414return (NULL);415}416417char *418symit_name(symit_data_t *si)419{420return (si->si_curname);421}422423424