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