dispsyms.c revision 12927:a27c46eb192b
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
47static const char *symbind[STB_NUM] = {
48/* STB_LOCL */		"LOCL",
49/* STB_GLOBAL */	"GLOB",
50/* STB_WEAK */		"WEAK"
51};
52
53static 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
69static void
70print_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
275static void
276process_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
328int
329main(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