xref: /illumos-gate/usr/src/cmd/sgs/ldd/common/ldd.c (revision a1bf6e2eba3dc9acc46299eac9c6ef1bc1e15c2b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  *	Copyright (c) 1988 AT&T
22  *	  All Rights Reserved
23  *
24  *
25  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
26  */
27 
28 /*
29  * Print the list of shared objects required by a dynamic executable or shared
30  * object.
31  *
32  * usage is: ldd [-d | -r] [-c] [-D] [-e envar] [-i] [-f] [-L] [-l] [-p] [-s]
33  *		[-U | -u] [-v] [-w] file(s)
34  *
35  * ldd opens the file and verifies the information in the elf header.
36  * If the file is a dynamic executable, we set up some environment variables
37  * and exec(2) the file.  If the file is a shared object, we preload the
38  * file with a dynamic executable stub. The runtime linker (ld.so.1) actually
39  * provides the diagnostic output, according to the environment variables set.
40  *
41  * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_[AE].
42  * The runtime linker will print the pathnames of all dynamic objects it
43  * loads, and then exit.  Note that we distiguish between ELF and AOUT objects
44  * when setting this environment variable - AOUT executables cause the mapping
45  * of sbcp, the dependencies of which the user isn't interested in.
46  *
47  * If -d or -r is specified, we also set LD_WARN=1; the runtime linker will
48  * perform its normal relocations and issue warning messages for unresolved
49  * references. It will then exit.
50  * If -r is specified, we set LD_BIND_NOW=1, so that the runtime linker
51  * will perform all relocations, otherwise (under -d) the runtime linker
52  * will not perform PLT (function) type relocations.
53  *
54  * If -c is specified we also set LD_NOCONFIG=1, thus disabling any
55  * configuration file use.
56  *
57  * If -D is specified we skip deferred dependency processing.  By default,
58  * ldd loads all deferred dependencies.  However, during normal process
59  * execution, deferred dependencies are only loaded when an explicit binding
60  * to an individual deferred reference is made.  As no user code is executed
61  * under ldd, explicit references to deferred symbols can't be triggered.
62  *
63  * If -e is specified the associated environment variable is set for the
64  * child process that will produce ldd's diagnostics.
65  *
66  * If -i is specified, we set LD_INIT=1. The order of inititialization
67  * sections to be executed is printed. We also set LD_WARN=1.
68  *
69  * If -f is specified, we will run ldd as root on executables that have
70  * an unsercure runtime linker that does not live under the "/usr/lib"
71  * directory.  By default we will not let this happen.
72  *
73  * If -l is specified it generates a warning for any auxiliary filter not found.
74  * Prior to 2.8 this forced any filters to load (all) their filtees.  This is
75  * now the default, however missing auxiliary filters don't generate any error
76  * diagniostic.  See also -L.
77  *
78  * If -L is specified we revert to lazy loading, thus any filtee or lazy
79  * dependency loading is deferred until relocations cause loading.  Without
80  * this option we set LD_LOADFLTR=1, thus forcing any filters to load (all)
81  * their filtees, and LD_NOLAZYLOAD=1 thus forcing immediate processing of
82  * any lazy loaded dependencies.
83  *
84  * If -s is specified we also set LD_TRACE_SEARCH_PATH=1, thus enabling
85  * the runtime linker to indicate the search algorithm used.
86  *
87  * If -v is specified we also set LD_VERBOSE=1, thus enabling the runtime
88  * linker to indicate all object dependencies (not just the first object
89  * loaded) together with any versioning requirements.
90  *
91  * If -U or -u is specified unused dependencies are detected.  -u causes
92  * LD_UNUSED=1 to be set, which causes dependencies that are unused within the
93  * process to be detected.  -U causes LD_UNREF=1 to be set, which causes
94  * unreferenced objects, and unreferenced cyclic dependencies to be detected.
95  * These options assert that at least -d is set as relocation references are
96  * what determine an objects use.
97  *
98  * If -w is specified, no unresolved weak references are allowed.  -w causes
99  * LD_NOUNRESWEAK=1 to be set.  By default, an unresolved weak reference is
100  * allowed, and a "0" is written to the relocation offset.  The -w option
101  * disables this default.  Any weak references that can not be resolved result
102  * in relocation error messages.  This option has no use without -r or -d.
103  *
104  * If the -p option is specified, no unresolved PARENT or EXTERN references are
105  * allowed.  -p causes LD_NOPAREXT=1 to be set.  By default, PARENT and EXTERN
106  * references, which have been explicitly assigned via a mapfile when a shared
107  * object was built, imply that a caller will provide the symbols, and hence
108  * these are not reported as relocation errors.  Note, the -p option is asserted
109  * by default when either the -r or -d options are used to inspect a dynamic
110  * executable.  This option has no use with a shared object without -r or -d.
111  */
112 #include	<fcntl.h>
113 #include	<stdio.h>
114 #include	<string.h>
115 #include	<_libelf.h>
116 #include	<stdlib.h>
117 #include	<unistd.h>
118 #include	<wait.h>
119 #include	<locale.h>
120 #include	<errno.h>
121 #include	<signal.h>
122 #include	"machdep.h"
123 #include	"sgs.h"
124 #include	"conv.h"
125 #include	"a.out.h"
126 #include	"msg.h"
127 
128 static int	elf_check(int, char *, char *, Elf *, int);
129 static int	aout_check(int, char *, char *, int, int);
130 static int	run(int, char *, char *, const char *, int);
131 
132 
133 /*
134  * Define all environment variable strings.  The character following the "="
135  * will be written to, to disable or enable the associated feature.
136  */
137 static char	bind[] =	"LD_BIND_NOW= ",
138 		load_elf[] =	"LD_TRACE_LOADED_OBJECTS_E= ",
139 		load_aout[] =	"LD_TRACE_LOADED_OBJECTS_A= ",
140 		path[] =	"LD_TRACE_SEARCH_PATHS= ",
141 		verb[] =	"LD_VERBOSE= ",
142 		warn[] =	"LD_WARN= ",
143 		conf[] =	"LD_NOCONFIG= ",
144 		fltr[] =	"LD_LOADFLTR= ",
145 		lazy[] =	"LD_NOLAZYLOAD=1",
146 		init[] =	"LD_INIT= ",
147 		uref[] =	"LD_UNREF= ",
148 		used[] =	"LD_UNUSED= ",
149 		weak[] =	"LD_NOUNRESWEAK= ",
150 		nope[] =	"LD_NOPAREXT= ",
151 		defr[] =	"LD_DEFERRED= ";
152 static char	*load;
153 
154 static const char	*prefile_32, *prefile_64, *prefile;
155 static APlist		*eopts = NULL;
156 
157 int
158 main(int argc, char **argv, char **envp)
159 {
160 	char	*str, *cname = argv[0];
161 
162 	Elf	*elf;
163 	int	cflag = 0, dflag = 0, fflag = 0, iflag = 0, Lflag = 0;
164 	int	lflag = 0, rflag = 0, sflag = 0, Uflag = 0, uflag = 0;
165 	int	Dflag = 0, pflag = 0, vflag = 0, wflag = 0;
166 	int	nfile, var, error = 0;
167 	Aliste	idx;
168 
169 	/*
170 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
171 	 * the binary.  If successful, conv_check_native() won't return.
172 	 *
173 	 * This is done to ensure that ldd can handle objects >2GB.
174 	 * ldd uses libelf, which is not large file capable. The
175 	 * 64-bit ldd can handle any sized object.
176 	 */
177 	(void) conv_check_native(argv, envp);
178 
179 	/*
180 	 * Establish locale.
181 	 */
182 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
183 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
184 
185 	/*
186 	 * verify command line syntax and process arguments
187 	 */
188 	opterr = 0;				/* disable getopt error mesg */
189 
190 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_GETOPT))) != EOF) {
191 		switch (var) {
192 		case 'c' :			/* enable config search */
193 			cflag = 1;
194 			break;
195 		case 'D' :			/* skip deferred dependencies */
196 			Dflag = 1;
197 			break;
198 		case 'd' :			/* perform data relocations */
199 			dflag = 1;
200 			if (rflag)
201 				error++;
202 			break;
203 		case 'e' :
204 			if (aplist_append(&eopts, optarg, 10) == NULL) {
205 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
206 				    cname);
207 				exit(1);
208 			}
209 			break;
210 		case 'f' :
211 			fflag = 1;
212 			break;
213 		case 'L' :
214 			Lflag = 1;
215 			break;
216 		case 'l' :
217 			lflag = 1;
218 			break;
219 		case 'i' :			/* print the order of .init */
220 			iflag = 1;
221 			break;
222 		case 'p' :
223 			pflag = 1;		/* expose unreferenced */
224 			break;			/*	parent or externals */
225 		case 'r' :			/* perform all relocations */
226 			rflag = 1;
227 			if (dflag)
228 				error++;
229 			break;
230 		case 's' :			/* enable search path output */
231 			sflag = 1;
232 			break;
233 		case 'U' :			/* list unreferenced */
234 			Uflag = 1;		/*	dependencies */
235 			if (uflag)
236 				error++;
237 			break;
238 		case 'u' :			/* list unused dependencies */
239 			uflag = 1;
240 			if (Uflag)
241 				error++;
242 			break;
243 		case 'v' :			/* enable verbose output */
244 			vflag = 1;
245 			break;
246 		case 'w' :			/* expose unresolved weak */
247 			wflag = 1;		/*	references */
248 			break;
249 		default :
250 			error++;
251 			break;
252 		}
253 		if (error)
254 			break;
255 	}
256 	if (error) {
257 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), cname);
258 		exit(1);
259 	}
260 
261 	/*
262 	 * Determine if any of the LD_PRELOAD family is already set in the
263 	 * environment, if so we'll continue to analyze each object with the
264 	 * appropriate setting.
265 	 */
266 	if (((prefile_32 = getenv(MSG_ORIG(MSG_LD_PRELOAD_32))) == NULL) ||
267 	    (*prefile_32 == '\0')) {
268 		prefile_32 = MSG_ORIG(MSG_STR_EMPTY);
269 	}
270 	if (((prefile_64 = getenv(MSG_ORIG(MSG_LD_PRELOAD_64))) == NULL) ||
271 	    (*prefile_64 == '\0')) {
272 		prefile_64 = MSG_ORIG(MSG_STR_EMPTY);
273 	}
274 	if (((prefile = getenv(MSG_ORIG(MSG_LD_PRELOAD))) == NULL) ||
275 	    (*prefile == '\0')) {
276 		prefile = MSG_ORIG(MSG_STR_EMPTY);
277 	}
278 
279 	/*
280 	 * Determine if any environment requests are for the LD_PRELOAD family,
281 	 * and if so override any environment settings we've established above.
282 	 */
283 	for (APLIST_TRAVERSE(eopts, idx, str)) {
284 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_32),
285 		    MSG_LD_PRELOAD_32_SIZE)) == 0) {
286 			str += MSG_LD_PRELOAD_32_SIZE;
287 			if ((*str++ == '=') && (*str != '\0'))
288 				prefile_32 = str;
289 			continue;
290 		}
291 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD_64),
292 		    MSG_LD_PRELOAD_64_SIZE)) == 0) {
293 			str += MSG_LD_PRELOAD_64_SIZE;
294 			if ((*str++ == '=') && (*str != '\0'))
295 				prefile_64 = str;
296 			continue;
297 		}
298 		if ((strncmp(str, MSG_ORIG(MSG_LD_PRELOAD),
299 		    MSG_LD_PRELOAD_SIZE)) == 0) {
300 			str += MSG_LD_PRELOAD_SIZE;
301 			if ((*str++ == '=') && (*str != '\0'))
302 				prefile = str;
303 			continue;
304 		}
305 	}
306 
307 	/*
308 	 * Set the appropriate relocation environment variables (Note unsetting
309 	 * the environment variables is done just in case the user already
310 	 * has these in their environment ... sort of thing the test folks
311 	 * would do :-)
312 	 */
313 	warn[sizeof (warn) - 2] = (dflag || rflag || Uflag || uflag) ? '1' :
314 	    '\0';
315 	bind[sizeof (bind) - 2] = (rflag) ? '1' : '\0';
316 	path[sizeof (path) - 2] = (sflag) ? '1' : '\0';
317 	verb[sizeof (verb) - 2] = (vflag) ? '1' : '\0';
318 	fltr[sizeof (fltr) - 2] = (Lflag) ? '\0' : (lflag) ? '2' : '1';
319 	init[sizeof (init) - 2] = (iflag) ? '1' : '\0';
320 	conf[sizeof (conf) - 2] = (cflag) ? '1' : '\0';
321 	lazy[sizeof (lazy) - 2] = (Lflag) ? '\0' : '1';
322 	uref[sizeof (uref) - 2] = (Uflag) ? '1' : '\0';
323 	used[sizeof (used) - 2] = (uflag) ? '1' : '\0';
324 	weak[sizeof (weak) - 2] = (wflag) ? '1' : '\0';
325 	nope[sizeof (nope) - 2] = (pflag) ? '1' : '\0';
326 	defr[sizeof (defr) - 2] = (Dflag) ? '\0' : '1';
327 
328 	/*
329 	 * coordinate libelf's version information
330 	 */
331 	if (elf_version(EV_CURRENT) == EV_NONE) {
332 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIBELF), cname,
333 		    EV_CURRENT);
334 		exit(1);
335 	}
336 
337 	/*
338 	 * Loop through remaining arguments.  Note that from here on there
339 	 * are no exit conditions so that we can process a list of files,
340 	 * any error condition is retained for a final exit status.
341 	 */
342 	nfile = argc - optind;
343 	for (; optind < argc; optind++) {
344 		char	*fname = argv[optind];
345 
346 		/*
347 		 * Open file (do this before checking access so that we can
348 		 * provide the user with better diagnostics).
349 		 */
350 		if ((var = open(fname, O_RDONLY)) == -1) {
351 			int	err = errno;
352 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), cname,
353 			    fname, strerror(err));
354 			error = 1;
355 			continue;
356 		}
357 
358 		/*
359 		 * Get the files elf descriptor and process it as an elf or
360 		 * a.out (4.x) file.
361 		 */
362 		elf = elf_begin(var, ELF_C_READ, (Elf *)0);
363 		switch (elf_kind(elf)) {
364 		case ELF_K_AR :
365 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO),
366 			    cname, fname);
367 			error = 1;
368 			break;
369 		case ELF_K_COFF:
370 			(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN),
371 			    cname, fname);
372 			error = 1;
373 			break;
374 		case ELF_K_ELF:
375 			if (elf_check(nfile, fname, cname, elf, fflag) != NULL)
376 				error = 1;
377 			break;
378 		default:
379 			/*
380 			 * This is either an unknown file or an aout format
381 			 */
382 			if (aout_check(nfile, fname, cname, var, fflag) != NULL)
383 				error = 1;
384 			break;
385 		}
386 		(void) elf_end(elf);
387 		(void) close(var);
388 	}
389 	return (error);
390 }
391 
392 
393 
394 static int
395 elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
396 {
397 	Conv_inv_buf_t	inv_buf;
398 	GElf_Ehdr 	ehdr;
399 	GElf_Phdr 	phdr;
400 	int		dynamic = 0, interp = 0, cnt, class;
401 
402 	/*
403 	 * verify information in file header
404 	 */
405 	if (gelf_getehdr(elf, &ehdr) == NULL) {
406 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETEHDR),
407 		    cname, fname, elf_errmsg(-1));
408 		return (1);
409 	}
410 
411 	/*
412 	 * Compatible machine
413 	 */
414 	if ((ehdr.e_machine != M_MACH_32) && (ehdr.e_machine != M_MACH_64) &&
415 	    (ehdr.e_machine != M_MACHPLUS)) {
416 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHTYPE), cname, fname,
417 		    conv_ehdr_mach(ehdr.e_machine, 0, &inv_buf));
418 		return (1);
419 	}
420 
421 	/*
422 	 * Compatible encoding (byte order)
423 	 */
424 	if (ehdr.e_ident[EI_DATA] != M_DATA) {
425 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_DATA), cname, fname,
426 		    conv_ehdr_data(ehdr.e_ident[EI_DATA], 0, &inv_buf));
427 		return (1);
428 	}
429 
430 	/*
431 	 * Compatible class
432 	 */
433 	switch (class = ehdr.e_ident[EI_CLASS]) {
434 	case ELFCLASS32:
435 		/*
436 		 * If M_MACH is not the same thing as M_MACHPLUS and this
437 		 * is an M_MACHPLUS object, then the corresponding header
438 		 * flag must be set.
439 		 */
440 		if ((ehdr.e_machine != M_MACH) &&
441 		    ((ehdr.e_flags & M_FLAGSPLUS) == 0)) {
442 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MACHFLAGS),
443 			    cname, fname);
444 			return (1);
445 		}
446 		break;
447 	case ELFCLASS64:
448 		/* Requires 64-bit kernel */
449 		if (conv_sys_eclass() == ELFCLASS32) {
450 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_KCLASS32),
451 			    cname, fname, conv_ehdr_class(class, 0, &inv_buf));
452 			return (1);
453 		}
454 		break;
455 	default:
456 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_CLASS), cname, fname,
457 		    conv_ehdr_class(class, 0, &inv_buf));
458 		return (1);
459 	}
460 
461 	/*
462 	 * Object type
463 	 */
464 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN) &&
465 	    (ehdr.e_type != ET_REL)) {
466 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_BADMAGIC),
467 		    cname, fname);
468 		return (1);
469 	}
470 
471 	/*
472 	 * Check that the file is executable.  Dynamic executables must be
473 	 * executable to be exec'ed.  Shared objects need not be executable to
474 	 * be mapped with a dynamic executable, however, by convention they're
475 	 * supposed to be executable.
476 	 */
477 	if (access(fname, X_OK) != 0) {
478 		if (ehdr.e_type == ET_EXEC) {
479 			(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_1),
480 			    cname, fname);
481 			return (1);
482 		}
483 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOTEXEC_2), cname,
484 		    fname);
485 	}
486 
487 	/*
488 	 * Determine whether we have a dynamic section or interpretor.
489 	 */
490 	for (cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) {
491 		if (dynamic && interp)
492 			break;
493 
494 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
495 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETPHDR),
496 			    cname, fname, elf_errmsg(-1));
497 			return (1);
498 		}
499 
500 		if (phdr.p_type == PT_DYNAMIC) {
501 			dynamic = 1;
502 			continue;
503 		}
504 
505 		if (phdr.p_type != PT_INTERP)
506 			continue;
507 
508 		interp = 1;
509 
510 		/*
511 		 * If fflag is not set, and euid == root, and the interpreter
512 		 * does not live under /lib, /usr/lib or /etc/lib then don't
513 		 * allow ldd to execute the image.  This prevents someone
514 		 * creating a `trojan horse' by substituting their own
515 		 * interpreter that could preform privileged operations
516 		 * when ldd is against it.
517 		 */
518 		if ((fflag == 0) && (geteuid() == 0) &&
519 		    (strcmp(fname, conv_lddstub(class)) != 0)) {
520 			char	*interpreter;
521 
522 			/*
523 			 * Does the interpreter live under a trusted directory.
524 			 */
525 			interpreter = elf_getident(elf, 0) + phdr.p_offset;
526 
527 			if ((strncmp(interpreter, MSG_ORIG(MSG_PTH_USRLIB),
528 			    MSG_PTH_USRLIB_SIZE) != 0) &&
529 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_LIB),
530 			    MSG_PTH_LIB_SIZE) != 0) &&
531 			    (strncmp(interpreter, MSG_ORIG(MSG_PTH_ETCLIB),
532 			    MSG_PTH_ETCLIB_SIZE) != 0)) {
533 				(void) fprintf(stderr, MSG_INTL(MSG_USP_ELFINS),
534 				    cname, fname, interpreter);
535 				return (1);
536 			}
537 		}
538 	}
539 
540 	/*
541 	 * Catch the case of a static executable (ie, an ET_EXEC that has a set
542 	 * of program headers but no PT_DYNAMIC).
543 	 */
544 	if (ehdr.e_phnum && !dynamic) {
545 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
546 		    fname);
547 		return (1);
548 	}
549 
550 	/*
551 	 * If there is a dynamic section, then check for the DF_1_NOHDR
552 	 * flag, and bail if it is present. Such objects are created using
553 	 * a mapfile option (?N in the version 1 syntax, or HDR_NOALLOC
554 	 * otherwise). The ELF header and program headers are
555 	 * not mapped as part of the first segment, and virtual addresses
556 	 * are computed without them. If ldd tries to interpret such
557 	 * a file, it will become confused and generate bad output or
558 	 * crash. Such objects are always special purpose files (like an OS
559 	 * kernel) --- files for which the ldd operation doesn't make sense.
560 	 */
561 	if (dynamic && (_gelf_getdyndtflags_1(elf) & DF_1_NOHDR)) {
562 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NOHDR), cname,
563 		    fname);
564 		return (1);
565 	}
566 
567 	load = load_elf;
568 
569 	/*
570 	 * Run the required program (shared and relocatable objects require the
571 	 * use of lddstub).
572 	 */
573 	if ((ehdr.e_type == ET_EXEC) && interp)
574 		return (run(nfile, cname, fname, (const char *)fname, class));
575 	else
576 		return (run(nfile, cname, fname, conv_lddstub(class), class));
577 }
578 
579 static int
580 aout_check(int nfile, char *fname, char *cname, int fd, int fflag)
581 {
582 	struct exec32	aout;
583 	int		err;
584 
585 	if (lseek(fd, 0, SEEK_SET) != 0) {
586 		err = errno;
587 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname,
588 		    strerror(err));
589 		return (1);
590 	}
591 	if (read(fd, (char *)&aout, sizeof (aout)) != sizeof (aout)) {
592 		err = errno;
593 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname,
594 		    strerror(err));
595 		return (1);
596 	}
597 	if (aout.a_machtype != M_SPARC) {
598 		(void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname);
599 		return (1);
600 	}
601 	if (N_BADMAG(aout) || !aout.a_dynamic) {
602 		(void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname,
603 		    fname);
604 		return (1);
605 	}
606 	if (!fflag && (geteuid() == 0)) {
607 		(void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname);
608 		return (1);
609 	}
610 
611 	/*
612 	 * Run the required program.
613 	 */
614 	if ((aout.a_magic == ZMAGIC) && (aout.a_entry <= sizeof (aout))) {
615 		load = load_elf;
616 		return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32),
617 		    ELFCLASS32));
618 	} else {
619 		load = load_aout;
620 		return (run(nfile, cname, fname, (const char *)fname,
621 		    ELFCLASS32));
622 	}
623 }
624 
625 
626 /*
627  * Run the required program, setting the preload and trace environment
628  * variables accordingly.
629  */
630 static int
631 run(int nfile, char *cname, char *fname, const char *ename, int class)
632 {
633 	const char	*preload = 0;
634 	int		pid, status;
635 
636 	if ((pid = fork()) == -1) {
637 		int	err = errno;
638 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), cname,
639 		    strerror(err));
640 		return (1);
641 	}
642 
643 	if (pid) {				/* parent */
644 		while (wait(&status) != pid)
645 			;
646 		if (WIFSIGNALED(status) && ((WSIGMASK & status) != SIGPIPE)) {
647 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
648 			    fname);
649 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_SIG),
650 			    (WSIGMASK & status), ((status & WCOREFLG) ?
651 			    MSG_INTL(MSG_SYS_EXEC_CORE) :
652 			    MSG_ORIG(MSG_STR_EMPTY)));
653 			status = 1;
654 		} else if (WHIBYTE(status)) {
655 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
656 			    fname);
657 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC_STAT),
658 			    WHIBYTE(status));
659 			status = 1;
660 		}
661 	} else {				/* child */
662 		Aliste	idx;
663 		char	*str;
664 		size_t	size;
665 
666 		/*
667 		 * When using ldd(1) to analyze a shared object we preload the
668 		 * shared object with lddstub.  Any additional preload
669 		 * requirements are added after the object being analyzed, this
670 		 * allows us to skip the first object but produce diagnostics
671 		 * for each other preloaded object.
672 		 */
673 		if (fname != ename) {
674 			char		*str;
675 			const char	*files = prefile;
676 			const char	*format = MSG_ORIG(MSG_STR_FMT1);
677 
678 			for (str = fname; *str; str++)
679 				if (*str == '/') {
680 					format = MSG_ORIG(MSG_STR_FMT2);
681 					break;
682 			}
683 
684 			preload = MSG_ORIG(MSG_LD_PRELOAD);
685 
686 			/*
687 			 * Determine which preload files and preload environment
688 			 * variable to use.
689 			 */
690 			if (class == ELFCLASS64) {
691 				if (prefile_64 != MSG_ORIG(MSG_STR_EMPTY)) {
692 					files = prefile_64;
693 					preload = MSG_ORIG(MSG_LD_PRELOAD_64);
694 				}
695 			} else {
696 				if (prefile_32 != MSG_ORIG(MSG_STR_EMPTY)) {
697 					files = prefile_32;
698 					preload = MSG_ORIG(MSG_LD_PRELOAD_32);
699 				}
700 			}
701 
702 			if ((str = (char *)malloc(strlen(preload) +
703 			    strlen(fname) + strlen(files) + 5)) == 0) {
704 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
705 				    cname);
706 				exit(1);
707 			}
708 
709 			(void) sprintf(str, format, preload, fname, files);
710 			if (putenv(str) != 0) {
711 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
712 				    cname);
713 				exit(1);
714 			}
715 
716 			/*
717 			 * The pointer "load" has be assigned to load_elf[] or
718 			 * load_aout[].  Use the size of load_elf[] as the size
719 			 * of load_aout[] is the same.
720 			 */
721 			load[sizeof (load_elf) - 2] = '2';
722 		} else
723 			load[sizeof (load_elf) - 2] = '1';
724 
725 
726 		/*
727 		 * Establish new environment variables to affect the child
728 		 * process.
729 		 */
730 		if ((putenv(warn) != 0) || (putenv(bind) != 0) ||
731 		    (putenv(path) != 0) || (putenv(verb) != 0) ||
732 		    (putenv(fltr) != 0) || (putenv(conf) != 0) ||
733 		    (putenv(init) != 0) || (putenv(lazy) != 0) ||
734 		    (putenv(uref) != 0) || (putenv(used) != 0) ||
735 		    (putenv(weak) != 0) || (putenv(load) != 0) ||
736 		    (putenv(nope) != 0) || (putenv(defr) != 0)) {
737 			(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED), cname);
738 			exit(1);
739 		}
740 
741 		/*
742 		 * Establish explicit environment requires (but don't override
743 		 * any preload request established to process a shared object).
744 		 */
745 		size = 0;
746 		for (APLIST_TRAVERSE(eopts, idx, str)) {
747 			if (preload) {
748 				if (size == 0)
749 					size = strlen(preload);
750 				if ((strncmp(preload, str, size) == 0) &&
751 				    (str[size] == '=')) {
752 					continue;
753 				}
754 			}
755 			if (putenv(str) != 0) {
756 				(void) fprintf(stderr, MSG_INTL(MSG_ENV_FAILED),
757 				    cname);
758 				exit(1);
759 			}
760 		}
761 
762 		/*
763 		 * Execute the object and let ld.so.1 do the rest.
764 		 */
765 		if (nfile > 1)
766 			(void) printf(MSG_ORIG(MSG_STR_FMT3), fname);
767 		(void) fflush(stdout);
768 		if ((execl(ename, ename, (char *)0)) == -1) {
769 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_EXEC), cname,
770 			    fname);
771 			perror(ename);
772 			_exit(0);
773 			/* NOTREACHED */
774 		}
775 	}
776 	return (status);
777 }
778 
779 const char *
780 _ldd_msg(Msg mid)
781 {
782 	return (gettext(MSG_ORIG(mid)));
783 }
784