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 <stdio.h> 28 #include <stdarg.h> 29 #include <errno.h> 30 #include <strings.h> 31 #include <dlfcn.h> 32 #include <debug.h> 33 #include "msg.h" 34 35 /* 36 * dbg_setup() can be called a number of times. The typical use through 37 * LD_OPTIONS, results in dbg_setup() being called as the first argument to 38 * ld(1). It's also possible to pass debugging tokens through the compiler, 39 * for example -Wl,-Dlibs -Wl-Ddetail, in which case multiple dbg_setup() 40 * calls are made. 41 * 42 * A distinction is also made between diagnostics being requested before any 43 * other ld(1) options are read, or whether the debugging options occur 44 * between other options on the command line. In the latter case, the 45 * debugging options can be used to isolate diagnostics around one or more 46 * input files. The "phase" argument allows us to select which phase of 47 * dbg_setup() processing we should isolate ourselves to. 48 * 49 * dbg_print() can require the output filename for use in the diagnostics 50 * created. Save the address of the output filename pointer for this use. 51 */ 52 static const char **Name = NULL; 53 static int Phase = 0; 54 55 /* Debug file output state */ 56 static struct { 57 FILE *fptr; /* File to send debug output */ 58 int close_needed; /* True if explicitly opened stream */ 59 } dbg_ofile = { 60 stderr, 61 0 62 }; 63 64 65 /* 66 * If there is an explicitly opened debug file, close it and reset the state. 67 */ 68 void 69 dbg_cleanup(void) 70 { 71 if (dbg_ofile.close_needed) { 72 (void) fclose(dbg_ofile.fptr); 73 dbg_ofile.close_needed = 0; 74 dbg_ofile.fptr = stderr; 75 } 76 } 77 78 /* 79 * Process debug tokens. Returns True (1) on success, and False (0) 80 * on failure. 81 */ 82 int 83 dbg_setup(Ofl_desc *ofl, const char *options, int phase) 84 { 85 const char *ofile; 86 87 if (Phase == 0) 88 Phase = phase; 89 else if (Phase != phase) 90 return (1); 91 92 Name = &ofl->ofl_name; 93 94 /* 95 * Call the debugging setup routine to initialize the mask and 96 * debug function array. 97 */ 98 if (Dbg_setup(DBG_CALLER_LD, options, dbg_desc, &ofile) == 0) 99 return (0); 100 101 /* 102 * If output= token was used, close the old file if necessary 103 * and open a new one if the file name is not NULL. 104 */ 105 if (ofile) { 106 dbg_cleanup(); 107 if (*ofile != '\0') { 108 FILE *fptr = fopen(ofile, MSG_ORIG(MSG_DBG_FOPEN_MODE)); 109 if (fptr == NULL) { 110 int err = errno; 111 112 eprintf(ofl->ofl_lml, ERR_FATAL, 113 MSG_INTL(MSG_SYS_OPEN), ofile, 114 strerror(err)); 115 return (0); 116 } else { 117 dbg_ofile.fptr = fptr; 118 dbg_ofile.close_needed = 1; 119 } 120 } 121 } 122 123 /* 124 * Now that the output file is established, generate help 125 * output if the user specified the debug help token. 126 */ 127 if (dbg_desc->d_extra & DBG_E_HELP) 128 Dbg_help(); 129 130 return (1); 131 } 132 133 /* PRINTFLIKE2 */ 134 void 135 dbg_print(Lm_list *lml, const char *format, ...) 136 { 137 static char *prestr = NULL; 138 va_list args; 139 140 #if defined(lint) 141 /* 142 * The lml argument is only meaningful for diagnostics sent to ld.so.1. 143 * Supress the lint error by making a dummy assignment. 144 */ 145 lml = NULL; 146 #endif 147 /* 148 * Knock off any newline indicator to signify that a diagnostic has 149 * been processed. 150 */ 151 dbg_desc->d_extra &= ~DBG_E_STDNL; 152 153 if (DBG_ISSNAME()) { 154 /* 155 * If the debugging options have requested each diagnostic line 156 * be prepended by a name create a prefix string. 157 */ 158 if ((prestr == NULL) && *Name) { 159 const char *name, *cls; 160 size_t len; 161 162 /* 163 * Select the fullname or basename of the output file 164 * being created. 165 */ 166 if (DBG_ISFNAME()) 167 name = *Name; 168 else { 169 if ((name = 170 strrchr(*Name, '/')) == NULL) 171 name = *Name; 172 else 173 name++; 174 } 175 len = strlen(name) + 176 strlen(MSG_INTL(MSG_DBG_NAME_FMT)) + 1; 177 178 /* 179 * Add the output file class if required. 180 */ 181 if (DBG_ISCLASS()) { 182 #if defined(_ELF64) 183 len += MSG_DBG_CLS64_FMT_SIZE; 184 cls = MSG_ORIG(MSG_DBG_CLS64_FMT); 185 #else 186 len += MSG_DBG_CLS32_FMT_SIZE; 187 cls = MSG_ORIG(MSG_DBG_CLS32_FMT); 188 #endif 189 } 190 191 /* 192 * Allocate a string to build the prefix. 193 */ 194 if ((prestr = libld_malloc(len)) == NULL) 195 prestr = (char *)MSG_INTL(MSG_DBG_DFLT_FMT); 196 else { 197 (void) snprintf(prestr, len, 198 MSG_INTL(MSG_DBG_NAME_FMT), name); 199 if (DBG_ISCLASS()) 200 (void) strcat(prestr, cls); 201 } 202 } 203 (void) fputs(prestr ? prestr : MSG_INTL(MSG_DBG_AOUT_FMT), 204 dbg_ofile.fptr); 205 } else 206 (void) fputs(MSG_INTL(MSG_DBG_DFLT_FMT), dbg_ofile.fptr); 207 208 va_start(args, format); 209 (void) vfprintf(dbg_ofile.fptr, format, args); 210 (void) fprintf(dbg_ofile.fptr, MSG_ORIG(MSG_STR_NL)); 211 va_end(args); 212 } 213