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 int dbg_add_pid; /* True to add pid to debug file name */ 47 static pid_t pid; 48 49 /* 50 * Enable diagnostic output. All debugging functions reside in the linker 51 * debugging library liblddbg.so which is lazy loaded when required. 52 */ 53 int 54 dbg_setup(const char *options, Dbg_desc *dbp) 55 { 56 rtld_stat_t status; 57 const char *ofile; 58 59 /* 60 * If we're running secure, only allow debugging if ld.so.1 itself is 61 * owned by root and has its mode setuid. Fail silently. 62 */ 63 if ((rtld_flags & RT_FL_SECURE) && (is_rtld_setuid() == 0)) 64 return (1); 65 66 /* 67 * As Dbg_setup() will effectively lazy load the necessary support 68 * libraries, make sure ld.so.1 is initialized for plt relocations. 69 */ 70 if (elf_rtld_load() == 0) 71 return (1); 72 73 /* 74 * Call the debugging setup routine. This function verifies the 75 * debugging tokens provided and returns a mask indicating the debugging 76 * categories selected. The mask effectively enables calls to the 77 * debugging library. 78 */ 79 if (Dbg_setup(DBG_CALLER_RTLD, options, dbp, &ofile) == 0) 80 return (0); 81 82 /* 83 * Obtain the process id. 84 */ 85 pid = getpid(); 86 87 /* 88 * If an LD_DEBUG_OUTPUT file was specified then we need to direct all 89 * diagnostics to the specified file. Add the process id as a file 90 * suffix so that multiple processes that inherit the same debugging 91 * environment variable don't fight over the same file. 92 * 93 * If LD_DEBUG_OUTPUT is not specified, and the output=file token 94 * was, then we direct all diagnostics to that file. Unlike 95 * LD_DEBUG_OUTPUT, we do not add the process id suffix. This 96 * is more convenient for interactive use. 97 * 98 * If neither redirection option is present, we send debugging 99 * output to stderr. Note that the caller will not be able 100 * to pipe or redirect this output at the shell level. libc 101 * has not yet initialized things to make that possible. 102 */ 103 if (dbg_file == NULL) { 104 if (ofile && (*ofile != '\0')) 105 dbg_file = ofile; 106 } else { 107 dbg_add_pid = 1; 108 } 109 110 if (dbg_file) { 111 char _file[MAXPATHLEN]; 112 const char *file; 113 114 if (dbg_add_pid) { 115 file = _file; 116 (void) snprintf(_file, MAXPATHLEN, 117 MSG_ORIG(MSG_DBG_FILE), dbg_file, pid); 118 } else { 119 file = dbg_file; 120 } 121 dbg_fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0666); 122 if (dbg_fd == -1) { 123 int err = errno; 124 125 eprintf(&lml_rtld, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 126 file, strerror(err)); 127 dbp->d_class = 0; 128 return (0); 129 } 130 } else { 131 /* 132 * The default is to direct debugging to the stderr. 133 */ 134 dbg_fd = 2; 135 } 136 137 /* 138 * Initialize the dev/inode pair to enable us to determine if 139 * the debugging file descriptor is still available once the 140 * application has been entered. 141 */ 142 (void) rtld_fstat(dbg_fd, &status); 143 dbg_dev = status.st_dev; 144 dbg_ino = status.st_ino; 145 146 /* 147 * Now that the output file is established, generate help 148 * output if the user specified the debug help token. 149 */ 150 if (dbp->d_extra & DBG_E_HELP) 151 Dbg_help(); 152 153 return (1); 154 } 155 156 /* 157 * Return True (1) if dbg_print() should produce output for the 158 * specified link-map list, and False (0) otherwise. 159 */ 160 static int 161 dbg_lmid_validate(Lm_list *lml) 162 { 163 const char *str; 164 Aliste idx; 165 166 /* 167 * The LDSO link-map list is a special case, requiring 168 * an explicit user request. 169 */ 170 if (lml->lm_flags & LML_FLG_RTLDLM) 171 return ((dbg_desc->d_extra & DBG_E_LMID_LDSO) != 0); 172 173 /* 174 * Approve special cases: 175 * - The link-map list has no name 176 * - lmid=all was set 177 * - lmid=alt was set, and this is not the BASE linkmap 178 */ 179 if ((lml->lm_lmidstr == NULL) || 180 ((dbg_desc->d_extra & DBG_E_LMID_ALL) != 0) || 181 (((dbg_desc->d_extra & DBG_E_LMID_ALT) != 0) && 182 ((lml->lm_flags & LML_FLG_BASELM) == 0))) 183 return (1); 184 185 /* 186 * If there is no list of specific link-map list names to check, 187 * then approval depends on lmid={ldso|alt} not being specified. 188 */ 189 if (aplist_nitems(dbg_desc->d_list) == 0) 190 return ((dbg_desc->d_extra & 191 (DBG_E_LMID_LDSO | DBG_E_LMID_ALT)) == 0); 192 193 /* 194 * Compare the link-map list name against the list of approved names 195 */ 196 for (APLIST_TRAVERSE(dbg_desc->d_list, idx, str)) 197 if (strcmp(lml->lm_lmidstr, str) == 0) 198 return (1); 199 200 /* Output for this linkmap is denied */ 201 return (0); 202 } 203 204 /* 205 * All diagnostic requests are funneled to this routine. 206 */ 207 /* PRINTFLIKE2 */ 208 void 209 dbg_print(Lm_list *lml, const char *format, ...) 210 { 211 va_list args; 212 char buffer[ERRSIZE + 1]; 213 pid_t _pid; 214 rtld_stat_t status; 215 Prfbuf prf; 216 217 /* 218 * Knock off any newline indicator to signify that a diagnostic has 219 * been processed. 220 */ 221 dbg_desc->d_extra &= ~DBG_E_STDNL; 222 223 /* 224 * If debugging has been isolated to individual link-map lists, 225 * determine whether this request originates from a link-map list that 226 * is being monitored. 227 */ 228 if (lml && (dbg_lmid_validate(lml) == 0)) 229 return; 230 231 /* 232 * If we're in the application make sure the debugging file descriptor 233 * is still available (ie, the user hasn't closed and/or reused the 234 * same descriptor). 235 */ 236 if (rtld_flags & RT_FL_APPLIC) { 237 if ((rtld_fstat(dbg_fd, &status) == -1) || 238 (status.st_dev != dbg_dev) || 239 (status.st_ino != dbg_ino)) { 240 if (dbg_file) { 241 /* 242 * If the user specified output file has been 243 * disconnected try and reconnect to it. 244 */ 245 char _file[MAXPATHLEN]; 246 const char *file; 247 248 if (dbg_add_pid) { 249 file = _file; 250 (void) snprintf(_file, MAXPATHLEN, 251 MSG_ORIG(MSG_DBG_FILE), dbg_file, 252 pid); 253 } else { 254 file = dbg_file; 255 } 256 if ((dbg_fd = open(file, (O_RDWR | O_APPEND), 257 0)) == -1) { 258 dbg_desc->d_class = 0; 259 return; 260 } 261 (void) rtld_fstat(dbg_fd, &status); 262 dbg_dev = status.st_dev; 263 dbg_ino = status.st_ino; 264 } else { 265 /* 266 * If stderr has been stolen from us simply 267 * turn debugging off. 268 */ 269 dbg_desc->d_class = 0; 270 return; 271 } 272 } 273 } 274 275 prf.pr_buf = prf.pr_cur = buffer; 276 prf.pr_len = ERRSIZE; 277 prf.pr_fd = dbg_fd; 278 279 /* 280 * Obtain the process id. 281 */ 282 _pid = getpid(); 283 284 if (lml) 285 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_PID), _pid); 286 else 287 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_UNDEF)); 288 prf.pr_cur--; 289 290 if (DBG_ISLMID() && lml && lml->lm_lmidstr) { 291 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_LMID), lml->lm_lmidstr); 292 prf.pr_cur--; 293 } 294 if (rtld_flags & RT_FL_THREADS) { 295 (void) bufprint(&prf, MSG_ORIG(MSG_DBG_THREAD), rt_thr_self()); 296 prf.pr_cur--; 297 } 298 299 /* 300 * Format the message and print it. 301 */ 302 va_start(args, format); 303 (void) doprf(format, args, &prf); 304 *(prf.pr_cur - 1) = '\n'; 305 (void) dowrite(&prf); 306 va_end(args); 307 } 308