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 }