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