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 <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/param.h> 30 #include <stdio.h> 31 #include <fcntl.h> 32 #include <stdarg.h> 33 #include <dlfcn.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <thread.h> 37 #include <debug.h> 38 #include "_rtld.h" 39 #include "_elf.h" 40 #include "msg.h" 41 42 43 static int dbg_fd; /* debugging output file descriptor */ 44 static dev_t dbg_dev; 45 static rtld_ino_t dbg_ino; 46 static pid_t pid; 47 48 /* 49 * Enable diagnostic output. All debugging functions reside in the linker 50 * debugging library liblddbg.so which is lazy loaded when required. 51 */ 52 uintptr_t 53 dbg_setup(const char *options, Dbg_desc *dbp) 54 { 55 uintptr_t ret; 56 rtld_stat_t status; 57 58 /* 59 * If we're running secure, only allow debugging if ld.so.1 itself is 60 * owned by root and has its mode setuid. Fail silently. 61 */ 62 if ((rtld_flags & RT_FL_SECURE) && (is_rtld_setuid() == 0)) 63 return (0); 64 65 /* 66 * As Dbg_setup() will effectively lazy load the necessary support 67 * libraries, make sure ld.so.1 is initialized for plt relocations. 68 */ 69 if (elf_rtld_load() == 0) 70 return (0); 71 72 /* 73 * Call the debugging setup routine. This function verifies the 74 * debugging tokens provided and returns a mask indicating the debugging 75 * categories selected. The mask effectively enables calls to the 76 * debugging library. 77 */ 78 if ((ret = Dbg_setup(options, dbp)) != (uintptr_t)1) 79 return (ret); 80 81 /* 82 * Obtain the process id. 83 */ 84 pid = getpid(); 85 86 /* 87 * If an LD_DEBUG_OUTPUT file was specified then we need to direct all 88 * diagnostics to the specified file. Add the process id as a file 89 * suffix so that multiple processes that inherit the same debugging 90 * environment variable don't fight over the same file. 91 */ 92 if (dbg_file) { 93 char file[MAXPATHLEN]; 94 95 (void) snprintf(file, MAXPATHLEN, MSG_ORIG(MSG_DBG_FILE), 96 dbg_file, pid); 97 if ((dbg_fd = open(file, (O_RDWR | O_CREAT), 0666)) == -1) { 98 int err = errno; 99 100 eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 101 file, strerror(err)); 102 dbp->d_class = 0; 103 return (0); 104 } 105 } else { 106 /* 107 * The default is to direct debugging to the stderr. 108 */ 109 dbg_fd = 2; 110 } 111 112 /* 113 * Initialize the dev/inode pair to enable us to determine if 114 * the debugging file descriptor is still available once the 115 * application has been entered. 116 */ 117 (void) rtld_fstat(dbg_fd, &status); 118 dbg_dev = status.st_dev; 119 dbg_ino = status.st_ino; 120 121 return (ret); 122 } 123 124 static int 125 dbg_lmid(Lm_list *lml) 126 { 127 const char *str; 128 Aliste idx; 129 130 for (APLIST_TRAVERSE(dbg_desc->d_list, idx, str)) { 131 if (strcmp(lml->lm_lmidstr, str) == 0) 132 return (1); 133 } 134 return (0); 135 } 136 137 /* 138 * All diagnostic requests are funneled to this routine. 139 */ 140 /* PRINTFLIKE2 */ 141 void 142 dbg_print(Lm_list *lml, const char *format, ...) 143 { 144 va_list args; 145 char buffer[ERRSIZE + 1]; 146 pid_t _pid; 147 rtld_stat_t status; 148 Prfbuf prf; 149 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 /* 157 * If debugging has been isolated to individual link-map lists, 158 * determine whether this request originates from a link-map list that 159 * is being monitored. Otherwise, process all link-map list diagnostics 160 * except those that originate from ld.so.1 processing its own 161 * dependencies. 162 */ 163 if (dbg_desc->d_list && lml && lml->lm_lmidstr) { 164 if (dbg_lmid(lml) == 0) 165 return; 166 } else if (lml && (lml->lm_flags & LML_FLG_RTLDLM)) 167 return; 168 169 /* 170 * If we're in the application make sure the debugging file descriptor 171 * is still available (ie, the user hasn't closed and/or reused the 172 * same descriptor). 173 */ 174 if (rtld_flags & RT_FL_APPLIC) { 175 if ((rtld_fstat(dbg_fd, &status) == -1) || 176 (status.st_dev != dbg_dev) || 177 (status.st_ino != dbg_ino)) { 178 if (dbg_file) { 179 /* 180 * If the user specified output file has been 181 * disconnected try and reconnect to it. 182 */ 183 char file[MAXPATHLEN]; 184 185 (void) snprintf(file, MAXPATHLEN, 186 MSG_ORIG(MSG_DBG_FILE), dbg_file, pid); 187 if ((dbg_fd = open(file, (O_RDWR | O_APPEND), 188 0)) == -1) { 189 dbg_desc->d_class = 0; 190 return; 191 } 192 (void) rtld_fstat(dbg_fd, &status); 193 dbg_dev = status.st_dev; 194 dbg_ino = status.st_ino; 195 } else { 196 /* 197 * If stderr has been stolen from us simply 198 * turn debugging off. 199 */ 200 dbg_desc->d_class = 0; 201 return; 202 } 203 } 204 } 205 206 prf.pr_buf = prf.pr_cur = buffer; 207 prf.pr_len = ERRSIZE; 208 prf.pr_fd = dbg_fd; 209 210 /* 211 * Obtain the process id. 212 */ 213 _pid = getpid(); 214 215 if (lml) 216 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 217 else 218 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 219 prf.pr_cur--; 220 221 if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 222 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 223 prf.pr_cur--; 224 } 225 if (rtld_flags & RT_FL_THREADS) { 226 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 227 prf.pr_cur--; 228 } 229 230 /* 231 * Format the message and print it. 232 */ 233 va_start(args, format); 234 (void) doprf(format, args, &prf); 235 *(prf.pr_cur - 1) = '\n'; 236 (void) dowrite(&prf); 237 va_end(args); 238 } 239