xref: /illumos-gate/usr/src/cmd/sgs/libld/common/debug.c (revision e23c41c9)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include	<stdio.h>
28 #include	<stdarg.h>
29 #include	<errno.h>
30 #include	<strings.h>
31 #include	<dlfcn.h>
32 #include	<debug.h>
33 #include	"msg.h"
34 
35 /*
36  * dbg_setup() can be called a number of times.  The typical use through
37  * LD_OPTIONS, results in dbg_setup() being called as the first argument to
38  * ld(1).  It's also possible to pass debugging tokens through the compiler,
39  * for example -Wl,-Dlibs -Wl-Ddetail, in which case multiple dbg_setup()
40  * calls are made.
41  *
42  * A distinction is also made between diagnostics being requested before any
43  * other ld(1) options are read, or whether the debugging options occur
44  * between other options on the command line.  In the latter case, the
45  * debugging options can be used to isolate diagnostics around one or more
46  * input files.  The "phase" argument allows us to select which phase of
47  * dbg_setup() processing we should isolate ourselves to.
48  *
49  * dbg_print() can require the output filename for use in the diagnostics
50  * created.  Save the address of the output filename pointer for this use.
51  */
52 static const char	**Name = NULL;
53 static int		Phase = 0;
54 
55 /* Debug file output state */
56 static struct {
57 	FILE	*fptr;	/* File to send debug output */
58 	int	close_needed;	/* True if explicitly opened stream */
59 } dbg_ofile = {
60 	stderr,
61 	0
62 };
63 
64 
65 /*
66  * If there is an explicitly opened debug file, close it and reset the state.
67  */
68 void
69 dbg_cleanup(void)
70 {
71 	if (dbg_ofile.close_needed) {
72 		(void) fclose(dbg_ofile.fptr);
73 		dbg_ofile.close_needed = 0;
74 		dbg_ofile.fptr = stderr;
75 	}
76 }
77 
78 /*
79  * Process debug tokens. Returns True (1) on success, and False (0)
80  * on failure.
81  */
82 int
83 dbg_setup(Ofl_desc *ofl, const char *options, int phase)
84 {
85 	const char	*ofile;
86 
87 	if (Phase == 0)
88 		Phase = phase;
89 	else if (Phase != phase)
90 		return (1);
91 
92 	Name = &ofl->ofl_name;
93 
94 	/*
95 	 * Call the debugging setup routine to initialize the mask and
96 	 * debug function array.
97 	 */
98 	if (Dbg_setup(DBG_CALLER_LD, options, dbg_desc, &ofile) == 0)
99 		return (0);
100 
101 	/*
102 	 * If output= token was used, close the old file if necessary
103 	 * and open a new one if the file name is not NULL.
104 	 */
105 	if (ofile) {
106 		dbg_cleanup();
107 		if (*ofile != '\0') {
108 			FILE *fptr = fopen(ofile, MSG_ORIG(MSG_DBG_FOPEN_MODE));
109 			if (fptr == NULL) {
110 				int	err = errno;
111 
112 				eprintf(ofl->ofl_lml, ERR_FATAL,
113 				    MSG_INTL(MSG_SYS_OPEN), ofile,
114 				    strerror(err));
115 				return (0);
116 			} else {
117 				dbg_ofile.fptr = fptr;
118 				dbg_ofile.close_needed = 1;
119 			}
120 		}
121 	}
122 
123 	/*
124 	 * Now that the output file is established, generate help
125 	 * output if the user specified the debug help token.
126 	 */
127 	if (dbg_desc->d_extra & DBG_E_HELP)
128 		Dbg_help();
129 
130 	return (1);
131 }
132 
133 /* PRINTFLIKE2 */
134 void
135 dbg_print(Lm_list *lml, const char *format, ...)
136 {
137 	static char	*prestr = NULL;
138 	va_list		args;
139 
140 #if	defined(lint)
141 	/*
142 	 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
143 	 * Supress the lint error by making a dummy assignment.
144 	 */
145 	lml = NULL;
146 #endif
147 	/*
148 	 * Knock off any newline indicator to signify that a diagnostic has
149 	 * been processed.
150 	 */
151 	dbg_desc->d_extra &= ~DBG_E_STDNL;
152 
153 	if (DBG_ISSNAME()) {
154 		/*
155 		 * If the debugging options have requested each diagnostic line
156 		 * be prepended by a name create a prefix string.
157 		 */
158 		if ((prestr == NULL) && *Name) {
159 			const char	*name, *cls;
160 			size_t		len;
161 
162 			/*
163 			 * Select the fullname or basename of the output file
164 			 * being created.
165 			 */
166 			if (DBG_ISFNAME())
167 				name = *Name;
168 			else {
169 				if ((name =
170 				    strrchr(*Name, '/')) == NULL)
171 					name = *Name;
172 				else
173 					name++;
174 			}
175 			len = strlen(name) +
176 			    strlen(MSG_INTL(MSG_DBG_NAME_FMT)) + 1;
177 
178 			/*
179 			 * Add the output file class if required.
180 			 */
181 			if (DBG_ISCLASS()) {
182 #if	defined(_ELF64)
183 				len += MSG_DBG_CLS64_FMT_SIZE;
184 				cls = MSG_ORIG(MSG_DBG_CLS64_FMT);
185 #else
186 				len += MSG_DBG_CLS32_FMT_SIZE;
187 				cls = MSG_ORIG(MSG_DBG_CLS32_FMT);
188 #endif
189 			}
190 
191 			/*
192 			 * Allocate a string to build the prefix.
193 			 */
194 			if ((prestr = libld_malloc(len)) == NULL)
195 				prestr = (char *)MSG_INTL(MSG_DBG_DFLT_FMT);
196 			else {
197 				(void) snprintf(prestr, len,
198 				    MSG_INTL(MSG_DBG_NAME_FMT), name);
199 				if (DBG_ISCLASS())
200 					(void) strcat(prestr, cls);
201 			}
202 		}
203 		(void) fputs(prestr ? prestr : MSG_INTL(MSG_DBG_AOUT_FMT),
204 		    dbg_ofile.fptr);
205 	} else
206 		(void) fputs(MSG_INTL(MSG_DBG_DFLT_FMT), dbg_ofile.fptr);
207 
208 	va_start(args, format);
209 	(void) vfprintf(dbg_ofile.fptr, format, args);
210 	(void) fprintf(dbg_ofile.fptr, MSG_ORIG(MSG_STR_NL));
211 	va_end(args);
212 }
213