summaryrefslogtreecommitdiff
path: root/usr/src/lib/libtnfprobe/trace_init.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libtnfprobe/trace_init.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libtnfprobe/trace_init.c')
-rw-r--r--usr/src/lib/libtnfprobe/trace_init.c249
1 files changed, 249 insertions, 0 deletions
diff --git a/usr/src/lib/libtnfprobe/trace_init.c b/usr/src/lib/libtnfprobe/trace_init.c
new file mode 100644
index 0000000000..d81c8bd0c9
--- /dev/null
+++ b/usr/src/lib/libtnfprobe/trace_init.c
@@ -0,0 +1,249 @@
+/*
+ * 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 <assert.h>
+#include <limits.h>
+#include <values.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+
+#include <thread.h>
+#include <sys/lwp.h>
+#include <errno.h>
+
+#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();
+}