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 /* 30 * Includes 31 */ 32 33 #ifndef DEBUG 34 #define NDEBUG 1 35 #endif 36 37 #include <assert.h> 38 #include <limits.h> 39 #include <values.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include <stdlib.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 #include <fcntl.h> 47 #include <dlfcn.h> 48 #include <sys/mman.h> 49 #include <sys/param.h> 50 51 #include <thread.h> 52 #include <sys/lwp.h> 53 #include <errno.h> 54 55 #include "tnf_trace.h" 56 57 58 /* 59 * Defines 60 */ 61 #define TNF_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 62 63 /* 64 * Declarations 65 */ 66 67 extern void thr_probe_setup(void *); 68 #pragma weak thr_probe_setup 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, fd, 0)) == (caddr_t)-1) { 208 goto SetBroken; 209 } 210 if (created_file == 1) { 211 /* explicitly zero the file XXX - performance problem */ 212 (void) memset(file_start, 0, tnf_trace_file_size); 213 } 214 _tnfw_b_control->tnf_buffer = file_start; 215 216 if (tnfw_b_init_buffer(file_start, tnf_trace_file_size / TNF_BLOCK_SIZE, 217 TNF_BLOCK_SIZE, B_TRUE) != TNFW_B_OK) { 218 goto SetBroken; 219 } 220 221 /* successful return */ 222 _tnfw_b_control->tnf_state = TNFW_B_RUNNING; 223 mutex_unlock(&init_mutex); 224 return (1); 225 226 SetBroken: 227 _tnfw_b_control->tnf_state = TNFW_B_BROKEN; 228 mutex_unlock(&init_mutex); 229 return (0); 230 231 } 232 233 /* 234 * _tnf_sched_init 235 */ 236 237 void 238 _tnf_sched_init(tnf_schedule_t *sched, hrtime_t t) 239 { 240 thread_t tid = 0; 241 242 sched->time_base = t; 243 /* thr_self() is stubbed out by libc for a non-threaded pgm */ 244 tid = thr_self(); 245 sched->tid = tid; 246 sched->lwpid = _lwp_self(); 247 sched->pid = getpid(); 248 } 249