1178481Sjb/* 2178481Sjb * CDDL HEADER START 3178481Sjb * 4178481Sjb * The contents of this file are subject to the terms of the 5178481Sjb * Common Development and Distribution License (the "License"). 6178481Sjb * You may not use this file except in compliance with the License. 7178481Sjb * 8178481Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9178481Sjb * or http://www.opensolaris.org/os/licensing. 10178481Sjb * See the License for the specific language governing permissions 11178481Sjb * and limitations under the License. 12178481Sjb * 13178481Sjb * When distributing Covered Code, include this CDDL HEADER in each 14178481Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15178481Sjb * If applicable, add the following below this CDDL HEADER, with the 16178481Sjb * fields enclosed by brackets "[]" replaced with your own identifying 17178481Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 18178481Sjb * 19178481Sjb * CDDL HEADER END 20178481Sjb */ 21178481Sjb/* 22178481Sjb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23178481Sjb * Use is subject to license terms. 24178481Sjb */ 25178481Sjb 26178481Sjb#pragma ident "%Z%%M% %I% %E% SMI" 27178481Sjb 28178481Sjb/* 29178481Sjb * Routines for retrieving CTF data from a .SUNW_ctf ELF section 30178481Sjb */ 31178481Sjb 32178481Sjb#include <stdio.h> 33178481Sjb#include <stdlib.h> 34178481Sjb#include <fcntl.h> 35178481Sjb#include <unistd.h> 36178481Sjb#include <gelf.h> 37178481Sjb#include <strings.h> 38178481Sjb#include <sys/types.h> 39178481Sjb 40178481Sjb#include "ctftools.h" 41178481Sjb#include "memory.h" 42178481Sjb#include "symbol.h" 43178481Sjb 44178481Sjbtypedef int read_cb_f(tdata_t *, char *, void *); 45178481Sjb 46178481Sjb/* 47178481Sjb * Return the source types that the object was generated from. 48178481Sjb */ 49178481Sjbsource_types_t 50178481Sjbbuilt_source_types(Elf *elf, char const *file) 51178481Sjb{ 52178481Sjb source_types_t types = SOURCE_NONE; 53178481Sjb symit_data_t *si; 54178481Sjb 55178481Sjb if ((si = symit_new(elf, file)) == NULL) 56178481Sjb return (SOURCE_NONE); 57178481Sjb 58178481Sjb while (symit_next(si, STT_FILE) != NULL) { 59178481Sjb char *name = symit_name(si); 60178481Sjb size_t len = strlen(name); 61178481Sjb if (len < 2 || name[len - 2] != '.') { 62178481Sjb types |= SOURCE_UNKNOWN; 63178481Sjb continue; 64178481Sjb } 65178481Sjb 66178481Sjb switch (name[len - 1]) { 67178481Sjb case 'c': 68178481Sjb types |= SOURCE_C; 69178481Sjb break; 70178481Sjb case 'h': 71178481Sjb /* ignore */ 72178481Sjb break; 73178481Sjb case 's': 74178546Sjb case 'S': 75178481Sjb types |= SOURCE_S; 76178481Sjb break; 77178481Sjb default: 78178481Sjb types |= SOURCE_UNKNOWN; 79178481Sjb } 80178481Sjb } 81178481Sjb 82178481Sjb symit_free(si); 83178481Sjb return (types); 84178481Sjb} 85178481Sjb 86178481Sjbstatic int 87178481Sjbread_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg, 88178481Sjb int require_ctf) 89178481Sjb{ 90178481Sjb Elf_Scn *ctfscn; 91178546Sjb Elf_Data *ctfdata = NULL; 92178481Sjb symit_data_t *si = NULL; 93178481Sjb int ctfscnidx; 94178481Sjb tdata_t *td; 95178481Sjb 96178481Sjb if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { 97178481Sjb if (require_ctf && 98178481Sjb (built_source_types(elf, file) & SOURCE_C)) { 99178481Sjb terminate("Input file %s was partially built from " 100178481Sjb "C sources, but no CTF data was present\n", file); 101178481Sjb } 102178481Sjb return (0); 103178481Sjb } 104178481Sjb 105178481Sjb if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL || 106178481Sjb (ctfdata = elf_getdata(ctfscn, NULL)) == NULL) 107178481Sjb elfterminate(file, "Cannot read CTF section"); 108178481Sjb 109178481Sjb /* Reconstruction of type tree */ 110178481Sjb if ((si = symit_new(elf, file)) == NULL) { 111178481Sjb warning("%s has no symbol table - skipping", file); 112178481Sjb return (0); 113178481Sjb } 114178481Sjb 115178481Sjb td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label); 116178481Sjb tdata_build_hashes(td); 117178481Sjb 118178481Sjb symit_free(si); 119178481Sjb 120178481Sjb if (td != NULL) { 121178481Sjb if (func(td, file, arg) < 0) 122178481Sjb return (-1); 123178481Sjb else 124178481Sjb return (1); 125178481Sjb } 126178481Sjb return (0); 127178481Sjb} 128178481Sjb 129178481Sjbstatic int 130178481Sjbread_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func, 131178481Sjb void *arg, int require_ctf) 132178481Sjb{ 133178481Sjb Elf *melf; 134178481Sjb Elf_Cmd cmd = ELF_C_READ; 135178481Sjb Elf_Arhdr *arh; 136178481Sjb int secnum = 1, found = 0; 137178481Sjb 138178481Sjb while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 139178481Sjb int rc = 0; 140178481Sjb 141178481Sjb if ((arh = elf_getarhdr(melf)) == NULL) { 142178481Sjb elfterminate(file, "Can't get archive header for " 143178481Sjb "member %d", secnum); 144178481Sjb } 145178481Sjb 146178481Sjb /* skip special sections - their names begin with "/" */ 147178481Sjb if (*arh->ar_name != '/') { 148178481Sjb size_t memlen = strlen(file) + 1 + 149178481Sjb strlen(arh->ar_name) + 1 + 1; 150178481Sjb char *memname = xmalloc(memlen); 151178481Sjb 152178481Sjb snprintf(memname, memlen, "%s(%s)", file, arh->ar_name); 153178481Sjb 154178481Sjb switch (elf_kind(melf)) { 155178481Sjb case ELF_K_AR: 156178481Sjb rc = read_archive(fd, melf, memname, label, 157178481Sjb func, arg, require_ctf); 158178481Sjb break; 159178481Sjb case ELF_K_ELF: 160178481Sjb rc = read_file(melf, memname, label, 161178481Sjb func, arg, require_ctf); 162178481Sjb break; 163178481Sjb default: 164178481Sjb terminate("%s: Unknown elf kind %d\n", 165178481Sjb memname, elf_kind(melf)); 166178481Sjb } 167178481Sjb 168178481Sjb free(memname); 169178481Sjb } 170178481Sjb 171178481Sjb cmd = elf_next(melf); 172178481Sjb (void) elf_end(melf); 173178481Sjb secnum++; 174178481Sjb 175178481Sjb if (rc < 0) 176178481Sjb return (rc); 177178481Sjb else 178178481Sjb found += rc; 179178481Sjb } 180178481Sjb 181178481Sjb return (found); 182178481Sjb} 183178481Sjb 184178481Sjbstatic int 185178481Sjbread_ctf_common(char *file, char *label, read_cb_f *func, void *arg, 186178481Sjb int require_ctf) 187178481Sjb{ 188178481Sjb Elf *elf; 189178481Sjb int found = 0; 190178481Sjb int fd; 191178481Sjb 192178481Sjb debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE")); 193178481Sjb 194178481Sjb (void) elf_version(EV_CURRENT); 195178481Sjb 196178481Sjb if ((fd = open(file, O_RDONLY)) < 0) 197178481Sjb terminate("%s: Cannot open for reading", file); 198178481Sjb if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 199178481Sjb elfterminate(file, "Cannot read"); 200178481Sjb 201178481Sjb switch (elf_kind(elf)) { 202178481Sjb case ELF_K_AR: 203178481Sjb found = read_archive(fd, elf, file, label, 204178481Sjb func, arg, require_ctf); 205178481Sjb break; 206178481Sjb 207178481Sjb case ELF_K_ELF: 208178481Sjb found = read_file(elf, file, label, 209178481Sjb func, arg, require_ctf); 210178481Sjb break; 211178481Sjb 212178481Sjb default: 213178481Sjb terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf)); 214178481Sjb } 215178481Sjb 216178481Sjb (void) elf_end(elf); 217178481Sjb (void) close(fd); 218178481Sjb 219178481Sjb return (found); 220178481Sjb} 221178481Sjb 222178481Sjb/*ARGSUSED*/ 223178481Sjbint 224178546Sjbread_ctf_save_cb(tdata_t *td, char *name __unused, void *retp) 225178481Sjb{ 226178481Sjb tdata_t **tdp = retp; 227178481Sjb 228178481Sjb *tdp = td; 229178481Sjb 230178481Sjb return (1); 231178481Sjb} 232178481Sjb 233178481Sjbint 234178481Sjbread_ctf(char **files, int n, char *label, read_cb_f *func, void *private, 235178481Sjb int require_ctf) 236178481Sjb{ 237178481Sjb int found; 238178481Sjb int i, rc; 239178481Sjb 240178481Sjb for (i = 0, found = 0; i < n; i++) { 241178481Sjb if ((rc = read_ctf_common(files[i], label, func, 242178481Sjb private, require_ctf)) < 0) 243178481Sjb return (rc); 244178481Sjb found += rc; 245178481Sjb } 246178481Sjb 247178481Sjb return (found); 248178481Sjb} 249178481Sjb 250178481Sjbstatic int 251178481Sjbcount_archive(int fd, Elf *elf, char *file) 252178481Sjb{ 253178481Sjb Elf *melf; 254178481Sjb Elf_Cmd cmd = ELF_C_READ; 255178481Sjb Elf_Arhdr *arh; 256178481Sjb int nfiles = 0, err = 0; 257178481Sjb 258178481Sjb while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 259178481Sjb if ((arh = elf_getarhdr(melf)) == NULL) { 260178481Sjb warning("Can't process input archive %s\n", 261178481Sjb file); 262178481Sjb err++; 263178481Sjb } 264178481Sjb 265178481Sjb if (*arh->ar_name != '/') 266178481Sjb nfiles++; 267178481Sjb 268178481Sjb cmd = elf_next(melf); 269178481Sjb (void) elf_end(melf); 270178481Sjb } 271178481Sjb 272178481Sjb if (err > 0) 273178481Sjb return (-1); 274178481Sjb 275178481Sjb return (nfiles); 276178481Sjb} 277178481Sjb 278178481Sjbint 279178481Sjbcount_files(char **files, int n) 280178481Sjb{ 281178481Sjb int nfiles = 0, err = 0; 282178481Sjb Elf *elf; 283178481Sjb int fd, rc, i; 284178481Sjb 285178481Sjb (void) elf_version(EV_CURRENT); 286178481Sjb 287178481Sjb for (i = 0; i < n; i++) { 288178481Sjb char *file = files[i]; 289178481Sjb 290178481Sjb if ((fd = open(file, O_RDONLY)) < 0) { 291178481Sjb warning("Can't read input file %s", file); 292178481Sjb err++; 293178481Sjb continue; 294178481Sjb } 295178481Sjb 296178481Sjb if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 297178481Sjb warning("Can't open input file %s: %s\n", file, 298178481Sjb elf_errmsg(-1)); 299178481Sjb err++; 300178481Sjb (void) close(fd); 301178481Sjb continue; 302178481Sjb } 303178481Sjb 304178481Sjb switch (elf_kind(elf)) { 305178481Sjb case ELF_K_AR: 306178481Sjb if ((rc = count_archive(fd, elf, file)) < 0) 307178481Sjb err++; 308178481Sjb else 309178481Sjb nfiles += rc; 310178481Sjb break; 311178481Sjb case ELF_K_ELF: 312178481Sjb nfiles++; 313178481Sjb break; 314178481Sjb default: 315178481Sjb warning("Input file %s is corrupt\n", file); 316178481Sjb err++; 317178481Sjb } 318178481Sjb 319178481Sjb (void) elf_end(elf); 320178481Sjb (void) close(fd); 321178481Sjb } 322178481Sjb 323178481Sjb if (err > 0) 324178481Sjb return (-1); 325178481Sjb 326178481Sjb debug(2, "Found %d files in %d input files\n", nfiles, n); 327178481Sjb 328178481Sjb return (nfiles); 329178481Sjb} 330178481Sjb 331178481Sjbstruct symit_data { 332178481Sjb GElf_Shdr si_shdr; 333178481Sjb Elf_Data *si_symd; 334178481Sjb Elf_Data *si_strd; 335178481Sjb GElf_Sym si_cursym; 336178481Sjb char *si_curname; 337178481Sjb char *si_curfile; 338178481Sjb int si_nument; 339178481Sjb int si_next; 340178481Sjb}; 341178481Sjb 342178481Sjbsymit_data_t * 343178481Sjbsymit_new(Elf *elf, const char *file) 344178481Sjb{ 345178481Sjb symit_data_t *si; 346178481Sjb Elf_Scn *scn; 347178481Sjb int symtabidx; 348178481Sjb 349178481Sjb if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0) 350178481Sjb return (NULL); 351178481Sjb 352178481Sjb si = xcalloc(sizeof (symit_data_t)); 353178481Sjb 354178481Sjb if ((scn = elf_getscn(elf, symtabidx)) == NULL || 355178481Sjb gelf_getshdr(scn, &si->si_shdr) == NULL || 356178481Sjb (si->si_symd = elf_getdata(scn, NULL)) == NULL) 357178481Sjb elfterminate(file, "Cannot read .symtab"); 358178481Sjb 359178481Sjb if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL || 360178481Sjb (si->si_strd = elf_getdata(scn, NULL)) == NULL) 361178481Sjb elfterminate(file, "Cannot read strings for .symtab"); 362178481Sjb 363178481Sjb si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize; 364178481Sjb 365178481Sjb return (si); 366178481Sjb} 367178481Sjb 368178481Sjbvoid 369178481Sjbsymit_free(symit_data_t *si) 370178481Sjb{ 371178481Sjb free(si); 372178481Sjb} 373178481Sjb 374178481Sjbvoid 375178481Sjbsymit_reset(symit_data_t *si) 376178481Sjb{ 377178481Sjb si->si_next = 0; 378178481Sjb} 379178481Sjb 380178481Sjbchar * 381178481Sjbsymit_curfile(symit_data_t *si) 382178481Sjb{ 383178481Sjb return (si->si_curfile); 384178481Sjb} 385178481Sjb 386178481SjbGElf_Sym * 387178481Sjbsymit_next(symit_data_t *si, int type) 388178481Sjb{ 389178481Sjb GElf_Sym sym; 390248991Sdim char *bname; 391178481Sjb int check_sym = (type == STT_OBJECT || type == STT_FUNC); 392178481Sjb 393178481Sjb for (; si->si_next < si->si_nument; si->si_next++) { 394178481Sjb gelf_getsym(si->si_symd, si->si_next, &si->si_cursym); 395178481Sjb gelf_getsym(si->si_symd, si->si_next, &sym); 396178481Sjb si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name; 397178481Sjb 398248991Sdim if (GELF_ST_TYPE(sym.st_info) == STT_FILE) { 399248991Sdim bname = strrchr(si->si_curname, '/'); 400248991Sdim si->si_curfile = bname == NULL ? si->si_curname : bname + 1; 401248991Sdim } 402178481Sjb 403178481Sjb if (GELF_ST_TYPE(sym.st_info) != type || 404178481Sjb sym.st_shndx == SHN_UNDEF) 405178481Sjb continue; 406178481Sjb 407178481Sjb if (check_sym && ignore_symbol(&sym, si->si_curname)) 408178481Sjb continue; 409178481Sjb 410178481Sjb si->si_next++; 411178481Sjb 412178481Sjb return (&si->si_cursym); 413178481Sjb } 414178481Sjb 415178481Sjb return (NULL); 416178481Sjb} 417178481Sjb 418178481Sjbchar * 419178481Sjbsymit_name(symit_data_t *si) 420178481Sjb{ 421178481Sjb return (si->si_curname); 422178481Sjb} 423