xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/debug.c (revision 7257d1b4)
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