10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*6812Sraf * Common Development and Distribution License (the "License"). 6*6812Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*6812Sraf 220Sstevel@tonic-gate /* 23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*6812Sraf * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Includes 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #ifndef DEBUG 340Sstevel@tonic-gate #define NDEBUG 1 350Sstevel@tonic-gate #endif 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <assert.h> 380Sstevel@tonic-gate #include <limits.h> 390Sstevel@tonic-gate #include <values.h> 400Sstevel@tonic-gate #include <stdio.h> 410Sstevel@tonic-gate #include <string.h> 420Sstevel@tonic-gate #include <unistd.h> 430Sstevel@tonic-gate #include <stdlib.h> 440Sstevel@tonic-gate #include <sys/types.h> 450Sstevel@tonic-gate #include <sys/stat.h> 460Sstevel@tonic-gate #include <fcntl.h> 470Sstevel@tonic-gate #include <dlfcn.h> 480Sstevel@tonic-gate #include <sys/mman.h> 490Sstevel@tonic-gate #include <sys/param.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <thread.h> 520Sstevel@tonic-gate #include <sys/lwp.h> 530Sstevel@tonic-gate #include <errno.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate #include "tnf_trace.h" 560Sstevel@tonic-gate 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * Defines 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate #define TNF_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 620Sstevel@tonic-gate 630Sstevel@tonic-gate /* 640Sstevel@tonic-gate * Declarations 650Sstevel@tonic-gate */ 660Sstevel@tonic-gate 670Sstevel@tonic-gate extern void thr_probe_setup(void *); 680Sstevel@tonic-gate #pragma weak thr_probe_setup 690Sstevel@tonic-gate 700Sstevel@tonic-gate /* 710Sstevel@tonic-gate * Globals 720Sstevel@tonic-gate */ 730Sstevel@tonic-gate 740Sstevel@tonic-gate static TNFW_B_CONTROL __tnfw_b_control_local = { 750Sstevel@tonic-gate TNFW_B_NOBUFFER, 760Sstevel@tonic-gate NULL, 770Sstevel@tonic-gate _tnf_trace_initialize, 780Sstevel@tonic-gate _tnf_fork_thread_setup, 790Sstevel@tonic-gate NULL 800Sstevel@tonic-gate }; 810Sstevel@tonic-gate 820Sstevel@tonic-gate TNFW_B_CONTROL *_tnfw_b_control = &__tnfw_b_control_local; 830Sstevel@tonic-gate 840Sstevel@tonic-gate static char *file_start; 850Sstevel@tonic-gate 860Sstevel@tonic-gate /* 870Sstevel@tonic-gate * Two Project Private Interfaces between prex and libtnfprobe - 880Sstevel@tonic-gate * tnf_trace_file_name and tnf_trace_file_size (three now ...) 890Sstevel@tonic-gate */ 900Sstevel@tonic-gate char tnf_trace_file_name[MAXPATHLEN] = ""; 910Sstevel@tonic-gate uint_t tnf_trace_file_size = 4194304; /* 4 Meg */ 920Sstevel@tonic-gate uint_t tnf_trace_file_min = (128 * 1024); 930Sstevel@tonic-gate 940Sstevel@tonic-gate tnf_ops_t tnf_trace_initial_tpd = { 950Sstevel@tonic-gate TNF_ALLOC_REUSABLE, /* mode */ 960Sstevel@tonic-gate tnfw_b_alloc, /* alloc */ 970Sstevel@tonic-gate tnfw_b_xcommit, /* commit */ 980Sstevel@tonic-gate tnfw_b_xabort, /* rollback */ 990Sstevel@tonic-gate { 1000Sstevel@tonic-gate B_FALSE /* tnfw_w_initialized */ 1010Sstevel@tonic-gate /* rest of struct is null */ 1020Sstevel@tonic-gate }, 1030Sstevel@tonic-gate 0 /* busy */ 1040Sstevel@tonic-gate }; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * tnf_process_enable: exported API to turn on tracing for the process 1080Sstevel@tonic-gate * (on by default). 1090Sstevel@tonic-gate */ 1100Sstevel@tonic-gate void 1110Sstevel@tonic-gate tnf_process_enable(void) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate TNFW_B_UNSET_STOPPED(_tnfw_b_control->tnf_state); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* 1170Sstevel@tonic-gate * tnf_process_disable: exported API to turn off tracing for the process. 1180Sstevel@tonic-gate */ 1190Sstevel@tonic-gate void 1200Sstevel@tonic-gate tnf_process_disable(void) 1210Sstevel@tonic-gate { 1220Sstevel@tonic-gate TNFW_B_SET_STOPPED(_tnfw_b_control->tnf_state); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* 1260Sstevel@tonic-gate * _tnf_trace_initialize 1270Sstevel@tonic-gate * prex is responsible for creating and zeroing the trace file. So, 1280Sstevel@tonic-gate * this routine expects the file to be there. It does try to handle 1290Sstevel@tonic-gate * the case where prex (run as root) for probing a setuid root program 1300Sstevel@tonic-gate * created the trace file as root. But, by the time the first probe is 1310Sstevel@tonic-gate * hit (and this function is called), the program has reduced it's 1320Sstevel@tonic-gate * privilege to its real user id - so the open fails. In this case, 1330Sstevel@tonic-gate * this function unlinks the trace file and creates it again with its 1340Sstevel@tonic-gate * current user id. The unlink can fail if the user does not have 1350Sstevel@tonic-gate * write permission in the directory where the trace file is - if so, 1360Sstevel@tonic-gate * tracing is set to broken. 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate int 1390Sstevel@tonic-gate _tnf_trace_initialize(void) 1400Sstevel@tonic-gate { 1410Sstevel@tonic-gate int fd; 1420Sstevel@tonic-gate int created_file = 0; 1430Sstevel@tonic-gate static mutex_t init_mutex = DEFAULTMUTEX; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * if this is a MT program and the primordial thread hasn't been 1470Sstevel@tonic-gate * setup yet, can't start tracing yet - THREAD_REG hasn't been 1480Sstevel@tonic-gate * initialized, so we can't call open() in libthread. 1490Sstevel@tonic-gate */ 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * Use dlsym to check for the present of thr_probe_setup. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate if ((((int(*)())dlsym(RTLD_DEFAULT, "thr_probe_setup")) != NULL) && 156*6812Sraf (thr_main() == -1)) { 1570Sstevel@tonic-gate return (0); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1610Sstevel@tonic-gate * lock is needed to to prevent multiple threads from 1620Sstevel@tonic-gate * mmapping the file. 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate mutex_lock(&init_mutex); 1650Sstevel@tonic-gate if (_tnfw_b_control->tnf_state != TNFW_B_NOBUFFER) { 1660Sstevel@tonic-gate mutex_unlock(&init_mutex); 1670Sstevel@tonic-gate return (1); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate _tnfw_b_control->tnf_pid = getpid(); 1710Sstevel@tonic-gate assert(tnf_trace_file_name[0] != '\0'); 1720Sstevel@tonic-gate fd = open(tnf_trace_file_name, O_RDWR, TNF_FILE_MODE); 1730Sstevel@tonic-gate if (fd < 0) { 1740Sstevel@tonic-gate if (errno == EACCES) { 1750Sstevel@tonic-gate /* 1760Sstevel@tonic-gate * fix for bug 1197494: permission denied when 1770Sstevel@tonic-gate * trying to open the file - happens for setuid root 1780Sstevel@tonic-gate * programs - prex creates the file with root ownership 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate if (unlink(tnf_trace_file_name) == -1) { 1810Sstevel@tonic-gate goto SetBroken; 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate /* try creating it rather than opening it */ 1840Sstevel@tonic-gate fd = open(tnf_trace_file_name, 185*6812Sraf O_CREAT | O_RDWR | O_TRUNC, TNF_FILE_MODE); 1860Sstevel@tonic-gate if (fd < 0) { 1870Sstevel@tonic-gate goto SetBroken; 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * expand file to needed size - ftruncate is not 1910Sstevel@tonic-gate * portable, hence using lseek + write. 1920Sstevel@tonic-gate */ 1930Sstevel@tonic-gate if (lseek(fd, tnf_trace_file_size-1, SEEK_SET) == -1) { 1940Sstevel@tonic-gate goto SetBroken; 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate if (write(fd, "", 1) != 1) { 1970Sstevel@tonic-gate goto SetBroken; 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate created_file = 1; 2000Sstevel@tonic-gate } else { 2010Sstevel@tonic-gate goto SetBroken; 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate /* mmap the file */ 2060Sstevel@tonic-gate if ((file_start = mmap(0, tnf_trace_file_size, 207*6812Sraf PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (caddr_t)-1) { 2080Sstevel@tonic-gate goto SetBroken; 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate if (created_file == 1) { 2110Sstevel@tonic-gate /* explicitly zero the file XXX - performance problem */ 2120Sstevel@tonic-gate (void) memset(file_start, 0, tnf_trace_file_size); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate _tnfw_b_control->tnf_buffer = file_start; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate if (tnfw_b_init_buffer(file_start, tnf_trace_file_size / TNF_BLOCK_SIZE, 217*6812Sraf TNF_BLOCK_SIZE, B_TRUE) != TNFW_B_OK) { 2180Sstevel@tonic-gate goto SetBroken; 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* successful return */ 2220Sstevel@tonic-gate _tnfw_b_control->tnf_state = TNFW_B_RUNNING; 2230Sstevel@tonic-gate mutex_unlock(&init_mutex); 2240Sstevel@tonic-gate return (1); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate SetBroken: 2270Sstevel@tonic-gate _tnfw_b_control->tnf_state = TNFW_B_BROKEN; 2280Sstevel@tonic-gate mutex_unlock(&init_mutex); 2290Sstevel@tonic-gate return (0); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate * _tnf_sched_init 2350Sstevel@tonic-gate */ 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate void 238*6812Sraf _tnf_sched_init(tnf_schedule_t *sched, hrtime_t t) 2390Sstevel@tonic-gate { 2400Sstevel@tonic-gate thread_t tid = 0; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate sched->time_base = t; 2430Sstevel@tonic-gate /* thr_self() is stubbed out by libc for a non-threaded pgm */ 2440Sstevel@tonic-gate tid = thr_self(); 2450Sstevel@tonic-gate sched->tid = tid; 2460Sstevel@tonic-gate sched->lwpid = _lwp_self(); 2470Sstevel@tonic-gate sched->pid = getpid(); 2480Sstevel@tonic-gate } 249