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