xref: /illumos-gate/usr/src/cmd/sgs/liblddbg/common/debug.c (revision 6e375c8351497b82ffa4f33cbf61d712999b4605)
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 <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 	{MSG_ORIG(MSG_TOK_DEMANGLE),	DBG_C_DEMANGLE,	0},
84 	{MSG_ORIG(MSG_TOK_CAP),		DBG_C_CAP,	0},
85 	{MSG_ORIG(MSG_TOK_INIT),	DBG_C_INIT,	0},
86 	{NULL,				NULL},
87 };
88 
89 /*
90  * Tokens may also define identifiers for diagnostics.  Presently, only ld.so.1
91  * uses these strings to identify, or isolate its output to selected link-map
92  * lists.  See ld.so.1:dbg_print().
93  */
94 const char *_Dbg_strs[] = {
95 	MSG_ORIG(MSG_TOK_BASE),		MSG_ORIG(MSG_TOK_LDSO),
96 	MSG_ORIG(MSG_TOK_NEWLM),	NULL
97 };
98 
99 /*
100  * Provide a debugging usage message
101  */
102 void
103 Dbg_usage()
104 {
105 	Dbg_util_nl(0, DBG_NL_FRC);
106 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_A));
107 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_B));
108 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_C));
109 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_D));
110 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_E));
111 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_F));
112 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_G));
113 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_H));
114 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_I));
115 	Dbg_util_nl(0, DBG_NL_FRC);
116 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_J));
117 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_K));
118 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_L));
119 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_M));
120 	Dbg_util_nl(0, DBG_NL_FRC);
121 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_N));
122 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_O));
123 	Dbg_util_nl(0, DBG_NL_FRC);
124 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_P));
125 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_Q));
126 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_R));
127 	dbg_print(0, MSG_INTL(MSG_USE_RTLD_S));
128 
129 	Dbg_util_nl(0, DBG_NL_FRC);
130 	dbg_print(0, MSG_INTL(MSG_USE_LD_A));
131 	dbg_print(0, MSG_INTL(MSG_USE_LD_B));
132 	dbg_print(0, MSG_INTL(MSG_USE_LD_C));
133 	dbg_print(0, MSG_INTL(MSG_USE_LD_D));
134 	dbg_print(0, MSG_INTL(MSG_USE_LD_E));
135 	dbg_print(0, MSG_INTL(MSG_USE_LD_F));
136 	dbg_print(0, MSG_INTL(MSG_USE_LD_G));
137 	dbg_print(0, MSG_INTL(MSG_USE_LD_H));
138 	Dbg_util_nl(0, DBG_NL_FRC);
139 	dbg_print(0, MSG_INTL(MSG_USE_LD_I));
140 	Dbg_util_nl(0, DBG_NL_FRC);
141 	dbg_print(0, MSG_INTL(MSG_USE_LD_J));
142 	dbg_print(0, MSG_INTL(MSG_USE_LD_K));
143 	Dbg_util_nl(0, DBG_NL_FRC);
144 	dbg_print(0, MSG_INTL(MSG_USE_LD_L));
145 	Dbg_util_nl(0, DBG_NL_FRC);
146 	dbg_print(0, MSG_INTL(MSG_USE_LD_M));
147 	dbg_print(0, MSG_INTL(MSG_USE_LD_N));
148 	dbg_print(0, MSG_INTL(MSG_USE_LD_O));
149 
150 	Dbg_util_nl(0, DBG_NL_FRC);
151 	Dbg_util_nl(0, DBG_NL_FRC);
152 	dbg_print(0, MSG_INTL(MSG_USE_ARGS));
153 	dbg_print(0, MSG_INTL(MSG_USE_AUDIT));
154 	dbg_print(0, MSG_INTL(MSG_USE_BASIC));
155 	dbg_print(0, MSG_INTL(MSG_USE_BINDINGS));
156 	dbg_print(0, MSG_INTL(MSG_USE_BINDINGS_2));
157 	dbg_print(0, MSG_INTL(MSG_USE_CAP));
158 	dbg_print(0, MSG_INTL(MSG_USE_DETAIL));
159 #ifdef	DEMANGLE
160 	dbg_print(0, MSG_INTL(MSG_USE_DEMANGLE));
161 #endif
162 	dbg_print(0, MSG_INTL(MSG_USE_ENTRY));
163 	dbg_print(0, MSG_INTL(MSG_USE_FILES));
164 	dbg_print(0, MSG_INTL(MSG_USE_GOT));
165 	dbg_print(0, MSG_INTL(MSG_USE_HELP));
166 	dbg_print(0, MSG_INTL(MSG_USE_INIT));
167 	dbg_print(0, MSG_INTL(MSG_USE_LIBS));
168 	dbg_print(0, MSG_INTL(MSG_USE_LIBS_2));
169 	dbg_print(0, MSG_INTL(MSG_USE_LMID));
170 	dbg_print(0, MSG_INTL(MSG_USE_LONG));
171 	dbg_print(0, MSG_INTL(MSG_USE_MAP));
172 	dbg_print(0, MSG_INTL(MSG_USE_MOVE));
173 	dbg_print(0, MSG_INTL(MSG_USE_RELOC));
174 	dbg_print(0, MSG_INTL(MSG_USE_SECTIONS));
175 	dbg_print(0, MSG_INTL(MSG_USE_SEGMENTS));
176 	dbg_print(0, MSG_INTL(MSG_USE_SEGMENTS_2));
177 	dbg_print(0, MSG_INTL(MSG_USE_STATS));
178 	dbg_print(0, MSG_INTL(MSG_USE_STRTAB));
179 	dbg_print(0, MSG_INTL(MSG_USE_STRTAB_2));
180 	dbg_print(0, MSG_INTL(MSG_USE_SUPPORT));
181 	dbg_print(0, MSG_INTL(MSG_USE_SYMBOLS));
182 	dbg_print(0, MSG_INTL(MSG_USE_SYMBOLS_2));
183 	dbg_print(0, MSG_INTL(MSG_USE_TLS));
184 	dbg_print(0, MSG_INTL(MSG_USE_UNUSED));
185 	dbg_print(0, MSG_INTL(MSG_USE_UNUSED_2));
186 	dbg_print(0, MSG_INTL(MSG_USE_VERSIONS));
187 	Dbg_util_nl(0, DBG_NL_FRC);
188 }
189 
190 /*
191  * Messaging support - funnel everything through dgettext() as this provides
192  * the real binding to libc.
193  */
194 const char *
195 _liblddbg_msg(Msg mid)
196 {
197 	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
198 }
199 
200 /*
201  * Validate and enable the appropriate debugging classes.
202  */
203 uintptr_t
204 Dbg_setup(const char *string, Dbg_desc *dbp)
205 {
206 	char		*name, *_name;	/* buffer in which to perform */
207 					/* strtok_r() operations. */
208 	char		*lasts;
209 	const char	*delimit = MSG_ORIG(MSG_STR_DELIMIT);
210 
211 	if ((_name = (char *)malloc(strlen(string) + 1)) == 0)
212 		return (S_ERROR);
213 	(void) strcpy(_name, string);
214 
215 	/*
216 	 * The token should be of the form "-Dtok,tok,tok,...".  Separate the
217 	 * pieces and build up the appropriate mask, unrecognized options are
218 	 * flagged.
219 	 */
220 	if ((name = strtok_r(_name, delimit, &lasts)) != NULL) {
221 		do {
222 			DBG_options	*opt;
223 			const char	*str;
224 			Boolean		set, found = FALSE;
225 			int		ndx = 0;
226 
227 			if (name[0] == '!') {
228 				set = FALSE;
229 				name++;
230 			} else
231 				set = TRUE;
232 
233 			/*
234 			 * First, determine if the token represents a class or
235 			 * extra.
236 			 */
237 			for (opt = _Dbg_options; opt->o_name != NULL; opt++) {
238 				if (strcmp(name, opt->o_name) != 0)
239 					continue;
240 
241 				if (set == TRUE) {
242 					if (opt->o_class)
243 						dbp->d_class |= opt->o_class;
244 					if (opt->o_extra)
245 						dbp->d_extra |= opt->o_extra;
246 				} else {
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 				}
252 				found = TRUE;
253 				break;
254 			}
255 			if (found == TRUE)
256 				continue;
257 
258 			/*
259 			 * Second, determine if the token represents a known
260 			 * diagnostic identifier.  Note, newlm identifiers are
261 			 * typically followed by a numeric id, for example
262 			 * newlm1, newlm2 ...  Thus we only compare the
263 			 * initial text of the string.
264 			 */
265 			while ((str = _Dbg_strs[ndx++]) != NULL)  {
266 				char	*tup;
267 
268 				if (strncmp(name, str, strlen(str)) != 0)
269 					continue;
270 
271 				/*
272 				 * Translate lmid identifier to uppercase.
273 				 */
274 				for (tup = name; *tup; tup++) {
275 					if ((*tup >= 'a') && (*tup <= 'z'))
276 						*tup = *tup - ('a' - 'A');
277 				}
278 
279 				/*
280 				 * Save this lmid.  The whole token buffer has
281 				 * been reallocated, so these names will remain
282 				 * once this routine returns.
283 				 */
284 				if (aplist_append(&dbp->d_list, name,
285 				    AL_CNT_DEBUG) == NULL)
286 					return (S_ERROR);
287 
288 				found = TRUE;
289 				break;
290 			}
291 
292 			if (found == FALSE)
293 				dbg_print(0, MSG_INTL(MSG_USE_UNRECOG), name);
294 
295 		} while ((name = strtok_r(NULL, delimit, &lasts)) != NULL);
296 	}
297 
298 	/*
299 	 * If the debug help option was specified dump a usage message.  If
300 	 * this is the only debug class, return an indication that the user
301 	 * should exit.
302 	 */
303 	if ((_Dbg_cnt++ == 0) && (dbp->d_class & DBG_C_HELP)) {
304 		Dbg_usage();
305 		if (dbp->d_class == DBG_C_HELP)
306 			return (0);
307 	}
308 	return (1);
309 }
310 
311 /*
312  * Define our own printing routine.  This provides a basic fallback, as ld(1)
313  * and ld.so.1(1) provide their own routines that augment their diagnostic
314  * output, and direct the output to stderr.  This item should be defined
315  * NODIRECT.
316  */
317 /* PRINTFLIKE2 */
318 void
319 dbg_print(Lm_list *lml, const char *format, ...)
320 {
321 	va_list ap;
322 
323 #if	defined(lint)
324 	/*
325 	 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
326 	 * Supress the lint error by making a dummy assignment.
327 	 */
328 	lml = 0;
329 #endif
330 	va_start(ap, format);
331 	(void) vprintf(format, ap);
332 	(void) printf(MSG_ORIG(MSG_STR_NL));
333 	va_end(ap);
334 }
335