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