1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 #include <err.h>
  13 #include <fcntl.h>
  14 #include <gelf.h>
  15 #include <libctf.h>
  16 #include <saveargs.h>
  17 #include <stdarg.h>
  18 #include <stdio.h>
  19 #include <stdlib.h>
  20 #include <strings.h>
  21 #include <unistd.h>
  22 
  23 extern const char *__progname;
  24 
  25 typedef struct symtab_sym {
  26         GElf_Sym ss_sym;
  27         char *ss_name;
  28         ctf_funcinfo_t ss_finfo;
  29         uint8_t *ss_data;
  30         size_t ss_size;
  31 } symtab_sym_t;
  32 
  33 static void
  34 walk_symtab(Elf *elf, char *fname, ctf_file_t *fp,
  35     void (*callback)(ctf_file_t *, symtab_sym_t *))
  36 {
  37         Elf_Scn *stab = NULL;
  38         Elf_Scn *text = NULL;
  39         Elf_Data *stabdata = NULL;
  40         Elf_Data *textdata = NULL;
  41         GElf_Ehdr ehdr;
  42         GElf_Shdr stabshdr;
  43         GElf_Shdr textshdr;
  44         int fd, foundtext = 0, foundstab = 0;
  45         symtab_sym_t ss;
  46 
  47         if ((gelf_getehdr(elf, &ehdr)) == NULL)
  48                 errx(1, "could not read ELF header from %s\n",
  49                     fname);
  50 
  51         while ((stab = elf_nextscn(elf, stab)) != NULL) {
  52                 (void) gelf_getshdr(stab, &stabshdr);
  53 
  54                 if (stabshdr.sh_type == SHT_SYMTAB) {
  55                         foundstab = 1;
  56                         break;
  57                 }
  58         }
  59 
  60         while ((text = elf_nextscn(elf, text)) != NULL) {
  61                 (void) gelf_getshdr(text, &textshdr);
  62 
  63                 if (strcmp(".text", elf_strptr(elf,
  64                     ehdr.e_shstrndx, (size_t)textshdr.sh_name)) == 0) {
  65                         foundtext = 1;
  66                         break;
  67                 }
  68         }
  69 
  70         if (!foundstab || !foundtext)
  71                 goto out;
  72 
  73         stabdata = elf_getdata(stab, NULL);
  74         textdata = elf_rawdata(text,  NULL);
  75         for (unsigned symdx = 0;
  76             symdx < (stabshdr.sh_size / stabshdr.sh_entsize);
  77             symdx++) {
  78                 (void) gelf_getsym(stabdata, symdx, &ss.ss_sym);
  79 
  80                 if ((GELF_ST_TYPE(ss.ss_sym.st_info) != STT_FUNC) ||
  81                     (ss.ss_sym.st_shndx == SHN_UNDEF))
  82                         continue;
  83 
  84                 ss.ss_name = elf_strptr(elf, stabshdr.sh_link,
  85                     ss.ss_sym.st_name);
  86                 ss.ss_data = ((uint8_t *)(textdata->d_buf)) +
  87                     (ss.ss_sym.st_value - textshdr.sh_addr);
  88 
  89                 if (ctf_func_info(fp, symdx, &ss.ss_finfo) == CTF_ERR) {
  90                         fprintf(stderr, "failed to get funcinfo for: %s\n",
  91                             ss.ss_name);
  92                         continue;
  93                 }
  94 
  95                 (void) callback(fp, &ss);
  96         }
  97 
  98 out:
  99         (void) elf_end(elf);
 100         (void) close(fd);
 101 }
 102 
 103 void
 104 check_sym(ctf_file_t *ctfp, symtab_sym_t *ss)
 105 {
 106         int rettype = ctf_type_kind(ctfp, ss->ss_finfo.ctc_return);
 107         int start_index = 0;
 108 
 109         if (ss->ss_finfo.ctc_argc == 0) /* No arguments, no point */
 110                 return;
 111 
 112         if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) &&
 113             ctf_type_size(ctfp, ss->ss_finfo.ctc_return) > 16)
 114                 start_index = 1;
 115 
 116         if (saveargs_has_args(ss->ss_data, ss->ss_sym.st_size,
 117             ss->ss_finfo.ctc_argc, start_index) != SAVEARGS_NO_ARGS)
 118                 printf("%s has %d saved args\n", ss->ss_name,
 119                     ss->ss_finfo.ctc_argc);
 120 }
 121 
 122 int
 123 main(int argc, char **argv)
 124 {
 125         Elf             *elf;
 126         ctf_file_t      *ctfp;
 127         int errp, fd;
 128 
 129         if (ctf_version(CTF_VERSION) == -1)
 130                 errx(1, "mismatched libctf versions\n");
 131 
 132         if (elf_version(EV_CURRENT) == EV_NONE)
 133                 errx(1, "mismatched libelf versions\n");
 134 
 135         if (argc != 2)
 136                 errx(2, "usage: %s <file>\n", __progname);
 137 
 138         if ((ctfp = ctf_open(argv[1], &errp)) == NULL)
 139                 errx(1, "failed to ctf_open file: %s: %s\n", argv[1],
 140                     ctf_errmsg(errp));
 141 
 142         if ((fd = open(argv[1], O_RDONLY)) == -1)
 143                 errx(1, "could not open %s\n", argv[1]);
 144 
 145         if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
 146                 errx(1, "could not interpret ELF from %s\n",
 147                     argv[1]);
 148 
 149         walk_symtab(elf, argv[1], ctfp, check_sym);
 150 
 151         return (0);
 152 }