xref: /illumos-gate/usr/src/cmd/sgs/libelf/demo/dispsyms.c (revision cd3e933325e68e23516a196a8fea7f49b1e497c3)
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 
50 static const char *symbind[STB_NUM] = {
51 /* STB_LOCL */		"LOCL",
52 /* STB_GLOBAL */	"GLOB",
53 /* STB_WEAK */		"WEAK"
54 };
55 
56 static 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 
72 static void
73 print_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 
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