debug.c revision 5892:b863dde33f1b
1107120Sjulian/*
2107120Sjulian * CDDL HEADER START
3139823Simp *
4139823Simp * The contents of this file are subject to the terms of the
5139823Simp * Common Development and Distribution License (the "License").
6107120Sjulian * You may not use this file except in compliance with the License.
7107120Sjulian *
8107120Sjulian * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9107120Sjulian * or http://www.opensolaris.org/os/licensing.
10107120Sjulian * See the License for the specific language governing permissions
11107120Sjulian * and limitations under the License.
12107120Sjulian *
13107120Sjulian * When distributing Covered Code, include this CDDL HEADER in each
14107120Sjulian * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15107120Sjulian * If applicable, add the following below this CDDL HEADER, with the
16107120Sjulian * fields enclosed by brackets "[]" replaced with your own identifying
17107120Sjulian * information: Portions Copyright [yyyy] [name of copyright owner]
18107120Sjulian *
19107120Sjulian * CDDL HEADER END
20107120Sjulian */
21107120Sjulian
22107120Sjulian/*
23107120Sjulian * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24107120Sjulian * Use is subject to license terms.
25107120Sjulian */
26107120Sjulian#pragma ident	"%Z%%M%	%I%	%E% SMI"
27107120Sjulian
28107120Sjulian#define		dgettext	_dgettext
29107120Sjulian
30114878Sjulian#include	<libintl.h>
31107120Sjulian#include	<sys/varargs.h>
32107120Sjulian#include	<stdio.h>
33107120Sjulian#include	<string.h>
34107120Sjulian#include	<stdlib.h>
35122634Semax#include	<alist.h>
36107120Sjulian#include	<debug.h>
37107120Sjulian#include	<_debug.h>
38107120Sjulian#include	<msg.h>
39107120Sjulian
40107120Sjulian/*
41107120Sjulian * Define a debug descriptor.  Note, although this provides the default
42107120Sjulian * definition to which most users bind, ld.so.1 must provide its own definition,
43107120Sjulian * and thus interposition is expected.  This item should be defined NODIRECT.
44107120Sjulian */
45107120Sjulianstatic Dbg_desc	_dbg_desc = { 0, 0, 0 };
46107120SjulianDbg_desc	*dbg_desc = &_dbg_desc;
47107120Sjulian
48int		_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 */
56DBG_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 */
99const 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 */
107void
108Dbg_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 */
199const 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 */
208uintptr_t
209Dbg_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 */
323void
324dbg_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