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 (c) 1994, by Sun Microsytems, Inc. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Includes 30 */ 31 32 #ifndef DEBUG 33 #define NDEBUG 1 34 #endif 35 36 #include <assert.h> 37 #include <limits.h> 38 #include <values.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <stdlib.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <fcntl.h> 46 #include <dlfcn.h> 47 #include <sys/mman.h> 48 #include <sys/param.h> 49 50 #include <thread.h> 51 #include <sys/lwp.h> 52 #include <errno.h> 53 54 #include "tnf_trace.h" 55 56 57 /* 58 * Defines 59 */ 60 #define TNF_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 61 62 /* 63 * Declarations 64 */ 65 66 extern void thr_probe_setup(void *); 67 #pragma weak thr_probe_setup 68 extern int _thr_main(void); 69 70 /* 71 * Globals 72 */ 73 74 static TNFW_B_CONTROL __tnfw_b_control_local = { 75 TNFW_B_NOBUFFER, 76 NULL, 77 _tnf_trace_initialize, 78 _tnf_fork_thread_setup, 79 NULL 80 }; 81 82 TNFW_B_CONTROL *_tnfw_b_control = &__tnfw_b_control_local; 83 84 static char *file_start; 85 86 /* 87 * Two Project Private Interfaces between prex and libtnfprobe - 88 * tnf_trace_file_name and tnf_trace_file_size (three now ...) 89 */ 90 char tnf_trace_file_name[MAXPATHLEN] = ""; 91 uint_t tnf_trace_file_size = 4194304; /* 4 Meg */ 92 uint_t tnf_trace_file_min = (128 * 1024); 93 94 tnf_ops_t tnf_trace_initial_tpd = { 95 TNF_ALLOC_REUSABLE, /* mode */ 96 tnfw_b_alloc, /* alloc */ 97 tnfw_b_xcommit, /* commit */ 98 tnfw_b_xabort, /* rollback */ 99 { 100 B_FALSE /* tnfw_w_initialized */ 101 /* rest of struct is null */ 102 }, 103 0 /* busy */ 104 }; 105 106 /* 107 * tnf_process_enable: exported API to turn on tracing for the process 108 * (on by default). 109 */ 110 void 111 tnf_process_enable(void) 112 { 113 TNFW_B_UNSET_STOPPED(_tnfw_b_control->tnf_state); 114 } 115 116 /* 117 * tnf_process_disable: exported API to turn off tracing for the process. 118 */ 119 void 120 tnf_process_disable(void) 121 { 122 TNFW_B_SET_STOPPED(_tnfw_b_control->tnf_state); 123 } 124 125 /* 126 * _tnf_trace_initialize 127 * prex is responsible for creating and zeroing the trace file. So, 128 * this routine expects the file to be there. It does try to handle 129 * the case where prex (run as root) for probing a setuid root program 130 * created the trace file as root. But, by the time the first probe is 131 * hit (and this function is called), the program has reduced it's 132 * privilege to its real user id - so the open fails. In this case, 133 * this function unlinks the trace file and creates it again with its 134 * current user id. The unlink can fail if the user does not have 135 * write permission in the directory where the trace file is - if so, 136 * tracing is set to broken. 137 */ 138 int 139 _tnf_trace_initialize(void) 140 { 141 int fd; 142 int created_file = 0; 143 static mutex_t init_mutex = DEFAULTMUTEX; 144 145 /* 146 * if this is a MT program and the primordial thread hasn't been 147 * setup yet, can't start tracing yet - THREAD_REG hasn't been 148 * initialized, so we can't call open() in libthread. 149 */ 150 151 /* 152 * Use dlsym to check for the present of thr_probe_setup. 153 */ 154 155 if ((((int(*)())dlsym(RTLD_DEFAULT, "thr_probe_setup")) != NULL) && 156 (_thr_main() == -1)) { 157 return (0); 158 } 159 160 /* 161 * lock is needed to to prevent multiple threads from 162 * mmapping the file. 163 */ 164 mutex_lock(&init_mutex); 165 if (_tnfw_b_control->tnf_state != TNFW_B_NOBUFFER) { 166 mutex_unlock(&init_mutex); 167 return (1); 168 } 169 170 _tnfw_b_control->tnf_pid = getpid(); 171 assert(tnf_trace_file_name[0] != '\0'); 172 fd = open(tnf_trace_file_name, O_RDWR, TNF_FILE_MODE); 173 if (fd < 0) { 174 if (errno == EACCES) { 175 /* 176 * fix for bug 1197494: permission denied when 177 * trying to open the file - happens for setuid root 178 * programs - prex creates the file with root ownership 179 */ 180 if (unlink(tnf_trace_file_name) == -1) { 181 goto SetBroken; 182 } 183 /* try creating it rather than opening it */ 184 fd = open(tnf_trace_file_name, 185 O_CREAT | O_RDWR | O_TRUNC, TNF_FILE_MODE); 186 if (fd < 0) { 187 goto SetBroken; 188 } 189 /* 190 * expand file to needed size - ftruncate is not 191 * portable, hence using lseek + write. 192 */ 193 if (lseek(fd, tnf_trace_file_size-1, SEEK_SET) == -1) { 194 goto SetBroken; 195 } 196 if (write(fd, "", 1) != 1) { 197 goto SetBroken; 198 } 199 created_file = 1; 200 } else { 201 goto SetBroken; 202 } 203 } 204 205 /* mmap the file */ 206 if ((file_start = mmap(0, tnf_trace_file_size, 207 PROT_READ | PROT_WRITE, MAP_SHARED, 208 fd, 0)) == (caddr_t) - 1) { 209 goto SetBroken; 210 } 211 if (created_file == 1) { 212 /* explicitly zero the file XXX - performance problem */ 213 (void) memset(file_start, 0, tnf_trace_file_size); 214 } 215 _tnfw_b_control->tnf_buffer = file_start; 216 217 if (tnfw_b_init_buffer(file_start, tnf_trace_file_size / TNF_BLOCK_SIZE, 218 TNF_BLOCK_SIZE, B_TRUE) != TNFW_B_OK) { 219 goto SetBroken; 220 } 221 222 /* successful return */ 223 _tnfw_b_control->tnf_state = TNFW_B_RUNNING; 224 mutex_unlock(&init_mutex); 225 return (1); 226 227 SetBroken: 228 _tnfw_b_control->tnf_state = TNFW_B_BROKEN; 229 mutex_unlock(&init_mutex); 230 return (0); 231 232 } 233 234 /* 235 * _tnf_sched_init 236 */ 237 238 void 239 _tnf_sched_init(tnf_schedule_t * sched, hrtime_t t) 240 { 241 thread_t tid = 0; 242 243 sched->time_base = t; 244 /* thr_self() is stubbed out by libc for a non-threaded pgm */ 245 tid = thr_self(); 246 sched->tid = tid; 247 sched->lwpid = _lwp_self(); 248 sched->pid = getpid(); 249 } 250