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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
44 #include <sys/types.h>
49 #include <sys/param.h>
55 #include "tnf_trace.h"
61 #define TNF_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
67 extern void thr_probe_setup(void *);
68 #pragma weak thr_probe_setup
74 static TNFW_B_CONTROL __tnfw_b_control_local
= {
77 _tnf_trace_initialize
,
78 _tnf_fork_thread_setup
,
82 TNFW_B_CONTROL
*_tnfw_b_control
= &__tnfw_b_control_local
;
84 static char *file_start
;
87 * Two Project Private Interfaces between prex and libtnfprobe -
88 * tnf_trace_file_name and tnf_trace_file_size (three now ...)
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);
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 */
100 B_FALSE
/* tnfw_w_initialized */
101 /* rest of struct is null */
107 * tnf_process_enable: exported API to turn on tracing for the process
111 tnf_process_enable(void)
113 TNFW_B_UNSET_STOPPED(_tnfw_b_control
->tnf_state
);
117 * tnf_process_disable: exported API to turn off tracing for the process.
120 tnf_process_disable(void)
122 TNFW_B_SET_STOPPED(_tnfw_b_control
->tnf_state
);
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.
139 _tnf_trace_initialize(void)
142 int created_file
= 0;
143 static mutex_t init_mutex
= DEFAULTMUTEX
;
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.
152 * Use dlsym to check for the present of thr_probe_setup.
155 if ((((int(*)())dlsym(RTLD_DEFAULT
, "thr_probe_setup")) != NULL
) &&
156 (thr_main() == -1)) {
161 * lock is needed to to prevent multiple threads from
164 mutex_lock(&init_mutex
);
165 if (_tnfw_b_control
->tnf_state
!= TNFW_B_NOBUFFER
) {
166 mutex_unlock(&init_mutex
);
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
);
174 if (errno
== EACCES
) {
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
180 if (unlink(tnf_trace_file_name
) == -1) {
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
);
190 * expand file to needed size - ftruncate is not
191 * portable, hence using lseek + write.
193 if (lseek(fd
, tnf_trace_file_size
-1, SEEK_SET
) == -1) {
196 if (write(fd
, "", 1) != 1) {
206 if ((file_start
= mmap(0, tnf_trace_file_size
,
207 PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0)) == (caddr_t
)-1) {
210 if (created_file
== 1) {
211 /* explicitly zero the file XXX - performance problem */
212 (void) memset(file_start
, 0, tnf_trace_file_size
);
214 _tnfw_b_control
->tnf_buffer
= file_start
;
216 if (tnfw_b_init_buffer(file_start
, tnf_trace_file_size
/ TNF_BLOCK_SIZE
,
217 TNF_BLOCK_SIZE
, B_TRUE
) != TNFW_B_OK
) {
221 /* successful return */
222 _tnfw_b_control
->tnf_state
= TNFW_B_RUNNING
;
223 mutex_unlock(&init_mutex
);
227 _tnfw_b_control
->tnf_state
= TNFW_B_BROKEN
;
228 mutex_unlock(&init_mutex
);
238 _tnf_sched_init(tnf_schedule_t
*sched
, hrtime_t t
)
242 sched
->time_base
= t
;
243 /* thr_self() is stubbed out by libc for a non-threaded pgm */
246 sched
->lwpid
= _lwp_self();
247 sched
->pid
= getpid();