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