xref: /illumos-gate/usr/src/cmd/sgs/libld/common/debug.c (revision 6a634c9d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
23*1007fd6fSAli Bahrami  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include	<stdio.h>
275aefb655Srie #include	<stdarg.h>
28e23c41c9SAli Bahrami #include	<errno.h>
295aefb655Srie #include	<strings.h>
307c478bd9Sstevel@tonic-gate #include	<dlfcn.h>
315aefb655Srie #include	<debug.h>
322017c965SRod Evans #include	<conv.h>
335aefb655Srie #include	"msg.h"
34*1007fd6fSAli Bahrami #include	"_libld.h"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /*
375aefb655Srie  * dbg_setup() can be called a number of times.  The typical use through
385aefb655Srie  * LD_OPTIONS, results in dbg_setup() being called as the first argument to
395aefb655Srie  * ld(1).  It's also possible to pass debugging tokens through the compiler,
405aefb655Srie  * for example -Wl,-Dlibs -Wl-Ddetail, in which case multiple dbg_setup()
415aefb655Srie  * calls are made.
425aefb655Srie  *
435aefb655Srie  * A distinction is also made between diagnostics being requested before any
445aefb655Srie  * other ld(1) options are read, or whether the debugging options occur
455aefb655Srie  * between other options on the command line.  In the latter case, the
465aefb655Srie  * debugging options can be used to isolate diagnostics around one or more
475aefb655Srie  * input files.  The "phase" argument allows us to select which phase of
485aefb655Srie  * dbg_setup() processing we should isolate ourselves to.
495aefb655Srie  *
505aefb655Srie  * dbg_print() can require the output filename for use in the diagnostics
515aefb655Srie  * created.  Save the address of the output filename pointer for this use.
527c478bd9Sstevel@tonic-gate  */
536b3ba5bdSAli Bahrami static const char	**Name = NULL;
545aefb655Srie static int		Phase = 0;
557c478bd9Sstevel@tonic-gate 
56e23c41c9SAli Bahrami /* Debug file output state */
57e23c41c9SAli Bahrami static struct {
58e23c41c9SAli Bahrami 	FILE	*fptr;	/* File to send debug output */
59e23c41c9SAli Bahrami 	int	close_needed;	/* True if explicitly opened stream */
60e23c41c9SAli Bahrami } dbg_ofile = {
61e23c41c9SAli Bahrami 	stderr,
62e23c41c9SAli Bahrami 	0
63e23c41c9SAli Bahrami };
64e23c41c9SAli Bahrami 
65e23c41c9SAli Bahrami 
66e23c41c9SAli Bahrami /*
67e23c41c9SAli Bahrami  * If there is an explicitly opened debug file, close it and reset the state.
68e23c41c9SAli Bahrami  */
69e23c41c9SAli Bahrami void
dbg_cleanup(void)70e23c41c9SAli Bahrami dbg_cleanup(void)
71e23c41c9SAli Bahrami {
72e23c41c9SAli Bahrami 	if (dbg_ofile.close_needed) {
73e23c41c9SAli Bahrami 		(void) fclose(dbg_ofile.fptr);
74e23c41c9SAli Bahrami 		dbg_ofile.close_needed = 0;
75e23c41c9SAli Bahrami 		dbg_ofile.fptr = stderr;
76e23c41c9SAli Bahrami 	}
77e23c41c9SAli Bahrami }
78e23c41c9SAli Bahrami 
79e23c41c9SAli Bahrami /*
80e23c41c9SAli Bahrami  * Process debug tokens. Returns True (1) on success, and False (0)
81e23c41c9SAli Bahrami  * on failure.
82e23c41c9SAli Bahrami  */
83e23c41c9SAli Bahrami int
dbg_setup(Ofl_desc * ofl,const char * options,int phase)84e23c41c9SAli Bahrami dbg_setup(Ofl_desc *ofl, const char *options, int phase)
857c478bd9Sstevel@tonic-gate {
86e23c41c9SAli Bahrami 	const char	*ofile;
87e23c41c9SAli Bahrami 
885aefb655Srie 	if (Phase == 0)
895aefb655Srie 		Phase = phase;
905aefb655Srie 	else if (Phase != phase)
91e23c41c9SAli Bahrami 		return (1);
927c478bd9Sstevel@tonic-gate 
93e23c41c9SAli Bahrami 	Name = &ofl->ofl_name;
945aefb655Srie 
957c478bd9Sstevel@tonic-gate 	/*
967c478bd9Sstevel@tonic-gate 	 * Call the debugging setup routine to initialize the mask and
977c478bd9Sstevel@tonic-gate 	 * debug function array.
987c478bd9Sstevel@tonic-gate 	 */
99e23c41c9SAli Bahrami 	if (Dbg_setup(DBG_CALLER_LD, options, dbg_desc, &ofile) == 0)
100e23c41c9SAli Bahrami 		return (0);
101e23c41c9SAli Bahrami 
102e23c41c9SAli Bahrami 	/*
103e23c41c9SAli Bahrami 	 * If output= token was used, close the old file if necessary
104e23c41c9SAli Bahrami 	 * and open a new one if the file name is not NULL.
105e23c41c9SAli Bahrami 	 */
106e23c41c9SAli Bahrami 	if (ofile) {
107e23c41c9SAli Bahrami 		dbg_cleanup();
108e23c41c9SAli Bahrami 		if (*ofile != '\0') {
109e23c41c9SAli Bahrami 			FILE *fptr = fopen(ofile, MSG_ORIG(MSG_DBG_FOPEN_MODE));
110e23c41c9SAli Bahrami 			if (fptr == NULL) {
111e23c41c9SAli Bahrami 				int	err = errno;
112e23c41c9SAli Bahrami 
113*1007fd6fSAli Bahrami 				ld_eprintf(ofl, ERR_FATAL,
114e23c41c9SAli Bahrami 				    MSG_INTL(MSG_SYS_OPEN), ofile,
115e23c41c9SAli Bahrami 				    strerror(err));
116e23c41c9SAli Bahrami 				return (0);
117e23c41c9SAli Bahrami 			} else {
118e23c41c9SAli Bahrami 				dbg_ofile.fptr = fptr;
119e23c41c9SAli Bahrami 				dbg_ofile.close_needed = 1;
120e23c41c9SAli Bahrami 			}
121e23c41c9SAli Bahrami 		}
122e23c41c9SAli Bahrami 	}
123e23c41c9SAli Bahrami 
124e23c41c9SAli Bahrami 	/*
12569112eddSAli Bahrami 	 * Now that the output file is established, identify the linker
12669112eddSAli Bahrami 	 * package, and generate help output if the user specified the
12769112eddSAli Bahrami 	 * debug help token.
128e23c41c9SAli Bahrami 	 */
12969112eddSAli Bahrami 	Dbg_version();
130e23c41c9SAli Bahrami 	if (dbg_desc->d_extra & DBG_E_HELP)
131e23c41c9SAli Bahrami 		Dbg_help();
132e23c41c9SAli Bahrami 
133e23c41c9SAli Bahrami 	return (1);
1345aefb655Srie }
1355aefb655Srie 
1365aefb655Srie /* PRINTFLIKE2 */
1375aefb655Srie void
dbg_print(Lm_list * lml,const char * format,...)1385aefb655Srie dbg_print(Lm_list *lml, const char *format, ...)
1395aefb655Srie {
1406b3ba5bdSAli Bahrami 	static char	*prestr = NULL;
1415aefb655Srie 	va_list		args;
1425aefb655Srie 
1435aefb655Srie #if	defined(lint)
1445aefb655Srie 	/*
1455aefb655Srie 	 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
1465aefb655Srie 	 * Supress the lint error by making a dummy assignment.
1475aefb655Srie 	 */
1486b3ba5bdSAli Bahrami 	lml = NULL;
1495aefb655Srie #endif
1505aefb655Srie 	/*
1515aefb655Srie 	 * Knock off any newline indicator to signify that a diagnostic has
1525aefb655Srie 	 * been processed.
1535aefb655Srie 	 */
1545aefb655Srie 	dbg_desc->d_extra &= ~DBG_E_STDNL;
1555aefb655Srie 
1565aefb655Srie 	if (DBG_ISSNAME()) {
1575aefb655Srie 		/*
1585aefb655Srie 		 * If the debugging options have requested each diagnostic line
1595aefb655Srie 		 * be prepended by a name create a prefix string.
1605aefb655Srie 		 */
1616b3ba5bdSAli Bahrami 		if ((prestr == NULL) && *Name) {
1625aefb655Srie 			const char	*name, *cls;
1635aefb655Srie 			size_t		len;
1645aefb655Srie 
1655aefb655Srie 			/*
1665aefb655Srie 			 * Select the fullname or basename of the output file
1675aefb655Srie 			 * being created.
1685aefb655Srie 			 */
1695aefb655Srie 			if (DBG_ISFNAME())
1705aefb655Srie 				name = *Name;
1715aefb655Srie 			else {
1725aefb655Srie 				if ((name =
1736b3ba5bdSAli Bahrami 				    strrchr(*Name, '/')) == NULL)
1745aefb655Srie 					name = *Name;
1755aefb655Srie 				else
1765aefb655Srie 					name++;
1775aefb655Srie 			}
1785aefb655Srie 			len = strlen(name) +
1795aefb655Srie 			    strlen(MSG_INTL(MSG_DBG_NAME_FMT)) + 1;
1805aefb655Srie 
1815aefb655Srie 			/*
1825aefb655Srie 			 * Add the output file class if required.
1835aefb655Srie 			 */
1845aefb655Srie 			if (DBG_ISCLASS()) {
1855aefb655Srie #if	defined(_ELF64)
1865aefb655Srie 				len += MSG_DBG_CLS64_FMT_SIZE;
1875aefb655Srie 				cls = MSG_ORIG(MSG_DBG_CLS64_FMT);
1885aefb655Srie #else
1895aefb655Srie 				len += MSG_DBG_CLS32_FMT_SIZE;
1905aefb655Srie 				cls = MSG_ORIG(MSG_DBG_CLS32_FMT);
1915aefb655Srie #endif
1925aefb655Srie 			}
1935aefb655Srie 
1945aefb655Srie 			/*
1955aefb655Srie 			 * Allocate a string to build the prefix.
1965aefb655Srie 			 */
1976b3ba5bdSAli Bahrami 			if ((prestr = libld_malloc(len)) == NULL)
1985aefb655Srie 				prestr = (char *)MSG_INTL(MSG_DBG_DFLT_FMT);
1995aefb655Srie 			else {
2005aefb655Srie 				(void) snprintf(prestr, len,
2015aefb655Srie 				    MSG_INTL(MSG_DBG_NAME_FMT), name);
2025aefb655Srie 				if (DBG_ISCLASS())
2035aefb655Srie 					(void) strcat(prestr, cls);
2045aefb655Srie 			}
2055aefb655Srie 		}
206e23c41c9SAli Bahrami 		(void) fputs(prestr ? prestr : MSG_INTL(MSG_DBG_AOUT_FMT),
207e23c41c9SAli Bahrami 		    dbg_ofile.fptr);
2085aefb655Srie 	} else
209e23c41c9SAli Bahrami 		(void) fputs(MSG_INTL(MSG_DBG_DFLT_FMT), dbg_ofile.fptr);
2105aefb655Srie 
2112017c965SRod Evans 	if (DBG_ISTIME()) {
2122017c965SRod Evans 		Conv_time_buf_t	buf;
2132017c965SRod Evans 		struct timeval	new;
2142017c965SRod Evans 
2152017c965SRod Evans 		if (gettimeofday(&new, NULL) == 0) {
2162017c965SRod Evans 			if (DBG_ISTTIME())
2172017c965SRod Evans 				(void) fputs(conv_time(&DBG_TOTALTIME, &new,
2182017c965SRod Evans 				    &buf), stderr);
2192017c965SRod Evans 			if (DBG_ISDTIME())
2202017c965SRod Evans 				(void) fputs(conv_time(&DBG_DELTATIME, &new,
2212017c965SRod Evans 				    &buf), stderr);
2222017c965SRod Evans 
2232017c965SRod Evans 			DBG_DELTATIME = new;
2242017c965SRod Evans 		}
2252017c965SRod Evans 	}
2262017c965SRod Evans 
2275aefb655Srie 	va_start(args, format);
228e23c41c9SAli Bahrami 	(void) vfprintf(dbg_ofile.fptr, format, args);
229e23c41c9SAli Bahrami 	(void) fprintf(dbg_ofile.fptr, MSG_ORIG(MSG_STR_NL));
2305aefb655Srie 	va_end(args);
2317c478bd9Sstevel@tonic-gate }
232