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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #define		dgettext	_dgettext
29 
30 #include	<libintl.h>
31 #include	<sys/varargs.h>
32 #include	<stdio.h>
33 #include	<string.h>
34 #include	<stdlib.h>
35 #include	<alist.h>
36 #include	<debug.h>
37 #include	<_debug.h>
38 #include	<msg.h>
39 
40 /*
41  * Define a debug descriptor.  Note, although this provides the default
42  * definition to which most users bind, ld.so.1 must provide its own definition,
43  * and thus interposition is expected.  This item should be defined NODIRECT.
44  */
45 static Dbg_desc	_dbg_desc = { 0, 0, 0 };
46 Dbg_desc	*dbg_desc = &_dbg_desc;
47 
48 int		_Dbg_cnt = 0;
49 
50 /*
51  * Debugging initialization and processing.  The dbg_options[] array defines
52  * a set of option strings that can be specified using the -D flag or from an
53  * environment variable.  For each option, a class is enabled in the d_class
54  * bit mask, or an extra flag is enabled in the d_extra bit mask.
55  */
56 DBG_options _Dbg_options[] = {
57 	{MSG_ORIG(MSG_TOK_DETAIL),	0,	DBG_E_DETAIL},
58 	{MSG_ORIG(MSG_TOK_LONG),	0,	DBG_E_LONG},
59 	{MSG_ORIG(MSG_TOK_NAME),	0,	DBG_E_SNAME},
60 	{MSG_ORIG(MSG_TOK_FULLNAME),	0,	DBG_E_SNAME | DBG_E_FNAME},
61 	{MSG_ORIG(MSG_TOK_CLASS),	0,	DBG_E_SNAME | DBG_E_CLASS},
62 	{MSG_ORIG(MSG_TOK_LMID),	0,	DBG_E_LMID},
63 
64 	{MSG_ORIG(MSG_TOK_ALL),		DBG_C_ALL,	0},
65 	{MSG_ORIG(MSG_TOK_ARGS),	DBG_C_ARGS,	0},
66 	{MSG_ORIG(MSG_TOK_BASIC),	DBG_C_BASIC,	0},
67 	{MSG_ORIG(MSG_TOK_BINDINGS),	DBG_C_BINDINGS,	0},
68 	{MSG_ORIG(MSG_TOK_ENTRY),	DBG_C_ENTRY,	0},
69 	{MSG_ORIG(MSG_TOK_FILES),	DBG_C_FILES,	0},
70 	{MSG_ORIG(MSG_TOK_HELP),	DBG_C_HELP,	0},
71 	{MSG_ORIG(MSG_TOK_LIBS),	DBG_C_LIBS,	0},
72 	{MSG_ORIG(MSG_TOK_MAP),		DBG_C_MAP,	0},
73 	{MSG_ORIG(MSG_TOK_RELOC),	DBG_C_RELOC,	0},
74 	{MSG_ORIG(MSG_TOK_SECTIONS),	DBG_C_SECTIONS,	0},
75 	{MSG_ORIG(MSG_TOK_SEGMENTS),	DBG_C_SEGMENTS,	0},
76 	{MSG_ORIG(MSG_TOK_SUPPORT),	DBG_C_SUPPORT,	0},
77 	{MSG_ORIG(MSG_TOK_SYMBOLS),	DBG_C_SYMBOLS,	0},
78 	{MSG_ORIG(MSG_TOK_TLS),		DBG_C_TLS,	0},
79 	{MSG_ORIG(MSG_TOK_AUDIT),	DBG_C_AUDITING,	0},
80 	{MSG_ORIG(MSG_TOK_VERSIONS),	DBG_C_VERSIONS,	0},
81 	{MSG_ORIG(MSG_TOK_GOT),		DBG_C_GOT,	0},
82 	{MSG_ORIG(MSG_TOK_MOVE),	DBG_C_MOVE,	0},
83 	{MSG_ORIG(MSG_TOK_STRTAB),	DBG_C_STRTAB,	0},
84 	{MSG_ORIG(MSG_TOK_STATS),	DBG_C_STATS,	0},
85 	{MSG_ORIG(MSG_TOK_UNUSED),	DBG_C_UNUSED,	0},
86 #ifdef	DEMANGLE
87 	{MSG_ORIG(MSG_TOK_DEMANGLE),	DBG_C_DEMANGLE,	0},
88 #endif
89 	{MSG_ORIG(MSG_TOK_CAP),		DBG_C_CAP,	0},
90 	{MSG_ORIG(MSG_TOK_INIT),	DBG_C_INIT,	0},
91 	{NULL,				NULL},
92 };
93 
94 /*
95  * Tokens may also define identifiers for diagnostics.  Presently, only ld.so.1
96  * uses these strings to identify, or isolate its output to selected link-map
97  * lists.  See ld.so.1:dbg_print().
98  */
99 const char *_Dbg_strs[] = {
100 	MSG_ORIG(MSG_TOK_BASE),		MSG_ORIG(MSG_TOK_LDSO),
101 	MSG_ORIG(MSG_TOK_NEWLM),	NULL
102 };
103 
104 /*
105  * Provide a debugging usage message
106  */
107 void
108 Dbg_usage()
109 {
110 	Dbg_util_nl(0, DBG_NL_FRC);
111 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_A));
112 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_B));
113 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_C));
114 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_D));
115 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_E));
116 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_F));
117 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_G));
118 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_H));
119 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_I));
120 	Dbg_util_nl(0, DBG_NL_FRC);
121 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_J));
122 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_K));
123 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_L));
124 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_M));
125 	Dbg_util_nl(0, DBG_NL_FRC);
126 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_N));
127 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_O));
128 	Dbg_util_nl(0, DBG_NL_FRC);
129 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_P));
130 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_Q));
131 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_R));
132 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_S));
133 
134 	Dbg_util_nl(0, DBG_NL_FRC);
135 	dbg_print(0, MSG_INTL(MSG_USE_LD_A));
136 	dbg_print(0, MSG_INTL(MSG_USE_LD_B));
137 	dbg_print(0, MSG_INTL(MSG_USE_LD_C));
138 	dbg_print(0, MSG_INTL(MSG_USE_LD_D));
139 	dbg_print(0, MSG_INTL(MSG_USE_LD_E));
140 	dbg_print(0, MSG_INTL(MSG_USE_LD_F));
141 	dbg_print(0, MSG_INTL(MSG_USE_LD_G));
142 	dbg_print(0, MSG_INTL(MSG_USE_LD_H));
143 	Dbg_util_nl(0, DBG_NL_FRC);
144 	dbg_print(0, MSG_INTL(MSG_USE_LD_I));
145 	Dbg_util_nl(0, DBG_NL_FRC);
146 	dbg_print(0, MSG_INTL(MSG_USE_LD_J));
147 	dbg_print(0, MSG_INTL(MSG_USE_LD_K));
148 	Dbg_util_nl(0, DBG_NL_FRC);
149 	dbg_print(0, MSG_INTL(MSG_USE_LD_L));
150 	Dbg_util_nl(0, DBG_NL_FRC);
151 	dbg_print(0, MSG_INTL(MSG_USE_LD_M));
152 	dbg_print(0, MSG_INTL(MSG_USE_LD_N));
153 	dbg_print(0, MSG_INTL(MSG_USE_LD_O));
154 
155 	Dbg_util_nl(0, DBG_NL_FRC);
156 	Dbg_util_nl(0, DBG_NL_FRC);
157 	dbg_print(0, MSG_INTL(MSG_USE_ARGS));
158 	dbg_print(0, MSG_INTL(MSG_USE_AUDIT));
159 	dbg_print(0, MSG_INTL(MSG_USE_BASIC));
160 	dbg_print(0, MSG_INTL(MSG_USE_BINDINGS));
161 	dbg_print(0, MSG_INTL(MSG_USE_BINDINGS_2));
162 	dbg_print(0, MSG_INTL(MSG_USE_CAP));
163 	dbg_print(0, MSG_INTL(MSG_USE_DETAIL));
164 #ifdef	DEMANGLE
165 	dbg_print(0, MSG_INTL(MSG_USE_DEMANGLE));
166 #endif
167 	dbg_print(0, MSG_INTL(MSG_USE_ENTRY));
168 	dbg_print(0, MSG_INTL(MSG_USE_FILES));
169 	dbg_print(0, MSG_INTL(MSG_USE_GOT));
170 	dbg_print(0, MSG_INTL(MSG_USE_HELP));
171 	dbg_print(0, MSG_INTL(MSG_USE_INIT));
172 	dbg_print(0, MSG_INTL(MSG_USE_LIBS));
173 	dbg_print(0, MSG_INTL(MSG_USE_LIBS_2));
174 	dbg_print(0, MSG_INTL(MSG_USE_LMID));
175 	dbg_print(0, MSG_INTL(MSG_USE_LONG));
176 	dbg_print(0, MSG_INTL(MSG_USE_MAP));
177 	dbg_print(0, MSG_INTL(MSG_USE_MOVE));
178 	dbg_print(0, MSG_INTL(MSG_USE_RELOC));
179 	dbg_print(0, MSG_INTL(MSG_USE_SECTIONS));
180 	dbg_print(0, MSG_INTL(MSG_USE_SEGMENTS));
181 	dbg_print(0, MSG_INTL(MSG_USE_SEGMENTS_2));
182 	dbg_print(0, MSG_INTL(MSG_USE_STATS));
183 	dbg_print(0, MSG_INTL(MSG_USE_STRTAB));
184 	dbg_print(0, MSG_INTL(MSG_USE_STRTAB_2));
185 	dbg_print(0, MSG_INTL(MSG_USE_SUPPORT));
186 	dbg_print(0, MSG_INTL(MSG_USE_SYMBOLS));
187 	dbg_print(0, MSG_INTL(MSG_USE_SYMBOLS_2));
188 	dbg_print(0, MSG_INTL(MSG_USE_TLS));
189 	dbg_print(0, MSG_INTL(MSG_USE_UNUSED));
190 	dbg_print(0, MSG_INTL(MSG_USE_UNUSED_2));
191 	dbg_print(0, MSG_INTL(MSG_USE_VERSIONS));
192 	Dbg_util_nl(0, DBG_NL_FRC);
193 }
194 
195 /*
196  * Messaging support - funnel everything through dgettext() as this provides
197  * the real binding to libc.
198  */
199 const char *
200 _liblddbg_msg(Msg mid)
201 {
202 	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
203 }
204 
205 /*
206  * Validate and enable the appropriate debugging classes.
207  */
208 uintptr_t
209 Dbg_setup(const char *string, Dbg_desc *dbp)
210 {
211 	char		*name, *_name;	/* buffer in which to perform */
212 					/* strtok_r() operations. */
213 	char		*lasts;
214 	const char	*delimit = MSG_ORIG(MSG_STR_DELIMIT);
215 
216 	if ((_name = (char *)malloc(strlen(string) + 1)) == 0)
217 		return (S_ERROR);
218 	(void) strcpy(_name, string);
219 
220 	/*
221 	 * The token should be of the form "-Dtok,tok,tok,...".  Separate the
222 	 * pieces and build up the appropriate mask, unrecognized options are
223 	 * flagged.
224 	 */
225 	if ((name = strtok_r(_name, delimit, &lasts)) != NULL) {
226 		do {
227 			DBG_options	*opt;
228 			const char	*str;
229 			Boolean		set, found = FALSE;
230 			int		ndx = 0;
231 
232 			if (name[0] == '!') {
233 				set = FALSE;
234 				name++;
235 			} else
236 				set = TRUE;
237 
238 			/*
239 			 * First, determine if the token represents a class or
240 			 * extra.
241 			 */
242 			for (opt = _Dbg_options; opt->o_name != NULL; opt++) {
243 				if (strcmp(name, opt->o_name) != 0)
244 					continue;
245 
246 				if (set == TRUE) {
247 					if (opt->o_class)
248 						dbp->d_class |= opt->o_class;
249 					if (opt->o_extra)
250 						dbp->d_extra |= opt->o_extra;
251 				} else {
252 					if (opt->o_class)
253 						dbp->d_class &= ~(opt->o_class);
254 					if (opt->o_extra)
255 						dbp->d_extra &= ~(opt->o_extra);
256 				}
257 				found = TRUE;
258 				break;
259 			}
260 			if (found == TRUE)
261 				continue;
262 
263 			/*
264 			 * Second, determine if the token represents a known
265 			 * diagnostic identifier.  Note, newlm identifiers are
266 			 * typically followed by a numeric id, for example
267 			 * newlm1, newlm2 ...  Thus we only compare the
268 			 * initial text of the string.
269 			 */
270 			while ((str = _Dbg_strs[ndx++]) != NULL)  {
271 				char	*tup;
272 
273 				if (strncmp(name, str, strlen(str)) != 0)
274 					continue;
275 
276 				/*
277 				 * Translate lmid identifier to uppercase.
278 				 */
279 				for (tup = name; *tup; tup++) {
280 					if ((*tup >= 'a') && (*tup <= 'z'))
281 						*tup = *tup - ('a' - 'A');
282 				}
283 
284 				/*
285 				 * Save this lmid.  The whole token buffer has
286 				 * been reallocated, so these names will remain
287 				 * once this routine returns.
288 				 */
289 				if (aplist_append(&dbp->d_list, name,
290 				    AL_CNT_DEBUG) == 0)
291 					return (S_ERROR);
292 
293 				found = TRUE;
294 				break;
295 			}
296 
297 			if (found == FALSE)
298 				dbg_print(0, MSG_INTL(MSG_USE_UNRECOG), name);
299 
300 		} while ((name = strtok_r(NULL, delimit, &lasts)) != NULL);
301 	}
302 
303 	/*
304 	 * If the debug help option was specified dump a usage message.  If
305 	 * this is the only debug class, return an indication that the user
306 	 * should exit.
307 	 */
308 	if ((_Dbg_cnt++ == 0) && (dbp->d_class & DBG_C_HELP)) {
309 		Dbg_usage();
310 		if (dbp->d_class == DBG_C_HELP)
311 			return (0);
312 	}
313 	return (1);
314 }
315 
316 /*
317  * Define our own printing routine.  This provides a basic fallback, as ld(1)
318  * and ld.so.1(1) provide their own routines that augment their diagnostic
319  * output, and direct the output to stderr.  This item should be defined
320  * NODIRECT.
321  */
322 /* PRINTFLIKE2 */
323 void
324 dbg_print(Lm_list *lml, const char *format, ...)
325 {
326 	va_list ap;
327 
328 #if	defined(lint)
329 	/*
330 	 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
331 	 * Supress the lint error by making a dummy assignment.
332 	 */
333 	lml = 0;
334 #endif
335 	va_start(ap, format);
336 	(void) vprintf(format, ap);
337 	(void) printf(MSG_ORIG(MSG_STR_NL));
338 	va_end(ap);
339 }
340