1*1673e404SJohn Birrell /* 2*1673e404SJohn Birrell * CDDL HEADER START 3*1673e404SJohn Birrell * 4*1673e404SJohn Birrell * The contents of this file are subject to the terms of the 5*1673e404SJohn Birrell * Common Development and Distribution License (the "License"). 6*1673e404SJohn Birrell * You may not use this file except in compliance with the License. 7*1673e404SJohn Birrell * 8*1673e404SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1673e404SJohn Birrell * or http://www.opensolaris.org/os/licensing. 10*1673e404SJohn Birrell * See the License for the specific language governing permissions 11*1673e404SJohn Birrell * and limitations under the License. 12*1673e404SJohn Birrell * 13*1673e404SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 14*1673e404SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1673e404SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 16*1673e404SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 17*1673e404SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 18*1673e404SJohn Birrell * 19*1673e404SJohn Birrell * CDDL HEADER END 20*1673e404SJohn Birrell */ 21*1673e404SJohn Birrell /* 22*1673e404SJohn Birrell * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*1673e404SJohn Birrell * Use is subject to license terms. 24*1673e404SJohn Birrell */ 25*1673e404SJohn Birrell 26*1673e404SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 27*1673e404SJohn Birrell 28*1673e404SJohn Birrell /* 29*1673e404SJohn Birrell * Routines for retrieving CTF data from a .SUNW_ctf ELF section 30*1673e404SJohn Birrell */ 31*1673e404SJohn Birrell 32*1673e404SJohn Birrell #include <stdio.h> 33*1673e404SJohn Birrell #include <stdlib.h> 34*1673e404SJohn Birrell #include <fcntl.h> 35*1673e404SJohn Birrell #include <unistd.h> 36*1673e404SJohn Birrell #include <gelf.h> 37*1673e404SJohn Birrell #include <strings.h> 38*1673e404SJohn Birrell #include <sys/types.h> 39*1673e404SJohn Birrell 40*1673e404SJohn Birrell #include "ctftools.h" 41*1673e404SJohn Birrell #include "memory.h" 42*1673e404SJohn Birrell #include "symbol.h" 43*1673e404SJohn Birrell 44*1673e404SJohn Birrell typedef int read_cb_f(tdata_t *, char *, void *); 45*1673e404SJohn Birrell 46*1673e404SJohn Birrell /* 47*1673e404SJohn Birrell * Return the source types that the object was generated from. 48*1673e404SJohn Birrell */ 49*1673e404SJohn Birrell source_types_t 50*1673e404SJohn Birrell built_source_types(Elf *elf, char const *file) 51*1673e404SJohn Birrell { 52*1673e404SJohn Birrell source_types_t types = SOURCE_NONE; 53*1673e404SJohn Birrell symit_data_t *si; 54*1673e404SJohn Birrell 55*1673e404SJohn Birrell if ((si = symit_new(elf, file)) == NULL) 56*1673e404SJohn Birrell return (SOURCE_NONE); 57*1673e404SJohn Birrell 58*1673e404SJohn Birrell while (symit_next(si, STT_FILE) != NULL) { 59*1673e404SJohn Birrell char *name = symit_name(si); 60*1673e404SJohn Birrell size_t len = strlen(name); 61*1673e404SJohn Birrell if (len < 2 || name[len - 2] != '.') { 62*1673e404SJohn Birrell types |= SOURCE_UNKNOWN; 63*1673e404SJohn Birrell continue; 64*1673e404SJohn Birrell } 65*1673e404SJohn Birrell 66*1673e404SJohn Birrell switch (name[len - 1]) { 67*1673e404SJohn Birrell case 'c': 68*1673e404SJohn Birrell types |= SOURCE_C; 69*1673e404SJohn Birrell break; 70*1673e404SJohn Birrell case 'h': 71*1673e404SJohn Birrell /* ignore */ 72*1673e404SJohn Birrell break; 73*1673e404SJohn Birrell case 's': 74*1673e404SJohn Birrell case 'S': 75*1673e404SJohn Birrell types |= SOURCE_S; 76*1673e404SJohn Birrell break; 77*1673e404SJohn Birrell default: 78*1673e404SJohn Birrell types |= SOURCE_UNKNOWN; 79*1673e404SJohn Birrell } 80*1673e404SJohn Birrell } 81*1673e404SJohn Birrell 82*1673e404SJohn Birrell symit_free(si); 83*1673e404SJohn Birrell return (types); 84*1673e404SJohn Birrell } 85*1673e404SJohn Birrell 86*1673e404SJohn Birrell static int 87*1673e404SJohn Birrell read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg, 88*1673e404SJohn Birrell int require_ctf) 89*1673e404SJohn Birrell { 90*1673e404SJohn Birrell Elf_Scn *ctfscn; 91*1673e404SJohn Birrell Elf_Data *ctfdata = NULL; 92*1673e404SJohn Birrell symit_data_t *si = NULL; 93*1673e404SJohn Birrell int ctfscnidx; 94*1673e404SJohn Birrell tdata_t *td; 95*1673e404SJohn Birrell 96*1673e404SJohn Birrell if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) { 97*1673e404SJohn Birrell if (require_ctf && 98*1673e404SJohn Birrell (built_source_types(elf, file) & SOURCE_C)) { 99*1673e404SJohn Birrell terminate("Input file %s was partially built from " 100*1673e404SJohn Birrell "C sources, but no CTF data was present\n", file); 101*1673e404SJohn Birrell } 102*1673e404SJohn Birrell return (0); 103*1673e404SJohn Birrell } 104*1673e404SJohn Birrell 105*1673e404SJohn Birrell if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL || 106*1673e404SJohn Birrell (ctfdata = elf_getdata(ctfscn, NULL)) == NULL) 107*1673e404SJohn Birrell elfterminate(file, "Cannot read CTF section"); 108*1673e404SJohn Birrell 109*1673e404SJohn Birrell /* Reconstruction of type tree */ 110*1673e404SJohn Birrell if ((si = symit_new(elf, file)) == NULL) { 111*1673e404SJohn Birrell warning("%s has no symbol table - skipping", file); 112*1673e404SJohn Birrell return (0); 113*1673e404SJohn Birrell } 114*1673e404SJohn Birrell 115*1673e404SJohn Birrell td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label); 116*1673e404SJohn Birrell tdata_build_hashes(td); 117*1673e404SJohn Birrell 118*1673e404SJohn Birrell symit_free(si); 119*1673e404SJohn Birrell 120*1673e404SJohn Birrell if (td != NULL) { 121*1673e404SJohn Birrell if (func(td, file, arg) < 0) 122*1673e404SJohn Birrell return (-1); 123*1673e404SJohn Birrell else 124*1673e404SJohn Birrell return (1); 125*1673e404SJohn Birrell } 126*1673e404SJohn Birrell return (0); 127*1673e404SJohn Birrell } 128*1673e404SJohn Birrell 129*1673e404SJohn Birrell static int 130*1673e404SJohn Birrell read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func, 131*1673e404SJohn Birrell void *arg, int require_ctf) 132*1673e404SJohn Birrell { 133*1673e404SJohn Birrell Elf *melf; 134*1673e404SJohn Birrell Elf_Cmd cmd = ELF_C_READ; 135*1673e404SJohn Birrell Elf_Arhdr *arh; 136*1673e404SJohn Birrell int secnum = 1, found = 0; 137*1673e404SJohn Birrell 138*1673e404SJohn Birrell while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 139*1673e404SJohn Birrell int rc = 0; 140*1673e404SJohn Birrell 141*1673e404SJohn Birrell if ((arh = elf_getarhdr(melf)) == NULL) { 142*1673e404SJohn Birrell elfterminate(file, "Can't get archive header for " 143*1673e404SJohn Birrell "member %d", secnum); 144*1673e404SJohn Birrell } 145*1673e404SJohn Birrell 146*1673e404SJohn Birrell /* skip special sections - their names begin with "/" */ 147*1673e404SJohn Birrell if (*arh->ar_name != '/') { 148*1673e404SJohn Birrell size_t memlen = strlen(file) + 1 + 149*1673e404SJohn Birrell strlen(arh->ar_name) + 1 + 1; 150*1673e404SJohn Birrell char *memname = xmalloc(memlen); 151*1673e404SJohn Birrell 152*1673e404SJohn Birrell snprintf(memname, memlen, "%s(%s)", file, arh->ar_name); 153*1673e404SJohn Birrell 154*1673e404SJohn Birrell switch (elf_kind(melf)) { 155*1673e404SJohn Birrell case ELF_K_AR: 156*1673e404SJohn Birrell rc = read_archive(fd, melf, memname, label, 157*1673e404SJohn Birrell func, arg, require_ctf); 158*1673e404SJohn Birrell break; 159*1673e404SJohn Birrell case ELF_K_ELF: 160*1673e404SJohn Birrell rc = read_file(melf, memname, label, 161*1673e404SJohn Birrell func, arg, require_ctf); 162*1673e404SJohn Birrell break; 163*1673e404SJohn Birrell default: 164*1673e404SJohn Birrell terminate("%s: Unknown elf kind %d\n", 165*1673e404SJohn Birrell memname, elf_kind(melf)); 166*1673e404SJohn Birrell } 167*1673e404SJohn Birrell 168*1673e404SJohn Birrell free(memname); 169*1673e404SJohn Birrell } 170*1673e404SJohn Birrell 171*1673e404SJohn Birrell cmd = elf_next(melf); 172*1673e404SJohn Birrell (void) elf_end(melf); 173*1673e404SJohn Birrell secnum++; 174*1673e404SJohn Birrell 175*1673e404SJohn Birrell if (rc < 0) 176*1673e404SJohn Birrell return (rc); 177*1673e404SJohn Birrell else 178*1673e404SJohn Birrell found += rc; 179*1673e404SJohn Birrell } 180*1673e404SJohn Birrell 181*1673e404SJohn Birrell return (found); 182*1673e404SJohn Birrell } 183*1673e404SJohn Birrell 184*1673e404SJohn Birrell static int 185*1673e404SJohn Birrell read_ctf_common(char *file, char *label, read_cb_f *func, void *arg, 186*1673e404SJohn Birrell int require_ctf) 187*1673e404SJohn Birrell { 188*1673e404SJohn Birrell Elf *elf; 189*1673e404SJohn Birrell int found = 0; 190*1673e404SJohn Birrell int fd; 191*1673e404SJohn Birrell 192*1673e404SJohn Birrell debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE")); 193*1673e404SJohn Birrell 194*1673e404SJohn Birrell (void) elf_version(EV_CURRENT); 195*1673e404SJohn Birrell 196*1673e404SJohn Birrell if ((fd = open(file, O_RDONLY)) < 0) 197*1673e404SJohn Birrell terminate("%s: Cannot open for reading", file); 198*1673e404SJohn Birrell if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 199*1673e404SJohn Birrell elfterminate(file, "Cannot read"); 200*1673e404SJohn Birrell 201*1673e404SJohn Birrell switch (elf_kind(elf)) { 202*1673e404SJohn Birrell case ELF_K_AR: 203*1673e404SJohn Birrell found = read_archive(fd, elf, file, label, 204*1673e404SJohn Birrell func, arg, require_ctf); 205*1673e404SJohn Birrell break; 206*1673e404SJohn Birrell 207*1673e404SJohn Birrell case ELF_K_ELF: 208*1673e404SJohn Birrell found = read_file(elf, file, label, 209*1673e404SJohn Birrell func, arg, require_ctf); 210*1673e404SJohn Birrell break; 211*1673e404SJohn Birrell 212*1673e404SJohn Birrell default: 213*1673e404SJohn Birrell terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf)); 214*1673e404SJohn Birrell } 215*1673e404SJohn Birrell 216*1673e404SJohn Birrell (void) elf_end(elf); 217*1673e404SJohn Birrell (void) close(fd); 218*1673e404SJohn Birrell 219*1673e404SJohn Birrell return (found); 220*1673e404SJohn Birrell } 221*1673e404SJohn Birrell 222*1673e404SJohn Birrell /*ARGSUSED*/ 223*1673e404SJohn Birrell int 224*1673e404SJohn Birrell read_ctf_save_cb(tdata_t *td, char *name __unused, void *retp) 225*1673e404SJohn Birrell { 226*1673e404SJohn Birrell tdata_t **tdp = retp; 227*1673e404SJohn Birrell 228*1673e404SJohn Birrell *tdp = td; 229*1673e404SJohn Birrell 230*1673e404SJohn Birrell return (1); 231*1673e404SJohn Birrell } 232*1673e404SJohn Birrell 233*1673e404SJohn Birrell int 234*1673e404SJohn Birrell read_ctf(char **files, int n, char *label, read_cb_f *func, void *private, 235*1673e404SJohn Birrell int require_ctf) 236*1673e404SJohn Birrell { 237*1673e404SJohn Birrell int found; 238*1673e404SJohn Birrell int i, rc; 239*1673e404SJohn Birrell 240*1673e404SJohn Birrell for (i = 0, found = 0; i < n; i++) { 241*1673e404SJohn Birrell if ((rc = read_ctf_common(files[i], label, func, 242*1673e404SJohn Birrell private, require_ctf)) < 0) 243*1673e404SJohn Birrell return (rc); 244*1673e404SJohn Birrell found += rc; 245*1673e404SJohn Birrell } 246*1673e404SJohn Birrell 247*1673e404SJohn Birrell return (found); 248*1673e404SJohn Birrell } 249*1673e404SJohn Birrell 250*1673e404SJohn Birrell static int 251*1673e404SJohn Birrell count_archive(int fd, Elf *elf, char *file) 252*1673e404SJohn Birrell { 253*1673e404SJohn Birrell Elf *melf; 254*1673e404SJohn Birrell Elf_Cmd cmd = ELF_C_READ; 255*1673e404SJohn Birrell Elf_Arhdr *arh; 256*1673e404SJohn Birrell int nfiles = 0, err = 0; 257*1673e404SJohn Birrell 258*1673e404SJohn Birrell while ((melf = elf_begin(fd, cmd, elf)) != NULL) { 259*1673e404SJohn Birrell if ((arh = elf_getarhdr(melf)) == NULL) { 260*1673e404SJohn Birrell warning("Can't process input archive %s\n", 261*1673e404SJohn Birrell file); 262*1673e404SJohn Birrell err++; 263*1673e404SJohn Birrell } 264*1673e404SJohn Birrell 265*1673e404SJohn Birrell if (*arh->ar_name != '/') 266*1673e404SJohn Birrell nfiles++; 267*1673e404SJohn Birrell 268*1673e404SJohn Birrell cmd = elf_next(melf); 269*1673e404SJohn Birrell (void) elf_end(melf); 270*1673e404SJohn Birrell } 271*1673e404SJohn Birrell 272*1673e404SJohn Birrell if (err > 0) 273*1673e404SJohn Birrell return (-1); 274*1673e404SJohn Birrell 275*1673e404SJohn Birrell return (nfiles); 276*1673e404SJohn Birrell } 277*1673e404SJohn Birrell 278*1673e404SJohn Birrell int 279*1673e404SJohn Birrell count_files(char **files, int n) 280*1673e404SJohn Birrell { 281*1673e404SJohn Birrell int nfiles = 0, err = 0; 282*1673e404SJohn Birrell Elf *elf; 283*1673e404SJohn Birrell int fd, rc, i; 284*1673e404SJohn Birrell 285*1673e404SJohn Birrell (void) elf_version(EV_CURRENT); 286*1673e404SJohn Birrell 287*1673e404SJohn Birrell for (i = 0; i < n; i++) { 288*1673e404SJohn Birrell char *file = files[i]; 289*1673e404SJohn Birrell 290*1673e404SJohn Birrell if ((fd = open(file, O_RDONLY)) < 0) { 291*1673e404SJohn Birrell warning("Can't read input file %s", file); 292*1673e404SJohn Birrell err++; 293*1673e404SJohn Birrell continue; 294*1673e404SJohn Birrell } 295*1673e404SJohn Birrell 296*1673e404SJohn Birrell if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 297*1673e404SJohn Birrell warning("Can't open input file %s: %s\n", file, 298*1673e404SJohn Birrell elf_errmsg(-1)); 299*1673e404SJohn Birrell err++; 300*1673e404SJohn Birrell (void) close(fd); 301*1673e404SJohn Birrell continue; 302*1673e404SJohn Birrell } 303*1673e404SJohn Birrell 304*1673e404SJohn Birrell switch (elf_kind(elf)) { 305*1673e404SJohn Birrell case ELF_K_AR: 306*1673e404SJohn Birrell if ((rc = count_archive(fd, elf, file)) < 0) 307*1673e404SJohn Birrell err++; 308*1673e404SJohn Birrell else 309*1673e404SJohn Birrell nfiles += rc; 310*1673e404SJohn Birrell break; 311*1673e404SJohn Birrell case ELF_K_ELF: 312*1673e404SJohn Birrell nfiles++; 313*1673e404SJohn Birrell break; 314*1673e404SJohn Birrell default: 315*1673e404SJohn Birrell warning("Input file %s is corrupt\n", file); 316*1673e404SJohn Birrell err++; 317*1673e404SJohn Birrell } 318*1673e404SJohn Birrell 319*1673e404SJohn Birrell (void) elf_end(elf); 320*1673e404SJohn Birrell (void) close(fd); 321*1673e404SJohn Birrell } 322*1673e404SJohn Birrell 323*1673e404SJohn Birrell if (err > 0) 324*1673e404SJohn Birrell return (-1); 325*1673e404SJohn Birrell 326*1673e404SJohn Birrell debug(2, "Found %d files in %d input files\n", nfiles, n); 327*1673e404SJohn Birrell 328*1673e404SJohn Birrell return (nfiles); 329*1673e404SJohn Birrell } 330*1673e404SJohn Birrell 331*1673e404SJohn Birrell struct symit_data { 332*1673e404SJohn Birrell GElf_Shdr si_shdr; 333*1673e404SJohn Birrell Elf_Data *si_symd; 334*1673e404SJohn Birrell Elf_Data *si_strd; 335*1673e404SJohn Birrell GElf_Sym si_cursym; 336*1673e404SJohn Birrell char *si_curname; 337*1673e404SJohn Birrell char *si_curfile; 338*1673e404SJohn Birrell int si_nument; 339*1673e404SJohn Birrell int si_next; 340*1673e404SJohn Birrell }; 341*1673e404SJohn Birrell 342*1673e404SJohn Birrell symit_data_t * 343*1673e404SJohn Birrell symit_new(Elf *elf, const char *file) 344*1673e404SJohn Birrell { 345*1673e404SJohn Birrell symit_data_t *si; 346*1673e404SJohn Birrell Elf_Scn *scn; 347*1673e404SJohn Birrell int symtabidx; 348*1673e404SJohn Birrell 349*1673e404SJohn Birrell if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0) 350*1673e404SJohn Birrell return (NULL); 351*1673e404SJohn Birrell 352*1673e404SJohn Birrell si = xcalloc(sizeof (symit_data_t)); 353*1673e404SJohn Birrell 354*1673e404SJohn Birrell if ((scn = elf_getscn(elf, symtabidx)) == NULL || 355*1673e404SJohn Birrell gelf_getshdr(scn, &si->si_shdr) == NULL || 356*1673e404SJohn Birrell (si->si_symd = elf_getdata(scn, NULL)) == NULL) 357*1673e404SJohn Birrell elfterminate(file, "Cannot read .symtab"); 358*1673e404SJohn Birrell 359*1673e404SJohn Birrell if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL || 360*1673e404SJohn Birrell (si->si_strd = elf_getdata(scn, NULL)) == NULL) 361*1673e404SJohn Birrell elfterminate(file, "Cannot read strings for .symtab"); 362*1673e404SJohn Birrell 363*1673e404SJohn Birrell si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize; 364*1673e404SJohn Birrell 365*1673e404SJohn Birrell return (si); 366*1673e404SJohn Birrell } 367*1673e404SJohn Birrell 368*1673e404SJohn Birrell void 369*1673e404SJohn Birrell symit_free(symit_data_t *si) 370*1673e404SJohn Birrell { 371*1673e404SJohn Birrell free(si); 372*1673e404SJohn Birrell } 373*1673e404SJohn Birrell 374*1673e404SJohn Birrell void 375*1673e404SJohn Birrell symit_reset(symit_data_t *si) 376*1673e404SJohn Birrell { 377*1673e404SJohn Birrell si->si_next = 0; 378*1673e404SJohn Birrell } 379*1673e404SJohn Birrell 380*1673e404SJohn Birrell char * 381*1673e404SJohn Birrell symit_curfile(symit_data_t *si) 382*1673e404SJohn Birrell { 383*1673e404SJohn Birrell return (si->si_curfile); 384*1673e404SJohn Birrell } 385*1673e404SJohn Birrell 386*1673e404SJohn Birrell GElf_Sym * 387*1673e404SJohn Birrell symit_next(symit_data_t *si, int type) 388*1673e404SJohn Birrell { 389*1673e404SJohn Birrell GElf_Sym sym; 390*1673e404SJohn Birrell int check_sym = (type == STT_OBJECT || type == STT_FUNC); 391*1673e404SJohn Birrell 392*1673e404SJohn Birrell for (; si->si_next < si->si_nument; si->si_next++) { 393*1673e404SJohn Birrell gelf_getsym(si->si_symd, si->si_next, &si->si_cursym); 394*1673e404SJohn Birrell gelf_getsym(si->si_symd, si->si_next, &sym); 395*1673e404SJohn Birrell si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name; 396*1673e404SJohn Birrell 397*1673e404SJohn Birrell if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 398*1673e404SJohn Birrell si->si_curfile = si->si_curname; 399*1673e404SJohn Birrell 400*1673e404SJohn Birrell if (GELF_ST_TYPE(sym.st_info) != type || 401*1673e404SJohn Birrell sym.st_shndx == SHN_UNDEF) 402*1673e404SJohn Birrell continue; 403*1673e404SJohn Birrell 404*1673e404SJohn Birrell if (check_sym && ignore_symbol(&sym, si->si_curname)) 405*1673e404SJohn Birrell continue; 406*1673e404SJohn Birrell 407*1673e404SJohn Birrell si->si_next++; 408*1673e404SJohn Birrell 409*1673e404SJohn Birrell return (&si->si_cursym); 410*1673e404SJohn Birrell } 411*1673e404SJohn Birrell 412*1673e404SJohn Birrell return (NULL); 413*1673e404SJohn Birrell } 414*1673e404SJohn Birrell 415*1673e404SJohn Birrell char * 416*1673e404SJohn Birrell symit_name(symit_data_t *si) 417*1673e404SJohn Birrell { 418*1673e404SJohn Birrell return (si->si_curname); 419*1673e404SJohn Birrell } 420