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