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