xref: /titanic_41/usr/src/cmd/sgs/libelf/demo/dispsyms.c (revision ba2e4443695ee6a6f420a35cd4fc3d3346d22932)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * dispsyms: Display Symbols
30  *
31  * This program demonstrates the use of the libelf interface to
32  * read an ELF file.  dispsyms will open an ELF file using
33  * elf_begin(ELF_C_READ) and examine search the ELF file
34  * for either a SHT_SYMTAB or SHT_DYNSYM symbol table.
35  * If it finds either - it will display the contents of
36  * the symbol tables it finds.
37  *
38  * Note:  This program also understands about the use
39  *	  of 'Extended ELF Section indexes' and will
40  *	  decode a corresponding SHT_SYMTAB_SHNDX
41  *	  section if required.
42  */
43 
44 
45 #include <stdio.h>
46 #include <libelf.h>
47 #include <gelf.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51 #include <string.h>
52 
53 static const char *symbind[STB_NUM] = {
54 /* STB_LOCL */		"LOCL",
55 /* STB_GLOBAL */	"GLOB",
56 /* STB_WEAK */		"WEAK"
57 };
58 
59 static const char *symtype[STT_NUM] = {
60 /* STT_NOTYPE */	"NOTY",
61 /* STT_OBJECT */	"OBJT",
62 /* STT_FUNC */		"FUNC",
63 /* STT_SECTION */	"SECT",
64 /* STT_FILE */		"FILE",
65 /* STT_COMMON */	"COMM",
66 /* STT_TLS */		"TLS"
67 };
68 
69 
70 #define	INTSTRLEN	32
71 
72 
73 static void
74 print_symtab(Elf *elf, const char *file)
75 {
76 	Elf_Scn		*scn;
77 	GElf_Shdr	shdr;
78 	GElf_Ehdr	ehdr;
79 	size_t		shstrndx;
80 
81 
82 	if (gelf_getehdr(elf, &ehdr) == 0) {
83 		(void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n",
84 			file, elf_errmsg(0));
85 		return;
86 	}
87 
88 	if (elf_getshstrndx(elf, &shstrndx) == 0) {
89 		(void) fprintf(stderr, "%s: elf_getshstrndx() failed: %s\n",
90 			file, elf_errmsg(0));
91 		return;
92 	}
93 
94 	scn = 0;
95 	while ((scn = elf_nextscn(elf, scn)) != 0) {
96 		uint_t		symcnt;
97 		uint_t		ndx;
98 		uint_t		nosymshndx;
99 		Elf_Data	*symdata;
100 		Elf_Data	*shndxdata;
101 
102 		if (gelf_getshdr(scn, &shdr) == 0) {
103 			(void) fprintf(stderr,
104 				"%s: elf_getshdr() failed: %s\n",
105 				file, elf_errmsg(0));
106 			return;
107 		}
108 		if ((shdr.sh_type != SHT_SYMTAB) &&
109 		    (shdr.sh_type != SHT_DYNSYM))
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 
287 static void
288 process_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 
341 int
342 main(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