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