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 #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 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 struct stat 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 * If an LD_DEBUG_OUTPUT file was specified then we need to direct all 83 * diagnostics to the specified file. Add the process id as a file 84 * suffix so that multiple processes that inherit the same debugging 85 * environment variable don't fight over the same file. 86 */ 87 if (dbg_file) { 88 char file[MAXPATHLEN]; 89 90 (void) snprintf(file, MAXPATHLEN, MSG_ORIG(MSG_DBG_FILE), 91 dbg_file, getpid()); 92 if ((dbg_fd = open(file, (O_RDWR | O_CREAT), 0666)) == -1) { 93 int err = errno; 94 95 eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 96 file, strerror(err)); 97 dbp->d_class = 0; 98 return (0); 99 } 100 } else { 101 /* 102 * The default is to direct debugging to the stderr. 103 */ 104 dbg_fd = 2; 105 } 106 107 /* 108 * Initialize the dev/inode pair to enable us to determine if 109 * the debugging file descriptor is still available once the 110 * application has been entered. 111 */ 112 (void) fstat(dbg_fd, &status); 113 dbg_dev = status.st_dev; 114 dbg_ino = status.st_ino; 115 pid = getpid(); 116 117 return (ret); 118 } 119 120 static int 121 dbg_lmid(Lm_list *lml) 122 { 123 const char *str; 124 Aliste idx; 125 126 for (APLIST_TRAVERSE(dbg_desc->d_list, idx, str)) { 127 if (strcmp(lml->lm_lmidstr, str) == 0) 128 return (1); 129 } 130 return (0); 131 } 132 133 /* 134 * All diagnostic requests are funneled to this routine. 135 */ 136 /* PRINTFLIKE2 */ 137 void 138 dbg_print(Lm_list *lml, const char *format, ...) 139 { 140 va_list args; 141 char buffer[ERRSIZE + 1]; 142 pid_t _pid; 143 struct stat status; 144 Prfbuf prf; 145 146 /* 147 * Knock off any newline indicator to signify that a diagnostic has 148 * been processed. 149 */ 150 dbg_desc->d_extra &= ~DBG_E_STDNL; 151 152 /* 153 * If debugging has been isolated to individual link-map lists, 154 * determine whether this request originates from a link-map list that 155 * is being monitored. Otherwise, process all link-map list diagnostics 156 * except those that originate from ld.so.1 processing its own 157 * dependencies. 158 */ 159 if (dbg_desc->d_list && lml && lml->lm_lmidstr) { 160 if (dbg_lmid(lml) == 0) 161 return; 162 } else if (lml && (lml->lm_flags & LML_FLG_RTLDLM)) 163 return; 164 165 /* 166 * If we're in the application make sure the debugging file descriptor 167 * is still available (ie, the user hasn't closed and/or reused the 168 * same descriptor). 169 */ 170 if (rtld_flags & RT_FL_APPLIC) { 171 if ((fstat(dbg_fd, &status) == -1) || 172 (status.st_dev != dbg_dev) || 173 (status.st_ino != dbg_ino)) { 174 if (dbg_file) { 175 /* 176 * If the user specified output file has been 177 * disconnected try and reconnect to it. 178 */ 179 char file[MAXPATHLEN]; 180 181 (void) snprintf(file, MAXPATHLEN, 182 MSG_ORIG(MSG_DBG_FILE), dbg_file, pid); 183 if ((dbg_fd = open(file, (O_RDWR | O_APPEND), 184 0)) == -1) { 185 dbg_desc->d_class = 0; 186 return; 187 } 188 (void) fstat(dbg_fd, &status); 189 dbg_dev = status.st_dev; 190 dbg_ino = status.st_ino; 191 } else { 192 /* 193 * If stderr has been stolen from us simply 194 * turn debugging off. 195 */ 196 dbg_desc->d_class = 0; 197 return; 198 } 199 } 200 } 201 202 prf.pr_buf = prf.pr_cur = buffer; 203 prf.pr_len = ERRSIZE; 204 prf.pr_fd = dbg_fd; 205 206 /* 207 * The getpid() call is a 'special' interface between ld.so.1 and dbx, 208 * because of this getpid() can't be called freely until after control 209 * has been given to the user program. Once the control has been given 210 * to the user program we know that the r_debug structure has been 211 * properly initialized for the debugger. 212 */ 213 if (rtld_flags & RT_FL_APPLIC) 214 _pid = getpid(); 215 else 216 _pid = pid; 217 218 if (lml) 219 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 220 else 221 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 222 prf.pr_cur--; 223 224 if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 225 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 226 prf.pr_cur--; 227 } 228 if (rtld_flags & RT_FL_THREADS) { 229 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 230 prf.pr_cur--; 231 } 232 233 /* 234 * Format the message and print it. 235 */ 236 va_start(args, format); 237 (void) doprf(format, args, &prf); 238 *(prf.pr_cur - 1) = '\n'; 239 (void) dowrite(&prf); 240 va_end(args); 241 } 242