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