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