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 2010 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_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 */ 104 static Boolean 105 process_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 */ 134 void 135 Dbg_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 */ 288 const 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 */ 308 static Boolean 309 process_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 */ 407 int 408 Dbg_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 */ 521 void 522 dbg_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