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