xref: /onnv-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision 4063:ca21bf366165)
11618Srie /*
21618Srie  * CDDL HEADER START
31618Srie  *
41618Srie  * The contents of this file are subject to the terms of the
51618Srie  * Common Development and Distribution License (the "License").
61618Srie  * You may not use this file except in compliance with the License.
71618Srie  *
81618Srie  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91618Srie  * or http://www.opensolaris.org/os/licensing.
101618Srie  * See the License for the specific language governing permissions
111618Srie  * and limitations under the License.
121618Srie  *
131618Srie  * When distributing Covered Code, include this CDDL HEADER in each
141618Srie  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151618Srie  * If applicable, add the following below this CDDL HEADER, with the
161618Srie  * fields enclosed by brackets "[]" replaced with your own identifying
171618Srie  * information: Portions Copyright [yyyy] [name of copyright owner]
181618Srie  *
191618Srie  * CDDL HEADER END
201618Srie  */
211618Srie 
221618Srie /*
233492Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241618Srie  * Use is subject to license terms.
251618Srie  */
261618Srie #pragma ident	"%Z%%M%	%I%	%E% SMI"
271618Srie 
281618Srie /*
291618Srie  * Dump an elf file.
301618Srie  */
311618Srie #include	<sys/param.h>
321618Srie #include	<fcntl.h>
331618Srie #include	<stdio.h>
341618Srie #include	<libelf.h>
351618Srie #include	<link.h>
361618Srie #include	<stdarg.h>
371618Srie #include	<unistd.h>
381618Srie #include	<libgen.h>
391618Srie #include	<libintl.h>
401618Srie #include	<locale.h>
411618Srie #include	<errno.h>
421618Srie #include	<strings.h>
431618Srie #include	<debug.h>
441618Srie #include	<conv.h>
451618Srie #include	<msg.h>
461618Srie #include	<_elfdump.h>
471618Srie 
48*4063Sab196087 const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
491618Srie 
501618Srie const char *
511618Srie _elfdump_msg(Msg mid)
521618Srie {
531618Srie 	return (gettext(MSG_ORIG(mid)));
541618Srie }
551618Srie 
561618Srie /*
571618Srie  * Determine whether a symbol name should be demangled.
581618Srie  */
591618Srie const char *
601618Srie demangle(const char *name, uint_t flags)
611618Srie {
621618Srie 	if (flags & FLG_DEMANGLE)
631618Srie 		return (Elf_demangle_name(name));
641618Srie 	else
651618Srie 		return ((char *)name);
661618Srie }
671618Srie 
681618Srie /*
691618Srie  * Define our own standard error routine.
701618Srie  */
711618Srie void
721618Srie failure(const char *file, const char *func)
731618Srie {
741618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
751618Srie 	    file, func, elf_errmsg(elf_errno()));
761618Srie }
771618Srie 
781618Srie /*
791618Srie  * The full usage message
801618Srie  */
811618Srie static void
821618Srie detail_usage()
831618Srie {
841618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
851618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
861618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
871618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
881618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
891618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
901618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
911618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
921618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
931618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1));
941618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
951618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
961618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
971618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
981618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
991618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
1001618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
1011618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
1021618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
1031618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
1041618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
1053492Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
1061618Srie }
1071618Srie 
1081618Srie static void
1091618Srie decide(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd)
1101618Srie {
1111618Srie 	if (gelf_getclass(elf) == ELFCLASS64)
1121618Srie 		regular64(file, elf, flags, Nname, wfd);
1131618Srie 	else
1141618Srie 		regular32(file, elf, flags, Nname, wfd);
1151618Srie }
1161618Srie 
1171618Srie static void
1181618Srie archive(const char *file, int fd, Elf *elf, uint_t flags, char *Nname,
1191618Srie     int wfd)
1201618Srie {
1211618Srie 	Elf_Cmd		cmd = ELF_C_READ;
1221618Srie 	Elf_Arhdr	*arhdr;
1231618Srie 	Elf		*_elf = 0;
1241618Srie 	size_t		ptr;
1251618Srie 	Elf_Arsym	*arsym = 0;
1261618Srie 
1271618Srie 	/*
1283492Sab196087 	 * Determine if the archive symbol table itself is required.
1291618Srie 	 */
1301618Srie 	if ((flags & FLG_SYMBOLS) && ((Nname == NULL) ||
1311618Srie 	    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) {
1321618Srie 		/*
1331618Srie 		 * Get the archive symbol table.
1341618Srie 		 */
1351618Srie 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
1361618Srie 			/*
1371618Srie 			 * The arsym could be 0 even though there was no error.
1381618Srie 			 * Print the error message only when there was
1391618Srie 			 * real error from elf_getarsym().
1401618Srie 			 */
1411618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
1421618Srie 			return;
1431618Srie 		}
1441618Srie 	}
1451618Srie 
1461618Srie 	/*
1471618Srie 	 * Print the archive symbol table only when the archive symbol
1481618Srie 	 * table exists and it was requested to print.
1491618Srie 	 */
1501618Srie 	if (arsym) {
1511618Srie 		size_t		cnt;
1521618Srie 		char		index[MAXNDXSIZE];
1531618Srie 		size_t		offset = 0, _offset = 0;
1541618Srie 
1551618Srie 		/*
1561618Srie 		 * Print out all the symbol entries.
1571618Srie 		 */
1581618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
1591618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
1601618Srie 
1611618Srie 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
1621618Srie 			/*
1631618Srie 			 * For each object obtain an elf descriptor so that we
1641618Srie 			 * can establish the members name.  Note, we have had
1651618Srie 			 * archives where the archive header has not been
1661618Srie 			 * obtainable so be lenient with errors.
1671618Srie 			 */
1681618Srie 			if ((offset == 0) || ((arsym->as_off != 0) &&
1691618Srie 			    (arsym->as_off != _offset))) {
1701618Srie 
1711618Srie 				if (_elf)
1721618Srie 					(void) elf_end(_elf);
1731618Srie 
1741618Srie 				if (elf_rand(elf, arsym->as_off) !=
1751618Srie 				    arsym->as_off) {
1761618Srie 					failure(file, MSG_ORIG(MSG_ELF_RAND));
1771618Srie 					arhdr = 0;
1781618Srie 				} else if ((_elf = elf_begin(fd,
1791618Srie 				    ELF_C_READ, elf)) == 0) {
1801618Srie 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
1811618Srie 					arhdr = 0;
1821618Srie 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
1831618Srie 					failure(file,
1841618Srie 					    MSG_ORIG(MSG_ELF_GETARHDR));
1851618Srie 					arhdr = 0;
1861618Srie 				}
1871618Srie 
1881618Srie 				_offset = arsym->as_off;
1891618Srie 				if (offset == 0)
1901618Srie 					offset = _offset;
1911618Srie 			}
1921618Srie 
1931618Srie 			(void) snprintf(index, MAXNDXSIZE,
1941618Srie 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
1951618Srie 			if (arsym->as_off)
1961618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
1971618Srie 				    /* LINTED */
1981618Srie 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
1991618Srie 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
2001618Srie 				    demangle(arsym->as_name, flags) :
2011618Srie 				    MSG_INTL(MSG_STR_NULL)));
2021618Srie 			else
2031618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
2041618Srie 				    /* LINTED */
2051618Srie 				    (int)arsym->as_off);
2061618Srie 		}
2071618Srie 
2081618Srie 		if (_elf)
2091618Srie 			(void) elf_end(_elf);
2101618Srie 
2111618Srie 		/*
2121618Srie 		 * If we only need the archive symbol table return.
2131618Srie 		 */
2141618Srie 		if ((flags & FLG_SYMBOLS) && Nname &&
2151618Srie 		    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))
2161618Srie 			return;
2171618Srie 
2181618Srie 		/*
2191618Srie 		 * Reset elf descriptor in preparation for processing each
2201618Srie 		 * member.
2211618Srie 		 */
2221618Srie 		if (offset)
2231618Srie 			(void) elf_rand(elf, offset);
2241618Srie 	}
2251618Srie 
2261618Srie 	/*
2271618Srie 	 * Process each object within the archive.
2281618Srie 	 */
2291618Srie 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
2301618Srie 		char	name[MAXPATHLEN];
2311618Srie 
2321618Srie 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
2331618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
2341618Srie 			return;
2351618Srie 		}
2361618Srie 		if (*arhdr->ar_name != '/') {
2371618Srie 			(void) snprintf(name, MAXPATHLEN,
2381618Srie 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
2391618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
2401618Srie 
2411618Srie 			switch (elf_kind(_elf)) {
2421618Srie 			case ELF_K_AR:
2431618Srie 				archive(name, fd, _elf, flags, Nname, wfd);
2441618Srie 				break;
2451618Srie 			case ELF_K_ELF:
2461618Srie 				decide(name, _elf, flags, Nname, wfd);
2471618Srie 				break;
2481618Srie 			default:
2491618Srie 				(void) fprintf(stderr,
2501618Srie 				    MSG_INTL(MSG_ERR_BADFILE), name);
2511618Srie 				break;
2521618Srie 			}
2531618Srie 		}
2541618Srie 
2551618Srie 		cmd = elf_next(_elf);
2561618Srie 		(void) elf_end(_elf);
2571618Srie 	}
2581618Srie }
2591618Srie 
2601618Srie int
2611618Srie main(int argc, char **argv, char **envp)
2621618Srie {
2631618Srie 	Elf		*elf;
2641618Srie 	int		var, fd, wfd = 0;
2651618Srie 	char		*Nname = NULL, *wname = 0;
2661618Srie 	uint_t		flags = 0;
2671618Srie 
2681618Srie 	/*
2691618Srie 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
2701618Srie 	 * the binary.  If successful, conv_check_native() won't return.
2711618Srie 	 */
2722647Srie 	(void) conv_check_native(argv, envp);
2731618Srie 
2741618Srie 	/*
2751618Srie 	 * Establish locale.
2761618Srie 	 */
2771618Srie 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
2781618Srie 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
2791618Srie 
2801618Srie 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
2811618Srie 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
2821618Srie 
2831618Srie 	opterr = 0;
2841618Srie 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
2851618Srie 		switch (var) {
2861618Srie 		case 'C':
2871618Srie 			flags |= FLG_DEMANGLE;
2881618Srie 			break;
2891618Srie 		case 'c':
2901618Srie 			flags |= FLG_SHDR;
2911618Srie 			break;
2921618Srie 		case 'd':
2931618Srie 			flags |= FLG_DYNAMIC;
2941618Srie 			break;
2951618Srie 		case 'e':
2961618Srie 			flags |= FLG_EHDR;
2971618Srie 			break;
2981618Srie 		case 'G':
2991618Srie 			flags |= FLG_GOT;
3001618Srie 			break;
3011618Srie 		case 'g':
3021618Srie 			flags |= FLG_GROUP;
3031618Srie 			break;
3041618Srie 		case 'H':
3051618Srie 			flags |= FLG_CAP;
3061618Srie 			break;
3071618Srie 		case 'h':
3081618Srie 			flags |= FLG_HASH;
3091618Srie 			break;
3101618Srie 		case 'i':
3111618Srie 			flags |= FLG_INTERP;
3121618Srie 			break;
3131618Srie 		case 'k':
3141618Srie 			flags |= FLG_CHECKSUM;
3151618Srie 			break;
3161618Srie 		case 'l':
3171618Srie 			flags |= FLG_LONGNAME;
3181618Srie 			break;
3191618Srie 		case 'm':
3201618Srie 			flags |= FLG_MOVE;
3211618Srie 			break;
3221618Srie 		case 'N':
3231618Srie 			Nname = optarg;
3241618Srie 			break;
3251618Srie 		case 'n':
3261618Srie 			flags |= FLG_NOTE;
3271618Srie 			break;
3281618Srie 		case 'p':
3291618Srie 			flags |= FLG_PHDR;
3301618Srie 			break;
3311618Srie 		case 'r':
3321618Srie 			flags |= FLG_RELOC;
3331618Srie 			break;
3343492Sab196087 		case 'S':
3353492Sab196087 			flags |= FLG_SORT;
3363492Sab196087 			break;
3371618Srie 		case 's':
3381618Srie 			flags |= FLG_SYMBOLS;
3391618Srie 			break;
3401618Srie 		case 'u':
3411618Srie 			flags |= FLG_UNWIND;
3421618Srie 			break;
3431618Srie 		case 'v':
3441618Srie 			flags |= FLG_VERSIONS;
3451618Srie 			break;
3461618Srie 		case 'w':
3471618Srie 			wname = optarg;
3481618Srie 			break;
3491618Srie 		case 'y':
3501618Srie 			flags |= FLG_SYMINFO;
3511618Srie 			break;
3521618Srie 		case '?':
3531618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
3541618Srie 			    basename(argv[0]));
3551618Srie 			detail_usage();
3561618Srie 			return (1);
3571618Srie 		default:
3581618Srie 			break;
3591618Srie 		}
3601618Srie 	}
3611618Srie 
3621618Srie 	/*
3631618Srie 	 * Validate any arguments.
3641618Srie 	 */
3651618Srie 	if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) {
3661618Srie 		if (!wname && !Nname) {
3671618Srie 			flags |= FLG_EVERYTHING;
3681618Srie 		} else if (!wname || !Nname) {
3691618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
3701618Srie 			    basename(argv[0]));
3711618Srie 			return (1);
3721618Srie 		}
3731618Srie 	}
3741618Srie 
3751618Srie 	if ((var = argc - optind) == 0) {
3761618Srie 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
3771618Srie 		    basename(argv[0]));
3781618Srie 		return (1);
3791618Srie 	}
3801618Srie 
3811618Srie 	/*
3821618Srie 	 * If the -l/-C option is specified, set up the liblddbg.so.
3831618Srie 	 */
3841618Srie 	if (flags & FLG_LONGNAME)
3851618Srie 		dbg_desc->d_extra |= DBG_E_LONG;
3861618Srie 	if (flags & FLG_DEMANGLE)
3871618Srie 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
3881618Srie 
3891618Srie 	/*
3901618Srie 	 * If the -w option has indicated an output file open it.  It's
3911618Srie 	 * arguable whether this option has much use when multiple files are
3921618Srie 	 * being processed.
3931618Srie 	 */
3941618Srie 	if (wname) {
3951618Srie 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
3961618Srie 		    0666)) < 0) {
3971618Srie 			int err = errno;
3981618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
3991618Srie 			    wname, strerror(err));
4001618Srie 			wfd = 0;
4011618Srie 		}
4021618Srie 	}
4031618Srie 
4041618Srie 	/*
4051618Srie 	 * Open the input file and initialize the elf interface.
4061618Srie 	 */
4071618Srie 	for (; optind < argc; optind++) {
4081618Srie 		const char	*file = argv[optind];
4091618Srie 
4101618Srie 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
4111618Srie 			int err = errno;
4121618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
4131618Srie 			    file, strerror(err));
4141618Srie 			continue;
4151618Srie 		}
4161618Srie 		(void) elf_version(EV_CURRENT);
4171618Srie 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
4181618Srie 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
4191618Srie 			(void) close(fd);
4201618Srie 			continue;
4211618Srie 		}
4221618Srie 
4231618Srie 		if (var > 1)
4241618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
4251618Srie 
4261618Srie 		switch (elf_kind(elf)) {
4271618Srie 		case ELF_K_AR:
4281618Srie 			archive(file, fd, elf, flags, Nname, wfd);
4291618Srie 			break;
4301618Srie 		case ELF_K_ELF:
4311618Srie 			decide(file, elf, flags, Nname, wfd);
4321618Srie 			break;
4331618Srie 		default:
4341618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
4351618Srie 			break;
4361618Srie 		}
4371618Srie 
4381618Srie 		(void) close(fd);
4391618Srie 		(void) elf_end(elf);
4401618Srie 	}
4411618Srie 
4421618Srie 	if (wfd)
4431618Srie 		(void) close(wfd);
4441618Srie 	return (0);
4451618Srie }
446