xref: /onnv-gate/usr/src/cmd/sgs/ldd/common/ldd.c (revision 12382:a717a64699bb)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51698Sab196087  * Common Development and Distribution License (the "License").
61698Sab196087  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
206150Srie  *
210Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
220Sstevel@tonic-gate  *	  All Rights Reserved
230Sstevel@tonic-gate  *
240Sstevel@tonic-gate  *
25*12382SAli.Bahrami@Oracle.COM  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Print the list of shared objects required by a dynamic executable or shared
300Sstevel@tonic-gate  * object.
310Sstevel@tonic-gate  *
326150Srie  * usage is: ldd [-d | -r] [-c] [-e envar] [-i] [-f] [-L] [-l] [-p] [-s]
334947Srie  *		[-U | -u] [-v] [-w] file(s)
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * ldd opens the file and verifies the information in the elf header.
360Sstevel@tonic-gate  * If the file is a dynamic executable, we set up some environment variables
370Sstevel@tonic-gate  * and exec(2) the file.  If the file is a shared object, we preload the
380Sstevel@tonic-gate  * file with a dynamic executable stub. The runtime linker (ld.so.1) actually
390Sstevel@tonic-gate  * provides the diagnostic output, according to the environment variables set.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_[AE].
420Sstevel@tonic-gate  * The runtime linker will print the pathnames of all dynamic objects it
430Sstevel@tonic-gate  * loads, and then exit.  Note that we distiguish between ELF and AOUT objects
440Sstevel@tonic-gate  * when setting this environment variable - AOUT executables cause the mapping
450Sstevel@tonic-gate  * of sbcp, the dependencies of which the user isn't interested in.
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  * If -d or -r is specified, we also set LD_WARN=1; the runtime linker will
480Sstevel@tonic-gate  * perform its normal relocations and issue warning messages for unresolved
490Sstevel@tonic-gate  * references. It will then exit.
500Sstevel@tonic-gate  * If -r is specified, we set LD_BIND_NOW=1, so that the runtime linker
510Sstevel@tonic-gate  * will perform all relocations, otherwise (under -d) the runtime linker
520Sstevel@tonic-gate  * will not perform PLT (function) type relocations.
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * If -c is specified we also set LD_NOCONFIG=1, thus disabling any
550Sstevel@tonic-gate  * configuration file use.
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * If -e is specified the associated environment variable is set for the
580Sstevel@tonic-gate  * child process that will produce ldd's diagnostics.
590Sstevel@tonic-gate  *
600Sstevel@tonic-gate  * If -i is specified, we set LD_INIT=1. The order of inititialization
610Sstevel@tonic-gate  * sections to be executed is printed. We also set LD_WARN=1.
620Sstevel@tonic-gate  *
630Sstevel@tonic-gate  * If -f is specified, we will run ldd as root on executables that have
640Sstevel@tonic-gate  * an unsercure runtime linker that does not live under the "/usr/lib"
650Sstevel@tonic-gate  * directory.  By default we will not let this happen.
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  * If -l is specified it generates a warning for any auxiliary filter not found.
680Sstevel@tonic-gate  * Prior to 2.8 this forced any filters to load (all) their filtees.  This is
690Sstevel@tonic-gate  * now the default, however missing auxiliary filters don't generate any error
700Sstevel@tonic-gate  * diagniostic.  See also -L.
710Sstevel@tonic-gate  *
720Sstevel@tonic-gate  * If -L is specified we revert to lazy loading, thus any filtee or lazy
730Sstevel@tonic-gate  * dependency loading is deferred until relocations cause loading.  Without
740Sstevel@tonic-gate  * this option we set LD_LOADFLTR=1, thus forcing any filters to load (all)
750Sstevel@tonic-gate  * their filtees, and LD_NOLAZYLOAD=1 thus forcing immediate processing of
760Sstevel@tonic-gate  * any lazy loaded dependencies.
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  * If -s is specified we also set LD_TRACE_SEARCH_PATH=1, thus enabling
790Sstevel@tonic-gate  * the runtime linker to indicate the search algorithm used.
800Sstevel@tonic-gate  *
810Sstevel@tonic-gate  * If -v is specified we also set LD_VERBOSE=1, thus enabling the runtime
820Sstevel@tonic-gate  * linker to indicate all object dependencies (not just the first object
830Sstevel@tonic-gate  * loaded) together with any versionig requirements.
840Sstevel@tonic-gate  *
850Sstevel@tonic-gate  * If -U or -u is specified unused dependencies are detected.  -u causes
860Sstevel@tonic-gate  * LD_UNUSED=1 to be set, which causes dependencies that are unused within the
870Sstevel@tonic-gate  * process to be detected.  -U causes LD_UNREF=1 to be set, which causes
880Sstevel@tonic-gate  * unreferenced objects, and unreferenced cyclic dependencies to be detected.
890Sstevel@tonic-gate  * These options assert that at least -d is set as relocation references are
900Sstevel@tonic-gate  * what determine an objects use.
914947Srie  *
924947Srie  * If -w is specified, no unresolved weak references are allowed.  -w causes
934947Srie  * LD_NOUNRESWEAK=1 to be set.  By default, an unresolved weak reference is
944947Srie  * allowed, and a "0" is written to the relocation offset.  The -w option
954947Srie  * disables this default.  Any weak references that can not be resolved result
966150Srie  * in relocation error messages.  This option has no use without -r or -d.
976150Srie  *
986150Srie  * If the -p option is specified, no unresolved PARENT or EXTERN references are
996150Srie  * allowed.  -p causes LD_NOPAREXT=1 to be set.  By default, PARENT and EXTERN
1006150Srie  * references, which have been explicitly assigned via a mapfile when a shared
1016150Srie  * object was built, imply that a caller will provide the symbols, and hence
1026150Srie  * these are not reported as relocation errors.  Note, the -p option is asserted
1036150Srie  * by default when either the -r or -d options are used to inspect a dynamic
1046150Srie  * executable.  This option has no use with a shared object without -r or -d.
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate #include	<fcntl.h>
1070Sstevel@tonic-gate #include	<stdio.h>
1080Sstevel@tonic-gate #include	<string.h>
1091698Sab196087 #include	<_libelf.h>
1100Sstevel@tonic-gate #include	<stdlib.h>
1110Sstevel@tonic-gate #include	<unistd.h>
1120Sstevel@tonic-gate #include	<wait.h>
1130Sstevel@tonic-gate #include	<locale.h>
1140Sstevel@tonic-gate #include	<errno.h>
1150Sstevel@tonic-gate #include	<signal.h>
1160Sstevel@tonic-gate #include	"machdep.h"
1170Sstevel@tonic-gate #include	"sgs.h"
1180Sstevel@tonic-gate #include	"conv.h"
1190Sstevel@tonic-gate #include	"a.out.h"
1200Sstevel@tonic-gate #include	"msg.h"
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static int	elf_check(int, char *, char *, Elf *, int);
1230Sstevel@tonic-gate static int	aout_check(int, char *, char *, int, int);
1240Sstevel@tonic-gate static int	run(int, char *, char *, const char *, int);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /*
1284947Srie  * Define all environment variable strings.  The character following the "="
1294947Srie  * will be written to, to disable or enable the associated feature.
1300Sstevel@tonic-gate  */
1310Sstevel@tonic-gate static char	bind[] =	"LD_BIND_NOW= ",
1320Sstevel@tonic-gate 		load_elf[] =	"LD_TRACE_LOADED_OBJECTS_E= ",
1330Sstevel@tonic-gate 		load_aout[] =	"LD_TRACE_LOADED_OBJECTS_A= ",
1340Sstevel@tonic-gate 		path[] =	"LD_TRACE_SEARCH_PATHS= ",
1350Sstevel@tonic-gate 		verb[] =	"LD_VERBOSE= ",
1360Sstevel@tonic-gate 		warn[] =	"LD_WARN= ",
1370Sstevel@tonic-gate 		conf[] =	"LD_NOCONFIG= ",
1380Sstevel@tonic-gate 		fltr[] =	"LD_LOADFLTR= ",
1390Sstevel@tonic-gate 		lazy[] =	"LD_NOLAZYLOAD=1",
1400Sstevel@tonic-gate 		init[] =	"LD_INIT= ",
1410Sstevel@tonic-gate 		uref[] =	"LD_UNREF= ",
1424947Srie 		used[] =	"LD_UNUSED= ",
1436150Srie 		weak[] =	"LD_NOUNRESWEAK= ",
1446150Srie 		nope[] =	"LD_NOPAREXT= ";
1450Sstevel@tonic-gate static char	*load;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate static const char	*prefile_32, *prefile_64, *prefile;
1489131SRod.Evans@Sun.COM static APlist		*eopts = NULL;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate int
1516223Sab196087 main(int argc, char **argv, char **envp)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	char	*str, *cname = argv[0];
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	Elf	*elf;
1560Sstevel@tonic-gate 	int	cflag = 0, dflag = 0, fflag = 0, iflag = 0, Lflag = 0;
1570Sstevel@tonic-gate 	int	lflag = 0, rflag = 0, sflag = 0, Uflag = 0, uflag = 0;
1586150Srie 	int	pflag = 0, vflag = 0, wflag = 0, nfile, var, error = 0;
1590Sstevel@tonic-gate 
1609131SRod.Evans@Sun.COM 	Aliste	idx;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/*
1636223Sab196087 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
1646223Sab196087 	 * the binary.  If successful, conv_check_native() won't return.
1656223Sab196087 	 *
1666223Sab196087 	 * This is done to ensure that ldd can handle objects >2GB.
1676223Sab196087 	 * ldd uses libelf, which is not large file capable. The
1686223Sab196087 	 * 64-bit ldd can handle any sized object.
1696223Sab196087 	 */
1706223Sab196087 	(void) conv_check_native(argv, envp);
1716223Sab196087 
1726223Sab196087 	/*
1730Sstevel@tonic-gate 	 * Establish locale.
1740Sstevel@tonic-gate 	 */
1750Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
1760Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/*
1790Sstevel@tonic-gate 	 * verify command line syntax and process arguments
1800Sstevel@tonic-gate 	 */
1810Sstevel@tonic-gate 	opterr = 0;				/* disable getopt error mesg */
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_GETOPT))) != EOF) {
1840Sstevel@tonic-gate 		switch (var) {
1850Sstevel@tonic-gate 		case 'c' :			/* enable config search */
1860Sstevel@tonic-gate 			cflag = 1;
1870Sstevel@tonic-gate 			break;
1880Sstevel@tonic-gate 		case 'd' :			/* perform data relocations */
1890Sstevel@tonic-gate 			dflag = 1;
1900Sstevel@tonic-gate 			if (rflag)
1910Sstevel@tonic-gate 				error++;
1920Sstevel@tonic-gate 			break;
1930Sstevel@tonic-gate 		case 'e' :
1949131SRod.Evans@Sun.COM 			if (aplist_append(&eopts, optarg, 10) == NULL) {
1950Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
1960Sstevel@tonic-gate 				    cname);
1970Sstevel@tonic-gate 				exit(1);
1980Sstevel@tonic-gate 			}
1990Sstevel@tonic-gate 			break;
2000Sstevel@tonic-gate 		case 'f' :
2010Sstevel@tonic-gate 			fflag = 1;
2020Sstevel@tonic-gate 			break;
2030Sstevel@tonic-gate 		case 'L' :
2040Sstevel@tonic-gate 			Lflag = 1;
2050Sstevel@tonic-gate 			break;
2060Sstevel@tonic-gate 		case 'l' :
2070Sstevel@tonic-gate 			lflag = 1;
2080Sstevel@tonic-gate 			break;
2090Sstevel@tonic-gate 		case 'i' :			/* print the order of .init */
2100Sstevel@tonic-gate 			iflag = 1;
2110Sstevel@tonic-gate 			break;
2126150Srie 		case 'p' :
2136150Srie 			pflag = 1;		/* expose unreferenced */
2146150Srie 			break;			/*	parent or externals */
2150Sstevel@tonic-gate 		case 'r' :			/* perform all relocations */
2160Sstevel@tonic-gate 			rflag = 1;
2170Sstevel@tonic-gate 			if (dflag)
2180Sstevel@tonic-gate 				error++;
2190Sstevel@tonic-gate 			break;
2200Sstevel@tonic-gate 		case 's' :			/* enable search path output */
2210Sstevel@tonic-gate 			sflag = 1;
2220Sstevel@tonic-gate 			break;
2230Sstevel@tonic-gate 		case 'U' :			/* list unreferenced */
2240Sstevel@tonic-gate 			Uflag = 1;		/*	dependencies */
2250Sstevel@tonic-gate 			if (uflag)
2260Sstevel@tonic-gate 				error++;
2270Sstevel@tonic-gate 			break;
2280Sstevel@tonic-gate 		case 'u' :			/* list unused dependencies */
2290Sstevel@tonic-gate 			uflag = 1;
2300Sstevel@tonic-gate 			if (Uflag)
2310Sstevel@tonic-gate 				error++;
2320Sstevel@tonic-gate 			break;
2330Sstevel@tonic-gate 		case 'v' :			/* enable verbose output */
2340Sstevel@tonic-gate 			vflag = 1;
2350Sstevel@tonic-gate 			break;
2366150Srie 		case 'w' :			/* expose unresolved weak */
2374947Srie 			wflag = 1;		/*	references */
2384947Srie 			break;
2390Sstevel@tonic-gate 		default :
2400Sstevel@tonic-gate 			error++;
2410Sstevel@tonic-gate 			break;
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate 		if (error)
2440Sstevel@tonic-gate 			break;
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	if (error) {
2470Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), cname);
2480Sstevel@tonic-gate 		exit(1);
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	/*
2520Sstevel@tonic-gate 	 * Determine if any of the LD_PRELOAD family is already set in the
2530Sstevel@tonic-gate 	 * environment, if so we'll continue to analyze each object with the
2540Sstevel@tonic-gate 	 * appropriate setting.
2550Sstevel@tonic-gate 	 */
2560Sstevel@tonic-gate 	if (((prefile_32 = getenv(MSG_ORIG(MSG_LD_PRELOAD_32))) == NULL) ||
2570Sstevel@tonic-gate 	    (*prefile_32 == '\0')) {
2580Sstevel@tonic-gate 		prefile_32 = MSG_ORIG(MSG_STR_EMPTY);
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 	if (((prefile_64 = getenv(MSG_ORIG(MSG_LD_PRELOAD_64))) == NULL) ||
2610Sstevel@tonic-gate 	    (*prefile_64 == '\0')) {
2620Sstevel@tonic-gate 		prefile_64 = MSG_ORIG(MSG_STR_EMPTY);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	if (((prefile = getenv(MSG_ORIG(MSG_LD_PRELOAD))) == NULL) ||
2650Sstevel@tonic-gate 	    (*prefile == '\0')) {
2660Sstevel@tonic-gate 		prefile = MSG_ORIG(MSG_STR_EMPTY);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	/*
2700Sstevel@tonic-gate 	 * Determine if any environment requests are for the LD_PRELOAD family,
2710Sstevel@tonic-gate 	 * and if so override any environment settings we've established above.
2720Sstevel@tonic-gate 	 */
2739131SRod.Evans@Sun.COM 	for (APLIST_TRAVERSE(eopts, idx, str)) {
2740Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_32),
2750Sstevel@tonic-gate 		    MSG_LD_PRELOAD_32_SIZE)) == 0) {
2760Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_32_SIZE;
2770Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
2780Sstevel@tonic-gate 				prefile_32 = str;
2790Sstevel@tonic-gate 			continue;
2800Sstevel@tonic-gate 		}
2810Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_64),
2820Sstevel@tonic-gate 		    MSG_LD_PRELOAD_64_SIZE)) == 0) {
2830Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_64_SIZE;
2840Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
2850Sstevel@tonic-gate 				prefile_64 = str;
2860Sstevel@tonic-gate 			continue;
2870Sstevel@tonic-gate 		}
2880Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD),
2890Sstevel@tonic-gate 		    MSG_LD_PRELOAD_SIZE)) == 0) {
2900Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_SIZE;
2910Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
2920Sstevel@tonic-gate 				prefile = str;
2930Sstevel@tonic-gate 			continue;
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/*
2980Sstevel@tonic-gate 	 * Set the appropriate relocation environment variables (Note unsetting
2990Sstevel@tonic-gate 	 * the environment variables is done just in case the user already
3000Sstevel@tonic-gate 	 * has these in their environment ... sort of thing the test folks
3010Sstevel@tonic-gate 	 * would do :-)
3020Sstevel@tonic-gate 	 */
3034947Srie 	warn[sizeof (warn) - 2] = (dflag || rflag || Uflag || uflag) ? '1' :
3040Sstevel@tonic-gate 	    '\0';
3054947Srie 	bind[sizeof (bind) - 2] = (rflag) ? '1' : '\0';
3064947Srie 	path[sizeof (path) - 2] = (sflag) ? '1' : '\0';
3074947Srie 	verb[sizeof (verb) - 2] = (vflag) ? '1' : '\0';
3084947Srie 	fltr[sizeof (fltr) - 2] = (Lflag) ? '\0' : (lflag) ? '2' : '1';
3094947Srie 	init[sizeof (init) - 2] = (iflag) ? '1' : '\0';
3104947Srie 	conf[sizeof (conf) - 2] = (cflag) ? '1' : '\0';
3114947Srie 	lazy[sizeof (lazy) - 2] = (Lflag) ? '\0' : '1';
3124947Srie 	uref[sizeof (uref) - 2] = (Uflag) ? '1' : '\0';
3134947Srie 	used[sizeof (used) - 2] = (uflag) ? '1' : '\0';
3144947Srie 	weak[sizeof (weak) - 2] = (wflag) ? '1' : '\0';
3156150Srie 	nope[sizeof (nope) - 2] = (pflag) ? '1' : '\0';
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * coordinate libelf's version information
3190Sstevel@tonic-gate 	 */
3200Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
3210Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIBELF), cname,
3220Sstevel@tonic-gate 		    EV_CURRENT);
3230Sstevel@tonic-gate 		exit(1);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * Loop through remaining arguments.  Note that from here on there
3280Sstevel@tonic-gate 	 * are no exit conditions so that we can process a list of files,
3290Sstevel@tonic-gate 	 * any error condition is retained for a final exit status.
3300Sstevel@tonic-gate 	 */
3310Sstevel@tonic-gate 	nfile = argc - optind;
3320Sstevel@tonic-gate 	for (; optind < argc; optind++) {
3330Sstevel@tonic-gate 		char	*fname = argv[optind];
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		/*
3360Sstevel@tonic-gate 		 * Open file (do this before checking access so that we can
3370Sstevel@tonic-gate 		 * provide the user with better diagnostics).
3380Sstevel@tonic-gate 		 */
3390Sstevel@tonic-gate 		if ((var = open(fname, O_RDONLY)) == -1) {
3400Sstevel@tonic-gate 			int	err = errno;
3410Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), cname,
3420Sstevel@tonic-gate 			    fname, strerror(err));
3430Sstevel@tonic-gate 			error = 1;
3440Sstevel@tonic-gate 			continue;
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		/*
3480Sstevel@tonic-gate 		 * Get the files elf descriptor and process it as an elf or
3490Sstevel@tonic-gate 		 * a.out (4.x) file.
3500Sstevel@tonic-gate 		 */
3510Sstevel@tonic-gate 		elf = elf_begin(var, ELF_C_READ, (Elf *)0);
3520Sstevel@tonic-gate 		switch (elf_kind(elf)) {
3530Sstevel@tonic-gate 		case ELF_K_AR :
3540Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO),
3550Sstevel@tonic-gate 			    cname, fname);
3560Sstevel@tonic-gate 			error = 1;
3570Sstevel@tonic-gate 			break;
3580Sstevel@tonic-gate 		case ELF_K_COFF:
3590Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN),
3600Sstevel@tonic-gate 			    cname, fname);
3610Sstevel@tonic-gate 			error = 1;
3620Sstevel@tonic-gate 			break;
3630Sstevel@tonic-gate 		case ELF_K_ELF:
3640Sstevel@tonic-gate 			if (elf_check(nfile, fname, cname, elf, fflag) != NULL)
3650Sstevel@tonic-gate 				error = 1;
3660Sstevel@tonic-gate 			break;
3670Sstevel@tonic-gate 		default:
3680Sstevel@tonic-gate 			/*
3690Sstevel@tonic-gate 			 * This is either an unknown file or an aout format
3700Sstevel@tonic-gate 			 */
3710Sstevel@tonic-gate 			if (aout_check(nfile, fname, cname, var, fflag) != NULL)
3720Sstevel@tonic-gate 				error = 1;
3730Sstevel@tonic-gate 			break;
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 		(void) elf_end(elf);
3760Sstevel@tonic-gate 		(void) close(var);
3770Sstevel@tonic-gate 	}
3780Sstevel@tonic-gate 	return (error);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate static int
3840Sstevel@tonic-gate elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
3850Sstevel@tonic-gate {
386*12382SAli.Bahrami@Oracle.COM 	Conv_inv_buf_t	inv_buf;
3870Sstevel@tonic-gate 	GElf_Ehdr 	ehdr;
3880Sstevel@tonic-gate 	GElf_Phdr 	phdr;
3890Sstevel@tonic-gate 	int		dynamic = 0, interp = 0, cnt, class;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	/*
3920Sstevel@tonic-gate 	 * verify information in file header
3930Sstevel@tonic-gate 	 */
3940Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
3950Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR),
3964947Srie 		    cname, fname, elf_errmsg(-1));
3970Sstevel@tonic-gate 		return (1);
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	/*
401*12382SAli.Bahrami@Oracle.COM 	 * Compatible machine
4020Sstevel@tonic-gate 	 */
403*12382SAli.Bahrami@Oracle.COM 	if ((ehdr.e_machine != M_MACH_32) && (ehdr.e_machine != M_MACH_64) &&
404*12382SAli.Bahrami@Oracle.COM 	    (ehdr.e_machine != M_MACHPLUS)) {
405*12382SAli.Bahrami@Oracle.COM 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHTYPE), cname, fname,
406*12382SAli.Bahrami@Oracle.COM 		    conv_ehdr_mach(ehdr.e_machine, 0, &inv_buf));
407*12382SAli.Bahrami@Oracle.COM 		return (1);
408*12382SAli.Bahrami@Oracle.COM 	}
409*12382SAli.Bahrami@Oracle.COM 
410*12382SAli.Bahrami@Oracle.COM 	/*
411*12382SAli.Bahrami@Oracle.COM 	 * Compatible encoding (byte order)
412*12382SAli.Bahrami@Oracle.COM 	 */
413*12382SAli.Bahrami@Oracle.COM 	if (ehdr.e_ident[EI_DATA] != M_DATA) {
414*12382SAli.Bahrami@Oracle.COM 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_DATA), cname, fname,
415*12382SAli.Bahrami@Oracle.COM 		    conv_ehdr_data(ehdr.e_ident[EI_DATA], 0, &inv_buf));
4160Sstevel@tonic-gate 		return (1);
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	/*
420*12382SAli.Bahrami@Oracle.COM 	 * Compatible class
421*12382SAli.Bahrami@Oracle.COM 	 */
422*12382SAli.Bahrami@Oracle.COM 	switch (class = ehdr.e_ident[EI_CLASS]) {
423*12382SAli.Bahrami@Oracle.COM 	case ELFCLASS32:
424*12382SAli.Bahrami@Oracle.COM 		/*
425*12382SAli.Bahrami@Oracle.COM 		 * If M_MACH is not the same thing as M_MACHPLUS and this
426*12382SAli.Bahrami@Oracle.COM 		 * is an M_MACHPLUS object, then the corresponding header
427*12382SAli.Bahrami@Oracle.COM 		 * flag must be set.
428*12382SAli.Bahrami@Oracle.COM 		 */
429*12382SAli.Bahrami@Oracle.COM 		if ((ehdr.e_machine != M_MACH) &&
430*12382SAli.Bahrami@Oracle.COM 		    ((ehdr.e_flags & M_FLAGSPLUS) == 0)) {
431*12382SAli.Bahrami@Oracle.COM 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHFLAGS),
432*12382SAli.Bahrami@Oracle.COM 			    cname, fname);
433*12382SAli.Bahrami@Oracle.COM 			return (1);
434*12382SAli.Bahrami@Oracle.COM 		}
435*12382SAli.Bahrami@Oracle.COM 		break;
436*12382SAli.Bahrami@Oracle.COM 	case ELFCLASS64:
437*12382SAli.Bahrami@Oracle.COM 		/* Requires 64-bit kernel */
438*12382SAli.Bahrami@Oracle.COM 		if (conv_sys_eclass() == ELFCLASS32) {
439*12382SAli.Bahrami@Oracle.COM 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_KCLASS32),
440*12382SAli.Bahrami@Oracle.COM 			    cname, fname, conv_ehdr_class(class, 0, &inv_buf));
441*12382SAli.Bahrami@Oracle.COM 			return (1);
442*12382SAli.Bahrami@Oracle.COM 		}
443*12382SAli.Bahrami@Oracle.COM 		break;
444*12382SAli.Bahrami@Oracle.COM 	default:
445*12382SAli.Bahrami@Oracle.COM 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_CLASS), cname, fname,
446*12382SAli.Bahrami@Oracle.COM 		    conv_ehdr_class(class, 0, &inv_buf));
447*12382SAli.Bahrami@Oracle.COM 		return (1);
448*12382SAli.Bahrami@Oracle.COM 	}
449*12382SAli.Bahrami@Oracle.COM 
450*12382SAli.Bahrami@Oracle.COM 	/*
451*12382SAli.Bahrami@Oracle.COM 	 * Object type
4520Sstevel@tonic-gate 	 */
4530Sstevel@tonic-gate 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN) &&
4540Sstevel@tonic-gate 	    (ehdr.e_type != ET_REL)) {
4550Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_BADMAGIC),
4564947Srie 		    cname, fname);
4570Sstevel@tonic-gate 		return (1);
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	/*
4610Sstevel@tonic-gate 	 * Check that the file is executable.  Dynamic executables must be
4620Sstevel@tonic-gate 	 * executable to be exec'ed.  Shared objects need not be executable to
4630Sstevel@tonic-gate 	 * be mapped with a dynamic executable, however, by convention they're
4640Sstevel@tonic-gate 	 * supposed to be executable.
4650Sstevel@tonic-gate 	 */
4660Sstevel@tonic-gate 	if (access(fname, X_OK) != 0) {
4670Sstevel@tonic-gate 		if (ehdr.e_type == ET_EXEC) {
4680Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_1),
4694947Srie 			    cname, fname);
4700Sstevel@tonic-gate 			return (1);
4710Sstevel@tonic-gate 		}
4720Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_2), cname,
4730Sstevel@tonic-gate 		    fname);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	/*
4770Sstevel@tonic-gate 	 * Determine whether we have a dynamic section or interpretor.
4780Sstevel@tonic-gate 	 */
4790Sstevel@tonic-gate 	for (cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) {
4800Sstevel@tonic-gate 		if (dynamic && interp)
4810Sstevel@tonic-gate 			break;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
4840Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETPHDR),
4854947Srie 			    cname, fname, elf_errmsg(-1));
4860Sstevel@tonic-gate 			return (1);
4870Sstevel@tonic-gate 		}
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		if (phdr.p_type == PT_DYNAMIC) {
4900Sstevel@tonic-gate 			dynamic = 1;
4910Sstevel@tonic-gate 			continue;
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		if (phdr.p_type != PT_INTERP)
4950Sstevel@tonic-gate 			continue;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 		interp = 1;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 		/*
5000Sstevel@tonic-gate 		 * If fflag is not set, and euid == root, and the interpreter
5010Sstevel@tonic-gate 		 * does not live under /lib, /usr/lib or /etc/lib then don't
5020Sstevel@tonic-gate 		 * allow ldd to execute the image.  This prevents someone
5030Sstevel@tonic-gate 		 * creating a `trojan horse' by substituting their own
5040Sstevel@tonic-gate 		 * interpreter that could preform privileged operations
5050Sstevel@tonic-gate 		 * when ldd is against it.
5060Sstevel@tonic-gate 		 */
5070Sstevel@tonic-gate 		if ((fflag == 0) && (geteuid() == 0) &&
5080Sstevel@tonic-gate 		    (strcmp(fname, conv_lddstub(class)) != 0)) {
5090Sstevel@tonic-gate 			char	*interpreter;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 			/*
5120Sstevel@tonic-gate 			 * Does the interpreter live under a trusted directory.
5130Sstevel@tonic-gate 			 */
5140Sstevel@tonic-gate 			interpreter = elf_getident(elf, 0) + phdr.p_offset;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 			if ((strncmp(interpreter, MSG_ORIG(MSG_PTH_USRLIB),
5170Sstevel@tonic-gate 			    MSG_PTH_USRLIB_SIZE) != 0) &&
5180Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_LIB),
5190Sstevel@tonic-gate 			    MSG_PTH_LIB_SIZE) != 0) &&
5200Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_ETCLIB),
5210Sstevel@tonic-gate 			    MSG_PTH_ETCLIB_SIZE) != 0)) {
5220Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_USP_ELFINS),
5234947Srie 				    cname, fname, interpreter);
5240Sstevel@tonic-gate 				return (1);
5250Sstevel@tonic-gate 			}
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	/*
5300Sstevel@tonic-gate 	 * Catch the case of a static executable (ie, an ET_EXEC that has a set
5310Sstevel@tonic-gate 	 * of program headers but no PT_DYNAMIC).
5320Sstevel@tonic-gate 	 */
5330Sstevel@tonic-gate 	if (ehdr.e_phnum && !dynamic) {
5340Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
5350Sstevel@tonic-gate 		    fname);
5360Sstevel@tonic-gate 		return (1);
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 
5391698Sab196087 	/*
5401698Sab196087 	 * If there is a dynamic section, then check for the DF_1_NOHDR
54111734SAli.Bahrami@Sun.COM 	 * flag, and bail if it is present. Such objects are created using
54211734SAli.Bahrami@Sun.COM 	 * a mapfile option (?N in the version 1 syntax, or HDR_NOALLOC
54311734SAli.Bahrami@Sun.COM 	 * otherwise). The ELF header and program headers are
5441698Sab196087 	 * not mapped as part of the first segment, and virtual addresses
5451698Sab196087 	 * are computed without them. If ldd tries to interpret such
5461698Sab196087 	 * a file, it will become confused and generate bad output or
5471698Sab196087 	 * crash. Such objects are always special purpose files (like an OS
5481698Sab196087 	 * kernel) --- files for which the ldd operation doesn't make sense.
5491698Sab196087 	 */
5501698Sab196087 	if (dynamic && (_gelf_getdyndtflags_1(elf) & DF_1_NOHDR)) {
5511698Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOHDR), cname,
5521698Sab196087 		    fname);
5531698Sab196087 		return (1);
5541698Sab196087 	}
5551698Sab196087 
5560Sstevel@tonic-gate 	load = load_elf;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	/*
5590Sstevel@tonic-gate 	 * Run the required program (shared and relocatable objects require the
5600Sstevel@tonic-gate 	 * use of lddstub).
5610Sstevel@tonic-gate 	 */
5620Sstevel@tonic-gate 	if ((ehdr.e_type == ET_EXEC) && interp)
5630Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname, class));
5640Sstevel@tonic-gate 	else
5650Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(class), class));
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate static int
5690Sstevel@tonic-gate aout_check(int nfile, char *fname, char *cname, int fd, int fflag)
5700Sstevel@tonic-gate {
5716223Sab196087 	struct exec32	aout;
5720Sstevel@tonic-gate 	int		err;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) != 0) {
5750Sstevel@tonic-gate 		err = errno;
5760Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname,
5770Sstevel@tonic-gate 		    strerror(err));
5780Sstevel@tonic-gate 		return (1);
5790Sstevel@tonic-gate 	}
5806223Sab196087 	if (read(fd, (char *)&aout, sizeof (aout)) != sizeof (aout)) {
5810Sstevel@tonic-gate 		err = errno;
5820Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname,
5830Sstevel@tonic-gate 		    strerror(err));
5840Sstevel@tonic-gate 		return (1);
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 	if (aout.a_machtype != M_SPARC) {
5870Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname);
5880Sstevel@tonic-gate 		return (1);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 	if (N_BADMAG(aout) || !aout.a_dynamic) {
5910Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
5920Sstevel@tonic-gate 		    fname);
5930Sstevel@tonic-gate 		return (1);
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 	if (!fflag && (geteuid() == 0)) {
5960Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname);
5970Sstevel@tonic-gate 		return (1);
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	/*
6010Sstevel@tonic-gate 	 * Run the required program.
6020Sstevel@tonic-gate 	 */
6036223Sab196087 	if ((aout.a_magic == ZMAGIC) && (aout.a_entry <= sizeof (aout))) {
6040Sstevel@tonic-gate 		load = load_elf;
6050Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32),
6060Sstevel@tonic-gate 		    ELFCLASS32));
6070Sstevel@tonic-gate 	} else {
6080Sstevel@tonic-gate 		load = load_aout;
6090Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname,
6100Sstevel@tonic-gate 		    ELFCLASS32));
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate /*
6160Sstevel@tonic-gate  * Run the required program, setting the preload and trace environment
6170Sstevel@tonic-gate  * variables accordingly.
6180Sstevel@tonic-gate  */
6190Sstevel@tonic-gate static int
6200Sstevel@tonic-gate run(int nfile, char *cname, char *fname, const char *ename, int class)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate 	const char	*preload = 0;
6230Sstevel@tonic-gate 	int		pid, status;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
6260Sstevel@tonic-gate 		int	err = errno;
6270Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), cname,
6280Sstevel@tonic-gate 		    strerror(err));
6290Sstevel@tonic-gate 		return (1);
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	if (pid) {				/* parent */
6330Sstevel@tonic-gate 		while (wait(&status) != pid)
6340Sstevel@tonic-gate 			;
6350Sstevel@tonic-gate 		if (WIFSIGNALED(status) && ((WSIGMASK & status) != SIGPIPE)) {
6360Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
6370Sstevel@tonic-gate 			    fname);
6380Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_SIG),
6390Sstevel@tonic-gate 			    (WSIGMASK & status), ((status & WCOREFLG) ?
6400Sstevel@tonic-gate 			    MSG_INTL(MSG_SYS_EXEC_CORE) :
6410Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_EMPTY)));
6420Sstevel@tonic-gate 			status = 1;
6430Sstevel@tonic-gate 		} else if (WHIBYTE(status)) {
6440Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
6450Sstevel@tonic-gate 			    fname);
6460Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_STAT),
6470Sstevel@tonic-gate 			    WHIBYTE(status));
6480Sstevel@tonic-gate 			status = 1;
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 	} else {				/* child */
6519131SRod.Evans@Sun.COM 		Aliste	idx;
6529131SRod.Evans@Sun.COM 		char	*str;
6539131SRod.Evans@Sun.COM 		size_t	size;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		/*
6560Sstevel@tonic-gate 		 * When using ldd(1) to analyze a shared object we preload the
6570Sstevel@tonic-gate 		 * shared object with lddstub.  Any additional preload
6580Sstevel@tonic-gate 		 * requirements are added after the object being analyzed, this
6590Sstevel@tonic-gate 		 * allows us to skip the first object but produce diagnostics
6600Sstevel@tonic-gate 		 * for each other preloaded object.
6610Sstevel@tonic-gate 		 */
6620Sstevel@tonic-gate 		if (fname != ename) {
6630Sstevel@tonic-gate 			char		*str;
6640Sstevel@tonic-gate 			const char	*files = prefile;
6650Sstevel@tonic-gate 			const char	*format = MSG_ORIG(MSG_STR_FMT1);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 			for (str = fname; *str; str++)
6680Sstevel@tonic-gate 				if (*str == '/') {
6690Sstevel@tonic-gate 					format = MSG_ORIG(MSG_STR_FMT2);
6700Sstevel@tonic-gate 					break;
6710Sstevel@tonic-gate 			}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 			preload = MSG_ORIG(MSG_LD_PRELOAD);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 			/*
6760Sstevel@tonic-gate 			 * Determine which preload files and preload environment
6770Sstevel@tonic-gate 			 * variable to use.
6780Sstevel@tonic-gate 			 */
6790Sstevel@tonic-gate 			if (class == ELFCLASS64) {
6800Sstevel@tonic-gate 				if (prefile_64 != MSG_ORIG(MSG_STR_EMPTY)) {
6810Sstevel@tonic-gate 					files = prefile_64;
6820Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_64);
6830Sstevel@tonic-gate 				}
6840Sstevel@tonic-gate 			} else {
6850Sstevel@tonic-gate 				if (prefile_32 != MSG_ORIG(MSG_STR_EMPTY)) {
6860Sstevel@tonic-gate 					files = prefile_32;
6870Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_32);
6880Sstevel@tonic-gate 				}
6890Sstevel@tonic-gate 			}
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 			if ((str = (char *)malloc(strlen(preload) +
6920Sstevel@tonic-gate 			    strlen(fname) + strlen(files) + 5)) == 0) {
6930Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
6940Sstevel@tonic-gate 				    cname);
6950Sstevel@tonic-gate 				exit(1);
6960Sstevel@tonic-gate 			}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 			(void) sprintf(str, format, preload, fname, files);
6990Sstevel@tonic-gate 			if (putenv(str) != 0) {
7000Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
7010Sstevel@tonic-gate 				    cname);
7020Sstevel@tonic-gate 				exit(1);
7030Sstevel@tonic-gate 			}
7044947Srie 
7054947Srie 			/*
7064947Srie 			 * The pointer "load" has be assigned to load_elf[] or
7074947Srie 			 * load_aout[].  Use the size of load_elf[] as the size
7084947Srie 			 * of load_aout[] is the same.
7094947Srie 			 */
7104947Srie 			load[sizeof (load_elf) - 2] = '2';
7110Sstevel@tonic-gate 		} else
7124947Srie 			load[sizeof (load_elf) - 2] = '1';
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 		/*
7160Sstevel@tonic-gate 		 * Establish new environment variables to affect the child
7170Sstevel@tonic-gate 		 * process.
7180Sstevel@tonic-gate 		 */
7190Sstevel@tonic-gate 		if ((putenv(warn) != 0) || (putenv(bind) != 0) ||
7200Sstevel@tonic-gate 		    (putenv(path) != 0) || (putenv(verb) != 0) ||
7210Sstevel@tonic-gate 		    (putenv(fltr) != 0) || (putenv(conf) != 0) ||
7220Sstevel@tonic-gate 		    (putenv(init) != 0) || (putenv(lazy) != 0) ||
7230Sstevel@tonic-gate 		    (putenv(uref) != 0) || (putenv(used) != 0) ||
7246150Srie 		    (putenv(weak) != 0) || (putenv(load) != 0) ||
7256150Srie 		    (putenv(nope) != 0)) {
7260Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED), cname);
7270Sstevel@tonic-gate 			exit(1);
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		/*
7310Sstevel@tonic-gate 		 * Establish explicit environment requires (but don't override
7320Sstevel@tonic-gate 		 * any preload request established to process a shared object).
7330Sstevel@tonic-gate 		 */
7340Sstevel@tonic-gate 		size = 0;
7359131SRod.Evans@Sun.COM 		for (APLIST_TRAVERSE(eopts, idx, str)) {
7360Sstevel@tonic-gate 			if (preload) {
7370Sstevel@tonic-gate 				if (size == 0)
7380Sstevel@tonic-gate 					size = strlen(preload);
7390Sstevel@tonic-gate 				if ((strncmp(preload, str, size) == 0) &&
7400Sstevel@tonic-gate 				    (str[size] == '=')) {
7410Sstevel@tonic-gate 					continue;
7420Sstevel@tonic-gate 				}
7430Sstevel@tonic-gate 			}
7440Sstevel@tonic-gate 			if (putenv(str) != 0) {
7450Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
7460Sstevel@tonic-gate 				    cname);
7470Sstevel@tonic-gate 				exit(1);
7480Sstevel@tonic-gate 			}
7490Sstevel@tonic-gate 		}
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 		/*
7520Sstevel@tonic-gate 		 * Execute the object and let ld.so.1 do the rest.
7530Sstevel@tonic-gate 		 */
7540Sstevel@tonic-gate 		if (nfile > 1)
7550Sstevel@tonic-gate 			(void) printf(MSG_ORIG(MSG_STR_FMT3), fname);
7560Sstevel@tonic-gate 		(void) fflush(stdout);
7570Sstevel@tonic-gate 		if ((execl(ename, ename, (char *)0)) == -1) {
7580Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
7590Sstevel@tonic-gate 			    fname);
7600Sstevel@tonic-gate 			perror(ename);
7610Sstevel@tonic-gate 			_exit(0);
7620Sstevel@tonic-gate 			/* NOTREACHED */
7630Sstevel@tonic-gate 		}
7640Sstevel@tonic-gate 	}
7650Sstevel@tonic-gate 	return (status);
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate const char *
7690Sstevel@tonic-gate _ldd_msg(Msg mid)
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate 	return (gettext(MSG_ORIG(mid)));
7720Sstevel@tonic-gate }
773