xref: /illumos-gate/usr/src/cmd/sgs/libelf/demo/dispsyms.c (revision 7b79d846)
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 /* STT_IFUNC */		"IFUNC"
65 };
66 #if STT_NUM != (STT_IFUNC + 1)
67 #error "STT_NUM has grown. Update symtype[]."
68 #endif
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 		    (shdr.sh_type != SHT_SUNW_LDYNSYM))
111 			continue;
112 
113 		/*
114 		 * Get the data associated with the Symbol
115 		 * section.
116 		 */
117 		if ((symdata = elf_getdata(scn, 0)) == 0) {
118 			(void) fprintf(stderr,
119 			    "%s: elf_getdata() failed: %s\n",
120 			    file, elf_errmsg(0));
121 			return;
122 		}
123 
124 		/*
125 		 * Print symbol table title and header for symbol display
126 		 */
127 		(void) printf("\nSymTab: %s:%s\n", file,
128 		    elf_strptr(elf, shstrndx, shdr.sh_name));
129 		(void) printf("  index   value    size     type "
130 		    "bind  oth shndx name\n");
131 
132 		/*
133 		 * We now iterate over the full symbol table printing
134 		 * the symbols as we go.
135 		 */
136 		shndxdata = 0;
137 		nosymshndx = 0;
138 		symcnt = shdr.sh_size / shdr.sh_entsize;
139 		for (ndx = 0; ndx < symcnt; ndx++) {
140 			GElf_Sym	sym;
141 			Elf32_Word	shndx;
142 			uint_t		type;
143 			uint_t		bind;
144 			uint_t		specshndx;
145 			char		bindbuf[INTSTRLEN];
146 			char		typebuf[INTSTRLEN];
147 			char		shndxbuf[INTSTRLEN];
148 			const char	*bindstr;
149 			const char	*typestr;
150 			const char	*shndxstr;
151 
152 			/*
153 			 * Get a symbol entry
154 			 */
155 			if (gelf_getsymshndx(symdata, shndxdata, ndx,
156 			    &sym, &shndx) == NULL) {
157 				(void) fprintf(stderr,
158 				    "%s: gelf_getsymshndx() failed: %s\n",
159 				    file, elf_errmsg(0));
160 				return;
161 			}
162 			/*
163 			 * Check to see if this symbol's st_shndx
164 			 * is using the 'Extended SHNDX table' for
165 			 * a SYMTAB.
166 			 *
167 			 * If it is - and we havn't searched before,
168 			 * go find the associated SHT_SYMTAB_SHNDX
169 			 * section.
170 			 */
171 			if ((sym.st_shndx == SHN_XINDEX) &&
172 			    (shndxdata == 0) && (nosymshndx == 0)) {
173 				Elf_Scn		*_scn;
174 				GElf_Shdr	_shdr;
175 				GElf_Word	symscnndx;
176 				_scn = 0;
177 				specshndx = 0;
178 				symscnndx = elf_ndxscn(scn);
179 
180 				while ((_scn = elf_nextscn(elf, _scn)) != 0) {
181 					if (gelf_getshdr(_scn, &_shdr) == 0)
182 						break;
183 					/*
184 					 * We've found the Symtab SHNDX table
185 					 * if it's of type SHT_SYMTAB_SHNDX
186 					 * and it's shdr.sh_link points to the
187 					 * section index for the current symbol
188 					 * table.
189 					 */
190 					if ((_shdr.sh_type ==
191 					    SHT_SYMTAB_SHNDX) &&
192 					    (_shdr.sh_link == symscnndx)) {
193 						if ((shndxdata =
194 						    elf_getdata(_scn, 0)) != 0)
195 							break;
196 					}
197 				}
198 				/*
199 				 * Get a symbol entry
200 				 */
201 				if (shndxdata &&
202 				    (gelf_getsymshndx(symdata, shndxdata, ndx,
203 				    &sym, &shndx) == NULL)) {
204 					(void) fprintf(stderr,
205 					    "%s: gelf_getsymshndx() "
206 					    "failed: %s\n",
207 					    file, elf_errmsg(0));
208 					return;
209 				}
210 				/*
211 				 * No Symtab SHNDX table was found.  We could
212 				 * give a fatal error here - instead we'll
213 				 * just mark that fact and display as much of
214 				 * the symbol table as we can.  Any symbol
215 				 * displayed with a XINDX section index has
216 				 * a bogus value.
217 				 */
218 				if (shndxdata == 0)
219 					nosymshndx = 1;
220 			}
221 
222 			/*
223 			 * Decode the type & binding information
224 			 */
225 			type = GELF_ST_TYPE(sym.st_info);
226 			bind = GELF_ST_BIND(sym.st_info);
227 
228 			if (type < STT_NUM)
229 				typestr = symtype[type];
230 			else {
231 				(void) snprintf(typebuf, INTSTRLEN,
232 				    "%d", type);
233 				typestr = typebuf;
234 			}
235 
236 			if (bind < STB_NUM)
237 				bindstr = symbind[bind];
238 			else {
239 				(void) snprintf(bindbuf, INTSTRLEN,
240 				    "%d", bind);
241 				bindstr = bindbuf;
242 			}
243 
244 
245 			specshndx = 0;
246 			if (sym.st_shndx <  SHN_LORESERVE)
247 				shndx = sym.st_shndx;
248 			else if ((sym.st_shndx != SHN_XINDEX) ||
249 			    (shndxdata == NULL)) {
250 				shndx = sym.st_shndx;
251 				specshndx = 1;
252 			}
253 
254 			if (shndx == SHN_UNDEF) {
255 				shndxstr = (const char *)"UNDEF";
256 
257 			} else if (specshndx) {
258 				if (shndx == SHN_ABS)
259 					shndxstr = (const char *)"ABS";
260 				else if (shndx == SHN_COMMON)
261 					shndxstr = (const char *)"COMM";
262 				else if (shndx == SHN_XINDEX)
263 					shndxstr = (const char *)"XIND";
264 				else {
265 					(void) snprintf(shndxbuf, INTSTRLEN,
266 					    "%ld", shndx);
267 					shndxstr = shndxbuf;
268 				}
269 			} else {
270 				(void) snprintf(shndxbuf, INTSTRLEN,
271 				    "%ld", shndx);
272 				shndxstr = shndxbuf;
273 			}
274 
275 			/*
276 			 * Display the symbol entry.
277 			 */
278 			(void) printf("[%3d] 0x%08llx 0x%08llx %-4s "
279 			    "%-6s %2d %5s %s\n",
280 			    ndx, sym.st_value, sym.st_size,
281 			    typestr, bindstr, sym.st_other, shndxstr,
282 			    elf_strptr(elf, shdr.sh_link, sym.st_name));
283 		}
284 	}
285 }
286 
287 
288 static void
289 process_elf(Elf *elf, char *file, int fd, int member)
290 {
291 	Elf_Cmd	cmd;
292 	Elf	*_elf;
293 
294 	switch (elf_kind(elf)) {
295 	case ELF_K_ELF:
296 		/*
297 		 * This is an ELF file, now attempt to find it's
298 		 * .comment section and to display it.
299 		 */
300 		print_symtab(elf, file);
301 		break;
302 	case ELF_K_AR:
303 		/*
304 		 * Archives contain multiple ELF files, which can each
305 		 * in turn be examined with libelf.
306 		 *
307 		 * The below loop will iterate over each member of the
308 		 * archive and recursivly call process_elf() for processing.
309 		 */
310 		cmd = ELF_C_READ;
311 		while ((_elf = elf_begin(fd, cmd, elf)) != 0) {
312 			Elf_Arhdr	*arhdr;
313 			char		buffer[1024];
314 
315 			arhdr = elf_getarhdr(_elf);
316 
317 			/*
318 			 * Build up file names based off of
319 			 * 'archivename(membername)'.
320 			 */
321 			(void) snprintf(buffer, 1024, "%s(%s)",
322 			    file, arhdr->ar_name);
323 
324 			/*
325 			 * recursivly process the ELF members.
326 			 */
327 			process_elf(_elf, buffer, fd, 1);
328 			cmd = elf_next(_elf);
329 			(void) elf_end(_elf);
330 		}
331 		break;
332 	default:
333 		if (!member)
334 			(void) fprintf(stderr,
335 			    "%s: unexpected elf_kind(): 0x%x\n",
336 			    file, elf_kind(elf));
337 		return;
338 	}
339 }
340 
341 
342 int
343 main(int argc, char **argv)
344 {
345 	int	i;
346 
347 
348 	if (argc < 2) {
349 		(void) printf("usage: %s elf_file ...\n", argv[0]);
350 		return (1);
351 	}
352 
353 	/*
354 	 * Initialize the elf library, must be called before elf_begin()
355 	 * can be called.
356 	 */
357 	if (elf_version(EV_CURRENT) == EV_NONE) {
358 		(void) fprintf(stderr,
359 		    "elf_version() failed: %s\n", elf_errmsg(0));
360 		return (1);
361 	}
362 
363 	for (i = 1; i < argc; i++) {
364 		int	fd;
365 		Elf	*elf;
366 		char	*elf_fname;
367 
368 		elf_fname = argv[i];
369 		if ((fd = open(elf_fname, O_RDONLY)) == -1) {
370 			perror("open");
371 			continue;
372 		}
373 
374 		/*
375 		 * Attempt to open an Elf descriptor Read-Only
376 		 * for each file.
377 		 */
378 		if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) {
379 			(void) fprintf(stderr, "elf_begin() failed: %s\n",
380 			    elf_errmsg(0));
381 			(void) close(fd);
382 			continue;
383 		}
384 
385 		/*
386 		 * Process each elf descriptor.
387 		 */
388 		process_elf(elf, elf_fname, fd, 0);
389 		(void) elf_end(elf);
390 		(void) close(fd);
391 	}
392 
393 	return (0);
394 }
395