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
walk_symtab(Elf * elf,char * fname,ctf_file_t * fp,void (* callback)(ctf_file_t *,symtab_sym_t *))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
check_sym(ctf_file_t * ctfp,symtab_sym_t * ss)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
main(int argc,char ** argv)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 }
168