xref: /onnv-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision 1618:8c9a4f31d225)
1*1618Srie /*
2*1618Srie  * CDDL HEADER START
3*1618Srie  *
4*1618Srie  * The contents of this file are subject to the terms of the
5*1618Srie  * Common Development and Distribution License (the "License").
6*1618Srie  * You may not use this file except in compliance with the License.
7*1618Srie  *
8*1618Srie  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1618Srie  * or http://www.opensolaris.org/os/licensing.
10*1618Srie  * See the License for the specific language governing permissions
11*1618Srie  * and limitations under the License.
12*1618Srie  *
13*1618Srie  * When distributing Covered Code, include this CDDL HEADER in each
14*1618Srie  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1618Srie  * If applicable, add the following below this CDDL HEADER, with the
16*1618Srie  * fields enclosed by brackets "[]" replaced with your own identifying
17*1618Srie  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1618Srie  *
19*1618Srie  * CDDL HEADER END
20*1618Srie  */
21*1618Srie 
22*1618Srie /*
23*1618Srie  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1618Srie  * Use is subject to license terms.
25*1618Srie  */
26*1618Srie #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*1618Srie 
28*1618Srie /*
29*1618Srie  * Dump an elf file.
30*1618Srie  */
31*1618Srie #include	<sys/param.h>
32*1618Srie #include	<fcntl.h>
33*1618Srie #include	<stdio.h>
34*1618Srie #include	<libelf.h>
35*1618Srie #include	<link.h>
36*1618Srie #include	<stdarg.h>
37*1618Srie #include	<unistd.h>
38*1618Srie #include	<libgen.h>
39*1618Srie #include	<libintl.h>
40*1618Srie #include	<locale.h>
41*1618Srie #include	<errno.h>
42*1618Srie #include	<strings.h>
43*1618Srie #include	<debug.h>
44*1618Srie #include	<conv.h>
45*1618Srie #include	<msg.h>
46*1618Srie #include	<_elfdump.h>
47*1618Srie 
48*1618Srie const Cache	cache_init = {NULL, NULL, NULL};
49*1618Srie 
50*1618Srie const char *
51*1618Srie _elfdump_msg(Msg mid)
52*1618Srie {
53*1618Srie 	return (gettext(MSG_ORIG(mid)));
54*1618Srie }
55*1618Srie 
56*1618Srie /*
57*1618Srie  * Determine whether a symbol name should be demangled.
58*1618Srie  */
59*1618Srie const char *
60*1618Srie demangle(const char *name, uint_t flags)
61*1618Srie {
62*1618Srie 	if (flags & FLG_DEMANGLE)
63*1618Srie 		return (Elf_demangle_name(name));
64*1618Srie 	else
65*1618Srie 		return ((char *)name);
66*1618Srie }
67*1618Srie 
68*1618Srie /*
69*1618Srie  * Define our own standard error routine.
70*1618Srie  */
71*1618Srie void
72*1618Srie failure(const char *file, const char *func)
73*1618Srie {
74*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
75*1618Srie 	    file, func, elf_errmsg(elf_errno()));
76*1618Srie }
77*1618Srie 
78*1618Srie /*
79*1618Srie  * The full usage message
80*1618Srie  */
81*1618Srie static void
82*1618Srie detail_usage()
83*1618Srie {
84*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
85*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
86*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
87*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
88*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
89*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
90*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
91*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
92*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
93*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1));
94*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
95*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
96*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
97*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
98*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
99*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
100*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
101*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
102*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
103*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
104*1618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
105*1618Srie }
106*1618Srie 
107*1618Srie static void
108*1618Srie decide(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd)
109*1618Srie {
110*1618Srie 	if (gelf_getclass(elf) == ELFCLASS64)
111*1618Srie 		regular64(file, elf, flags, Nname, wfd);
112*1618Srie 	else
113*1618Srie 		regular32(file, elf, flags, Nname, wfd);
114*1618Srie }
115*1618Srie 
116*1618Srie static void
117*1618Srie archive(const char *file, int fd, Elf *elf, uint_t flags, char *Nname,
118*1618Srie     int wfd)
119*1618Srie {
120*1618Srie 	Elf_Cmd		cmd = ELF_C_READ;
121*1618Srie 	Elf_Arhdr	*arhdr;
122*1618Srie 	Elf		*_elf = 0;
123*1618Srie 	size_t		ptr;
124*1618Srie 	Elf_Arsym	*arsym = 0;
125*1618Srie 
126*1618Srie 	/*
127*1618Srie 	 * Determine if the archive sysmbol table itself is required.
128*1618Srie 	 */
129*1618Srie 	if ((flags & FLG_SYMBOLS) && ((Nname == NULL) ||
130*1618Srie 	    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) {
131*1618Srie 		/*
132*1618Srie 		 * Get the archive symbol table.
133*1618Srie 		 */
134*1618Srie 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
135*1618Srie 			/*
136*1618Srie 			 * The arsym could be 0 even though there was no error.
137*1618Srie 			 * Print the error message only when there was
138*1618Srie 			 * real error from elf_getarsym().
139*1618Srie 			 */
140*1618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
141*1618Srie 			return;
142*1618Srie 		}
143*1618Srie 	}
144*1618Srie 
145*1618Srie 	/*
146*1618Srie 	 * Print the archive symbol table only when the archive symbol
147*1618Srie 	 * table exists and it was requested to print.
148*1618Srie 	 */
149*1618Srie 	if (arsym) {
150*1618Srie 		size_t		cnt;
151*1618Srie 		char		index[MAXNDXSIZE];
152*1618Srie 		size_t		offset = 0, _offset = 0;
153*1618Srie 
154*1618Srie 		/*
155*1618Srie 		 * Print out all the symbol entries.
156*1618Srie 		 */
157*1618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
158*1618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
159*1618Srie 
160*1618Srie 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
161*1618Srie 			/*
162*1618Srie 			 * For each object obtain an elf descriptor so that we
163*1618Srie 			 * can establish the members name.  Note, we have had
164*1618Srie 			 * archives where the archive header has not been
165*1618Srie 			 * obtainable so be lenient with errors.
166*1618Srie 			 */
167*1618Srie 			if ((offset == 0) || ((arsym->as_off != 0) &&
168*1618Srie 			    (arsym->as_off != _offset))) {
169*1618Srie 
170*1618Srie 				if (_elf)
171*1618Srie 					(void) elf_end(_elf);
172*1618Srie 
173*1618Srie 				if (elf_rand(elf, arsym->as_off) !=
174*1618Srie 				    arsym->as_off) {
175*1618Srie 					failure(file, MSG_ORIG(MSG_ELF_RAND));
176*1618Srie 					arhdr = 0;
177*1618Srie 				} else if ((_elf = elf_begin(fd,
178*1618Srie 				    ELF_C_READ, elf)) == 0) {
179*1618Srie 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
180*1618Srie 					arhdr = 0;
181*1618Srie 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
182*1618Srie 					failure(file,
183*1618Srie 					    MSG_ORIG(MSG_ELF_GETARHDR));
184*1618Srie 					arhdr = 0;
185*1618Srie 				}
186*1618Srie 
187*1618Srie 				_offset = arsym->as_off;
188*1618Srie 				if (offset == 0)
189*1618Srie 					offset = _offset;
190*1618Srie 			}
191*1618Srie 
192*1618Srie 			(void) snprintf(index, MAXNDXSIZE,
193*1618Srie 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
194*1618Srie 			if (arsym->as_off)
195*1618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
196*1618Srie 				    /* LINTED */
197*1618Srie 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
198*1618Srie 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
199*1618Srie 				    demangle(arsym->as_name, flags) :
200*1618Srie 				    MSG_INTL(MSG_STR_NULL)));
201*1618Srie 			else
202*1618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
203*1618Srie 				    /* LINTED */
204*1618Srie 				    (int)arsym->as_off);
205*1618Srie 		}
206*1618Srie 
207*1618Srie 		if (_elf)
208*1618Srie 			(void) elf_end(_elf);
209*1618Srie 
210*1618Srie 		/*
211*1618Srie 		 * If we only need the archive symbol table return.
212*1618Srie 		 */
213*1618Srie 		if ((flags & FLG_SYMBOLS) && Nname &&
214*1618Srie 		    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))
215*1618Srie 			return;
216*1618Srie 
217*1618Srie 		/*
218*1618Srie 		 * Reset elf descriptor in preparation for processing each
219*1618Srie 		 * member.
220*1618Srie 		 */
221*1618Srie 		if (offset)
222*1618Srie 			(void) elf_rand(elf, offset);
223*1618Srie 	}
224*1618Srie 
225*1618Srie 	/*
226*1618Srie 	 * Process each object within the archive.
227*1618Srie 	 */
228*1618Srie 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
229*1618Srie 		char	name[MAXPATHLEN];
230*1618Srie 
231*1618Srie 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
232*1618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
233*1618Srie 			return;
234*1618Srie 		}
235*1618Srie 		if (*arhdr->ar_name != '/') {
236*1618Srie 			(void) snprintf(name, MAXPATHLEN,
237*1618Srie 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
238*1618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
239*1618Srie 
240*1618Srie 			switch (elf_kind(_elf)) {
241*1618Srie 			case ELF_K_AR:
242*1618Srie 				archive(name, fd, _elf, flags, Nname, wfd);
243*1618Srie 				break;
244*1618Srie 			case ELF_K_ELF:
245*1618Srie 				decide(name, _elf, flags, Nname, wfd);
246*1618Srie 				break;
247*1618Srie 			default:
248*1618Srie 				(void) fprintf(stderr,
249*1618Srie 				    MSG_INTL(MSG_ERR_BADFILE), name);
250*1618Srie 				break;
251*1618Srie 			}
252*1618Srie 		}
253*1618Srie 
254*1618Srie 		cmd = elf_next(_elf);
255*1618Srie 		(void) elf_end(_elf);
256*1618Srie 	}
257*1618Srie }
258*1618Srie 
259*1618Srie int
260*1618Srie main(int argc, char **argv, char **envp)
261*1618Srie {
262*1618Srie 	Elf		*elf;
263*1618Srie 	int		var, fd, wfd = 0;
264*1618Srie 	char		*Nname = NULL, *wname = 0;
265*1618Srie 	uint_t		flags = 0;
266*1618Srie 
267*1618Srie 	/*
268*1618Srie 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
269*1618Srie 	 * the binary.  If successful, conv_check_native() won't return.
270*1618Srie 	 */
271*1618Srie 	conv_check_native(argv, envp);
272*1618Srie 
273*1618Srie 	/*
274*1618Srie 	 * Establish locale.
275*1618Srie 	 */
276*1618Srie 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
277*1618Srie 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
278*1618Srie 
279*1618Srie 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
280*1618Srie 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
281*1618Srie 
282*1618Srie 	opterr = 0;
283*1618Srie 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
284*1618Srie 		switch (var) {
285*1618Srie 		case 'C':
286*1618Srie 			flags |= FLG_DEMANGLE;
287*1618Srie 			break;
288*1618Srie 		case 'c':
289*1618Srie 			flags |= FLG_SHDR;
290*1618Srie 			break;
291*1618Srie 		case 'd':
292*1618Srie 			flags |= FLG_DYNAMIC;
293*1618Srie 			break;
294*1618Srie 		case 'e':
295*1618Srie 			flags |= FLG_EHDR;
296*1618Srie 			break;
297*1618Srie 		case 'G':
298*1618Srie 			flags |= FLG_GOT;
299*1618Srie 			break;
300*1618Srie 		case 'g':
301*1618Srie 			flags |= FLG_GROUP;
302*1618Srie 			break;
303*1618Srie 		case 'H':
304*1618Srie 			flags |= FLG_CAP;
305*1618Srie 			break;
306*1618Srie 		case 'h':
307*1618Srie 			flags |= FLG_HASH;
308*1618Srie 			break;
309*1618Srie 		case 'i':
310*1618Srie 			flags |= FLG_INTERP;
311*1618Srie 			break;
312*1618Srie 		case 'k':
313*1618Srie 			flags |= FLG_CHECKSUM;
314*1618Srie 			break;
315*1618Srie 		case 'l':
316*1618Srie 			flags |= FLG_LONGNAME;
317*1618Srie 			break;
318*1618Srie 		case 'm':
319*1618Srie 			flags |= FLG_MOVE;
320*1618Srie 			break;
321*1618Srie 		case 'N':
322*1618Srie 			Nname = optarg;
323*1618Srie 			break;
324*1618Srie 		case 'n':
325*1618Srie 			flags |= FLG_NOTE;
326*1618Srie 			break;
327*1618Srie 		case 'p':
328*1618Srie 			flags |= FLG_PHDR;
329*1618Srie 			break;
330*1618Srie 		case 'r':
331*1618Srie 			flags |= FLG_RELOC;
332*1618Srie 			break;
333*1618Srie 		case 's':
334*1618Srie 			flags |= FLG_SYMBOLS;
335*1618Srie 			break;
336*1618Srie 		case 'u':
337*1618Srie 			flags |= FLG_UNWIND;
338*1618Srie 			break;
339*1618Srie 		case 'v':
340*1618Srie 			flags |= FLG_VERSIONS;
341*1618Srie 			break;
342*1618Srie 		case 'w':
343*1618Srie 			wname = optarg;
344*1618Srie 			break;
345*1618Srie 		case 'y':
346*1618Srie 			flags |= FLG_SYMINFO;
347*1618Srie 			break;
348*1618Srie 		case '?':
349*1618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
350*1618Srie 			    basename(argv[0]));
351*1618Srie 			detail_usage();
352*1618Srie 			return (1);
353*1618Srie 		default:
354*1618Srie 			break;
355*1618Srie 		}
356*1618Srie 	}
357*1618Srie 
358*1618Srie 	/*
359*1618Srie 	 * Validate any arguments.
360*1618Srie 	 */
361*1618Srie 	if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) {
362*1618Srie 		if (!wname && !Nname) {
363*1618Srie 			flags |= FLG_EVERYTHING;
364*1618Srie 		} else if (!wname || !Nname) {
365*1618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
366*1618Srie 			    basename(argv[0]));
367*1618Srie 			return (1);
368*1618Srie 		}
369*1618Srie 	}
370*1618Srie 
371*1618Srie 	if ((var = argc - optind) == 0) {
372*1618Srie 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
373*1618Srie 		    basename(argv[0]));
374*1618Srie 		return (1);
375*1618Srie 	}
376*1618Srie 
377*1618Srie 	/*
378*1618Srie 	 * If the -l/-C option is specified, set up the liblddbg.so.
379*1618Srie 	 */
380*1618Srie 	if (flags & FLG_LONGNAME)
381*1618Srie 		dbg_desc->d_extra |= DBG_E_LONG;
382*1618Srie 	if (flags & FLG_DEMANGLE)
383*1618Srie 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
384*1618Srie 
385*1618Srie 	/*
386*1618Srie 	 * If the -w option has indicated an output file open it.  It's
387*1618Srie 	 * arguable whether this option has much use when multiple files are
388*1618Srie 	 * being processed.
389*1618Srie 	 */
390*1618Srie 	if (wname) {
391*1618Srie 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
392*1618Srie 		    0666)) < 0) {
393*1618Srie 			int err = errno;
394*1618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
395*1618Srie 			    wname, strerror(err));
396*1618Srie 			wfd = 0;
397*1618Srie 		}
398*1618Srie 	}
399*1618Srie 
400*1618Srie 	/*
401*1618Srie 	 * Open the input file and initialize the elf interface.
402*1618Srie 	 */
403*1618Srie 	for (; optind < argc; optind++) {
404*1618Srie 		const char	*file = argv[optind];
405*1618Srie 
406*1618Srie 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
407*1618Srie 			int err = errno;
408*1618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
409*1618Srie 			    file, strerror(err));
410*1618Srie 			continue;
411*1618Srie 		}
412*1618Srie 		(void) elf_version(EV_CURRENT);
413*1618Srie 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
414*1618Srie 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
415*1618Srie 			(void) close(fd);
416*1618Srie 			continue;
417*1618Srie 		}
418*1618Srie 
419*1618Srie 		if (var > 1)
420*1618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
421*1618Srie 
422*1618Srie 		switch (elf_kind(elf)) {
423*1618Srie 		case ELF_K_AR:
424*1618Srie 			archive(file, fd, elf, flags, Nname, wfd);
425*1618Srie 			break;
426*1618Srie 		case ELF_K_ELF:
427*1618Srie 			decide(file, elf, flags, Nname, wfd);
428*1618Srie 			break;
429*1618Srie 		default:
430*1618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
431*1618Srie 			break;
432*1618Srie 		}
433*1618Srie 
434*1618Srie 		(void) close(fd);
435*1618Srie 		(void) elf_end(elf);
436*1618Srie 	}
437*1618Srie 
438*1618Srie 	if (wfd)
439*1618Srie 		(void) close(wfd);
440*1618Srie 	return (0);
441*1618Srie }
442