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