xref: /onnv-gate/usr/src/cmd/sgs/ldd/common/ldd.c (revision 12498:12c4df7d2890)
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  *
2512382SAli.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  *
32*12498SRod.Evans@Sun.COM  * usage is: ldd [-d | -r] [-c] [-D] [-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  *
5712449SRod.Evans@Sun.COM  * If -D is specified we skip deferred dependency processing.  By default,
5812449SRod.Evans@Sun.COM  * ldd loads all deferred dependencies.  However, during normal process
5912449SRod.Evans@Sun.COM  * execution, deferred dependencies are only loaded when an explicit binding
6012449SRod.Evans@Sun.COM  * to an individual deferred reference is made.  As no user code is executed
6112449SRod.Evans@Sun.COM  * under ldd, explicit references to deferred symbols can't be triggered.
6212449SRod.Evans@Sun.COM  *
630Sstevel@tonic-gate  * If -e is specified the associated environment variable is set for the
640Sstevel@tonic-gate  * child process that will produce ldd's diagnostics.
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  * If -i is specified, we set LD_INIT=1. The order of inititialization
670Sstevel@tonic-gate  * sections to be executed is printed. We also set LD_WARN=1.
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  * If -f is specified, we will run ldd as root on executables that have
700Sstevel@tonic-gate  * an unsercure runtime linker that does not live under the "/usr/lib"
710Sstevel@tonic-gate  * directory.  By default we will not let this happen.
720Sstevel@tonic-gate  *
730Sstevel@tonic-gate  * If -l is specified it generates a warning for any auxiliary filter not found.
740Sstevel@tonic-gate  * Prior to 2.8 this forced any filters to load (all) their filtees.  This is
750Sstevel@tonic-gate  * now the default, however missing auxiliary filters don't generate any error
760Sstevel@tonic-gate  * diagniostic.  See also -L.
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  * If -L is specified we revert to lazy loading, thus any filtee or lazy
790Sstevel@tonic-gate  * dependency loading is deferred until relocations cause loading.  Without
800Sstevel@tonic-gate  * this option we set LD_LOADFLTR=1, thus forcing any filters to load (all)
810Sstevel@tonic-gate  * their filtees, and LD_NOLAZYLOAD=1 thus forcing immediate processing of
820Sstevel@tonic-gate  * any lazy loaded dependencies.
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  * If -s is specified we also set LD_TRACE_SEARCH_PATH=1, thus enabling
850Sstevel@tonic-gate  * the runtime linker to indicate the search algorithm used.
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  * If -v is specified we also set LD_VERBOSE=1, thus enabling the runtime
880Sstevel@tonic-gate  * linker to indicate all object dependencies (not just the first object
8912449SRod.Evans@Sun.COM  * loaded) together with any versioning requirements.
900Sstevel@tonic-gate  *
910Sstevel@tonic-gate  * If -U or -u is specified unused dependencies are detected.  -u causes
920Sstevel@tonic-gate  * LD_UNUSED=1 to be set, which causes dependencies that are unused within the
930Sstevel@tonic-gate  * process to be detected.  -U causes LD_UNREF=1 to be set, which causes
940Sstevel@tonic-gate  * unreferenced objects, and unreferenced cyclic dependencies to be detected.
950Sstevel@tonic-gate  * These options assert that at least -d is set as relocation references are
960Sstevel@tonic-gate  * what determine an objects use.
974947Srie  *
984947Srie  * If -w is specified, no unresolved weak references are allowed.  -w causes
994947Srie  * LD_NOUNRESWEAK=1 to be set.  By default, an unresolved weak reference is
1004947Srie  * allowed, and a "0" is written to the relocation offset.  The -w option
1014947Srie  * disables this default.  Any weak references that can not be resolved result
1026150Srie  * in relocation error messages.  This option has no use without -r or -d.
1036150Srie  *
1046150Srie  * If the -p option is specified, no unresolved PARENT or EXTERN references are
1056150Srie  * allowed.  -p causes LD_NOPAREXT=1 to be set.  By default, PARENT and EXTERN
1066150Srie  * references, which have been explicitly assigned via a mapfile when a shared
1076150Srie  * object was built, imply that a caller will provide the symbols, and hence
1086150Srie  * these are not reported as relocation errors.  Note, the -p option is asserted
1096150Srie  * by default when either the -r or -d options are used to inspect a dynamic
1106150Srie  * executable.  This option has no use with a shared object without -r or -d.
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate #include	<fcntl.h>
1130Sstevel@tonic-gate #include	<stdio.h>
1140Sstevel@tonic-gate #include	<string.h>
1151698Sab196087 #include	<_libelf.h>
1160Sstevel@tonic-gate #include	<stdlib.h>
1170Sstevel@tonic-gate #include	<unistd.h>
1180Sstevel@tonic-gate #include	<wait.h>
1190Sstevel@tonic-gate #include	<locale.h>
1200Sstevel@tonic-gate #include	<errno.h>
1210Sstevel@tonic-gate #include	<signal.h>
1220Sstevel@tonic-gate #include	"machdep.h"
1230Sstevel@tonic-gate #include	"sgs.h"
1240Sstevel@tonic-gate #include	"conv.h"
1250Sstevel@tonic-gate #include	"a.out.h"
1260Sstevel@tonic-gate #include	"msg.h"
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate static int	elf_check(int, char *, char *, Elf *, int);
1290Sstevel@tonic-gate static int	aout_check(int, char *, char *, int, int);
1300Sstevel@tonic-gate static int	run(int, char *, char *, const char *, int);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /*
1344947Srie  * Define all environment variable strings.  The character following the "="
1354947Srie  * will be written to, to disable or enable the associated feature.
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate static char	bind[] =	"LD_BIND_NOW= ",
1380Sstevel@tonic-gate 		load_elf[] =	"LD_TRACE_LOADED_OBJECTS_E= ",
1390Sstevel@tonic-gate 		load_aout[] =	"LD_TRACE_LOADED_OBJECTS_A= ",
1400Sstevel@tonic-gate 		path[] =	"LD_TRACE_SEARCH_PATHS= ",
1410Sstevel@tonic-gate 		verb[] =	"LD_VERBOSE= ",
1420Sstevel@tonic-gate 		warn[] =	"LD_WARN= ",
1430Sstevel@tonic-gate 		conf[] =	"LD_NOCONFIG= ",
1440Sstevel@tonic-gate 		fltr[] =	"LD_LOADFLTR= ",
1450Sstevel@tonic-gate 		lazy[] =	"LD_NOLAZYLOAD=1",
1460Sstevel@tonic-gate 		init[] =	"LD_INIT= ",
1470Sstevel@tonic-gate 		uref[] =	"LD_UNREF= ",
1484947Srie 		used[] =	"LD_UNUSED= ",
1496150Srie 		weak[] =	"LD_NOUNRESWEAK= ",
15012449SRod.Evans@Sun.COM 		nope[] =	"LD_NOPAREXT= ",
15112449SRod.Evans@Sun.COM 		defr[] =	"LD_DEFERRED= ";
1520Sstevel@tonic-gate static char	*load;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate static const char	*prefile_32, *prefile_64, *prefile;
1559131SRod.Evans@Sun.COM static APlist		*eopts = NULL;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate int
main(int argc,char ** argv,char ** envp)1586223Sab196087 main(int argc, char **argv, char **envp)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	char	*str, *cname = argv[0];
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	Elf	*elf;
1630Sstevel@tonic-gate 	int	cflag = 0, dflag = 0, fflag = 0, iflag = 0, Lflag = 0;
1640Sstevel@tonic-gate 	int	lflag = 0, rflag = 0, sflag = 0, Uflag = 0, uflag = 0;
16512449SRod.Evans@Sun.COM 	int	Dflag = 0, pflag = 0, vflag = 0, wflag = 0;
16612449SRod.Evans@Sun.COM 	int	nfile, var, error = 0;
1679131SRod.Evans@Sun.COM 	Aliste	idx;
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/*
1706223Sab196087 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
1716223Sab196087 	 * the binary.  If successful, conv_check_native() won't return.
1726223Sab196087 	 *
1736223Sab196087 	 * This is done to ensure that ldd can handle objects >2GB.
1746223Sab196087 	 * ldd uses libelf, which is not large file capable. The
1756223Sab196087 	 * 64-bit ldd can handle any sized object.
1766223Sab196087 	 */
1776223Sab196087 	(void) conv_check_native(argv, envp);
1786223Sab196087 
1796223Sab196087 	/*
1800Sstevel@tonic-gate 	 * Establish locale.
1810Sstevel@tonic-gate 	 */
1820Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
1830Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	/*
1860Sstevel@tonic-gate 	 * verify command line syntax and process arguments
1870Sstevel@tonic-gate 	 */
1880Sstevel@tonic-gate 	opterr = 0;				/* disable getopt error mesg */
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_GETOPT))) != EOF) {
1910Sstevel@tonic-gate 		switch (var) {
1920Sstevel@tonic-gate 		case 'c' :			/* enable config search */
1930Sstevel@tonic-gate 			cflag = 1;
1940Sstevel@tonic-gate 			break;
19512449SRod.Evans@Sun.COM 		case 'D' :			/* skip deferred dependencies */
19612449SRod.Evans@Sun.COM 			Dflag = 1;
19712449SRod.Evans@Sun.COM 			break;
1980Sstevel@tonic-gate 		case 'd' :			/* perform data relocations */
1990Sstevel@tonic-gate 			dflag = 1;
2000Sstevel@tonic-gate 			if (rflag)
2010Sstevel@tonic-gate 				error++;
2020Sstevel@tonic-gate 			break;
2030Sstevel@tonic-gate 		case 'e' :
2049131SRod.Evans@Sun.COM 			if (aplist_append(&eopts, optarg, 10) == NULL) {
2050Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
2060Sstevel@tonic-gate 				    cname);
2070Sstevel@tonic-gate 				exit(1);
2080Sstevel@tonic-gate 			}
2090Sstevel@tonic-gate 			break;
2100Sstevel@tonic-gate 		case 'f' :
2110Sstevel@tonic-gate 			fflag = 1;
2120Sstevel@tonic-gate 			break;
2130Sstevel@tonic-gate 		case 'L' :
2140Sstevel@tonic-gate 			Lflag = 1;
2150Sstevel@tonic-gate 			break;
2160Sstevel@tonic-gate 		case 'l' :
2170Sstevel@tonic-gate 			lflag = 1;
2180Sstevel@tonic-gate 			break;
2190Sstevel@tonic-gate 		case 'i' :			/* print the order of .init */
2200Sstevel@tonic-gate 			iflag = 1;
2210Sstevel@tonic-gate 			break;
2226150Srie 		case 'p' :
2236150Srie 			pflag = 1;		/* expose unreferenced */
2246150Srie 			break;			/*	parent or externals */
2250Sstevel@tonic-gate 		case 'r' :			/* perform all relocations */
2260Sstevel@tonic-gate 			rflag = 1;
2270Sstevel@tonic-gate 			if (dflag)
2280Sstevel@tonic-gate 				error++;
2290Sstevel@tonic-gate 			break;
2300Sstevel@tonic-gate 		case 's' :			/* enable search path output */
2310Sstevel@tonic-gate 			sflag = 1;
2320Sstevel@tonic-gate 			break;
2330Sstevel@tonic-gate 		case 'U' :			/* list unreferenced */
2340Sstevel@tonic-gate 			Uflag = 1;		/*	dependencies */
2350Sstevel@tonic-gate 			if (uflag)
2360Sstevel@tonic-gate 				error++;
2370Sstevel@tonic-gate 			break;
2380Sstevel@tonic-gate 		case 'u' :			/* list unused dependencies */
2390Sstevel@tonic-gate 			uflag = 1;
2400Sstevel@tonic-gate 			if (Uflag)
2410Sstevel@tonic-gate 				error++;
2420Sstevel@tonic-gate 			break;
2430Sstevel@tonic-gate 		case 'v' :			/* enable verbose output */
2440Sstevel@tonic-gate 			vflag = 1;
2450Sstevel@tonic-gate 			break;
2466150Srie 		case 'w' :			/* expose unresolved weak */
2474947Srie 			wflag = 1;		/*	references */
2484947Srie 			break;
2490Sstevel@tonic-gate 		default :
2500Sstevel@tonic-gate 			error++;
2510Sstevel@tonic-gate 			break;
2520Sstevel@tonic-gate 		}
2530Sstevel@tonic-gate 		if (error)
2540Sstevel@tonic-gate 			break;
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 	if (error) {
2570Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), cname);
2580Sstevel@tonic-gate 		exit(1);
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	/*
2620Sstevel@tonic-gate 	 * Determine if any of the LD_PRELOAD family is already set in the
2630Sstevel@tonic-gate 	 * environment, if so we'll continue to analyze each object with the
2640Sstevel@tonic-gate 	 * appropriate setting.
2650Sstevel@tonic-gate 	 */
2660Sstevel@tonic-gate 	if (((prefile_32 = getenv(MSG_ORIG(MSG_LD_PRELOAD_32))) == NULL) ||
2670Sstevel@tonic-gate 	    (*prefile_32 == '\0')) {
2680Sstevel@tonic-gate 		prefile_32 = MSG_ORIG(MSG_STR_EMPTY);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 	if (((prefile_64 = getenv(MSG_ORIG(MSG_LD_PRELOAD_64))) == NULL) ||
2710Sstevel@tonic-gate 	    (*prefile_64 == '\0')) {
2720Sstevel@tonic-gate 		prefile_64 = MSG_ORIG(MSG_STR_EMPTY);
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 	if (((prefile = getenv(MSG_ORIG(MSG_LD_PRELOAD))) == NULL) ||
2750Sstevel@tonic-gate 	    (*prefile == '\0')) {
2760Sstevel@tonic-gate 		prefile = MSG_ORIG(MSG_STR_EMPTY);
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	/*
2800Sstevel@tonic-gate 	 * Determine if any environment requests are for the LD_PRELOAD family,
2810Sstevel@tonic-gate 	 * and if so override any environment settings we've established above.
2820Sstevel@tonic-gate 	 */
2839131SRod.Evans@Sun.COM 	for (APLIST_TRAVERSE(eopts, idx, str)) {
2840Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_32),
2850Sstevel@tonic-gate 		    MSG_LD_PRELOAD_32_SIZE)) == 0) {
2860Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_32_SIZE;
2870Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
2880Sstevel@tonic-gate 				prefile_32 = str;
2890Sstevel@tonic-gate 			continue;
2900Sstevel@tonic-gate 		}
2910Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_64),
2920Sstevel@tonic-gate 		    MSG_LD_PRELOAD_64_SIZE)) == 0) {
2930Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_64_SIZE;
2940Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
2950Sstevel@tonic-gate 				prefile_64 = str;
2960Sstevel@tonic-gate 			continue;
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD),
2990Sstevel@tonic-gate 		    MSG_LD_PRELOAD_SIZE)) == 0) {
3000Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_SIZE;
3010Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
3020Sstevel@tonic-gate 				prefile = str;
3030Sstevel@tonic-gate 			continue;
3040Sstevel@tonic-gate 		}
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	/*
3080Sstevel@tonic-gate 	 * Set the appropriate relocation environment variables (Note unsetting
3090Sstevel@tonic-gate 	 * the environment variables is done just in case the user already
3100Sstevel@tonic-gate 	 * has these in their environment ... sort of thing the test folks
3110Sstevel@tonic-gate 	 * would do :-)
3120Sstevel@tonic-gate 	 */
3134947Srie 	warn[sizeof (warn) - 2] = (dflag || rflag || Uflag || uflag) ? '1' :
3140Sstevel@tonic-gate 	    '\0';
3154947Srie 	bind[sizeof (bind) - 2] = (rflag) ? '1' : '\0';
3164947Srie 	path[sizeof (path) - 2] = (sflag) ? '1' : '\0';
3174947Srie 	verb[sizeof (verb) - 2] = (vflag) ? '1' : '\0';
3184947Srie 	fltr[sizeof (fltr) - 2] = (Lflag) ? '\0' : (lflag) ? '2' : '1';
3194947Srie 	init[sizeof (init) - 2] = (iflag) ? '1' : '\0';
3204947Srie 	conf[sizeof (conf) - 2] = (cflag) ? '1' : '\0';
3214947Srie 	lazy[sizeof (lazy) - 2] = (Lflag) ? '\0' : '1';
3224947Srie 	uref[sizeof (uref) - 2] = (Uflag) ? '1' : '\0';
3234947Srie 	used[sizeof (used) - 2] = (uflag) ? '1' : '\0';
3244947Srie 	weak[sizeof (weak) - 2] = (wflag) ? '1' : '\0';
3256150Srie 	nope[sizeof (nope) - 2] = (pflag) ? '1' : '\0';
32612449SRod.Evans@Sun.COM 	defr[sizeof (defr) - 2] = (Dflag) ? '\0' : '1';
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	/*
3290Sstevel@tonic-gate 	 * coordinate libelf's version information
3300Sstevel@tonic-gate 	 */
3310Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
3320Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIBELF), cname,
3330Sstevel@tonic-gate 		    EV_CURRENT);
3340Sstevel@tonic-gate 		exit(1);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/*
3380Sstevel@tonic-gate 	 * Loop through remaining arguments.  Note that from here on there
3390Sstevel@tonic-gate 	 * are no exit conditions so that we can process a list of files,
3400Sstevel@tonic-gate 	 * any error condition is retained for a final exit status.
3410Sstevel@tonic-gate 	 */
3420Sstevel@tonic-gate 	nfile = argc - optind;
3430Sstevel@tonic-gate 	for (; optind < argc; optind++) {
3440Sstevel@tonic-gate 		char	*fname = argv[optind];
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 		/*
3470Sstevel@tonic-gate 		 * Open file (do this before checking access so that we can
3480Sstevel@tonic-gate 		 * provide the user with better diagnostics).
3490Sstevel@tonic-gate 		 */
3500Sstevel@tonic-gate 		if ((var = open(fname, O_RDONLY)) == -1) {
3510Sstevel@tonic-gate 			int	err = errno;
3520Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), cname,
3530Sstevel@tonic-gate 			    fname, strerror(err));
3540Sstevel@tonic-gate 			error = 1;
3550Sstevel@tonic-gate 			continue;
3560Sstevel@tonic-gate 		}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 		/*
3590Sstevel@tonic-gate 		 * Get the files elf descriptor and process it as an elf or
3600Sstevel@tonic-gate 		 * a.out (4.x) file.
3610Sstevel@tonic-gate 		 */
3620Sstevel@tonic-gate 		elf = elf_begin(var, ELF_C_READ, (Elf *)0);
3630Sstevel@tonic-gate 		switch (elf_kind(elf)) {
3640Sstevel@tonic-gate 		case ELF_K_AR :
3650Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO),
3660Sstevel@tonic-gate 			    cname, fname);
3670Sstevel@tonic-gate 			error = 1;
3680Sstevel@tonic-gate 			break;
3690Sstevel@tonic-gate 		case ELF_K_COFF:
3700Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN),
3710Sstevel@tonic-gate 			    cname, fname);
3720Sstevel@tonic-gate 			error = 1;
3730Sstevel@tonic-gate 			break;
3740Sstevel@tonic-gate 		case ELF_K_ELF:
3750Sstevel@tonic-gate 			if (elf_check(nfile, fname, cname, elf, fflag) != NULL)
3760Sstevel@tonic-gate 				error = 1;
3770Sstevel@tonic-gate 			break;
3780Sstevel@tonic-gate 		default:
3790Sstevel@tonic-gate 			/*
3800Sstevel@tonic-gate 			 * This is either an unknown file or an aout format
3810Sstevel@tonic-gate 			 */
3820Sstevel@tonic-gate 			if (aout_check(nfile, fname, cname, var, fflag) != NULL)
3830Sstevel@tonic-gate 				error = 1;
3840Sstevel@tonic-gate 			break;
3850Sstevel@tonic-gate 		}
3860Sstevel@tonic-gate 		(void) elf_end(elf);
3870Sstevel@tonic-gate 		(void) close(var);
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 	return (error);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate static int
elf_check(int nfile,char * fname,char * cname,Elf * elf,int fflag)3950Sstevel@tonic-gate elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
3960Sstevel@tonic-gate {
39712382SAli.Bahrami@Oracle.COM 	Conv_inv_buf_t	inv_buf;
3980Sstevel@tonic-gate 	GElf_Ehdr 	ehdr;
3990Sstevel@tonic-gate 	GElf_Phdr 	phdr;
4000Sstevel@tonic-gate 	int		dynamic = 0, interp = 0, cnt, class;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/*
4030Sstevel@tonic-gate 	 * verify information in file header
4040Sstevel@tonic-gate 	 */
4050Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
4060Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR),
4074947Srie 		    cname, fname, elf_errmsg(-1));
4080Sstevel@tonic-gate 		return (1);
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/*
41212382SAli.Bahrami@Oracle.COM 	 * Compatible machine
4130Sstevel@tonic-gate 	 */
41412382SAli.Bahrami@Oracle.COM 	if ((ehdr.e_machine != M_MACH_32) && (ehdr.e_machine != M_MACH_64) &&
41512382SAli.Bahrami@Oracle.COM 	    (ehdr.e_machine != M_MACHPLUS)) {
41612382SAli.Bahrami@Oracle.COM 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHTYPE), cname, fname,
41712382SAli.Bahrami@Oracle.COM 		    conv_ehdr_mach(ehdr.e_machine, 0, &inv_buf));
41812382SAli.Bahrami@Oracle.COM 		return (1);
41912382SAli.Bahrami@Oracle.COM 	}
42012382SAli.Bahrami@Oracle.COM 
42112382SAli.Bahrami@Oracle.COM 	/*
42212382SAli.Bahrami@Oracle.COM 	 * Compatible encoding (byte order)
42312382SAli.Bahrami@Oracle.COM 	 */
42412382SAli.Bahrami@Oracle.COM 	if (ehdr.e_ident[EI_DATA] != M_DATA) {
42512382SAli.Bahrami@Oracle.COM 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_DATA), cname, fname,
42612382SAli.Bahrami@Oracle.COM 		    conv_ehdr_data(ehdr.e_ident[EI_DATA], 0, &inv_buf));
4270Sstevel@tonic-gate 		return (1);
4280Sstevel@tonic-gate 	}
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/*
43112382SAli.Bahrami@Oracle.COM 	 * Compatible class
43212382SAli.Bahrami@Oracle.COM 	 */
43312382SAli.Bahrami@Oracle.COM 	switch (class = ehdr.e_ident[EI_CLASS]) {
43412382SAli.Bahrami@Oracle.COM 	case ELFCLASS32:
43512382SAli.Bahrami@Oracle.COM 		/*
43612382SAli.Bahrami@Oracle.COM 		 * If M_MACH is not the same thing as M_MACHPLUS and this
43712382SAli.Bahrami@Oracle.COM 		 * is an M_MACHPLUS object, then the corresponding header
43812382SAli.Bahrami@Oracle.COM 		 * flag must be set.
43912382SAli.Bahrami@Oracle.COM 		 */
44012382SAli.Bahrami@Oracle.COM 		if ((ehdr.e_machine != M_MACH) &&
44112382SAli.Bahrami@Oracle.COM 		    ((ehdr.e_flags & M_FLAGSPLUS) == 0)) {
44212382SAli.Bahrami@Oracle.COM 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHFLAGS),
44312382SAli.Bahrami@Oracle.COM 			    cname, fname);
44412382SAli.Bahrami@Oracle.COM 			return (1);
44512382SAli.Bahrami@Oracle.COM 		}
44612382SAli.Bahrami@Oracle.COM 		break;
44712382SAli.Bahrami@Oracle.COM 	case ELFCLASS64:
44812382SAli.Bahrami@Oracle.COM 		/* Requires 64-bit kernel */
44912382SAli.Bahrami@Oracle.COM 		if (conv_sys_eclass() == ELFCLASS32) {
45012382SAli.Bahrami@Oracle.COM 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_KCLASS32),
45112382SAli.Bahrami@Oracle.COM 			    cname, fname, conv_ehdr_class(class, 0, &inv_buf));
45212382SAli.Bahrami@Oracle.COM 			return (1);
45312382SAli.Bahrami@Oracle.COM 		}
45412382SAli.Bahrami@Oracle.COM 		break;
45512382SAli.Bahrami@Oracle.COM 	default:
45612382SAli.Bahrami@Oracle.COM 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_CLASS), cname, fname,
45712382SAli.Bahrami@Oracle.COM 		    conv_ehdr_class(class, 0, &inv_buf));
45812382SAli.Bahrami@Oracle.COM 		return (1);
45912382SAli.Bahrami@Oracle.COM 	}
46012382SAli.Bahrami@Oracle.COM 
46112382SAli.Bahrami@Oracle.COM 	/*
46212382SAli.Bahrami@Oracle.COM 	 * Object type
4630Sstevel@tonic-gate 	 */
4640Sstevel@tonic-gate 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN) &&
4650Sstevel@tonic-gate 	    (ehdr.e_type != ET_REL)) {
4660Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_BADMAGIC),
4674947Srie 		    cname, fname);
4680Sstevel@tonic-gate 		return (1);
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	/*
4720Sstevel@tonic-gate 	 * Check that the file is executable.  Dynamic executables must be
4730Sstevel@tonic-gate 	 * executable to be exec'ed.  Shared objects need not be executable to
4740Sstevel@tonic-gate 	 * be mapped with a dynamic executable, however, by convention they're
4750Sstevel@tonic-gate 	 * supposed to be executable.
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	if (access(fname, X_OK) != 0) {
4780Sstevel@tonic-gate 		if (ehdr.e_type == ET_EXEC) {
4790Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_1),
4804947Srie 			    cname, fname);
4810Sstevel@tonic-gate 			return (1);
4820Sstevel@tonic-gate 		}
4830Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_2), cname,
4840Sstevel@tonic-gate 		    fname);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/*
4880Sstevel@tonic-gate 	 * Determine whether we have a dynamic section or interpretor.
4890Sstevel@tonic-gate 	 */
4900Sstevel@tonic-gate 	for (cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) {
4910Sstevel@tonic-gate 		if (dynamic && interp)
4920Sstevel@tonic-gate 			break;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
4950Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETPHDR),
4964947Srie 			    cname, fname, elf_errmsg(-1));
4970Sstevel@tonic-gate 			return (1);
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 		if (phdr.p_type == PT_DYNAMIC) {
5010Sstevel@tonic-gate 			dynamic = 1;
5020Sstevel@tonic-gate 			continue;
5030Sstevel@tonic-gate 		}
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		if (phdr.p_type != PT_INTERP)
5060Sstevel@tonic-gate 			continue;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 		interp = 1;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 		/*
5110Sstevel@tonic-gate 		 * If fflag is not set, and euid == root, and the interpreter
5120Sstevel@tonic-gate 		 * does not live under /lib, /usr/lib or /etc/lib then don't
5130Sstevel@tonic-gate 		 * allow ldd to execute the image.  This prevents someone
5140Sstevel@tonic-gate 		 * creating a `trojan horse' by substituting their own
5150Sstevel@tonic-gate 		 * interpreter that could preform privileged operations
5160Sstevel@tonic-gate 		 * when ldd is against it.
5170Sstevel@tonic-gate 		 */
5180Sstevel@tonic-gate 		if ((fflag == 0) && (geteuid() == 0) &&
5190Sstevel@tonic-gate 		    (strcmp(fname, conv_lddstub(class)) != 0)) {
5200Sstevel@tonic-gate 			char	*interpreter;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 			/*
5230Sstevel@tonic-gate 			 * Does the interpreter live under a trusted directory.
5240Sstevel@tonic-gate 			 */
5250Sstevel@tonic-gate 			interpreter = elf_getident(elf, 0) + phdr.p_offset;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 			if ((strncmp(interpreter, MSG_ORIG(MSG_PTH_USRLIB),
5280Sstevel@tonic-gate 			    MSG_PTH_USRLIB_SIZE) != 0) &&
5290Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_LIB),
5300Sstevel@tonic-gate 			    MSG_PTH_LIB_SIZE) != 0) &&
5310Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_ETCLIB),
5320Sstevel@tonic-gate 			    MSG_PTH_ETCLIB_SIZE) != 0)) {
5330Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_USP_ELFINS),
5344947Srie 				    cname, fname, interpreter);
5350Sstevel@tonic-gate 				return (1);
5360Sstevel@tonic-gate 			}
5370Sstevel@tonic-gate 		}
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * Catch the case of a static executable (ie, an ET_EXEC that has a set
5420Sstevel@tonic-gate 	 * of program headers but no PT_DYNAMIC).
5430Sstevel@tonic-gate 	 */
5440Sstevel@tonic-gate 	if (ehdr.e_phnum && !dynamic) {
5450Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
5460Sstevel@tonic-gate 		    fname);
5470Sstevel@tonic-gate 		return (1);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 
5501698Sab196087 	/*
5511698Sab196087 	 * If there is a dynamic section, then check for the DF_1_NOHDR
55211734SAli.Bahrami@Sun.COM 	 * flag, and bail if it is present. Such objects are created using
55311734SAli.Bahrami@Sun.COM 	 * a mapfile option (?N in the version 1 syntax, or HDR_NOALLOC
55411734SAli.Bahrami@Sun.COM 	 * otherwise). The ELF header and program headers are
5551698Sab196087 	 * not mapped as part of the first segment, and virtual addresses
5561698Sab196087 	 * are computed without them. If ldd tries to interpret such
5571698Sab196087 	 * a file, it will become confused and generate bad output or
5581698Sab196087 	 * crash. Such objects are always special purpose files (like an OS
5591698Sab196087 	 * kernel) --- files for which the ldd operation doesn't make sense.
5601698Sab196087 	 */
5611698Sab196087 	if (dynamic && (_gelf_getdyndtflags_1(elf) & DF_1_NOHDR)) {
5621698Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOHDR), cname,
5631698Sab196087 		    fname);
5641698Sab196087 		return (1);
5651698Sab196087 	}
5661698Sab196087 
5670Sstevel@tonic-gate 	load = load_elf;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	/*
5700Sstevel@tonic-gate 	 * Run the required program (shared and relocatable objects require the
5710Sstevel@tonic-gate 	 * use of lddstub).
5720Sstevel@tonic-gate 	 */
5730Sstevel@tonic-gate 	if ((ehdr.e_type == ET_EXEC) && interp)
5740Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname, class));
5750Sstevel@tonic-gate 	else
5760Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(class), class));
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate static int
aout_check(int nfile,char * fname,char * cname,int fd,int fflag)5800Sstevel@tonic-gate aout_check(int nfile, char *fname, char *cname, int fd, int fflag)
5810Sstevel@tonic-gate {
5826223Sab196087 	struct exec32	aout;
5830Sstevel@tonic-gate 	int		err;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) != 0) {
5860Sstevel@tonic-gate 		err = errno;
5870Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname,
5880Sstevel@tonic-gate 		    strerror(err));
5890Sstevel@tonic-gate 		return (1);
5900Sstevel@tonic-gate 	}
5916223Sab196087 	if (read(fd, (char *)&aout, sizeof (aout)) != sizeof (aout)) {
5920Sstevel@tonic-gate 		err = errno;
5930Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname,
5940Sstevel@tonic-gate 		    strerror(err));
5950Sstevel@tonic-gate 		return (1);
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 	if (aout.a_machtype != M_SPARC) {
5980Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname);
5990Sstevel@tonic-gate 		return (1);
6000Sstevel@tonic-gate 	}
6010Sstevel@tonic-gate 	if (N_BADMAG(aout) || !aout.a_dynamic) {
6020Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
6030Sstevel@tonic-gate 		    fname);
6040Sstevel@tonic-gate 		return (1);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 	if (!fflag && (geteuid() == 0)) {
6070Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname);
6080Sstevel@tonic-gate 		return (1);
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	/*
6120Sstevel@tonic-gate 	 * Run the required program.
6130Sstevel@tonic-gate 	 */
6146223Sab196087 	if ((aout.a_magic == ZMAGIC) && (aout.a_entry <= sizeof (aout))) {
6150Sstevel@tonic-gate 		load = load_elf;
6160Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32),
6170Sstevel@tonic-gate 		    ELFCLASS32));
6180Sstevel@tonic-gate 	} else {
6190Sstevel@tonic-gate 		load = load_aout;
6200Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname,
6210Sstevel@tonic-gate 		    ELFCLASS32));
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate /*
6270Sstevel@tonic-gate  * Run the required program, setting the preload and trace environment
6280Sstevel@tonic-gate  * variables accordingly.
6290Sstevel@tonic-gate  */
6300Sstevel@tonic-gate static int
run(int nfile,char * cname,char * fname,const char * ename,int class)6310Sstevel@tonic-gate run(int nfile, char *cname, char *fname, const char *ename, int class)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate 	const char	*preload = 0;
6340Sstevel@tonic-gate 	int		pid, status;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
6370Sstevel@tonic-gate 		int	err = errno;
6380Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), cname,
6390Sstevel@tonic-gate 		    strerror(err));
6400Sstevel@tonic-gate 		return (1);
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	if (pid) {				/* parent */
6440Sstevel@tonic-gate 		while (wait(&status) != pid)
6450Sstevel@tonic-gate 			;
6460Sstevel@tonic-gate 		if (WIFSIGNALED(status) && ((WSIGMASK & status) != SIGPIPE)) {
6470Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
6480Sstevel@tonic-gate 			    fname);
6490Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_SIG),
6500Sstevel@tonic-gate 			    (WSIGMASK & status), ((status & WCOREFLG) ?
6510Sstevel@tonic-gate 			    MSG_INTL(MSG_SYS_EXEC_CORE) :
6520Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_EMPTY)));
6530Sstevel@tonic-gate 			status = 1;
6540Sstevel@tonic-gate 		} else if (WHIBYTE(status)) {
6550Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
6560Sstevel@tonic-gate 			    fname);
6570Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_STAT),
6580Sstevel@tonic-gate 			    WHIBYTE(status));
6590Sstevel@tonic-gate 			status = 1;
6600Sstevel@tonic-gate 		}
6610Sstevel@tonic-gate 	} else {				/* child */
6629131SRod.Evans@Sun.COM 		Aliste	idx;
6639131SRod.Evans@Sun.COM 		char	*str;
6649131SRod.Evans@Sun.COM 		size_t	size;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 		/*
6670Sstevel@tonic-gate 		 * When using ldd(1) to analyze a shared object we preload the
6680Sstevel@tonic-gate 		 * shared object with lddstub.  Any additional preload
6690Sstevel@tonic-gate 		 * requirements are added after the object being analyzed, this
6700Sstevel@tonic-gate 		 * allows us to skip the first object but produce diagnostics
6710Sstevel@tonic-gate 		 * for each other preloaded object.
6720Sstevel@tonic-gate 		 */
6730Sstevel@tonic-gate 		if (fname != ename) {
6740Sstevel@tonic-gate 			char		*str;
6750Sstevel@tonic-gate 			const char	*files = prefile;
6760Sstevel@tonic-gate 			const char	*format = MSG_ORIG(MSG_STR_FMT1);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 			for (str = fname; *str; str++)
6790Sstevel@tonic-gate 				if (*str == '/') {
6800Sstevel@tonic-gate 					format = MSG_ORIG(MSG_STR_FMT2);
6810Sstevel@tonic-gate 					break;
6820Sstevel@tonic-gate 			}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 			preload = MSG_ORIG(MSG_LD_PRELOAD);
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 			/*
6870Sstevel@tonic-gate 			 * Determine which preload files and preload environment
6880Sstevel@tonic-gate 			 * variable to use.
6890Sstevel@tonic-gate 			 */
6900Sstevel@tonic-gate 			if (class == ELFCLASS64) {
6910Sstevel@tonic-gate 				if (prefile_64 != MSG_ORIG(MSG_STR_EMPTY)) {
6920Sstevel@tonic-gate 					files = prefile_64;
6930Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_64);
6940Sstevel@tonic-gate 				}
6950Sstevel@tonic-gate 			} else {
6960Sstevel@tonic-gate 				if (prefile_32 != MSG_ORIG(MSG_STR_EMPTY)) {
6970Sstevel@tonic-gate 					files = prefile_32;
6980Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_32);
6990Sstevel@tonic-gate 				}
7000Sstevel@tonic-gate 			}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 			if ((str = (char *)malloc(strlen(preload) +
7030Sstevel@tonic-gate 			    strlen(fname) + strlen(files) + 5)) == 0) {
7040Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
7050Sstevel@tonic-gate 				    cname);
7060Sstevel@tonic-gate 				exit(1);
7070Sstevel@tonic-gate 			}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 			(void) sprintf(str, format, preload, fname, files);
7100Sstevel@tonic-gate 			if (putenv(str) != 0) {
7110Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
7120Sstevel@tonic-gate 				    cname);
7130Sstevel@tonic-gate 				exit(1);
7140Sstevel@tonic-gate 			}
7154947Srie 
7164947Srie 			/*
7174947Srie 			 * The pointer "load" has be assigned to load_elf[] or
7184947Srie 			 * load_aout[].  Use the size of load_elf[] as the size
7194947Srie 			 * of load_aout[] is the same.
7204947Srie 			 */
7214947Srie 			load[sizeof (load_elf) - 2] = '2';
7220Sstevel@tonic-gate 		} else
7234947Srie 			load[sizeof (load_elf) - 2] = '1';
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 		/*
7270Sstevel@tonic-gate 		 * Establish new environment variables to affect the child
7280Sstevel@tonic-gate 		 * process.
7290Sstevel@tonic-gate 		 */
7300Sstevel@tonic-gate 		if ((putenv(warn) != 0) || (putenv(bind) != 0) ||
7310Sstevel@tonic-gate 		    (putenv(path) != 0) || (putenv(verb) != 0) ||
7320Sstevel@tonic-gate 		    (putenv(fltr) != 0) || (putenv(conf) != 0) ||
7330Sstevel@tonic-gate 		    (putenv(init) != 0) || (putenv(lazy) != 0) ||
7340Sstevel@tonic-gate 		    (putenv(uref) != 0) || (putenv(used) != 0) ||
7356150Srie 		    (putenv(weak) != 0) || (putenv(load) != 0) ||
73612449SRod.Evans@Sun.COM 		    (putenv(nope) != 0) || (putenv(defr) != 0)) {
7370Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED), cname);
7380Sstevel@tonic-gate 			exit(1);
7390Sstevel@tonic-gate 		}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 		/*
7420Sstevel@tonic-gate 		 * Establish explicit environment requires (but don't override
7430Sstevel@tonic-gate 		 * any preload request established to process a shared object).
7440Sstevel@tonic-gate 		 */
7450Sstevel@tonic-gate 		size = 0;
7469131SRod.Evans@Sun.COM 		for (APLIST_TRAVERSE(eopts, idx, str)) {
7470Sstevel@tonic-gate 			if (preload) {
7480Sstevel@tonic-gate 				if (size == 0)
7490Sstevel@tonic-gate 					size = strlen(preload);
7500Sstevel@tonic-gate 				if ((strncmp(preload, str, size) == 0) &&
7510Sstevel@tonic-gate 				    (str[size] == '=')) {
7520Sstevel@tonic-gate 					continue;
7530Sstevel@tonic-gate 				}
7540Sstevel@tonic-gate 			}
7550Sstevel@tonic-gate 			if (putenv(str) != 0) {
7560Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
7570Sstevel@tonic-gate 				    cname);
7580Sstevel@tonic-gate 				exit(1);
7590Sstevel@tonic-gate 			}
7600Sstevel@tonic-gate 		}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		/*
7630Sstevel@tonic-gate 		 * Execute the object and let ld.so.1 do the rest.
7640Sstevel@tonic-gate 		 */
7650Sstevel@tonic-gate 		if (nfile > 1)
7660Sstevel@tonic-gate 			(void) printf(MSG_ORIG(MSG_STR_FMT3), fname);
7670Sstevel@tonic-gate 		(void) fflush(stdout);
7680Sstevel@tonic-gate 		if ((execl(ename, ename, (char *)0)) == -1) {
7690Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
7700Sstevel@tonic-gate 			    fname);
7710Sstevel@tonic-gate 			perror(ename);
7720Sstevel@tonic-gate 			_exit(0);
7730Sstevel@tonic-gate 			/* NOTREACHED */
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 	return (status);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate const char *
_ldd_msg(Msg mid)7800Sstevel@tonic-gate _ldd_msg(Msg mid)
7810Sstevel@tonic-gate {
7820Sstevel@tonic-gate 	return (gettext(MSG_ORIG(mid)));
7830Sstevel@tonic-gate }
784