xref: /onnv-gate/usr/src/cmd/sgs/link_audit/common/truss.c (revision 12927:a27c46eb192b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53731Srie  * Common Development and Distribution License (the "License").
63731Srie  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*12927SRod.Evans@Sun.COM 
220Sstevel@tonic-gate /*
23*12927SRod.Evans@Sun.COM  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate #include <link.h>
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <stdio.h>
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <signal.h>
340Sstevel@tonic-gate #include "env.h"
350Sstevel@tonic-gate #include "mach.h"
360Sstevel@tonic-gate 
37*12927SRod.Evans@Sun.COM static Elist		*bindto_list = NULL;
38*12927SRod.Evans@Sun.COM static Elist		*bindfrom_list = NULL;
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static uint_t		pidout = 0;
410Sstevel@tonic-gate static pid_t		pid;
420Sstevel@tonic-gate static FILE		*outfile = stderr;
430Sstevel@tonic-gate static uint_t		indent = 1;
440Sstevel@tonic-gate static uint_t		indent_level = 1;
450Sstevel@tonic-gate static uint_t		trussall = 0;
460Sstevel@tonic-gate static uint_t		noexit = 0;
470Sstevel@tonic-gate static sigset_t		iset;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * It's not possible to gather the return code on routines
510Sstevel@tonic-gate  * which actually have a dependence on the 'stack frame structure'.
520Sstevel@tonic-gate  * Below is a list of known symbols which have this dependency,
530Sstevel@tonic-gate  * truss.so will disable the la_pltexit() entry point for these
540Sstevel@tonic-gate  * routines, which will remove the requirement for the extra
550Sstevel@tonic-gate  * stackframe that the link_auditing interface creates.
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * NOTE: this list *must* be mainted in alphabetical order.
580Sstevel@tonic-gate  *	 if this list ever became to long a faster search mechanism
590Sstevel@tonic-gate  *	 should be considered.
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate static char	*spec_sym[] = {
623731Srie #if	defined(__sparc)
630Sstevel@tonic-gate 	".stret1",
640Sstevel@tonic-gate 	".stret2",
650Sstevel@tonic-gate 	".stret4",
660Sstevel@tonic-gate 	".stret8",
670Sstevel@tonic-gate #endif
680Sstevel@tonic-gate 	"__getcontext",
690Sstevel@tonic-gate 	"_getcontext",
700Sstevel@tonic-gate 	"_getsp",
710Sstevel@tonic-gate 	"_longjmp",
720Sstevel@tonic-gate 	"_setcontext",
730Sstevel@tonic-gate 	"_setjmp",
740Sstevel@tonic-gate 	"_siglongjmp",
750Sstevel@tonic-gate 	"_sigsetjmp",
760Sstevel@tonic-gate 	"_vfork",
770Sstevel@tonic-gate 	"getcontext",
780Sstevel@tonic-gate 	"getsp",
790Sstevel@tonic-gate 	"longjmp",
800Sstevel@tonic-gate 	"setcontext",
810Sstevel@tonic-gate 	"setjmp",
820Sstevel@tonic-gate 	"siglongjmp",
830Sstevel@tonic-gate 	"sigsetjmp",
840Sstevel@tonic-gate 	"vfork",
850Sstevel@tonic-gate 	(char *)0
860Sstevel@tonic-gate };
870Sstevel@tonic-gate 
880Sstevel@tonic-gate uint_t
la_version(uint_t version)890Sstevel@tonic-gate la_version(uint_t version)
900Sstevel@tonic-gate {
910Sstevel@tonic-gate 	char	*str;
92*12927SRod.Evans@Sun.COM 
930Sstevel@tonic-gate 	if (version > LAV_CURRENT)
940Sstevel@tonic-gate 		(void) fprintf(stderr, "truss.so: unexpected version: %d\n",
95*12927SRod.Evans@Sun.COM 		    version);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	build_env_list(&bindto_list, (const char *)"TRUSS_BINDTO");
980Sstevel@tonic-gate 	build_env_list(&bindfrom_list, (const char *)"TRUSS_BINDFROM");
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	if (checkenv((const char *)"TRUSS_PID")) {
1010Sstevel@tonic-gate 		pidout = 1;
1020Sstevel@tonic-gate 		pid = getpid();
1030Sstevel@tonic-gate 	} else {
1040Sstevel@tonic-gate 		char	*str = "LD_AUDIT=";
1050Sstevel@tonic-gate 		/*
1060Sstevel@tonic-gate 		 * This disables truss output in subsequent fork()/exec
1070Sstevel@tonic-gate 		 * processes.
1080Sstevel@tonic-gate 		 */
1090Sstevel@tonic-gate 		(void) putenv(str);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	if (checkenv((const char *)"TRUSS_NOEXIT")) {
1130Sstevel@tonic-gate 		noexit++;
1140Sstevel@tonic-gate 		indent = 0;
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	if (checkenv((const char *)"TRUSS_NOINDENT"))
1180Sstevel@tonic-gate 		indent = 0;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	if (checkenv((const char *)"TRUSS_ALL"))
1210Sstevel@tonic-gate 		trussall++;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if (str = checkenv((const char *)"TRUSS_OUTPUT")) {
1240Sstevel@tonic-gate 		FILE	*fp;
1250Sstevel@tonic-gate 		char	fname[MAXPATHLEN];
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 		if (pidout)
1280Sstevel@tonic-gate 			(void) snprintf(fname, MAXPATHLEN, "%s.%d", str,
1290Sstevel@tonic-gate 			    (int)pid);
1300Sstevel@tonic-gate 		else
1310Sstevel@tonic-gate 			(void) strncpy(fname, str, MAXPATHLEN);
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 		if (fp = fopen(fname, (const char *)"w")) {
1340Sstevel@tonic-gate 			outfile = fp;
1350Sstevel@tonic-gate 		} else
1360Sstevel@tonic-gate 			(void) fprintf(stderr,
1370Sstevel@tonic-gate 			    "truss.so: unable to open file=`%s': %s\n",
1380Sstevel@tonic-gate 			    fname, strerror(errno));
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/*
1420Sstevel@tonic-gate 	 * Initalize iset to the full set of signals to be masked durring
1430Sstevel@tonic-gate 	 * pltenter/pltexit
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	(void) sigfillset(&iset);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	return (LAV_CURRENT);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate /* ARGSUSED1 */
1510Sstevel@tonic-gate uint_t
la_objopen(Link_map * lmp,Lmid_t lmid,uintptr_t * cookie)1520Sstevel@tonic-gate la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate 	uint_t	flags;
1550Sstevel@tonic-gate 	char	*basename;
1560Sstevel@tonic-gate 	static int	first = 1;
1570Sstevel@tonic-gate 
158*12927SRod.Evans@Sun.COM 	if ((bindto_list == NULL) || (trussall))
1590Sstevel@tonic-gate 		flags = LA_FLG_BINDTO;
1600Sstevel@tonic-gate 	else if (check_list(bindto_list, lmp->l_name))
1610Sstevel@tonic-gate 		flags = LA_FLG_BINDTO;
1620Sstevel@tonic-gate 	else
1630Sstevel@tonic-gate 		flags = 0;
1640Sstevel@tonic-gate 
165*12927SRod.Evans@Sun.COM 	if (((bindfrom_list == NULL) && first) || trussall ||
1660Sstevel@tonic-gate 	    (check_list(bindfrom_list, lmp->l_name)))
1670Sstevel@tonic-gate 		flags |= LA_FLG_BINDFROM;
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	first = 0;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	if (flags) {
172*12927SRod.Evans@Sun.COM 		if ((basename = strrchr(lmp->l_name, '/')) != NULL)
1730Sstevel@tonic-gate 			basename++;
1740Sstevel@tonic-gate 		else
1750Sstevel@tonic-gate 			basename = lmp->l_name;
1760Sstevel@tonic-gate 		*cookie = (uintptr_t)basename;
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	return (flags);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /* ARGSUSED1 */
1830Sstevel@tonic-gate #if	defined(_LP64)
1840Sstevel@tonic-gate uintptr_t
la_symbind64(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcook,uintptr_t * defcook,uint_t * sb_flags,const char * sym_name)1850Sstevel@tonic-gate la_symbind64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcook,
1860Sstevel@tonic-gate 	uintptr_t *defcook, uint_t *sb_flags, const char *sym_name)
1870Sstevel@tonic-gate #else
1880Sstevel@tonic-gate uintptr_t
1890Sstevel@tonic-gate la_symbind32(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcook,
1900Sstevel@tonic-gate 	uintptr_t *defcook, uint_t *sb_flags)
1910Sstevel@tonic-gate #endif
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate #if	!defined(_LP64)
1940Sstevel@tonic-gate 	const char	*sym_name = (const char *)symp->st_name;
1950Sstevel@tonic-gate #endif
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if (noexit)
1990Sstevel@tonic-gate 		*sb_flags |= LA_SYMB_NOPLTEXIT;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * Check to see if this symbol is one of the 'special' symbols.
2030Sstevel@tonic-gate 	 * If so we disable PLTEXIT calls for that symbol.
2040Sstevel@tonic-gate 	 */
2050Sstevel@tonic-gate 	if ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0) {
2060Sstevel@tonic-gate 		uint_t	ndx;
2070Sstevel@tonic-gate 		char	*str;
2080Sstevel@tonic-gate 		/* LINTED */
2090Sstevel@tonic-gate 		for (ndx = 0; str = spec_sym[ndx]; ndx++) {
2100Sstevel@tonic-gate 			int	cmpval;
2110Sstevel@tonic-gate 			cmpval = strcmp(sym_name, str);
2120Sstevel@tonic-gate 			if (cmpval < 0)
2130Sstevel@tonic-gate 				break;
2140Sstevel@tonic-gate 			if (cmpval == 0) {
2150Sstevel@tonic-gate 				*sb_flags |= LA_SYMB_NOPLTEXIT;
2160Sstevel@tonic-gate 				break;
2170Sstevel@tonic-gate 			}
2180Sstevel@tonic-gate 		}
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 	return (symp->st_value);
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate /* ARGSUSED1 */
2240Sstevel@tonic-gate #if	defined(__sparcv9)
2250Sstevel@tonic-gate uintptr_t
la_sparcv9_pltenter(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcookie,uintptr_t * defcookie,La_sparcv9_regs * regset,uint_t * sb_flags,const char * sym_name)2260Sstevel@tonic-gate la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2270Sstevel@tonic-gate 	uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags,
2280Sstevel@tonic-gate 	const char *sym_name)
2290Sstevel@tonic-gate #elif	defined(__sparc)
2300Sstevel@tonic-gate uintptr_t
2310Sstevel@tonic-gate la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2320Sstevel@tonic-gate 	uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags)
2330Sstevel@tonic-gate #elif   defined(__amd64)
2340Sstevel@tonic-gate uintptr_t
2350Sstevel@tonic-gate la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2360Sstevel@tonic-gate 	uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags,
2370Sstevel@tonic-gate 	const char *sym_name)
2380Sstevel@tonic-gate #elif   defined(__i386)
2390Sstevel@tonic-gate uintptr_t
2400Sstevel@tonic-gate la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2410Sstevel@tonic-gate 	uintptr_t *defcookie, La_i86_regs *regset, uint_t *sb_flags)
2420Sstevel@tonic-gate #endif
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	char		*istr;
2450Sstevel@tonic-gate 	char		*defname = (char *)(*defcookie);
2460Sstevel@tonic-gate 	char		*refname = (char *)(*refcookie);
2470Sstevel@tonic-gate #if	!defined(_LP64)
2480Sstevel@tonic-gate 	const char	*sym_name = (const char *)symp->st_name;
2490Sstevel@tonic-gate #endif
2500Sstevel@tonic-gate 	sigset_t	oset;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &iset, &oset);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	if (pidout)
2550Sstevel@tonic-gate 		(void) fprintf(outfile, "%5d:", (int)getpid());
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	if ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0)
2580Sstevel@tonic-gate 		istr = "";
2590Sstevel@tonic-gate 	else
2600Sstevel@tonic-gate 		istr = "*";
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	(void) fprintf(outfile, "%-15s -> %15s:%-*s%s(0x%lx, 0x%lx, 0x%lx)\n",
2630Sstevel@tonic-gate 		refname, defname, indent_level, istr, sym_name,
2640Sstevel@tonic-gate 		(long)GETARG0(regset), (long)GETARG1(regset),
2650Sstevel@tonic-gate 		(long)GETARG2(regset));
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	(void) fflush(outfile);
2680Sstevel@tonic-gate 	if (indent && ((*sb_flags & LA_SYMB_NOPLTEXIT) == 0))
2690Sstevel@tonic-gate 		indent_level++;
2700Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
2710Sstevel@tonic-gate 	return (symp->st_value);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate /* ARGSUSED1 */
2750Sstevel@tonic-gate #if	defined(_LP64)
2760Sstevel@tonic-gate /* ARGSUSED */
2770Sstevel@tonic-gate uintptr_t
la_pltexit64(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcookie,uintptr_t * defcookie,uintptr_t retval,const char * sym_name)2780Sstevel@tonic-gate la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2790Sstevel@tonic-gate 	uintptr_t *defcookie, uintptr_t retval, const char *sym_name)
2800Sstevel@tonic-gate #else
2810Sstevel@tonic-gate uintptr_t
2820Sstevel@tonic-gate la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2830Sstevel@tonic-gate 	uintptr_t *defcookie, uintptr_t retval)
2840Sstevel@tonic-gate #endif
2850Sstevel@tonic-gate {
2860Sstevel@tonic-gate 	char		*defname = (char *)(*defcookie);
2870Sstevel@tonic-gate 	char		*refname = (char *)(*refcookie);
2880Sstevel@tonic-gate 	sigset_t	oset;
2890Sstevel@tonic-gate #if	!defined(_LP64)
2900Sstevel@tonic-gate 	const char	*sym_name = (const char *)symp->st_name;
2910Sstevel@tonic-gate #endif
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &iset, &oset);
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	if (pidout)
2960Sstevel@tonic-gate 		(void) fprintf(outfile, "%5d:", (int)pid);
2970Sstevel@tonic-gate 	if (indent)
2980Sstevel@tonic-gate 		indent_level--;
2990Sstevel@tonic-gate 	(void) fprintf(outfile, "%-15s -> %15s:%*s%s - 0x%lx\n", refname,
3000Sstevel@tonic-gate 		defname, indent_level, "", sym_name, (ulong_t)retval);
3010Sstevel@tonic-gate 	(void) fflush(outfile);
3020Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
3030Sstevel@tonic-gate 	return (retval);
3040Sstevel@tonic-gate }
305