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