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 67extern void thr_probe_setup(void *); 68#pragma weak thr_probe_setup 69 70/* 71 * Globals 72 */ 73 74static 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 82TNFW_B_CONTROL *_tnfw_b_control = &__tnfw_b_control_local; 83 84static 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 */ 90char tnf_trace_file_name[MAXPATHLEN] = ""; 91uint_t tnf_trace_file_size = 4194304; /* 4 Meg */ 92uint_t tnf_trace_file_min = (128 * 1024); 93 94tnf_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 */ 110void 111tnf_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 */ 119void 120tnf_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 */ 138int 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 226SetBroken: 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 237void 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