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 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * dispsyms: Display Symbols
27 *
28 * This program demonstrates the use of the libelf interface to
29 * read an ELF file. dispsyms will open an ELF file using
30 * elf_begin(ELF_C_READ) and examine search the ELF file
31 * for a symbol table (SHT_SYMTAB, SHT_DYNSYM, or SHT_SUNW_LDYNSYM).
32 * It will display the contents of any symbol tables it finds.
33 *
34 * Note: This program also understands about the use
35 * of 'Extended ELF Section indexes' and will
36 * decode a corresponding SHT_SYMTAB_SHNDX
37 * section if required.
38 */
39 #include <stdio.h>
40 #include <libelf.h>
41 #include <gelf.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 static const char *symbind[STB_NUM] = {
48 /* STB_LOCL */ "LOCL",
49 /* STB_GLOBAL */ "GLOB",
50 /* STB_WEAK */ "WEAK"
51 };
52
53 static const char *symtype[STT_NUM] = {
54 /* STT_NOTYPE */ "NOTY",
55 /* STT_OBJECT */ "OBJT",
56 /* STT_FUNC */ "FUNC",
57 /* STT_SECTION */ "SECT",
58 /* STT_FILE */ "FILE",
59 /* STT_COMMON */ "COMM",
60 /* STT_TLS */ "TLS"
61 };
62 #if STT_NUM != (STT_TLS + 1)
63 #error "STT_NUM has grown. Update symtype[]."
64 #endif
65
66 #define INTSTRLEN 32
67
68
69 static void
print_symtab(Elf * elf,const char * file)70 print_symtab(Elf *elf, const char *file)
71 {
72 Elf_Scn *scn = NULL;
73 GElf_Shdr shdr;
74 GElf_Ehdr ehdr;
75 size_t shstrndx;
76
77
78 if (gelf_getehdr(elf, &ehdr) == NULL) {
79 (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n",
80 file, elf_errmsg(0));
81 return;
82 }
83
84 if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
85 (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n",
86 file, elf_errmsg(0));
87 return;
88 }
89
90 while ((scn = elf_nextscn(elf, scn)) != NULL) {
91 uint_t symcnt, ndx, nosymshndx;
92 Elf_Data *symdata, *shndxdata;
93
94 if (gelf_getshdr(scn, &shdr) == NULL) {
95 (void) fprintf(stderr,
96 "%s: elf_getshdr() failed: %s\n",
97 file, elf_errmsg(0));
98 return;
99 }
100 if ((shdr.sh_type != SHT_SYMTAB) &&
101 (shdr.sh_type != SHT_DYNSYM) &&
102 (shdr.sh_type != SHT_SUNW_LDYNSYM))
103 continue;
104
105 /*
106 * Get the data associated with the Symbol
107 * section.
108 */
109 if ((symdata = elf_getdata(scn, NULL)) == NULL) {
110 (void) fprintf(stderr,
111 "%s: elf_getdata() failed: %s\n",
112 file, elf_errmsg(0));
113 return;
114 }
115
116 /*
117 * Print symbol table title and header for symbol display
118 */
119 (void) printf("\nSymTab: %s:%s\n", file,
120 elf_strptr(elf, shstrndx, shdr.sh_name));
121 (void) printf(" index value size type "
122 "bind oth shndx name\n");
123
124 /*
125 * We now iterate over the full symbol table printing
126 * the symbols as we go.
127 */
128 shndxdata = 0;
129 nosymshndx = 0;
130 symcnt = shdr.sh_size / shdr.sh_entsize;
131 for (ndx = 0; ndx < symcnt; ndx++) {
132 GElf_Sym sym;
133 Elf32_Word shndx;
134 uint_t type, bind, specshndx;
135 char bindbuf[INTSTRLEN];
136 char typebuf[INTSTRLEN];
137 char shndxbuf[INTSTRLEN];
138 const char *bindstr, *typestr, *shndxstr;
139
140 /*
141 * Get a symbol entry
142 */
143 if (gelf_getsymshndx(symdata, shndxdata, ndx,
144 &sym, &shndx) == NULL) {
145 (void) fprintf(stderr,
146 "%s: gelf_getsymshndx() failed: %s\n",
147 file, elf_errmsg(0));
148 return;
149 }
150 /*
151 * Check to see if this symbol's st_shndx is using
152 * the 'Extended SHNDX table' for a SYMTAB.
153 *
154 * If it is - and we haven't searched before, go
155 * find the associated SHT_SYMTAB_SHNDX section.
156 */
157 if ((sym.st_shndx == SHN_XINDEX) &&
158 (shndxdata == 0) && (nosymshndx == 0)) {
159 Elf_Scn *_scn = NULL;
160 GElf_Shdr _shdr;
161 GElf_Word symscnndx;
162
163 specshndx = 0;
164 symscnndx = elf_ndxscn(scn);
165
166 while ((_scn =
167 elf_nextscn(elf, _scn)) != NULL) {
168 if (gelf_getshdr(_scn, &_shdr) == NULL)
169 break;
170
171 /*
172 * We've found the Symtab SHNDX table
173 * if it's of type SHT_SYMTAB_SHNDX
174 * and it's shdr.sh_link points to the
175 * section index for the current symbol
176 * table.
177 */
178 if ((_shdr.sh_type ==
179 SHT_SYMTAB_SHNDX) &&
180 (_shdr.sh_link == symscnndx) &&
181 ((shndxdata = elf_getdata(_scn,
182 NULL)) != NULL))
183 break;
184 }
185 /*
186 * Get a symbol entry
187 */
188 if (shndxdata &&
189 (gelf_getsymshndx(symdata, shndxdata, ndx,
190 &sym, &shndx) == NULL)) {
191 (void) fprintf(stderr,
192 "%s: gelf_getsymshndx() "
193 "failed: %s\n",
194 file, elf_errmsg(0));
195 return;
196 }
197 /*
198 * No Symtab SHNDX table was found. We could
199 * give a fatal error here - instead we'll
200 * just mark that fact and display as much of
201 * the symbol table as we can. Any symbol
202 * displayed with a XINDX section index has
203 * a bogus value.
204 */
205 if (shndxdata == 0)
206 nosymshndx = 1;
207 }
208
209 /*
210 * Decode the type & binding information
211 */
212 type = GELF_ST_TYPE(sym.st_info);
213 bind = GELF_ST_BIND(sym.st_info);
214
215 if (type < STT_NUM)
216 typestr = symtype[type];
217 else {
218 (void) snprintf(typebuf, INTSTRLEN,
219 "%d", type);
220 typestr = typebuf;
221 }
222
223 if (bind < STB_NUM)
224 bindstr = symbind[bind];
225 else {
226 (void) snprintf(bindbuf, INTSTRLEN,
227 "%d", bind);
228 bindstr = bindbuf;
229 }
230
231
232 specshndx = 0;
233 if (sym.st_shndx < SHN_LORESERVE)
234 shndx = sym.st_shndx;
235 else if ((sym.st_shndx != SHN_XINDEX) ||
236 (shndxdata == NULL)) {
237 shndx = sym.st_shndx;
238 specshndx = 1;
239 }
240
241 if (shndx == SHN_UNDEF) {
242 shndxstr = (const char *)"UNDEF";
243
244 } else if (specshndx) {
245 if (shndx == SHN_ABS)
246 shndxstr = (const char *)"ABS";
247 else if (shndx == SHN_COMMON)
248 shndxstr = (const char *)"COMM";
249 else if (shndx == SHN_XINDEX)
250 shndxstr = (const char *)"XIND";
251 else {
252 (void) snprintf(shndxbuf, INTSTRLEN,
253 "%ld", shndx);
254 shndxstr = shndxbuf;
255 }
256 } else {
257 (void) snprintf(shndxbuf, INTSTRLEN,
258 "%ld", shndx);
259 shndxstr = shndxbuf;
260 }
261
262 /*
263 * Display the symbol entry.
264 */
265 (void) printf("[%3d] 0x%08llx 0x%08llx %-4s "
266 "%-6s %2d %5s %s\n",
267 ndx, sym.st_value, sym.st_size,
268 typestr, bindstr, sym.st_other, shndxstr,
269 elf_strptr(elf, shdr.sh_link, sym.st_name));
270 }
271 }
272 }
273
274
275 static void
process_elf(Elf * elf,char * file,int fd,int member)276 process_elf(Elf *elf, char *file, int fd, int member)
277 {
278 Elf_Cmd cmd;
279 Elf *_elf;
280
281 switch (elf_kind(elf)) {
282 case ELF_K_ELF:
283 /*
284 * This is an ELF file, now attempt to find it's
285 * .comment section and to display it.
286 */
287 print_symtab(elf, file);
288 break;
289 case ELF_K_AR:
290 /*
291 * Archives contain multiple ELF files, which can each
292 * in turn be examined with libelf.
293 *
294 * The below loop will iterate over each member of the
295 * archive and recursively call process_elf().
296 */
297 cmd = ELF_C_READ;
298 while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
299 Elf_Arhdr *arhdr;
300 char buffer[1024];
301
302 arhdr = elf_getarhdr(_elf);
303
304 /*
305 * Build up file names based off of
306 * 'archivename(membername)'.
307 */
308 (void) snprintf(buffer, 1024, "%s(%s)",
309 file, arhdr->ar_name);
310
311 /*
312 * Recursively process the ELF members.
313 */
314 process_elf(_elf, buffer, fd, 1);
315 cmd = elf_next(_elf);
316 (void) elf_end(_elf);
317 }
318 break;
319 default:
320 if (!member)
321 (void) fprintf(stderr,
322 "%s: unexpected elf_kind(): 0x%x\n",
323 file, elf_kind(elf));
324 return;
325 }
326 }
327
328 int
main(int argc,char ** argv)329 main(int argc, char **argv)
330 {
331 int i;
332
333 if (argc < 2) {
334 (void) printf("usage: %s elf_file ...\n", argv[0]);
335 return (1);
336 }
337
338 /*
339 * Initialize the elf library, must be called before elf_begin()
340 * can be called.
341 */
342 if (elf_version(EV_CURRENT) == EV_NONE) {
343 (void) fprintf(stderr,
344 "elf_version() failed: %s\n", elf_errmsg(0));
345 return (1);
346 }
347
348 for (i = 1; i < argc; i++) {
349 int fd;
350 Elf *elf;
351 char *elf_fname;
352
353 elf_fname = argv[i];
354 if ((fd = open(elf_fname, O_RDONLY)) == -1) {
355 perror("open");
356 continue;
357 }
358
359 /*
360 * Attempt to open an Elf descriptor Read-Only
361 * for each file.
362 */
363 if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) {
364 (void) fprintf(stderr, "elf_begin() failed: %s\n",
365 elf_errmsg(0));
366 (void) close(fd);
367 continue;
368 }
369
370 /*
371 * Process each elf descriptor.
372 */
373 process_elf(elf, elf_fname, fd, 0);
374 (void) elf_end(elf);
375 (void) close(fd);
376 }
377
378 return (0);
379 }
380