debug.c revision 11690:1c19a1778a4f
18835SDarren.Moffat@Sun.COM/*
28835SDarren.Moffat@Sun.COM * CDDL HEADER START
38835SDarren.Moffat@Sun.COM *
48835SDarren.Moffat@Sun.COM * The contents of this file are subject to the terms of the
58835SDarren.Moffat@Sun.COM * Common Development and Distribution License (the "License").
68835SDarren.Moffat@Sun.COM * You may not use this file except in compliance with the License.
78835SDarren.Moffat@Sun.COM *
88835SDarren.Moffat@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98835SDarren.Moffat@Sun.COM * or http://www.opensolaris.org/os/licensing.
108835SDarren.Moffat@Sun.COM * See the License for the specific language governing permissions
118835SDarren.Moffat@Sun.COM * and limitations under the License.
128835SDarren.Moffat@Sun.COM *
138835SDarren.Moffat@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
148835SDarren.Moffat@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158835SDarren.Moffat@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
168835SDarren.Moffat@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
178835SDarren.Moffat@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
188835SDarren.Moffat@Sun.COM *
198835SDarren.Moffat@Sun.COM * CDDL HEADER END
208835SDarren.Moffat@Sun.COM */
218835SDarren.Moffat@Sun.COM
228835SDarren.Moffat@Sun.COM/*
238835SDarren.Moffat@Sun.COM * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
248835SDarren.Moffat@Sun.COM * Use is subject to license terms.
258835SDarren.Moffat@Sun.COM */
268835SDarren.Moffat@Sun.COM
278835SDarren.Moffat@Sun.COM#include <libintl.h>
288835SDarren.Moffat@Sun.COM#include <sys/varargs.h>
298835SDarren.Moffat@Sun.COM#include <stdio.h>
308835SDarren.Moffat@Sun.COM#include <string.h>
318835SDarren.Moffat@Sun.COM#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 */
42static Dbg_desc	_dbg_desc = { 0, 0, NULL, { 0, 0 }, { 0, 0 } };
43Dbg_desc	*dbg_desc = &_dbg_desc;
44
45int		_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 */
53static DBG_options _Dbg_options[] = {	/* Options accepted by both linkers */
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_HELP),	0,	DBG_E_HELP},
57	{MSG_ORIG(MSG_TOK_TTIME),	0,	DBG_E_TTIME},
58	{MSG_ORIG(MSG_TOK_DTIME),	0,	DBG_E_DTIME},
59
60	{MSG_ORIG(MSG_TOK_ALL),		DBG_C_ALL & ~DBG_C_DEMANGLE,	0},
61	{MSG_ORIG(MSG_TOK_BASIC),	DBG_C_BASIC,			0},
62	{MSG_ORIG(MSG_TOK_CAP),		DBG_C_CAP,			0},
63	{MSG_ORIG(MSG_TOK_DEMANGLE),	DBG_C_DEMANGLE,			0},
64	{MSG_ORIG(MSG_TOK_FILES),	DBG_C_FILES,			0},
65	{MSG_ORIG(MSG_TOK_LIBS),	DBG_C_LIBS,			0},
66	{MSG_ORIG(MSG_TOK_MOVE),	DBG_C_MOVE,			0},
67	{MSG_ORIG(MSG_TOK_RELOC),	DBG_C_RELOC,			0},
68	{MSG_ORIG(MSG_TOK_SYMBOLS),	DBG_C_SYMBOLS,			0},
69	{MSG_ORIG(MSG_TOK_TLS),		DBG_C_TLS,			0},
70	{MSG_ORIG(MSG_TOK_UNUSED),	DBG_C_UNUSED,			0},
71	{MSG_ORIG(MSG_TOK_VERSIONS),	DBG_C_VERSIONS,			0},
72	{NULL,				0,				0},
73};
74
75static DBG_options _Dbg_options_ld[] = {	/* ld only options */
76	{MSG_ORIG(MSG_TOK_CLASS),	0,	DBG_E_SNAME | DBG_E_CLASS},
77	{MSG_ORIG(MSG_TOK_FULLNAME),	0,	DBG_E_SNAME | DBG_E_FNAME},
78	{MSG_ORIG(MSG_TOK_NAME),	0,	DBG_E_SNAME},
79
80	{MSG_ORIG(MSG_TOK_ARGS),	DBG_C_ARGS,	0},
81	{MSG_ORIG(MSG_TOK_ENTRY),	DBG_C_ENTRY,	0},
82	{MSG_ORIG(MSG_TOK_GOT),		DBG_C_GOT,	0},
83	{MSG_ORIG(MSG_TOK_MAP),		DBG_C_MAP,	0},
84	{MSG_ORIG(MSG_TOK_SECTIONS),	DBG_C_SECTIONS,	0},
85	{MSG_ORIG(MSG_TOK_SEGMENTS),	DBG_C_SEGMENTS,	0},
86	{MSG_ORIG(MSG_TOK_STATS),	DBG_C_STATS,	0},
87	{MSG_ORIG(MSG_TOK_STRTAB),	DBG_C_STRTAB,	0},
88	{MSG_ORIG(MSG_TOK_SUPPORT),	DBG_C_SUPPORT,	0},
89	{NULL,				0,		0},
90};
91
92static DBG_options _Dbg_options_rtld[] = {	/* ld.so.1 only options */
93	{MSG_ORIG(MSG_TOK_AUDIT),	DBG_C_AUDITING,	0},
94	{MSG_ORIG(MSG_TOK_BINDINGS),	DBG_C_BINDINGS,	0},
95	{MSG_ORIG(MSG_TOK_CALLBACK),    DBG_C_CALLBACK,	0},
96	{MSG_ORIG(MSG_TOK_INIT),	DBG_C_INIT,	0},
97	{NULL,				0,		0},
98};
99
100/*
101 * Compare name to the options found in optarr. If one matches,
102 * update *dbp and return TRUE. Otherwise, FALSE.
103 */
104static Boolean
105process_options(const char *name, Boolean set, Dbg_desc *dbp,
106    DBG_options *optarr)
107{
108	DBG_options	*opt;
109
110	for (opt = optarr; opt->o_name != NULL; opt++) {
111		if (strcmp(name, opt->o_name) != 0)
112			continue;
113
114		if (set == TRUE) {
115			if (opt->o_class)
116				dbp->d_class |= opt->o_class;
117			if (opt->o_extra)
118				dbp->d_extra |= opt->o_extra;
119		} else {
120			if (opt->o_class)
121				dbp->d_class &= ~(opt->o_class);
122			if (opt->o_extra)
123				dbp->d_extra &= ~(opt->o_extra);
124		}
125		return (TRUE);
126	}
127
128	return (FALSE);
129}
130
131/*
132 * Provide a debugging usage message
133 */
134void
135Dbg_help(void)
136{
137	Dbg_util_nl(0, DBG_NL_FRC);
138	dbg_print(0, MSG_INTL(MSG_USE_R1_A));
139	dbg_print(0, MSG_INTL(MSG_USE_R1_B));
140	dbg_print(0, MSG_INTL(MSG_USE_R1_C));
141	dbg_print(0, MSG_INTL(MSG_USE_R1_D));
142	dbg_print(0, MSG_INTL(MSG_USE_R1_E));
143	dbg_print(0, MSG_INTL(MSG_USE_R1_F));
144	dbg_print(0, MSG_INTL(MSG_USE_R1_G));
145
146	Dbg_util_nl(0, DBG_NL_FRC);
147	dbg_print(0, MSG_INTL(MSG_USE_R2_A));
148	dbg_print(0, MSG_INTL(MSG_USE_R2_B));
149	dbg_print(0, MSG_INTL(MSG_USE_R2_C));
150	dbg_print(0, MSG_INTL(MSG_USE_R2_D));
151	dbg_print(0, MSG_INTL(MSG_USE_R2_E));
152	dbg_print(0, MSG_INTL(MSG_USE_R2_F));
153	dbg_print(0, MSG_INTL(MSG_USE_R2_G));
154	dbg_print(0, MSG_INTL(MSG_USE_R2_H));
155	dbg_print(0, MSG_INTL(MSG_USE_R2_I));
156	dbg_print(0, MSG_INTL(MSG_USE_R2_J));
157	dbg_print(0, MSG_INTL(MSG_USE_R2_K));
158	dbg_print(0, MSG_INTL(MSG_USE_R2_L));
159	dbg_print(0, MSG_INTL(MSG_USE_R2_M));
160	dbg_print(0, MSG_INTL(MSG_USE_R2_N));
161	dbg_print(0, MSG_INTL(MSG_USE_R2_O));
162	dbg_print(0, MSG_INTL(MSG_USE_R2_P));
163	dbg_print(0, MSG_INTL(MSG_USE_R2_Q));
164
165	Dbg_util_nl(0, DBG_NL_FRC);
166	dbg_print(0, MSG_INTL(MSG_USE_R2_R));
167	dbg_print(0, MSG_INTL(MSG_USE_R2_S));
168	dbg_print(0, MSG_INTL(MSG_USE_R2_T));
169	dbg_print(0, MSG_INTL(MSG_USE_R2_U));
170	dbg_print(0, MSG_INTL(MSG_USE_R2_V));
171	dbg_print(0, MSG_INTL(MSG_USE_R2_W));
172
173	Dbg_util_nl(0, DBG_NL_FRC);
174	dbg_print(0, MSG_INTL(MSG_USE_R3_A));
175	dbg_print(0, MSG_INTL(MSG_USE_R3_B));
176	dbg_print(0, MSG_INTL(MSG_USE_R3_C));
177	dbg_print(0, MSG_INTL(MSG_USE_R3_D));
178	dbg_print(0, MSG_INTL(MSG_USE_R3_E));
179	dbg_print(0, MSG_INTL(MSG_USE_R3_F));
180	dbg_print(0, MSG_INTL(MSG_USE_R3_G));
181
182	Dbg_util_nl(0, DBG_NL_FRC);
183	dbg_print(0, MSG_INTL(MSG_USE_R3_H));
184	dbg_print(0, MSG_INTL(MSG_USE_R3_F));
185	dbg_print(0, MSG_INTL(MSG_USE_R3_I));
186	dbg_print(0, MSG_INTL(MSG_USE_R3_J));
187	dbg_print(0, MSG_INTL(MSG_USE_R3_K));
188	dbg_print(0, MSG_INTL(MSG_USE_R3_L));
189	dbg_print(0, MSG_INTL(MSG_USE_R3_M));
190
191	Dbg_util_nl(0, DBG_NL_FRC);
192	dbg_print(0, MSG_INTL(MSG_USE_R3_N));
193
194	Dbg_util_nl(0, DBG_NL_FRC);
195	dbg_print(0, MSG_INTL(MSG_USE_HDR_DCT));
196	dbg_print(0, MSG_INTL(MSG_USE_HDR_BOTH));
197	dbg_print(0, MSG_INTL(MSG_USE_R4_A));
198	dbg_print(0, MSG_INTL(MSG_USE_R4_B));
199	dbg_print(0, MSG_INTL(MSG_USE_R4_B2));
200	dbg_print(0, MSG_INTL(MSG_USE_R4_C));
201	dbg_print(0, MSG_INTL(MSG_USE_R4_C2));
202	dbg_print(0, MSG_INTL(MSG_USE_R4_C3));
203	dbg_print(0, MSG_INTL(MSG_USE_R4_D));
204	dbg_print(0, MSG_INTL(MSG_USE_R4_E));
205	dbg_print(0, MSG_INTL(MSG_USE_R4_E2));
206	dbg_print(0, MSG_INTL(MSG_USE_R4_E3));
207	dbg_print(0, MSG_INTL(MSG_USE_R4_F));
208	dbg_print(0, MSG_INTL(MSG_USE_R4_F2));
209	dbg_print(0, MSG_INTL(MSG_USE_R4_F3));
210	dbg_print(0, MSG_INTL(MSG_USE_R4_F4));
211	dbg_print(0, MSG_INTL(MSG_USE_R4_F5));
212	dbg_print(0, MSG_INTL(MSG_USE_R4_F6));
213
214	Dbg_util_nl(0, DBG_NL_FRC);
215	dbg_print(0, MSG_INTL(MSG_USE_HDR_RTLD));
216	dbg_print(0, MSG_INTL(MSG_USE_R5_A));
217	dbg_print(0, MSG_INTL(MSG_USE_R5_A2));
218	dbg_print(0, MSG_INTL(MSG_USE_R5_A3));
219	dbg_print(0, MSG_INTL(MSG_USE_R5_A4));
220	dbg_print(0, MSG_INTL(MSG_USE_R5_A5));
221	dbg_print(0, MSG_INTL(MSG_USE_R5_A6));
222	dbg_print(0, MSG_INTL(MSG_USE_R5_A7));
223	dbg_print(0, MSG_INTL(MSG_USE_R5_A8));
224	dbg_print(0, MSG_INTL(MSG_USE_R5_A9));
225	dbg_print(0, MSG_INTL(MSG_USE_R5_A0));
226	dbg_print(0, MSG_INTL(MSG_USE_R5_B));
227	dbg_print(0, MSG_INTL(MSG_USE_R5_C));
228	dbg_print(0, MSG_INTL(MSG_USE_R5_D));
229	dbg_print(0, MSG_INTL(MSG_USE_R5_E));
230	dbg_print(0, MSG_INTL(MSG_USE_R5_F));
231
232	Dbg_util_nl(0, DBG_NL_FRC);
233	dbg_print(0, MSG_INTL(MSG_USE_HDR_LD));
234	dbg_print(0, MSG_INTL(MSG_USE_R6_A));
235	dbg_print(0, MSG_INTL(MSG_USE_R6_B));
236	dbg_print(0, MSG_INTL(MSG_USE_R6_C));
237	dbg_print(0, MSG_INTL(MSG_USE_R6_C2));
238
239	Dbg_util_nl(0, DBG_NL_FRC);
240	dbg_print(0, MSG_INTL(MSG_USE_HDR_CST));
241	dbg_print(0, MSG_INTL(MSG_USE_HDR_BOTH));
242	dbg_print(0, MSG_INTL(MSG_USE_R7_A));
243	dbg_print(0, MSG_INTL(MSG_USE_R7_B));
244	dbg_print(0, MSG_INTL(MSG_USE_R7_C));
245	dbg_print(0, MSG_INTL(MSG_USE_R7_D));
246	dbg_print(0, MSG_INTL(MSG_USE_R7_E));
247	dbg_print(0, MSG_INTL(MSG_USE_R7_F));
248	dbg_print(0, MSG_INTL(MSG_USE_R7_F2));
249	dbg_print(0, MSG_INTL(MSG_USE_R7_G));
250	dbg_print(0, MSG_INTL(MSG_USE_R7_H));
251	dbg_print(0, MSG_INTL(MSG_USE_R7_I));
252	dbg_print(0, MSG_INTL(MSG_USE_R7_I2));
253	dbg_print(0, MSG_INTL(MSG_USE_R7_J));
254	dbg_print(0, MSG_INTL(MSG_USE_R7_K));
255	dbg_print(0, MSG_INTL(MSG_USE_R7_K2));
256	dbg_print(0, MSG_INTL(MSG_USE_R7_L));
257
258	Dbg_util_nl(0, DBG_NL_FRC);
259	dbg_print(0, MSG_INTL(MSG_USE_HDR_RTLD));
260	dbg_print(0, MSG_INTL(MSG_USE_R8_A));
261	dbg_print(0, MSG_INTL(MSG_USE_R8_B));
262	dbg_print(0, MSG_INTL(MSG_USE_R8_B2));
263	dbg_print(0, MSG_INTL(MSG_USE_R8_C));
264	dbg_print(0, MSG_INTL(MSG_USE_R8_C2));
265	dbg_print(0, MSG_INTL(MSG_USE_R8_D));
266
267	Dbg_util_nl(0, DBG_NL_FRC);
268	dbg_print(0, MSG_INTL(MSG_USE_HDR_LD));
269	dbg_print(0, MSG_INTL(MSG_USE_R9_A));
270	dbg_print(0, MSG_INTL(MSG_USE_R9_B));
271	dbg_print(0, MSG_INTL(MSG_USE_R9_C));
272	dbg_print(0, MSG_INTL(MSG_USE_R9_D));
273	dbg_print(0, MSG_INTL(MSG_USE_R9_E));
274	dbg_print(0, MSG_INTL(MSG_USE_R9_F));
275	dbg_print(0, MSG_INTL(MSG_USE_R9_F2));
276	dbg_print(0, MSG_INTL(MSG_USE_R9_G));
277	dbg_print(0, MSG_INTL(MSG_USE_R9_H));
278	dbg_print(0, MSG_INTL(MSG_USE_R9_H2));
279	dbg_print(0, MSG_INTL(MSG_USE_R9_I));
280
281	Dbg_util_nl(0, DBG_NL_FRC);
282}
283
284/*
285 * Messaging support - funnel everything through dgettext() as this provides
286 * the real binding to libc.
287 */
288const char *
289_liblddbg_msg(Msg mid)
290{
291	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
292}
293
294/*
295 * Given a name starting with "lmid", finish processing it. Return TRUE
296 * if a valid lmid token was seen, and FALSE for any error.
297 *
298 * exit:
299 *	On failure, returns FALSE, indicating a syntax error
300 *
301 *	On success:
302 *	-	Appropriate flags in dbg->d_extra have been set
303 *	-	Any link-map list names specified have been added to
304 *		d_list, for the rtld dbg_print() to compare against
305 *		link-map list names.
306 *	-	TRUE is returned.
307 */
308static Boolean
309process_lmid(char *name, Dbg_desc *dbp)
310{
311	/*
312	 * "lmid" can have an optional argument. Allowed values are "all",
313	 * "alt[0-9]+", "base", or "ldso". Alt has a variable ending, but
314	 * we can use process_options() to handle the other three.
315	 */
316	static DBG_options options_lmid[] = {
317		{MSG_ORIG(MSG_TOK_LMID_ALL),	0,	DBG_E_LMID_ALL},
318		{MSG_ORIG(MSG_TOK_LMID_BASE),	0,	DBG_E_LMID_BASE},
319		{MSG_ORIG(MSG_TOK_LMID_LDSO),	0,	DBG_E_LMID_LDSO},
320		{NULL,				NULL},
321	};
322
323	Dbg_desc	tmp_db;
324	const char	*lmid_opt;
325
326	/* If it's a plain "lmid", we can set the flag and return now */
327	if (name[MSG_TOK_LMID_SIZE] == '\0') {
328		dbp->d_extra |= DBG_E_LMID;
329		return (TRUE);
330	}
331
332	/* If there's no value, its an error */
333	if (conv_strproc_extract_value(name, MSG_TOK_LMID_SIZE,
334	    CONV_SPEXV_F_UCASE, &lmid_opt) == 0)
335		return (FALSE);
336
337	/*
338	 * ALL, BASE, or LDSO?
339	 */
340	tmp_db.d_extra = 0;
341	if (process_options(lmid_opt, TRUE, &tmp_db, options_lmid)) {
342		/*
343		 * If BASE, and we haven't already seen it, add it to the
344		 * rtld name matching list. For the others, setting the
345		 * e_extra bit suffices.
346		 */
347		if (((tmp_db.d_extra & DBG_E_LMID_BASE) != 0) &&
348		    ((dbp->d_extra & DBG_E_LMID_BASE) == 0) &&
349		    (aplist_append(&dbp->d_list, MSG_ORIG(MSG_TOK_LMID_BASE),
350		    AL_CNT_DEBUG) == NULL))
351			return (FALSE);
352
353		/* Add the resulting flags into the callers descriptor */
354		dbp->d_extra |= DBG_E_LMID | tmp_db.d_extra;
355		return (TRUE);
356	}
357
358	/*
359	 * ALT?
360	 */
361	if (strncmp(lmid_opt, MSG_ORIG(MSG_TOK_LMID_ALT),
362	    MSG_TOK_LMID_ALT_SIZE) == 0) {
363		const char *tail = lmid_opt + MSG_TOK_LMID_ALT_SIZE;
364
365		/* 'ALT' without a # means "all alternative link-map lists" */
366		if (*tail == '\0') {
367			dbp->d_extra |= DBG_E_LMID | DBG_E_LMID_ALT;
368			return (TRUE);
369		}
370
371		/*
372		 * It is ALT[0-9]+. Make sure the characters following 'ALT'
373		 * are numbers, and then add it to the rtld name matching list.
374		 */
375		for (; *tail; tail++)
376			if ((*tail < '0') || (*tail > '9'))
377				return (FALSE);
378
379		if (aplist_append(&dbp->d_list, lmid_opt, AL_CNT_DEBUG) == NULL)
380			return (FALSE);
381		dbp->d_extra |= DBG_E_LMID;
382		return (TRUE);
383	}
384
385	/* It's nothing we recognize */
386	return (FALSE);
387}
388
389/*
390 * Validate and enable the appropriate debugging classes.
391 *
392 * entry:
393 *	string - String to be analyzed for debugging options
394 *	dbp - Pointer to debug descriptor to be initialized
395 *	outfile_ret - NULL, or pointer to receive result of 'output='
396 *		token. A NULL value means that the 'output=' token
397 *		is not accepted. A non-NULL value means that it is.
398 *
399 * exit:
400 *	On failure, False (0) is returned.
401 *
402 *	On success, string has been parsed, and the descriptor referenced
403 *	by dbp has been initialized. If outfile is non-NULL, *outfile will
404 *	be set to NULL if the 'output=' token is not present, and to the
405 *	user supplied string otherwise. True (1) is returned.
406 */
407int
408Dbg_setup(dbg_setup_caller_t caller, const char *string, Dbg_desc *dbp,
409    const char **outfile)
410{
411	char		*name, *_name;	/* buffer in which to perform */
412					/* strtok_r() operations. */
413	char		*lasts;
414	const char	*delimit = MSG_ORIG(MSG_STR_DELIMIT);
415
416	/*
417	 * Clear the help flags --- these items only apply for a single
418	 * call to Dbg_setup().
419	 */
420	dbp->d_extra &= ~(DBG_E_HELP | DBG_E_HELP_EXIT);
421
422	if ((_name = (char *)malloc(strlen(string) + 1)) == NULL)
423		return (0);
424	(void) strcpy(_name, string);
425
426	if (outfile)
427		*outfile = NULL;   /* No output file yet */
428
429	/*
430	 * The token should be of the form "-Dtok,tok,tok,...".  Separate the
431	 * pieces and build up the appropriate mask, unrecognized options are
432	 * flagged.
433	 */
434	if ((name = strtok_r(_name, delimit, &lasts)) != NULL) {
435		do {
436			Boolean		set;
437
438			/* Remove leading and trailing whitespace */
439			name = conv_strproc_trim(name);
440
441			if (name[0] == '!') {
442				set = FALSE;
443				name++;
444			} else
445				set = TRUE;
446
447			if (*name == '\0')
448				continue;	/* Skip null token */
449
450			/*
451			 * First, determine if the token represents a class or
452			 * extra.
453			 */
454			if (process_options(name, set, dbp, _Dbg_options))
455				continue;
456			switch (caller) {
457			case DBG_CALLER_LD:	/* ld only tokens */
458				if (process_options(name, set, dbp,
459				    _Dbg_options_ld))
460					continue;
461				break;
462			case DBG_CALLER_RTLD:	/* rtld only tokens */
463				if (process_options(name, set, dbp,
464				    _Dbg_options_rtld))
465					continue;
466				break;
467			}
468
469			/* The remaining options do not accept negation */
470			if (!set) {
471				dbg_print(0, MSG_INTL(MSG_USE_CNTNEGOPT), name);
472				continue;
473			}
474
475			/*
476			 * Is it an 'output=' token? This item is a special
477			 * case because it depends on the presence of
478			 * a non-NULL outfile argument, and because the
479			 * part following the '=' is variable.
480			 */
481			if ((outfile != NULL) &&
482			    strncmp(name, MSG_ORIG(MSG_TOK_OUTFILE),
483			    MSG_TOK_OUTFILE_SIZE) == 0) {
484				if (conv_strproc_extract_value(name,
485				    MSG_TOK_OUTFILE_SIZE, 0, outfile))
486					continue;
487			}
488
489			/*
490			 * Only the rtld "lmid" token is left.
491			 */
492			if ((caller == DBG_CALLER_RTLD) && (strncmp(name,
493			    MSG_ORIG(MSG_TOK_LMID), MSG_TOK_LMID_SIZE) == 0) &&
494			    process_lmid(name, dbp))
495				continue;
496
497			/* If we make it here, the token is not understood */
498			dbg_print(0, MSG_INTL(MSG_USE_UNRECOG), name);
499
500		} while ((name = strtok_r(NULL, delimit, &lasts)) != NULL);
501	}
502
503	/*
504	 * If the debug help option was specified and this is the only debug
505	 * class, return an indication that the user should exit.
506	 */
507	if ((_Dbg_cnt++ == 0) && (dbp->d_extra & DBG_E_HELP) &&
508	    (dbp->d_class == 0))
509		dbp->d_extra |= DBG_E_HELP_EXIT;
510
511	return (1);
512}
513
514/*
515 * Define our own printing routine.  This provides a basic fallback, as ld(1)
516 * and ld.so.1(1) provide their own routines that augment their diagnostic
517 * output, and direct the output to stderr.  This item should be defined
518 * NODIRECT.
519 */
520/* PRINTFLIKE2 */
521void
522dbg_print(Lm_list *lml, const char *format, ...)
523{
524	va_list ap;
525
526#if	defined(lint)
527	/*
528	 * The lml argument is only meaningful for diagnostics sent to ld.so.1.
529	 * Supress the lint error by making a dummy assignment.
530	 */
531	lml = 0;
532#endif
533	va_start(ap, format);
534	(void) vprintf(format, ap);
535	(void) printf(MSG_ORIG(MSG_STR_NL));
536	va_end(ap);
537}
538