/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1994, by Sun Microsytems, Inc. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Includes */ #ifndef DEBUG #define NDEBUG 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tnf_trace.h" /* * Defines */ #define TNF_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /* * Declarations */ extern void thr_probe_setup(void *); #pragma weak thr_probe_setup extern int _thr_main(void); /* * Globals */ static TNFW_B_CONTROL __tnfw_b_control_local = { TNFW_B_NOBUFFER, NULL, _tnf_trace_initialize, _tnf_fork_thread_setup, NULL }; TNFW_B_CONTROL *_tnfw_b_control = &__tnfw_b_control_local; static char *file_start; /* * Two Project Private Interfaces between prex and libtnfprobe - * tnf_trace_file_name and tnf_trace_file_size (three now ...) */ char tnf_trace_file_name[MAXPATHLEN] = ""; uint_t tnf_trace_file_size = 4194304; /* 4 Meg */ uint_t tnf_trace_file_min = (128 * 1024); tnf_ops_t tnf_trace_initial_tpd = { TNF_ALLOC_REUSABLE, /* mode */ tnfw_b_alloc, /* alloc */ tnfw_b_xcommit, /* commit */ tnfw_b_xabort, /* rollback */ { B_FALSE /* tnfw_w_initialized */ /* rest of struct is null */ }, 0 /* busy */ }; /* * tnf_process_enable: exported API to turn on tracing for the process * (on by default). */ void tnf_process_enable(void) { TNFW_B_UNSET_STOPPED(_tnfw_b_control->tnf_state); } /* * tnf_process_disable: exported API to turn off tracing for the process. */ void tnf_process_disable(void) { TNFW_B_SET_STOPPED(_tnfw_b_control->tnf_state); } /* * _tnf_trace_initialize * prex is responsible for creating and zeroing the trace file. So, * this routine expects the file to be there. It does try to handle * the case where prex (run as root) for probing a setuid root program * created the trace file as root. But, by the time the first probe is * hit (and this function is called), the program has reduced it's * privilege to its real user id - so the open fails. In this case, * this function unlinks the trace file and creates it again with its * current user id. The unlink can fail if the user does not have * write permission in the directory where the trace file is - if so, * tracing is set to broken. */ int _tnf_trace_initialize(void) { int fd; int created_file = 0; static mutex_t init_mutex = DEFAULTMUTEX; /* * if this is a MT program and the primordial thread hasn't been * setup yet, can't start tracing yet - THREAD_REG hasn't been * initialized, so we can't call open() in libthread. */ /* * Use dlsym to check for the present of thr_probe_setup. */ if ((((int(*)())dlsym(RTLD_DEFAULT, "thr_probe_setup")) != NULL) && (_thr_main() == -1)) { return (0); } /* * lock is needed to to prevent multiple threads from * mmapping the file. */ mutex_lock(&init_mutex); if (_tnfw_b_control->tnf_state != TNFW_B_NOBUFFER) { mutex_unlock(&init_mutex); return (1); } _tnfw_b_control->tnf_pid = getpid(); assert(tnf_trace_file_name[0] != '\0'); fd = open(tnf_trace_file_name, O_RDWR, TNF_FILE_MODE); if (fd < 0) { if (errno == EACCES) { /* * fix for bug 1197494: permission denied when * trying to open the file - happens for setuid root * programs - prex creates the file with root ownership */ if (unlink(tnf_trace_file_name) == -1) { goto SetBroken; } /* try creating it rather than opening it */ fd = open(tnf_trace_file_name, O_CREAT | O_RDWR | O_TRUNC, TNF_FILE_MODE); if (fd < 0) { goto SetBroken; } /* * expand file to needed size - ftruncate is not * portable, hence using lseek + write. */ if (lseek(fd, tnf_trace_file_size-1, SEEK_SET) == -1) { goto SetBroken; } if (write(fd, "", 1) != 1) { goto SetBroken; } created_file = 1; } else { goto SetBroken; } } /* mmap the file */ if ((file_start = mmap(0, tnf_trace_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (caddr_t) - 1) { goto SetBroken; } if (created_file == 1) { /* explicitly zero the file XXX - performance problem */ (void) memset(file_start, 0, tnf_trace_file_size); } _tnfw_b_control->tnf_buffer = file_start; if (tnfw_b_init_buffer(file_start, tnf_trace_file_size / TNF_BLOCK_SIZE, TNF_BLOCK_SIZE, B_TRUE) != TNFW_B_OK) { goto SetBroken; } /* successful return */ _tnfw_b_control->tnf_state = TNFW_B_RUNNING; mutex_unlock(&init_mutex); return (1); SetBroken: _tnfw_b_control->tnf_state = TNFW_B_BROKEN; mutex_unlock(&init_mutex); return (0); } /* * _tnf_sched_init */ void _tnf_sched_init(tnf_schedule_t * sched, hrtime_t t) { thread_t tid = 0; sched->time_base = t; /* thr_self() is stubbed out by libc for a non-threaded pgm */ tid = thr_self(); sched->tid = tid; sched->lwpid = _lwp_self(); sched->pid = getpid(); }