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