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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <libintl.h> 30 #include <sys/varargs.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <stdlib.h> 34 #include <alist.h> 35 #include <debug.h> 36 #include <_debug.h> 37 #include <msg.h> 38 39 /* 40 * Define a debug descriptor. Note, although this provides the default 41 * definition to which most users bind, ld.so.1 must provide its own definition, 42 * and thus interposition is expected. This item should be defined NODIRECT. 43 */ 44 static Dbg_desc _dbg_desc = { 0, 0, 0 }; 45 Dbg_desc *dbg_desc = &_dbg_desc; 46 47 int _Dbg_cnt = 0; 48 49 /* 50 * Debugging initialization and processing. The dbg_options[] array defines 51 * a set of option strings that can be specified using the -D flag or from an 52 * environment variable. For each option, a class is enabled in the d_class 53 * bit mask, or an extra flag is enabled in the d_extra bit mask. 54 */ 55 DBG_options _Dbg_options[] = { 56 {MSG_ORIG(MSG_TOK_DETAIL), 0, DBG_E_DETAIL}, 57 {MSG_ORIG(MSG_TOK_LONG), 0, DBG_E_LONG}, 58 {MSG_ORIG(MSG_TOK_NAME), 0, DBG_E_SNAME}, 59 {MSG_ORIG(MSG_TOK_FULLNAME), 0, DBG_E_SNAME | DBG_E_FNAME}, 60 {MSG_ORIG(MSG_TOK_CLASS), 0, DBG_E_SNAME | DBG_E_CLASS}, 61 {MSG_ORIG(MSG_TOK_LMID), 0, DBG_E_LMID}, 62 63 {MSG_ORIG(MSG_TOK_ALL), DBG_C_ALL, 0}, 64 {MSG_ORIG(MSG_TOK_ARGS), DBG_C_ARGS, 0}, 65 {MSG_ORIG(MSG_TOK_BASIC), DBG_C_BASIC, 0}, 66 {MSG_ORIG(MSG_TOK_BINDINGS), DBG_C_BINDINGS, 0}, 67 {MSG_ORIG(MSG_TOK_ENTRY), DBG_C_ENTRY, 0}, 68 {MSG_ORIG(MSG_TOK_FILES), DBG_C_FILES, 0}, 69 {MSG_ORIG(MSG_TOK_HELP), DBG_C_HELP, 0}, 70 {MSG_ORIG(MSG_TOK_LIBS), DBG_C_LIBS, 0}, 71 {MSG_ORIG(MSG_TOK_MAP), DBG_C_MAP, 0}, 72 {MSG_ORIG(MSG_TOK_RELOC), DBG_C_RELOC, 0}, 73 {MSG_ORIG(MSG_TOK_SECTIONS), DBG_C_SECTIONS, 0}, 74 {MSG_ORIG(MSG_TOK_SEGMENTS), DBG_C_SEGMENTS, 0}, 75 {MSG_ORIG(MSG_TOK_SUPPORT), DBG_C_SUPPORT, 0}, 76 {MSG_ORIG(MSG_TOK_SYMBOLS), DBG_C_SYMBOLS, 0}, 77 {MSG_ORIG(MSG_TOK_TLS), DBG_C_TLS, 0}, 78 {MSG_ORIG(MSG_TOK_AUDIT), DBG_C_AUDITING, 0}, 79 {MSG_ORIG(MSG_TOK_VERSIONS), DBG_C_VERSIONS, 0}, 80 {MSG_ORIG(MSG_TOK_GOT), DBG_C_GOT, 0}, 81 {MSG_ORIG(MSG_TOK_MOVE), DBG_C_MOVE, 0}, 82 {MSG_ORIG(MSG_TOK_STRTAB), DBG_C_STRTAB, 0}, 83 {MSG_ORIG(MSG_TOK_STATS), DBG_C_STATS, 0}, 84 {MSG_ORIG(MSG_TOK_UNUSED), DBG_C_UNUSED, 0}, 85 #ifdef DEMANGLE 86 {MSG_ORIG(MSG_TOK_DEMANGLE), DBG_C_DEMANGLE, 0}, 87 #endif 88 {MSG_ORIG(MSG_TOK_CAP), DBG_C_CAP, 0}, 89 {MSG_ORIG(MSG_TOK_INIT), DBG_C_INIT, 0}, 90 {NULL, NULL}, 91 }; 92 93 /* 94 * Tokens may also define identifiers for diagnostics. Presently, only ld.so.1 95 * uses these strings to identify, or isolate its output to selected link-map 96 * lists. See ld.so.1:dbg_print(). 97 */ 98 const char *_Dbg_strs[] = { 99 MSG_ORIG(MSG_TOK_BASE), MSG_ORIG(MSG_TOK_LDSO), 100 MSG_ORIG(MSG_TOK_NEWLM), NULL 101 }; 102 103 /* 104 * Provide a debugging usage message 105 */ 106 void 107 Dbg_usage() 108 { 109 Dbg_util_nl(0, DBG_NL_FRC); 110 dbg_print(0, MSG_INTL(MSG_USE_RTLD_A)); 111 dbg_print(0, MSG_INTL(MSG_USE_RTLD_B)); 112 dbg_print(0, MSG_INTL(MSG_USE_RTLD_C)); 113 dbg_print(0, MSG_INTL(MSG_USE_RTLD_D)); 114 dbg_print(0, MSG_INTL(MSG_USE_RTLD_E)); 115 dbg_print(0, MSG_INTL(MSG_USE_RTLD_F)); 116 dbg_print(0, MSG_INTL(MSG_USE_RTLD_G)); 117 dbg_print(0, MSG_INTL(MSG_USE_RTLD_H)); 118 dbg_print(0, MSG_INTL(MSG_USE_RTLD_I)); 119 Dbg_util_nl(0, DBG_NL_FRC); 120 dbg_print(0, MSG_INTL(MSG_USE_RTLD_J)); 121 dbg_print(0, MSG_INTL(MSG_USE_RTLD_K)); 122 dbg_print(0, MSG_INTL(MSG_USE_RTLD_L)); 123 dbg_print(0, MSG_INTL(MSG_USE_RTLD_M)); 124 Dbg_util_nl(0, DBG_NL_FRC); 125 dbg_print(0, MSG_INTL(MSG_USE_RTLD_N)); 126 dbg_print(0, MSG_INTL(MSG_USE_RTLD_O)); 127 Dbg_util_nl(0, DBG_NL_FRC); 128 dbg_print(0, MSG_INTL(MSG_USE_RTLD_P)); 129 dbg_print(0, MSG_INTL(MSG_USE_RTLD_Q)); 130 dbg_print(0, MSG_INTL(MSG_USE_RTLD_R)); 131 dbg_print(0, MSG_INTL(MSG_USE_RTLD_S)); 132 133 Dbg_util_nl(0, DBG_NL_FRC); 134 dbg_print(0, MSG_INTL(MSG_USE_LD_A)); 135 dbg_print(0, MSG_INTL(MSG_USE_LD_B)); 136 dbg_print(0, MSG_INTL(MSG_USE_LD_C)); 137 dbg_print(0, MSG_INTL(MSG_USE_LD_D)); 138 dbg_print(0, MSG_INTL(MSG_USE_LD_E)); 139 dbg_print(0, MSG_INTL(MSG_USE_LD_F)); 140 dbg_print(0, MSG_INTL(MSG_USE_LD_G)); 141 dbg_print(0, MSG_INTL(MSG_USE_LD_H)); 142 Dbg_util_nl(0, DBG_NL_FRC); 143 dbg_print(0, MSG_INTL(MSG_USE_LD_I)); 144 Dbg_util_nl(0, DBG_NL_FRC); 145 dbg_print(0, MSG_INTL(MSG_USE_LD_J)); 146 dbg_print(0, MSG_INTL(MSG_USE_LD_K)); 147 Dbg_util_nl(0, DBG_NL_FRC); 148 dbg_print(0, MSG_INTL(MSG_USE_LD_L)); 149 Dbg_util_nl(0, DBG_NL_FRC); 150 dbg_print(0, MSG_INTL(MSG_USE_LD_M)); 151 dbg_print(0, MSG_INTL(MSG_USE_LD_N)); 152 dbg_print(0, MSG_INTL(MSG_USE_LD_O)); 153 154 Dbg_util_nl(0, DBG_NL_FRC); 155 Dbg_util_nl(0, DBG_NL_FRC); 156 dbg_print(0, MSG_INTL(MSG_USE_ARGS)); 157 dbg_print(0, MSG_INTL(MSG_USE_AUDIT)); 158 dbg_print(0, MSG_INTL(MSG_USE_BASIC)); 159 dbg_print(0, MSG_INTL(MSG_USE_BINDINGS)); 160 dbg_print(0, MSG_INTL(MSG_USE_BINDINGS_2)); 161 dbg_print(0, MSG_INTL(MSG_USE_CAP)); 162 dbg_print(0, MSG_INTL(MSG_USE_DETAIL)); 163 #ifdef DEMANGLE 164 dbg_print(0, MSG_INTL(MSG_USE_DEMANGLE)); 165 #endif 166 dbg_print(0, MSG_INTL(MSG_USE_ENTRY)); 167 dbg_print(0, MSG_INTL(MSG_USE_FILES)); 168 dbg_print(0, MSG_INTL(MSG_USE_GOT)); 169 dbg_print(0, MSG_INTL(MSG_USE_HELP)); 170 dbg_print(0, MSG_INTL(MSG_USE_INIT)); 171 dbg_print(0, MSG_INTL(MSG_USE_LIBS)); 172 dbg_print(0, MSG_INTL(MSG_USE_LIBS_2)); 173 dbg_print(0, MSG_INTL(MSG_USE_LMID)); 174 dbg_print(0, MSG_INTL(MSG_USE_LONG)); 175 dbg_print(0, MSG_INTL(MSG_USE_MAP)); 176 dbg_print(0, MSG_INTL(MSG_USE_MOVE)); 177 dbg_print(0, MSG_INTL(MSG_USE_RELOC)); 178 dbg_print(0, MSG_INTL(MSG_USE_SECTIONS)); 179 dbg_print(0, MSG_INTL(MSG_USE_SEGMENTS)); 180 dbg_print(0, MSG_INTL(MSG_USE_SEGMENTS_2)); 181 dbg_print(0, MSG_INTL(MSG_USE_STATS)); 182 dbg_print(0, MSG_INTL(MSG_USE_STRTAB)); 183 dbg_print(0, MSG_INTL(MSG_USE_STRTAB_2)); 184 dbg_print(0, MSG_INTL(MSG_USE_SUPPORT)); 185 dbg_print(0, MSG_INTL(MSG_USE_SYMBOLS)); 186 dbg_print(0, MSG_INTL(MSG_USE_SYMBOLS_2)); 187 dbg_print(0, MSG_INTL(MSG_USE_TLS)); 188 dbg_print(0, MSG_INTL(MSG_USE_UNUSED)); 189 dbg_print(0, MSG_INTL(MSG_USE_UNUSED_2)); 190 dbg_print(0, MSG_INTL(MSG_USE_VERSIONS)); 191 Dbg_util_nl(0, DBG_NL_FRC); 192 } 193 194 /* 195 * Messaging support - funnel everything through dgettext() as this provides 196 * the real binding to libc. 197 */ 198 const char * 199 _liblddbg_msg(Msg mid) 200 { 201 return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 202 } 203 204 /* 205 * Validate and enable the appropriate debugging classes. 206 */ 207 uintptr_t 208 Dbg_setup(const char *string, Dbg_desc *dbp) 209 { 210 char *name, *_name; /* buffer in which to perform */ 211 /* strtok_r() operations. */ 212 char *lasts; 213 const char *delimit = MSG_ORIG(MSG_STR_DELIMIT); 214 215 if ((_name = (char *)malloc(strlen(string) + 1)) == 0) 216 return (S_ERROR); 217 (void) strcpy(_name, string); 218 219 /* 220 * The token should be of the form "-Dtok,tok,tok,...". Separate the 221 * pieces and build up the appropriate mask, unrecognized options are 222 * flagged. 223 */ 224 if ((name = strtok_r(_name, delimit, &lasts)) != NULL) { 225 do { 226 DBG_options *opt; 227 const char *str; 228 Boolean set, found = FALSE; 229 int ndx = 0; 230 231 if (name[0] == '!') { 232 set = FALSE; 233 name++; 234 } else 235 set = TRUE; 236 237 /* 238 * First, determine if the token represents a class or 239 * extra. 240 */ 241 for (opt = _Dbg_options; opt->o_name != NULL; opt++) { 242 if (strcmp(name, opt->o_name) != 0) 243 continue; 244 245 if (set == TRUE) { 246 if (opt->o_class) 247 dbp->d_class |= opt->o_class; 248 if (opt->o_extra) 249 dbp->d_extra |= opt->o_extra; 250 } else { 251 if (opt->o_class) 252 dbp->d_class &= ~(opt->o_class); 253 if (opt->o_extra) 254 dbp->d_extra &= ~(opt->o_extra); 255 } 256 found = TRUE; 257 break; 258 } 259 if (found == TRUE) 260 continue; 261 262 /* 263 * Second, determine if the token represents a known 264 * diagnostic identifier. Note, newlm identifiers are 265 * typically followed by a numeric id, for example 266 * newlm1, newlm2 ... Thus we only compare the 267 * initial text of the string. 268 */ 269 while ((str = _Dbg_strs[ndx++]) != NULL) { 270 char *tup; 271 272 if (strncmp(name, str, strlen(str)) != 0) 273 continue; 274 275 /* 276 * Translate lmid identifier to uppercase. 277 */ 278 for (tup = name; *tup; tup++) { 279 if ((*tup >= 'a') && (*tup <= 'z')) 280 *tup = *tup - ('a' - 'A'); 281 } 282 283 /* 284 * Save this lmid. The whole token buffer has 285 * been reallocated, so these names will remain 286 * once this routine returns. 287 */ 288 if (aplist_append(&dbp->d_list, name, 289 AL_CNT_DEBUG) == 0) 290 return (S_ERROR); 291 292 found = TRUE; 293 break; 294 } 295 296 if (found == FALSE) 297 dbg_print(0, MSG_INTL(MSG_USE_UNRECOG), name); 298 299 } while ((name = strtok_r(NULL, delimit, &lasts)) != NULL); 300 } 301 302 /* 303 * If the debug help option was specified dump a usage message. If 304 * this is the only debug class, return an indication that the user 305 * should exit. 306 */ 307 if ((_Dbg_cnt++ == 0) && (dbp->d_class & DBG_C_HELP)) { 308 Dbg_usage(); 309 if (dbp->d_class == DBG_C_HELP) 310 return (0); 311 } 312 return (1); 313 } 314 315 /* 316 * Define our own printing routine. This provides a basic fallback, as ld(1) 317 * and ld.so.1(1) provide their own routines that augment their diagnostic 318 * output, and direct the output to stderr. This item should be defined 319 * NODIRECT. 320 */ 321 /* PRINTFLIKE2 */ 322 void 323 dbg_print(Lm_list *lml, const char *format, ...) 324 { 325 va_list ap; 326 327 #if defined(lint) 328 /* 329 * The lml argument is only meaningful for diagnostics sent to ld.so.1. 330 * Supress the lint error by making a dummy assignment. 331 */ 332 lml = 0; 333 #endif 334 va_start(ap, format); 335 (void) vprintf(format, ap); 336 (void) printf(MSG_ORIG(MSG_STR_NL)); 337 va_end(ap); 338 } 339