xref: /titanic_50/usr/src/cmd/sgs/link_audit/common/truss.c (revision c77a61a72b5ecdc507d6cf104142edd371a16c84)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 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 <link.h>
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include "env.h"
39 #include "mach.h"
40 
41 static Elist		*bindto_list = 0;
42 static Elist		*bindfrom_list = 0;
43 
44 static uint_t		pidout = 0;
45 static pid_t		pid;
46 static FILE		*outfile = stderr;
47 static uint_t		indent = 1;
48 static uint_t		indent_level = 1;
49 static uint_t		trussall = 0;
50 static uint_t		noexit = 0;
51 static sigset_t		iset;
52 
53 
54 /*
55  * It's not possible to gather the return code on routines
56  * which actually have a dependence on the 'stack frame structure'.
57  * Below is a list of known symbols which have this dependency,
58  * truss.so will disable the la_pltexit() entry point for these
59  * routines, which will remove the requirement for the extra
60  * stackframe that the link_auditing interface creates.
61  *
62  * NOTE: this list *must* be mainted in alphabetical order.
63  *	 if this list ever became to long a faster search mechanism
64  *	 should be considered.
65  */
66 static char	*spec_sym[] = {
67 #if defined(sparc)
68 	".stret1",
69 	".stret2",
70 	".stret4",
71 	".stret8",
72 #endif
73 	"__getcontext",
74 	"_getcontext",
75 	"_getsp",
76 	"_longjmp",
77 	"_setcontext",
78 	"_setjmp",
79 	"_siglongjmp",
80 	"_sigsetjmp",
81 	"_vfork",
82 	"getcontext",
83 	"getsp",
84 	"longjmp",
85 	"setcontext",
86 	"setjmp",
87 	"siglongjmp",
88 	"sigsetjmp",
89 	"vfork",
90 	(char *)0
91 };
92 
93 
94 uint_t
95 la_version(uint_t version)
96 {
97 	char	*str;
98 	if (version > LAV_CURRENT)
99 		(void) fprintf(stderr, "truss.so: unexpected version: %d\n",
100 			version);
101 
102 	build_env_list(&bindto_list, (const char *)"TRUSS_BINDTO");
103 	build_env_list(&bindfrom_list, (const char *)"TRUSS_BINDFROM");
104 
105 	if (checkenv((const char *)"TRUSS_PID")) {
106 		pidout = 1;
107 		pid = getpid();
108 	} else {
109 		char	*str = "LD_AUDIT=";
110 		/*
111 		 * This disables truss output in subsequent fork()/exec
112 		 * processes.
113 		 */
114 		(void) putenv(str);
115 	}
116 
117 	if (checkenv((const char *)"TRUSS_NOEXIT")) {
118 		noexit++;
119 		indent = 0;
120 	}
121 
122 	if (checkenv((const char *)"TRUSS_NOINDENT"))
123 		indent = 0;
124 
125 	if (checkenv((const char *)"TRUSS_ALL"))
126 		trussall++;
127 
128 	if (str = checkenv((const char *)"TRUSS_OUTPUT")) {
129 		FILE	*fp;
130 		char	fname[MAXPATHLEN];
131 
132 		if (pidout)
133 			(void) snprintf(fname, MAXPATHLEN, "%s.%d", str,
134 			    (int)pid);
135 		else
136 			(void) strncpy(fname, str, MAXPATHLEN);
137 
138 		if (fp = fopen(fname, (const char *)"w")) {
139 			outfile = fp;
140 		} else
141 			(void) fprintf(stderr,
142 			    "truss.so: unable to open file=`%s': %s\n",
143 			    fname, strerror(errno));
144 	}
145 
146 	/*
147 	 * Initalize iset to the full set of signals to be masked durring
148 	 * pltenter/pltexit
149 	 */
150 	(void) sigfillset(&iset);
151 
152 	return (LAV_CURRENT);
153 }
154 
155 
156 /* ARGSUSED1 */
157 uint_t
158 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie)
159 {
160 	uint_t	flags;
161 	char	*basename;
162 	static int	first = 1;
163 
164 	if ((bindto_list == 0) || (trussall))
165 		flags = LA_FLG_BINDTO;
166 	else if (check_list(bindto_list, lmp->l_name))
167 		flags = LA_FLG_BINDTO;
168 	else
169 		flags = 0;
170 
171 	if (((bindfrom_list == 0) && first) || trussall ||
172 	    (check_list(bindfrom_list, lmp->l_name)))
173 		flags |= LA_FLG_BINDFROM;
174 
175 	first = 0;
176 
177 	if (flags) {
178 		if ((basename = strrchr(lmp->l_name, '/')) != 0)
179 			basename++;
180 		else
181 			basename = lmp->l_name;
182 		*cookie = (uintptr_t)basename;
183 	}
184 
185 	return (flags);
186 }
187 
188 /* ARGSUSED1 */
189 #if	defined(_LP64)
190 uintptr_t
191 la_symbind64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcook,
192 	uintptr_t *defcook, uint_t *sb_flags, const char *sym_name)
193 #else
194 uintptr_t
195 la_symbind32(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcook,
196 	uintptr_t *defcook, uint_t *sb_flags)
197 #endif
198 {
199 #if	!defined(_LP64)
200 	const char	*sym_name = (const char *)symp->st_name;
201 #endif
202 
203 
204 	if (noexit)
205 		*sb_flags |= LA_SYMB_NOPLTEXIT;
206 
207 	/*
208 	 * Check to see if this symbol is one of the 'special' symbols.
209 	 * If so we disable PLTEXIT calls for that symbol.
210 	 */
211 	if ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0) {
212 		uint_t	ndx;
213 		char	*str;
214 		/* LINTED */
215 		for (ndx = 0; str = spec_sym[ndx]; ndx++) {
216 			int	cmpval;
217 			cmpval = strcmp(sym_name, str);
218 			if (cmpval < 0)
219 				break;
220 			if (cmpval == 0) {
221 				*sb_flags |= LA_SYMB_NOPLTEXIT;
222 				break;
223 			}
224 		}
225 	}
226 	return (symp->st_value);
227 }
228 
229 
230 
231 /* ARGSUSED1 */
232 #if	defined(__sparcv9)
233 uintptr_t
234 la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
235 	uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags,
236 	const char *sym_name)
237 #elif	defined(__sparc)
238 uintptr_t
239 la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
240 	uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags)
241 #elif   defined(__amd64)
242 uintptr_t
243 la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
244 	uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags,
245 	const char *sym_name)
246 #elif   defined(__i386)
247 uintptr_t
248 la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
249 	uintptr_t *defcookie, La_i86_regs *regset, uint_t *sb_flags)
250 #endif
251 {
252 	char		*istr;
253 	char		*defname = (char *)(*defcookie);
254 	char		*refname = (char *)(*refcookie);
255 #if	!defined(_LP64)
256 	const char	*sym_name = (const char *)symp->st_name;
257 #endif
258 	sigset_t	oset;
259 
260 	(void) sigprocmask(SIG_BLOCK, &iset, &oset);
261 
262 	if (pidout)
263 		(void) fprintf(outfile, "%5d:", (int)getpid());
264 
265 	if ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0)
266 		istr = "";
267 	else
268 		istr = "*";
269 
270 	(void) fprintf(outfile, "%-15s -> %15s:%-*s%s(0x%lx, 0x%lx, 0x%lx)\n",
271 		refname, defname, indent_level, istr, sym_name,
272 		(long)GETARG0(regset), (long)GETARG1(regset),
273 		(long)GETARG2(regset));
274 
275 	(void) fflush(outfile);
276 	if (indent && ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0))
277 		indent_level++;
278 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
279 	return (symp->st_value);
280 }
281 
282 
283 /* ARGSUSED1 */
284 #if	defined(_LP64)
285 /* ARGSUSED */
286 uintptr_t
287 la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
288 	uintptr_t *defcookie, uintptr_t retval, const char *sym_name)
289 #else
290 uintptr_t
291 la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
292 	uintptr_t *defcookie, uintptr_t retval)
293 #endif
294 {
295 	char		*defname = (char *)(*defcookie);
296 	char		*refname = (char *)(*refcookie);
297 	sigset_t	oset;
298 #if	!defined(_LP64)
299 	const char	*sym_name = (const char *)symp->st_name;
300 #endif
301 
302 	(void) sigprocmask(SIG_BLOCK, &iset, &oset);
303 
304 	if (pidout)
305 		(void) fprintf(outfile, "%5d:", (int)pid);
306 	if (indent)
307 		indent_level--;
308 	(void) fprintf(outfile, "%-15s -> %15s:%*s%s - 0x%lx\n", refname,
309 		defname, indent_level, "", sym_name, (ulong_t)retval);
310 	(void) fflush(outfile);
311 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
312 	return (retval);
313 }
314