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