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