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 /*
  23  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
  24  * Copyright (c) 2011, Robert Mustacchi, Inc. All rights reserved.
  25  * Copyright 2013, Richard Lowe.
  26  */
  27 
  28 #include <err.h>
  29 #include <fcntl.h>
  30 #include <gelf.h>
  31 #include <libctf.h>
  32 #include <saveargs.h>
  33 #include <stdarg.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <strings.h>
  37 #include <unistd.h>
  38 
  39 extern const char *__progname;
  40 
  41 typedef struct symtab_sym {
  42         GElf_Sym ss_sym;
  43         char *ss_name;
  44         ctf_funcinfo_t ss_finfo;
  45         uint8_t *ss_data;
  46         size_t ss_size;
  47 } symtab_sym_t;
  48 
  49 static void
  50 walk_symtab(Elf *elf, char *fname, ctf_file_t *fp,
  51     void (*callback)(ctf_file_t *, symtab_sym_t *))
  52 {
  53         Elf_Scn *stab = NULL;
  54         Elf_Scn *text = NULL;
  55         Elf_Data *stabdata = NULL;
  56         Elf_Data *textdata = NULL;
  57         GElf_Ehdr ehdr;
  58         GElf_Shdr stabshdr;
  59         GElf_Shdr textshdr;
  60         int foundtext = 0, foundstab = 0;
  61         symtab_sym_t ss;
  62 
  63         if ((gelf_getehdr(elf, &ehdr)) == NULL)
  64                 errx(1, "could not read ELF header from %s\n",
  65                     fname);
  66 
  67         while ((stab = elf_nextscn(elf, stab)) != NULL) {
  68                 (void) gelf_getshdr(stab, &stabshdr);
  69 
  70                 if (stabshdr.sh_type == SHT_SYMTAB) {
  71                         foundstab = 1;
  72                         break;
  73                 }
  74         }
  75 
  76         while ((text = elf_nextscn(elf, text)) != NULL) {
  77                 (void) gelf_getshdr(text, &textshdr);
  78 
  79                 if (strcmp(".text", elf_strptr(elf,
  80                     ehdr.e_shstrndx, (size_t)textshdr.sh_name)) == 0) {
  81                         foundtext = 1;
  82                         break;
  83                 }
  84         }
  85 
  86         if (!foundstab || !foundtext)
  87                 return;
  88 
  89         stabdata = elf_getdata(stab, NULL);
  90         textdata = elf_rawdata(text,  NULL);
  91         for (unsigned symdx = 0;
  92             symdx < (stabshdr.sh_size / stabshdr.sh_entsize);
  93             symdx++) {
  94                 (void) gelf_getsym(stabdata, symdx, &ss.ss_sym);
  95 
  96                 if ((GELF_ST_TYPE(ss.ss_sym.st_info) != STT_FUNC) ||
  97                     (ss.ss_sym.st_shndx == SHN_UNDEF))
  98                         continue;
  99 
 100                 ss.ss_name = elf_strptr(elf, stabshdr.sh_link,
 101                     ss.ss_sym.st_name);
 102                 ss.ss_data = ((uint8_t *)(textdata->d_buf)) +
 103                     (ss.ss_sym.st_value - textshdr.sh_addr);
 104 
 105                 if (ctf_func_info(fp, symdx, &ss.ss_finfo) == CTF_ERR) {
 106                         fprintf(stderr, "failed to get funcinfo for: %s\n",
 107                             ss.ss_name);
 108                         continue;
 109                 }
 110 
 111                 (void) callback(fp, &ss);
 112         }
 113 }
 114 
 115 void
 116 check_sym(ctf_file_t *ctfp, symtab_sym_t *ss)
 117 {
 118         int rettype = ctf_type_kind(ctfp, ss->ss_finfo.ctc_return);
 119         int start_index = 0;
 120 
 121         if (ss->ss_finfo.ctc_argc == 0) /* No arguments, no point */
 122                 return;
 123 
 124         if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) &&
 125             ctf_type_size(ctfp, ss->ss_finfo.ctc_return) > 16)
 126                 start_index = 1;
 127 
 128         if (saveargs_has_args(ss->ss_data, ss->ss_sym.st_size,
 129             ss->ss_finfo.ctc_argc, start_index) != SAVEARGS_NO_ARGS)
 130                 printf("%s has %d saved args\n", ss->ss_name,
 131                     ss->ss_finfo.ctc_argc);
 132 }
 133 
 134 int
 135 main(int argc, char **argv)
 136 {
 137         Elf             *elf;
 138         ctf_file_t      *ctfp;
 139         int errp, fd;
 140 
 141         if (ctf_version(CTF_VERSION) == -1)
 142                 errx(1, "mismatched libctf versions\n");
 143 
 144         if (elf_version(EV_CURRENT) == EV_NONE)
 145                 errx(1, "mismatched libelf versions\n");
 146 
 147         if (argc != 2)
 148                 errx(2, "usage: %s <file>\n", __progname);
 149 
 150         if ((ctfp = ctf_open(argv[1], &errp)) == NULL)
 151                 errx(1, "failed to ctf_open file: %s: %s\n", argv[1],
 152                     ctf_errmsg(errp));
 153 
 154         if ((fd = open(argv[1], O_RDONLY)) == -1)
 155                 errx(1, "could not open %s\n", argv[1]);
 156 
 157         if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
 158                 errx(1, "could not interpret ELF from %s\n",
 159                     argv[1]);
 160 
 161         walk_symtab(elf, argv[1], ctfp, check_sym);
 162 
 163         (void) elf_end(elf);
 164         (void) close(fd);
 165 
 166         return (0);
 167 }