xref: /illumos-gate/usr/src/cmd/sgs/ldd/common/ldd.c (revision f441771b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54899432aSab  * Common Development and Distribution License (the "License").
64899432aSab  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
20dae2dfb7Srie  *
217c478bd9Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
227c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
237c478bd9Sstevel@tonic-gate  *
247c478bd9Sstevel@tonic-gate  *
255bd55801SAli Bahrami  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Print the list of shared objects required by a dynamic executable or shared
307c478bd9Sstevel@tonic-gate  * object.
317c478bd9Sstevel@tonic-gate  *
32*f441771bSRod Evans  * usage is: ldd [-d | -r] [-D] [-c] [-e envar] [-i] [-f] [-L] [-l] [-p] [-s]
33df4628cbSrie  *		[-U | -u] [-v] [-w] file(s)
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * ldd opens the file and verifies the information in the elf header.
367c478bd9Sstevel@tonic-gate  * If the file is a dynamic executable, we set up some environment variables
377c478bd9Sstevel@tonic-gate  * and exec(2) the file.  If the file is a shared object, we preload the
387c478bd9Sstevel@tonic-gate  * file with a dynamic executable stub. The runtime linker (ld.so.1) actually
397c478bd9Sstevel@tonic-gate  * provides the diagnostic output, according to the environment variables set.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_[AE].
427c478bd9Sstevel@tonic-gate  * The runtime linker will print the pathnames of all dynamic objects it
437c478bd9Sstevel@tonic-gate  * loads, and then exit.  Note that we distiguish between ELF and AOUT objects
447c478bd9Sstevel@tonic-gate  * when setting this environment variable - AOUT executables cause the mapping
457c478bd9Sstevel@tonic-gate  * of sbcp, the dependencies of which the user isn't interested in.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * If -d or -r is specified, we also set LD_WARN=1; the runtime linker will
487c478bd9Sstevel@tonic-gate  * perform its normal relocations and issue warning messages for unresolved
497c478bd9Sstevel@tonic-gate  * references. It will then exit.
507c478bd9Sstevel@tonic-gate  * If -r is specified, we set LD_BIND_NOW=1, so that the runtime linker
517c478bd9Sstevel@tonic-gate  * will perform all relocations, otherwise (under -d) the runtime linker
527c478bd9Sstevel@tonic-gate  * will not perform PLT (function) type relocations.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * If -c is specified we also set LD_NOCONFIG=1, thus disabling any
557c478bd9Sstevel@tonic-gate  * configuration file use.
567c478bd9Sstevel@tonic-gate  *
57*f441771bSRod Evans  * If -D is specified we skip deferred dependency processing.  By default,
58*f441771bSRod Evans  * ldd loads all deferred dependencies.  However, during normal process
59*f441771bSRod Evans  * execution, deferred dependencies are only loaded when an explicit binding
60*f441771bSRod Evans  * to an individual deferred reference is made.  As no user code is executed
61*f441771bSRod Evans  * under ldd, explicit references to deferred symbols can't be triggered.
62*f441771bSRod Evans  *
637c478bd9Sstevel@tonic-gate  * If -e is specified the associated environment variable is set for the
647c478bd9Sstevel@tonic-gate  * child process that will produce ldd's diagnostics.
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * If -i is specified, we set LD_INIT=1. The order of inititialization
677c478bd9Sstevel@tonic-gate  * sections to be executed is printed. We also set LD_WARN=1.
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  * If -f is specified, we will run ldd as root on executables that have
707c478bd9Sstevel@tonic-gate  * an unsercure runtime linker that does not live under the "/usr/lib"
717c478bd9Sstevel@tonic-gate  * directory.  By default we will not let this happen.
727c478bd9Sstevel@tonic-gate  *
737c478bd9Sstevel@tonic-gate  * If -l is specified it generates a warning for any auxiliary filter not found.
747c478bd9Sstevel@tonic-gate  * Prior to 2.8 this forced any filters to load (all) their filtees.  This is
757c478bd9Sstevel@tonic-gate  * now the default, however missing auxiliary filters don't generate any error
767c478bd9Sstevel@tonic-gate  * diagniostic.  See also -L.
777c478bd9Sstevel@tonic-gate  *
787c478bd9Sstevel@tonic-gate  * If -L is specified we revert to lazy loading, thus any filtee or lazy
797c478bd9Sstevel@tonic-gate  * dependency loading is deferred until relocations cause loading.  Without
807c478bd9Sstevel@tonic-gate  * this option we set LD_LOADFLTR=1, thus forcing any filters to load (all)
817c478bd9Sstevel@tonic-gate  * their filtees, and LD_NOLAZYLOAD=1 thus forcing immediate processing of
827c478bd9Sstevel@tonic-gate  * any lazy loaded dependencies.
837c478bd9Sstevel@tonic-gate  *
847c478bd9Sstevel@tonic-gate  * If -s is specified we also set LD_TRACE_SEARCH_PATH=1, thus enabling
857c478bd9Sstevel@tonic-gate  * the runtime linker to indicate the search algorithm used.
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  * If -v is specified we also set LD_VERBOSE=1, thus enabling the runtime
887c478bd9Sstevel@tonic-gate  * linker to indicate all object dependencies (not just the first object
89*f441771bSRod Evans  * loaded) together with any versioning requirements.
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * If -U or -u is specified unused dependencies are detected.  -u causes
927c478bd9Sstevel@tonic-gate  * LD_UNUSED=1 to be set, which causes dependencies that are unused within the
937c478bd9Sstevel@tonic-gate  * process to be detected.  -U causes LD_UNREF=1 to be set, which causes
947c478bd9Sstevel@tonic-gate  * unreferenced objects, and unreferenced cyclic dependencies to be detected.
957c478bd9Sstevel@tonic-gate  * These options assert that at least -d is set as relocation references are
967c478bd9Sstevel@tonic-gate  * what determine an objects use.
97df4628cbSrie  *
98df4628cbSrie  * If -w is specified, no unresolved weak references are allowed.  -w causes
99df4628cbSrie  * LD_NOUNRESWEAK=1 to be set.  By default, an unresolved weak reference is
100df4628cbSrie  * allowed, and a "0" is written to the relocation offset.  The -w option
101df4628cbSrie  * disables this default.  Any weak references that can not be resolved result
102dae2dfb7Srie  * in relocation error messages.  This option has no use without -r or -d.
103dae2dfb7Srie  *
104dae2dfb7Srie  * If the -p option is specified, no unresolved PARENT or EXTERN references are
105dae2dfb7Srie  * allowed.  -p causes LD_NOPAREXT=1 to be set.  By default, PARENT and EXTERN
106dae2dfb7Srie  * references, which have been explicitly assigned via a mapfile when a shared
107dae2dfb7Srie  * object was built, imply that a caller will provide the symbols, and hence
108dae2dfb7Srie  * these are not reported as relocation errors.  Note, the -p option is asserted
109dae2dfb7Srie  * by default when either the -r or -d options are used to inspect a dynamic
110dae2dfb7Srie  * executable.  This option has no use with a shared object without -r or -d.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate #include	<fcntl.h>
1137c478bd9Sstevel@tonic-gate #include	<stdio.h>
1147c478bd9Sstevel@tonic-gate #include	<string.h>
1154899432aSab #include	<_libelf.h>
1167c478bd9Sstevel@tonic-gate #include	<stdlib.h>
1177c478bd9Sstevel@tonic-gate #include	<unistd.h>
1187c478bd9Sstevel@tonic-gate #include	<wait.h>
1197c478bd9Sstevel@tonic-gate #include	<locale.h>
1207c478bd9Sstevel@tonic-gate #include	<errno.h>
1217c478bd9Sstevel@tonic-gate #include	<signal.h>
1227c478bd9Sstevel@tonic-gate #include	"machdep.h"
1237c478bd9Sstevel@tonic-gate #include	"sgs.h"
1247c478bd9Sstevel@tonic-gate #include	"conv.h"
1257c478bd9Sstevel@tonic-gate #include	"a.out.h"
1267c478bd9Sstevel@tonic-gate #include	"msg.h"
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static int	elf_check(int, char *, char *, Elf *, int);
1297c478bd9Sstevel@tonic-gate static int	aout_check(int, char *, char *, int, int);
1307c478bd9Sstevel@tonic-gate static int	run(int, char *, char *, const char *, int);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
134df4628cbSrie  * Define all environment variable strings.  The character following the "="
135df4628cbSrie  * will be written to, to disable or enable the associated feature.
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate static char	bind[] =	"LD_BIND_NOW= ",
1387c478bd9Sstevel@tonic-gate 		load_elf[] =	"LD_TRACE_LOADED_OBJECTS_E= ",
1397c478bd9Sstevel@tonic-gate 		load_aout[] =	"LD_TRACE_LOADED_OBJECTS_A= ",
1407c478bd9Sstevel@tonic-gate 		path[] =	"LD_TRACE_SEARCH_PATHS= ",
1417c478bd9Sstevel@tonic-gate 		verb[] =	"LD_VERBOSE= ",
1427c478bd9Sstevel@tonic-gate 		warn[] =	"LD_WARN= ",
1437c478bd9Sstevel@tonic-gate 		conf[] =	"LD_NOCONFIG= ",
1447c478bd9Sstevel@tonic-gate 		fltr[] =	"LD_LOADFLTR= ",
1457c478bd9Sstevel@tonic-gate 		lazy[] =	"LD_NOLAZYLOAD=1",
1467c478bd9Sstevel@tonic-gate 		init[] =	"LD_INIT= ",
1477c478bd9Sstevel@tonic-gate 		uref[] =	"LD_UNREF= ",
148df4628cbSrie 		used[] =	"LD_UNUSED= ",
149dae2dfb7Srie 		weak[] =	"LD_NOUNRESWEAK= ",
150*f441771bSRod Evans 		nope[] =	"LD_NOPAREXT= ",
151*f441771bSRod Evans 		defr[] =	"LD_DEFERRED= ";
1527c478bd9Sstevel@tonic-gate static char	*load;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static const char	*prefile_32, *prefile_64, *prefile;
15557ef7aa9SRod Evans static APlist		*eopts = NULL;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate int
158df14233eSab main(int argc, char **argv, char **envp)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	char	*str, *cname = argv[0];
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	Elf	*elf;
1637c478bd9Sstevel@tonic-gate 	int	cflag = 0, dflag = 0, fflag = 0, iflag = 0, Lflag = 0;
1647c478bd9Sstevel@tonic-gate 	int	lflag = 0, rflag = 0, sflag = 0, Uflag = 0, uflag = 0;
165*f441771bSRod Evans 	int	Dflag = 0, pflag = 0, vflag = 0, wflag = 0;
166*f441771bSRod Evans 	int	nfile, var, error = 0;
16757ef7aa9SRod Evans 	Aliste	idx;
1687c478bd9Sstevel@tonic-gate 
169df14233eSab 	/*
170df14233eSab 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
171df14233eSab 	 * the binary.  If successful, conv_check_native() won't return.
172df14233eSab 	 *
173df14233eSab 	 * This is done to ensure that ldd can handle objects >2GB.
174df14233eSab 	 * ldd uses libelf, which is not large file capable. The
175df14233eSab 	 * 64-bit ldd can handle any sized object.
176df14233eSab 	 */
177df14233eSab 	(void) conv_check_native(argv, envp);
178df14233eSab 
1797c478bd9Sstevel@tonic-gate 	/*
1807c478bd9Sstevel@tonic-gate 	 * Establish locale.
1817c478bd9Sstevel@tonic-gate 	 */
1827c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
1837c478bd9Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/*
1867c478bd9Sstevel@tonic-gate 	 * verify command line syntax and process arguments
1877c478bd9Sstevel@tonic-gate 	 */
1887c478bd9Sstevel@tonic-gate 	opterr = 0;				/* disable getopt error mesg */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_GETOPT))) != EOF) {
1917c478bd9Sstevel@tonic-gate 		switch (var) {
1927c478bd9Sstevel@tonic-gate 		case 'c' :			/* enable config search */
1937c478bd9Sstevel@tonic-gate 			cflag = 1;
1947c478bd9Sstevel@tonic-gate 			break;
195*f441771bSRod Evans 		case 'D' :			/* skip deferred dependencies */
196*f441771bSRod Evans 			Dflag = 1;
197*f441771bSRod Evans 			break;
1987c478bd9Sstevel@tonic-gate 		case 'd' :			/* perform data relocations */
1997c478bd9Sstevel@tonic-gate 			dflag = 1;
2007c478bd9Sstevel@tonic-gate 			if (rflag)
2017c478bd9Sstevel@tonic-gate 				error++;
2027c478bd9Sstevel@tonic-gate 			break;
2037c478bd9Sstevel@tonic-gate 		case 'e' :
20457ef7aa9SRod Evans 			if (aplist_append(&eopts, optarg, 10) == NULL) {
2057c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
2067c478bd9Sstevel@tonic-gate 				    cname);
2077c478bd9Sstevel@tonic-gate 				exit(1);
2087c478bd9Sstevel@tonic-gate 			}
2097c478bd9Sstevel@tonic-gate 			break;
2107c478bd9Sstevel@tonic-gate 		case 'f' :
2117c478bd9Sstevel@tonic-gate 			fflag = 1;
2127c478bd9Sstevel@tonic-gate 			break;
2137c478bd9Sstevel@tonic-gate 		case 'L' :
2147c478bd9Sstevel@tonic-gate 			Lflag = 1;
2157c478bd9Sstevel@tonic-gate 			break;
2167c478bd9Sstevel@tonic-gate 		case 'l' :
2177c478bd9Sstevel@tonic-gate 			lflag = 1;
2187c478bd9Sstevel@tonic-gate 			break;
2197c478bd9Sstevel@tonic-gate 		case 'i' :			/* print the order of .init */
2207c478bd9Sstevel@tonic-gate 			iflag = 1;
2217c478bd9Sstevel@tonic-gate 			break;
222dae2dfb7Srie 		case 'p' :
223dae2dfb7Srie 			pflag = 1;		/* expose unreferenced */
224dae2dfb7Srie 			break;			/*	parent or externals */
2257c478bd9Sstevel@tonic-gate 		case 'r' :			/* perform all relocations */
2267c478bd9Sstevel@tonic-gate 			rflag = 1;
2277c478bd9Sstevel@tonic-gate 			if (dflag)
2287c478bd9Sstevel@tonic-gate 				error++;
2297c478bd9Sstevel@tonic-gate 			break;
2307c478bd9Sstevel@tonic-gate 		case 's' :			/* enable search path output */
2317c478bd9Sstevel@tonic-gate 			sflag = 1;
2327c478bd9Sstevel@tonic-gate 			break;
2337c478bd9Sstevel@tonic-gate 		case 'U' :			/* list unreferenced */
2347c478bd9Sstevel@tonic-gate 			Uflag = 1;		/*	dependencies */
2357c478bd9Sstevel@tonic-gate 			if (uflag)
2367c478bd9Sstevel@tonic-gate 				error++;
2377c478bd9Sstevel@tonic-gate 			break;
2387c478bd9Sstevel@tonic-gate 		case 'u' :			/* list unused dependencies */
2397c478bd9Sstevel@tonic-gate 			uflag = 1;
2407c478bd9Sstevel@tonic-gate 			if (Uflag)
2417c478bd9Sstevel@tonic-gate 				error++;
2427c478bd9Sstevel@tonic-gate 			break;
2437c478bd9Sstevel@tonic-gate 		case 'v' :			/* enable verbose output */
2447c478bd9Sstevel@tonic-gate 			vflag = 1;
2457c478bd9Sstevel@tonic-gate 			break;
246dae2dfb7Srie 		case 'w' :			/* expose unresolved weak */
247df4628cbSrie 			wflag = 1;		/*	references */
248df4628cbSrie 			break;
2497c478bd9Sstevel@tonic-gate 		default :
2507c478bd9Sstevel@tonic-gate 			error++;
2517c478bd9Sstevel@tonic-gate 			break;
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 		if (error)
2547c478bd9Sstevel@tonic-gate 			break;
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 	if (error) {
2577c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), cname);
2587c478bd9Sstevel@tonic-gate 		exit(1);
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	/*
2627c478bd9Sstevel@tonic-gate 	 * Determine if any of the LD_PRELOAD family is already set in the
2637c478bd9Sstevel@tonic-gate 	 * environment, if so we'll continue to analyze each object with the
2647c478bd9Sstevel@tonic-gate 	 * appropriate setting.
2657c478bd9Sstevel@tonic-gate 	 */
2667c478bd9Sstevel@tonic-gate 	if (((prefile_32 = getenv(MSG_ORIG(MSG_LD_PRELOAD_32))) == NULL) ||
2677c478bd9Sstevel@tonic-gate 	    (*prefile_32 == '\0')) {
2687c478bd9Sstevel@tonic-gate 		prefile_32 = MSG_ORIG(MSG_STR_EMPTY);
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	if (((prefile_64 = getenv(MSG_ORIG(MSG_LD_PRELOAD_64))) == NULL) ||
2717c478bd9Sstevel@tonic-gate 	    (*prefile_64 == '\0')) {
2727c478bd9Sstevel@tonic-gate 		prefile_64 = MSG_ORIG(MSG_STR_EMPTY);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	if (((prefile = getenv(MSG_ORIG(MSG_LD_PRELOAD))) == NULL) ||
2757c478bd9Sstevel@tonic-gate 	    (*prefile == '\0')) {
2767c478bd9Sstevel@tonic-gate 		prefile = MSG_ORIG(MSG_STR_EMPTY);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	/*
2807c478bd9Sstevel@tonic-gate 	 * Determine if any environment requests are for the LD_PRELOAD family,
2817c478bd9Sstevel@tonic-gate 	 * and if so override any environment settings we've established above.
2827c478bd9Sstevel@tonic-gate 	 */
28357ef7aa9SRod Evans 	for (APLIST_TRAVERSE(eopts, idx, str)) {
2847c478bd9Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_32),
2857c478bd9Sstevel@tonic-gate 		    MSG_LD_PRELOAD_32_SIZE)) == 0) {
2867c478bd9Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_32_SIZE;
2877c478bd9Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
2887c478bd9Sstevel@tonic-gate 				prefile_32 = str;
2897c478bd9Sstevel@tonic-gate 			continue;
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_64),
2927c478bd9Sstevel@tonic-gate 		    MSG_LD_PRELOAD_64_SIZE)) == 0) {
2937c478bd9Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_64_SIZE;
2947c478bd9Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
2957c478bd9Sstevel@tonic-gate 				prefile_64 = str;
2967c478bd9Sstevel@tonic-gate 			continue;
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD),
2997c478bd9Sstevel@tonic-gate 		    MSG_LD_PRELOAD_SIZE)) == 0) {
3007c478bd9Sstevel@tonic-gate 			str += MSG_LD_PRELOAD_SIZE;
3017c478bd9Sstevel@tonic-gate 			if ((*str++ == '=') && (*str != '\0'))
3027c478bd9Sstevel@tonic-gate 				prefile = str;
3037c478bd9Sstevel@tonic-gate 			continue;
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/*
3087c478bd9Sstevel@tonic-gate 	 * Set the appropriate relocation environment variables (Note unsetting
3097c478bd9Sstevel@tonic-gate 	 * the environment variables is done just in case the user already
3107c478bd9Sstevel@tonic-gate 	 * has these in their environment ... sort of thing the test folks
3117c478bd9Sstevel@tonic-gate 	 * would do :-)
3127c478bd9Sstevel@tonic-gate 	 */
313df4628cbSrie 	warn[sizeof (warn) - 2] = (dflag || rflag || Uflag || uflag) ? '1' :
3147c478bd9Sstevel@tonic-gate 	    '\0';
315df4628cbSrie 	bind[sizeof (bind) - 2] = (rflag) ? '1' : '\0';
316df4628cbSrie 	path[sizeof (path) - 2] = (sflag) ? '1' : '\0';
317df4628cbSrie 	verb[sizeof (verb) - 2] = (vflag) ? '1' : '\0';
318df4628cbSrie 	fltr[sizeof (fltr) - 2] = (Lflag) ? '\0' : (lflag) ? '2' : '1';
319df4628cbSrie 	init[sizeof (init) - 2] = (iflag) ? '1' : '\0';
320df4628cbSrie 	conf[sizeof (conf) - 2] = (cflag) ? '1' : '\0';
321df4628cbSrie 	lazy[sizeof (lazy) - 2] = (Lflag) ? '\0' : '1';
322df4628cbSrie 	uref[sizeof (uref) - 2] = (Uflag) ? '1' : '\0';
323df4628cbSrie 	used[sizeof (used) - 2] = (uflag) ? '1' : '\0';
324df4628cbSrie 	weak[sizeof (weak) - 2] = (wflag) ? '1' : '\0';
325dae2dfb7Srie 	nope[sizeof (nope) - 2] = (pflag) ? '1' : '\0';
326*f441771bSRod Evans 	defr[sizeof (defr) - 2] = (Dflag) ? '\0' : '1';
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * coordinate libelf's version information
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
3327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIBELF), cname,
3337c478bd9Sstevel@tonic-gate 		    EV_CURRENT);
3347c478bd9Sstevel@tonic-gate 		exit(1);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/*
3387c478bd9Sstevel@tonic-gate 	 * Loop through remaining arguments.  Note that from here on there
3397c478bd9Sstevel@tonic-gate 	 * are no exit conditions so that we can process a list of files,
3407c478bd9Sstevel@tonic-gate 	 * any error condition is retained for a final exit status.
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	nfile = argc - optind;
3437c478bd9Sstevel@tonic-gate 	for (; optind < argc; optind++) {
3447c478bd9Sstevel@tonic-gate 		char	*fname = argv[optind];
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 		/*
3477c478bd9Sstevel@tonic-gate 		 * Open file (do this before checking access so that we can
3487c478bd9Sstevel@tonic-gate 		 * provide the user with better diagnostics).
3497c478bd9Sstevel@tonic-gate 		 */
3507c478bd9Sstevel@tonic-gate 		if ((var = open(fname, O_RDONLY)) == -1) {
3517c478bd9Sstevel@tonic-gate 			int	err = errno;
3527c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), cname,
3537c478bd9Sstevel@tonic-gate 			    fname, strerror(err));
3547c478bd9Sstevel@tonic-gate 			error = 1;
3557c478bd9Sstevel@tonic-gate 			continue;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		/*
3597c478bd9Sstevel@tonic-gate 		 * Get the files elf descriptor and process it as an elf or
3607c478bd9Sstevel@tonic-gate 		 * a.out (4.x) file.
3617c478bd9Sstevel@tonic-gate 		 */
3627c478bd9Sstevel@tonic-gate 		elf = elf_begin(var, ELF_C_READ, (Elf *)0);
3637c478bd9Sstevel@tonic-gate 		switch (elf_kind(elf)) {
3647c478bd9Sstevel@tonic-gate 		case ELF_K_AR :
3657c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO),
3667c478bd9Sstevel@tonic-gate 			    cname, fname);
3677c478bd9Sstevel@tonic-gate 			error = 1;
3687c478bd9Sstevel@tonic-gate 			break;
3697c478bd9Sstevel@tonic-gate 		case ELF_K_COFF:
3707c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN),
3717c478bd9Sstevel@tonic-gate 			    cname, fname);
3727c478bd9Sstevel@tonic-gate 			error = 1;
3737c478bd9Sstevel@tonic-gate 			break;
3747c478bd9Sstevel@tonic-gate 		case ELF_K_ELF:
3757c478bd9Sstevel@tonic-gate 			if (elf_check(nfile, fname, cname, elf, fflag) != NULL)
3767c478bd9Sstevel@tonic-gate 				error = 1;
3777c478bd9Sstevel@tonic-gate 			break;
3787c478bd9Sstevel@tonic-gate 		default:
3797c478bd9Sstevel@tonic-gate 			/*
3807c478bd9Sstevel@tonic-gate 			 * This is either an unknown file or an aout format
3817c478bd9Sstevel@tonic-gate 			 */
3827c478bd9Sstevel@tonic-gate 			if (aout_check(nfile, fname, cname, var, fflag) != NULL)
3837c478bd9Sstevel@tonic-gate 				error = 1;
3847c478bd9Sstevel@tonic-gate 			break;
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 		(void) elf_end(elf);
3877c478bd9Sstevel@tonic-gate 		(void) close(var);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	return (error);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate static int
3957c478bd9Sstevel@tonic-gate elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
3967c478bd9Sstevel@tonic-gate {
3975bd55801SAli Bahrami 	Conv_inv_buf_t	inv_buf;
3987c478bd9Sstevel@tonic-gate 	GElf_Ehdr 	ehdr;
3997c478bd9Sstevel@tonic-gate 	GElf_Phdr 	phdr;
4007c478bd9Sstevel@tonic-gate 	int		dynamic = 0, interp = 0, cnt, class;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	/*
4037c478bd9Sstevel@tonic-gate 	 * verify information in file header
4047c478bd9Sstevel@tonic-gate 	 */
4057c478bd9Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
4067c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR),
407df4628cbSrie 		    cname, fname, elf_errmsg(-1));
4087c478bd9Sstevel@tonic-gate 		return (1);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/*
4125bd55801SAli Bahrami 	 * Compatible machine
4137c478bd9Sstevel@tonic-gate 	 */
4145bd55801SAli Bahrami 	if ((ehdr.e_machine != M_MACH_32) && (ehdr.e_machine != M_MACH_64) &&
4155bd55801SAli Bahrami 	    (ehdr.e_machine != M_MACHPLUS)) {
4165bd55801SAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHTYPE), cname, fname,
4175bd55801SAli Bahrami 		    conv_ehdr_mach(ehdr.e_machine, 0, &inv_buf));
4187c478bd9Sstevel@tonic-gate 		return (1);
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/*
4225bd55801SAli Bahrami 	 * Compatible encoding (byte order)
4237c478bd9Sstevel@tonic-gate 	 */
4245bd55801SAli Bahrami 	if (ehdr.e_ident[EI_DATA] != M_DATA) {
4255bd55801SAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_DATA), cname, fname,
4265bd55801SAli Bahrami 		    conv_ehdr_data(ehdr.e_ident[EI_DATA], 0, &inv_buf));
4277c478bd9Sstevel@tonic-gate 		return (1);
4287c478bd9Sstevel@tonic-gate 	}
4295bd55801SAli Bahrami 
4305bd55801SAli Bahrami 	/*
4315bd55801SAli Bahrami 	 * Compatible class
4325bd55801SAli Bahrami 	 */
4335bd55801SAli Bahrami 	switch (class = ehdr.e_ident[EI_CLASS]) {
4345bd55801SAli Bahrami 	case ELFCLASS32:
4355bd55801SAli Bahrami 		/*
4365bd55801SAli Bahrami 		 * If M_MACH is not the same thing as M_MACHPLUS and this
4375bd55801SAli Bahrami 		 * is an M_MACHPLUS object, then the corresponding header
4385bd55801SAli Bahrami 		 * flag must be set.
4395bd55801SAli Bahrami 		 */
4405bd55801SAli Bahrami 		if ((ehdr.e_machine != M_MACH) &&
4415bd55801SAli Bahrami 		    ((ehdr.e_flags & M_FLAGSPLUS) == 0)) {
4425bd55801SAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHFLAGS),
443df4628cbSrie 			    cname, fname);
4447c478bd9Sstevel@tonic-gate 			return (1);
4457c478bd9Sstevel@tonic-gate 		}
4465bd55801SAli Bahrami 		break;
4475bd55801SAli Bahrami 	case ELFCLASS64:
4485bd55801SAli Bahrami 		/* Requires 64-bit kernel */
4495bd55801SAli Bahrami 		if (conv_sys_eclass() == ELFCLASS32) {
4505bd55801SAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_KCLASS32),
4515bd55801SAli Bahrami 			    cname, fname, conv_ehdr_class(class, 0, &inv_buf));
4527c478bd9Sstevel@tonic-gate 			return (1);
4537c478bd9Sstevel@tonic-gate 		}
4545bd55801SAli Bahrami 		break;
4555bd55801SAli Bahrami 	default:
4565bd55801SAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_CLASS), cname, fname,
4575bd55801SAli Bahrami 		    conv_ehdr_class(class, 0, &inv_buf));
4585bd55801SAli Bahrami 		return (1);
4595bd55801SAli Bahrami 	}
4605bd55801SAli Bahrami 
4615bd55801SAli Bahrami 	/*
4625bd55801SAli Bahrami 	 * Object type
4635bd55801SAli Bahrami 	 */
4645bd55801SAli Bahrami 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN) &&
4655bd55801SAli Bahrami 	    (ehdr.e_type != ET_REL)) {
4665bd55801SAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_BADMAGIC),
4675bd55801SAli Bahrami 		    cname, fname);
4685bd55801SAli Bahrami 		return (1);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	/*
4727c478bd9Sstevel@tonic-gate 	 * Check that the file is executable.  Dynamic executables must be
4737c478bd9Sstevel@tonic-gate 	 * executable to be exec'ed.  Shared objects need not be executable to
4747c478bd9Sstevel@tonic-gate 	 * be mapped with a dynamic executable, however, by convention they're
4757c478bd9Sstevel@tonic-gate 	 * supposed to be executable.
4767c478bd9Sstevel@tonic-gate 	 */
4777c478bd9Sstevel@tonic-gate 	if (access(fname, X_OK) != 0) {
4787c478bd9Sstevel@tonic-gate 		if (ehdr.e_type == ET_EXEC) {
4797c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_1),
480df4628cbSrie 			    cname, fname);
4817c478bd9Sstevel@tonic-gate 			return (1);
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_2), cname,
4847c478bd9Sstevel@tonic-gate 		    fname);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/*
4887c478bd9Sstevel@tonic-gate 	 * Determine whether we have a dynamic section or interpretor.
4897c478bd9Sstevel@tonic-gate 	 */
4907c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) {
4917c478bd9Sstevel@tonic-gate 		if (dynamic && interp)
4927c478bd9Sstevel@tonic-gate 			break;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
4957c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETPHDR),
496df4628cbSrie 			    cname, fname, elf_errmsg(-1));
4977c478bd9Sstevel@tonic-gate 			return (1);
4987c478bd9Sstevel@tonic-gate 		}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		if (phdr.p_type == PT_DYNAMIC) {
5017c478bd9Sstevel@tonic-gate 			dynamic = 1;
5027c478bd9Sstevel@tonic-gate 			continue;
5037c478bd9Sstevel@tonic-gate 		}
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 		if (phdr.p_type != PT_INTERP)
5067c478bd9Sstevel@tonic-gate 			continue;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		interp = 1;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 		/*
5117c478bd9Sstevel@tonic-gate 		 * If fflag is not set, and euid == root, and the interpreter
5127c478bd9Sstevel@tonic-gate 		 * does not live under /lib, /usr/lib or /etc/lib then don't
5137c478bd9Sstevel@tonic-gate 		 * allow ldd to execute the image.  This prevents someone
5147c478bd9Sstevel@tonic-gate 		 * creating a `trojan horse' by substituting their own
5157c478bd9Sstevel@tonic-gate 		 * interpreter that could preform privileged operations
5167c478bd9Sstevel@tonic-gate 		 * when ldd is against it.
5177c478bd9Sstevel@tonic-gate 		 */
5187c478bd9Sstevel@tonic-gate 		if ((fflag == 0) && (geteuid() == 0) &&
5197c478bd9Sstevel@tonic-gate 		    (strcmp(fname, conv_lddstub(class)) != 0)) {
5207c478bd9Sstevel@tonic-gate 			char	*interpreter;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 			/*
5237c478bd9Sstevel@tonic-gate 			 * Does the interpreter live under a trusted directory.
5247c478bd9Sstevel@tonic-gate 			 */
5257c478bd9Sstevel@tonic-gate 			interpreter = elf_getident(elf, 0) + phdr.p_offset;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 			if ((strncmp(interpreter, MSG_ORIG(MSG_PTH_USRLIB),
5287c478bd9Sstevel@tonic-gate 			    MSG_PTH_USRLIB_SIZE) != 0) &&
5297c478bd9Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_LIB),
5307c478bd9Sstevel@tonic-gate 			    MSG_PTH_LIB_SIZE) != 0) &&
5317c478bd9Sstevel@tonic-gate 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_ETCLIB),
5327c478bd9Sstevel@tonic-gate 			    MSG_PTH_ETCLIB_SIZE) != 0)) {
5337c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_USP_ELFINS),
534df4628cbSrie 				    cname, fname, interpreter);
5357c478bd9Sstevel@tonic-gate 				return (1);
5367c478bd9Sstevel@tonic-gate 			}
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	/*
5417c478bd9Sstevel@tonic-gate 	 * Catch the case of a static executable (ie, an ET_EXEC that has a set
5427c478bd9Sstevel@tonic-gate 	 * of program headers but no PT_DYNAMIC).
5437c478bd9Sstevel@tonic-gate 	 */
5447c478bd9Sstevel@tonic-gate 	if (ehdr.e_phnum && !dynamic) {
5457c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
5467c478bd9Sstevel@tonic-gate 		    fname);
5477c478bd9Sstevel@tonic-gate 		return (1);
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 
5504899432aSab 	/*
5514899432aSab 	 * If there is a dynamic section, then check for the DF_1_NOHDR
55269112eddSAli Bahrami 	 * flag, and bail if it is present. Such objects are created using
55369112eddSAli Bahrami 	 * a mapfile option (?N in the version 1 syntax, or HDR_NOALLOC
55469112eddSAli Bahrami 	 * otherwise). The ELF header and program headers are
5554899432aSab 	 * not mapped as part of the first segment, and virtual addresses
5564899432aSab 	 * are computed without them. If ldd tries to interpret such
5574899432aSab 	 * a file, it will become confused and generate bad output or
5584899432aSab 	 * crash. Such objects are always special purpose files (like an OS
5594899432aSab 	 * kernel) --- files for which the ldd operation doesn't make sense.
5604899432aSab 	 */
5614899432aSab 	if (dynamic && (_gelf_getdyndtflags_1(elf) & DF_1_NOHDR)) {
5624899432aSab 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOHDR), cname,
5634899432aSab 		    fname);
5644899432aSab 		return (1);
5654899432aSab 	}
5664899432aSab 
5677c478bd9Sstevel@tonic-gate 	load = load_elf;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	/*
5707c478bd9Sstevel@tonic-gate 	 * Run the required program (shared and relocatable objects require the
5717c478bd9Sstevel@tonic-gate 	 * use of lddstub).
5727c478bd9Sstevel@tonic-gate 	 */
5737c478bd9Sstevel@tonic-gate 	if ((ehdr.e_type == ET_EXEC) && interp)
5747c478bd9Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname, class));
5757c478bd9Sstevel@tonic-gate 	else
5767c478bd9Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(class), class));
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate static int
5807c478bd9Sstevel@tonic-gate aout_check(int nfile, char *fname, char *cname, int fd, int fflag)
5817c478bd9Sstevel@tonic-gate {
582df14233eSab 	struct exec32	aout;
5837c478bd9Sstevel@tonic-gate 	int		err;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) != 0) {
5867c478bd9Sstevel@tonic-gate 		err = errno;
5877c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname,
5887c478bd9Sstevel@tonic-gate 		    strerror(err));
5897c478bd9Sstevel@tonic-gate 		return (1);
5907c478bd9Sstevel@tonic-gate 	}
591df14233eSab 	if (read(fd, (char *)&aout, sizeof (aout)) != sizeof (aout)) {
5927c478bd9Sstevel@tonic-gate 		err = errno;
5937c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname,
5947c478bd9Sstevel@tonic-gate 		    strerror(err));
5957c478bd9Sstevel@tonic-gate 		return (1);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 	if (aout.a_machtype != M_SPARC) {
5987c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname);
5997c478bd9Sstevel@tonic-gate 		return (1);
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 	if (N_BADMAG(aout) || !aout.a_dynamic) {
6027c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
6037c478bd9Sstevel@tonic-gate 		    fname);
6047c478bd9Sstevel@tonic-gate 		return (1);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 	if (!fflag && (geteuid() == 0)) {
6077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname);
6087c478bd9Sstevel@tonic-gate 		return (1);
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/*
6127c478bd9Sstevel@tonic-gate 	 * Run the required program.
6137c478bd9Sstevel@tonic-gate 	 */
614df14233eSab 	if ((aout.a_magic == ZMAGIC) && (aout.a_entry <= sizeof (aout))) {
6157c478bd9Sstevel@tonic-gate 		load = load_elf;
6167c478bd9Sstevel@tonic-gate 		return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32),
6177c478bd9Sstevel@tonic-gate 		    ELFCLASS32));
6187c478bd9Sstevel@tonic-gate 	} else {
6197c478bd9Sstevel@tonic-gate 		load = load_aout;
6207c478bd9Sstevel@tonic-gate 		return (run(nfile, cname, fname, (const char *)fname,
6217c478bd9Sstevel@tonic-gate 		    ELFCLASS32));
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate /*
6277c478bd9Sstevel@tonic-gate  * Run the required program, setting the preload and trace environment
6287c478bd9Sstevel@tonic-gate  * variables accordingly.
6297c478bd9Sstevel@tonic-gate  */
6307c478bd9Sstevel@tonic-gate static int
6317c478bd9Sstevel@tonic-gate run(int nfile, char *cname, char *fname, const char *ename, int class)
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate 	const char	*preload = 0;
6347c478bd9Sstevel@tonic-gate 	int		pid, status;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
6377c478bd9Sstevel@tonic-gate 		int	err = errno;
6387c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), cname,
6397c478bd9Sstevel@tonic-gate 		    strerror(err));
6407c478bd9Sstevel@tonic-gate 		return (1);
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	if (pid) {				/* parent */
6447c478bd9Sstevel@tonic-gate 		while (wait(&status) != pid)
6457c478bd9Sstevel@tonic-gate 			;
6467c478bd9Sstevel@tonic-gate 		if (WIFSIGNALED(status) && ((WSIGMASK & status) != SIGPIPE)) {
6477c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
6487c478bd9Sstevel@tonic-gate 			    fname);
6497c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_SIG),
6507c478bd9Sstevel@tonic-gate 			    (WSIGMASK & status), ((status & WCOREFLG) ?
6517c478bd9Sstevel@tonic-gate 			    MSG_INTL(MSG_SYS_EXEC_CORE) :
6527c478bd9Sstevel@tonic-gate 			    MSG_ORIG(MSG_STR_EMPTY)));
6537c478bd9Sstevel@tonic-gate 			status = 1;
6547c478bd9Sstevel@tonic-gate 		} else if (WHIBYTE(status)) {
6557c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
6567c478bd9Sstevel@tonic-gate 			    fname);
6577c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_STAT),
6587c478bd9Sstevel@tonic-gate 			    WHIBYTE(status));
6597c478bd9Sstevel@tonic-gate 			status = 1;
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 	} else {				/* child */
66257ef7aa9SRod Evans 		Aliste	idx;
66357ef7aa9SRod Evans 		char	*str;
66457ef7aa9SRod Evans 		size_t	size;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 		/*
6677c478bd9Sstevel@tonic-gate 		 * When using ldd(1) to analyze a shared object we preload the
6687c478bd9Sstevel@tonic-gate 		 * shared object with lddstub.  Any additional preload
6697c478bd9Sstevel@tonic-gate 		 * requirements are added after the object being analyzed, this
6707c478bd9Sstevel@tonic-gate 		 * allows us to skip the first object but produce diagnostics
6717c478bd9Sstevel@tonic-gate 		 * for each other preloaded object.
6727c478bd9Sstevel@tonic-gate 		 */
6737c478bd9Sstevel@tonic-gate 		if (fname != ename) {
6747c478bd9Sstevel@tonic-gate 			char		*str;
6757c478bd9Sstevel@tonic-gate 			const char	*files = prefile;
6767c478bd9Sstevel@tonic-gate 			const char	*format = MSG_ORIG(MSG_STR_FMT1);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 			for (str = fname; *str; str++)
6797c478bd9Sstevel@tonic-gate 				if (*str == '/') {
6807c478bd9Sstevel@tonic-gate 					format = MSG_ORIG(MSG_STR_FMT2);
6817c478bd9Sstevel@tonic-gate 					break;
6827c478bd9Sstevel@tonic-gate 			}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 			preload = MSG_ORIG(MSG_LD_PRELOAD);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 			/*
6877c478bd9Sstevel@tonic-gate 			 * Determine which preload files and preload environment
6887c478bd9Sstevel@tonic-gate 			 * variable to use.
6897c478bd9Sstevel@tonic-gate 			 */
6907c478bd9Sstevel@tonic-gate 			if (class == ELFCLASS64) {
6917c478bd9Sstevel@tonic-gate 				if (prefile_64 != MSG_ORIG(MSG_STR_EMPTY)) {
6927c478bd9Sstevel@tonic-gate 					files = prefile_64;
6937c478bd9Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_64);
6947c478bd9Sstevel@tonic-gate 				}
6957c478bd9Sstevel@tonic-gate 			} else {
6967c478bd9Sstevel@tonic-gate 				if (prefile_32 != MSG_ORIG(MSG_STR_EMPTY)) {
6977c478bd9Sstevel@tonic-gate 					files = prefile_32;
6987c478bd9Sstevel@tonic-gate 					preload = MSG_ORIG(MSG_LD_PRELOAD_32);
6997c478bd9Sstevel@tonic-gate 				}
7007c478bd9Sstevel@tonic-gate 			}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 			if ((str = (char *)malloc(strlen(preload) +
7037c478bd9Sstevel@tonic-gate 			    strlen(fname) + strlen(files) + 5)) == 0) {
7047c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
7057c478bd9Sstevel@tonic-gate 				    cname);
7067c478bd9Sstevel@tonic-gate 				exit(1);
7077c478bd9Sstevel@tonic-gate 			}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 			(void) sprintf(str, format, preload, fname, files);
7107c478bd9Sstevel@tonic-gate 			if (putenv(str) != 0) {
7117c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
7127c478bd9Sstevel@tonic-gate 				    cname);
7137c478bd9Sstevel@tonic-gate 				exit(1);
7147c478bd9Sstevel@tonic-gate 			}
715df4628cbSrie 
716df4628cbSrie 			/*
717df4628cbSrie 			 * The pointer "load" has be assigned to load_elf[] or
718df4628cbSrie 			 * load_aout[].  Use the size of load_elf[] as the size
719df4628cbSrie 			 * of load_aout[] is the same.
720df4628cbSrie 			 */
721df4628cbSrie 			load[sizeof (load_elf) - 2] = '2';
7227c478bd9Sstevel@tonic-gate 		} else
723df4628cbSrie 			load[sizeof (load_elf) - 2] = '1';
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		/*
7277c478bd9Sstevel@tonic-gate 		 * Establish new environment variables to affect the child
7287c478bd9Sstevel@tonic-gate 		 * process.
7297c478bd9Sstevel@tonic-gate 		 */
7307c478bd9Sstevel@tonic-gate 		if ((putenv(warn) != 0) || (putenv(bind) != 0) ||
7317c478bd9Sstevel@tonic-gate 		    (putenv(path) != 0) || (putenv(verb) != 0) ||
7327c478bd9Sstevel@tonic-gate 		    (putenv(fltr) != 0) || (putenv(conf) != 0) ||
7337c478bd9Sstevel@tonic-gate 		    (putenv(init) != 0) || (putenv(lazy) != 0) ||
7347c478bd9Sstevel@tonic-gate 		    (putenv(uref) != 0) || (putenv(used) != 0) ||
735dae2dfb7Srie 		    (putenv(weak) != 0) || (putenv(load) != 0) ||
736*f441771bSRod Evans 		    (putenv(nope) != 0) || (putenv(defr) != 0)) {
7377c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED), cname);
7387c478bd9Sstevel@tonic-gate 			exit(1);
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 		/*
7427c478bd9Sstevel@tonic-gate 		 * Establish explicit environment requires (but don't override
7437c478bd9Sstevel@tonic-gate 		 * any preload request established to process a shared object).
7447c478bd9Sstevel@tonic-gate 		 */
7457c478bd9Sstevel@tonic-gate 		size = 0;
74657ef7aa9SRod Evans 		for (APLIST_TRAVERSE(eopts, idx, str)) {
7477c478bd9Sstevel@tonic-gate 			if (preload) {
7487c478bd9Sstevel@tonic-gate 				if (size == 0)
7497c478bd9Sstevel@tonic-gate 					size = strlen(preload);
7507c478bd9Sstevel@tonic-gate 				if ((strncmp(preload, str, size) == 0) &&
7517c478bd9Sstevel@tonic-gate 				    (str[size] == '=')) {
7527c478bd9Sstevel@tonic-gate 					continue;
7537c478bd9Sstevel@tonic-gate 				}
7547c478bd9Sstevel@tonic-gate 			}
7557c478bd9Sstevel@tonic-gate 			if (putenv(str) != 0) {
7567c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
7577c478bd9Sstevel@tonic-gate 				    cname);
7587c478bd9Sstevel@tonic-gate 				exit(1);
7597c478bd9Sstevel@tonic-gate 			}
7607c478bd9Sstevel@tonic-gate 		}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		/*
7637c478bd9Sstevel@tonic-gate 		 * Execute the object and let ld.so.1 do the rest.
7647c478bd9Sstevel@tonic-gate 		 */
7657c478bd9Sstevel@tonic-gate 		if (nfile > 1)
7667c478bd9Sstevel@tonic-gate 			(void) printf(MSG_ORIG(MSG_STR_FMT3), fname);
7677c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
7687c478bd9Sstevel@tonic-gate 		if ((execl(ename, ename, (char *)0)) == -1) {
7697c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
7707c478bd9Sstevel@tonic-gate 			    fname);
7717c478bd9Sstevel@tonic-gate 			perror(ename);
7727c478bd9Sstevel@tonic-gate 			_exit(0);
7737c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
7747c478bd9Sstevel@tonic-gate 		}
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 	return (status);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate const char *
7807c478bd9Sstevel@tonic-gate _ldd_msg(Msg mid)
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate 	return (gettext(MSG_ORIG(mid)));
7837c478bd9Sstevel@tonic-gate }
784