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