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