1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Includes 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 34*7c478bd9Sstevel@tonic-gate #define NDEBUG 1 35*7c478bd9Sstevel@tonic-gate #endif 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <thread.h> 38*7c478bd9Sstevel@tonic-gate #include <pthread.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/lwp.h> 40*7c478bd9Sstevel@tonic-gate #include <synch.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 44*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 45*7c478bd9Sstevel@tonic-gate #include <dlfcn.h> 46*7c478bd9Sstevel@tonic-gate #include <string.h> 47*7c478bd9Sstevel@tonic-gate #include <unistd.h> 48*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 49*7c478bd9Sstevel@tonic-gate #include <assert.h> 50*7c478bd9Sstevel@tonic-gate #include <stdio.h> 51*7c478bd9Sstevel@tonic-gate #include <errno.h> 52*7c478bd9Sstevel@tonic-gate #ifdef sparc 53*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 54*7c478bd9Sstevel@tonic-gate #endif /* sparc */ 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate #include "tnf_trace.h" 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* 59*7c478bd9Sstevel@tonic-gate * Typedefs 60*7c478bd9Sstevel@tonic-gate */ 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate typedef tnf_ops_t *(*tnf_context_t)(void); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate typedef void * (*start_func_t)(void *arg); 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate typedef int (*tnf_thr_create_func_t)(void *stk, 67*7c478bd9Sstevel@tonic-gate size_t stksize, 68*7c478bd9Sstevel@tonic-gate start_func_t startfunc, 69*7c478bd9Sstevel@tonic-gate void *arg, 70*7c478bd9Sstevel@tonic-gate long flags, 71*7c478bd9Sstevel@tonic-gate thread_t *newthread); 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate typedef int (*tnf_pthread_create_func_t)(pthread_t *thr, 74*7c478bd9Sstevel@tonic-gate const pthread_attr_t *attr, 75*7c478bd9Sstevel@tonic-gate start_func_t startfunc, 76*7c478bd9Sstevel@tonic-gate void * arg); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate typedef void (*tnf_thr_exit_func_t)(void *) __NORETURN; 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate typedef void (*tnf_pthread_exit_func_t)(void *) __NORETURN; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate typedef pid_t (*fork_t)(void); 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate typedef int (*tnf_thr_stksegment_func_t)(stack_t *s); 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate typedef struct args { 87*7c478bd9Sstevel@tonic-gate start_func_t real_func; 88*7c478bd9Sstevel@tonic-gate void *real_arg; 89*7c478bd9Sstevel@tonic-gate } args_t; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * Local Declarations 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate static void * tnf_threaded_test(void *dummy, 96*7c478bd9Sstevel@tonic-gate tnf_probe_control_t *probe_p, 97*7c478bd9Sstevel@tonic-gate tnf_probe_setup_t *set_p); 98*7c478bd9Sstevel@tonic-gate static void * tnf_non_threaded_test(void *dummy, 99*7c478bd9Sstevel@tonic-gate tnf_probe_control_t *probe_p, 100*7c478bd9Sstevel@tonic-gate tnf_probe_setup_t *set_p); 101*7c478bd9Sstevel@tonic-gate static tnf_ops_t *tnf_probe_getfunc(void); 102*7c478bd9Sstevel@tonic-gate static void *probestart(void *arg); 103*7c478bd9Sstevel@tonic-gate static pid_t common_fork(fork_t real_fork); 104*7c478bd9Sstevel@tonic-gate static void probe_setup(void *data); 105*7c478bd9Sstevel@tonic-gate static tnf_ops_t *tnf_get_ops(); 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * Static Globals 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate extern tnf_ops_t tnf_trace_initial_tpd; 112*7c478bd9Sstevel@tonic-gate static void *tpd = &tnf_trace_initial_tpd; 113*7c478bd9Sstevel@tonic-gate #ifdef sparc 114*7c478bd9Sstevel@tonic-gate static size_t tnf_probe_dsize = 0; 115*7c478bd9Sstevel@tonic-gate #endif /* sparc */ 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * Project Private interfaces: 119*7c478bd9Sstevel@tonic-gate * These are interfaces between prex and libtnfw, or 120*7c478bd9Sstevel@tonic-gate * between libtnfw and libtthread. 121*7c478bd9Sstevel@tonic-gate */ 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate /* variable indicates if libtnfw has sync'ed up with libthread or not */ 124*7c478bd9Sstevel@tonic-gate long __tnf_probe_thr_sync = 0; 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* head of the list that is used to chain all probes */ 127*7c478bd9Sstevel@tonic-gate tnf_probe_control_t *__tnf_probe_list_head = NULL; 128*7c478bd9Sstevel@tonic-gate int __tnf_probe_list_valid = 0; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* notify function that libthread calls after primordial thread is created */ 131*7c478bd9Sstevel@tonic-gate void __tnf_probe_notify(void); 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate tnf_probe_test_func_t tnf_threaded_test_addr = tnf_threaded_test; 134*7c478bd9Sstevel@tonic-gate tnf_probe_test_func_t tnf_non_threaded_test_addr = tnf_non_threaded_test; 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * Externs 139*7c478bd9Sstevel@tonic-gate */ 140*7c478bd9Sstevel@tonic-gate #pragma weak thr_probe_getfunc_addr 141*7c478bd9Sstevel@tonic-gate extern tnf_context_t thr_probe_getfunc_addr; 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate #pragma weak thr_probe_setup 144*7c478bd9Sstevel@tonic-gate extern void thr_probe_setup(void *); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 147*7c478bd9Sstevel@tonic-gate /* ----------------------- Public Functions ----------------------- */ 148*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * probe_setup() - the thread probe setup function for the non-threaded 152*7c478bd9Sstevel@tonic-gate * case. 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate static void 155*7c478bd9Sstevel@tonic-gate probe_setup(void *data) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 158*7c478bd9Sstevel@tonic-gate /* #### - TEMPORARY */ 159*7c478bd9Sstevel@tonic-gate fprintf(stderr, "probe_setup: \n"); 160*7c478bd9Sstevel@tonic-gate #endif 161*7c478bd9Sstevel@tonic-gate tpd = data; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate } /* end probe_setup */ 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * __tnf_probe_notify() - libthread calls this function to notify us 167*7c478bd9Sstevel@tonic-gate * that the primordial thread has been created. 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate void 171*7c478bd9Sstevel@tonic-gate __tnf_probe_notify(void) 172*7c478bd9Sstevel@tonic-gate { 173*7c478bd9Sstevel@tonic-gate tnf_probe_control_t *prbctl_p; 174*7c478bd9Sstevel@tonic-gate tnf_probe_test_func_t test_func; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* paranoia: thr_probe_setup should be defined */ 177*7c478bd9Sstevel@tonic-gate assert(thr_probe_setup != 0); 178*7c478bd9Sstevel@tonic-gate if (thr_probe_setup != 0) thr_probe_setup(tpd); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* 181*7c478bd9Sstevel@tonic-gate * no race with prex if we set flag first 182*7c478bd9Sstevel@tonic-gate * - this is an idempotent operation 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate __tnf_probe_thr_sync = 1; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 187*7c478bd9Sstevel@tonic-gate { 188*7c478bd9Sstevel@tonic-gate char tmp_buf[512]; 189*7c478bd9Sstevel@tonic-gate (void) sprintf(tmp_buf, "__tnf_probe_notify: \n"); 190*7c478bd9Sstevel@tonic-gate (void) write(2, tmp_buf, strlen(tmp_buf)); 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate #endif 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * Use dlsym to test for the present of "thr_probe_getfunc_addr" . 195*7c478bd9Sstevel@tonic-gate */ 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate test_func = (((int(*)())dlsym(RTLD_DEFAULT, 198*7c478bd9Sstevel@tonic-gate "thr_probe_getfunc_addr")) != NULL) ? tnf_threaded_test : 0; 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate assert(test_func); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * I think in this case that we do not need to check the 204*7c478bd9Sstevel@tonic-gate * __tnf_probe_list_valid flag since __tnf_probe_notify is 205*7c478bd9Sstevel@tonic-gate * called very early. 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* replace all existing test functions with libthread's test func */ 209*7c478bd9Sstevel@tonic-gate for (prbctl_p = __tnf_probe_list_head; prbctl_p; 210*7c478bd9Sstevel@tonic-gate prbctl_p = prbctl_p->next) 211*7c478bd9Sstevel@tonic-gate if (prbctl_p->test_func) 212*7c478bd9Sstevel@tonic-gate prbctl_p->test_func = test_func; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate return; 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate } /* end __tnf_probe_notify */ 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate /* 219*7c478bd9Sstevel@tonic-gate * _tnf_fork_thread_setup - function called by buffering layer 220*7c478bd9Sstevel@tonic-gate * whenever it finds a thread in the newly forked process that 221*7c478bd9Sstevel@tonic-gate * hasn't been re-initialized in this process. 222*7c478bd9Sstevel@tonic-gate */ 223*7c478bd9Sstevel@tonic-gate void 224*7c478bd9Sstevel@tonic-gate _tnf_fork_thread_setup(void) 225*7c478bd9Sstevel@tonic-gate { 226*7c478bd9Sstevel@tonic-gate tnf_ops_t *ops; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate #ifdef DEBUGFUNCS 229*7c478bd9Sstevel@tonic-gate { 230*7c478bd9Sstevel@tonic-gate char tmp_buf[512]; 231*7c478bd9Sstevel@tonic-gate (void) sprintf(tmp_buf, "in _tnf_fork_thread_setup: \n"); 232*7c478bd9Sstevel@tonic-gate (void) write(2, tmp_buf, strlen(tmp_buf)); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate #endif 235*7c478bd9Sstevel@tonic-gate /* get the tpd */ 236*7c478bd9Sstevel@tonic-gate ops = tnf_get_ops(); 237*7c478bd9Sstevel@tonic-gate if (!ops) 238*7c478bd9Sstevel@tonic-gate return; 239*7c478bd9Sstevel@tonic-gate /* null out tag_index, so that a new one is initialized and written */ 240*7c478bd9Sstevel@tonic-gate ops->schedule.record_p = 0; 241*7c478bd9Sstevel@tonic-gate return; 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 246*7c478bd9Sstevel@tonic-gate /* ---------------------- Interposed Functions -------------------- */ 247*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* 250*7c478bd9Sstevel@tonic-gate * thr_create() - this function is interposed in front of the 251*7c478bd9Sstevel@tonic-gate * actual thread create function in libthread. 252*7c478bd9Sstevel@tonic-gate */ 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate int 255*7c478bd9Sstevel@tonic-gate thr_create(void *stk, 256*7c478bd9Sstevel@tonic-gate size_t stksize, 257*7c478bd9Sstevel@tonic-gate void * (*real_func)(void *), 258*7c478bd9Sstevel@tonic-gate void *real_arg, 259*7c478bd9Sstevel@tonic-gate long flags, 260*7c478bd9Sstevel@tonic-gate thread_t *new_thread) 261*7c478bd9Sstevel@tonic-gate { 262*7c478bd9Sstevel@tonic-gate static tnf_thr_create_func_t real_thr_create = NULL; 263*7c478bd9Sstevel@tonic-gate args_t *arg_p; 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate #ifdef VERYVERBOSE 266*7c478bd9Sstevel@tonic-gate fprintf(stderr, "hello from the interposed thr_create parent\n"); 267*7c478bd9Sstevel@tonic-gate #endif 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* use dlsym to find the address of the "real" thr_create function */ 270*7c478bd9Sstevel@tonic-gate if (real_thr_create == NULL) { 271*7c478bd9Sstevel@tonic-gate real_thr_create = (tnf_thr_create_func_t) 272*7c478bd9Sstevel@tonic-gate dlsym(RTLD_NEXT, "thr_create"); 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate assert(real_thr_create); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* set up the interposed argument block */ 277*7c478bd9Sstevel@tonic-gate arg_p = (args_t *)malloc(sizeof (args_t)); 278*7c478bd9Sstevel@tonic-gate assert(arg_p); 279*7c478bd9Sstevel@tonic-gate arg_p->real_func = real_func; 280*7c478bd9Sstevel@tonic-gate arg_p->real_arg = real_arg; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate return ((*real_thr_create)(stk, stksize, probestart, (void *) arg_p, 283*7c478bd9Sstevel@tonic-gate flags, new_thread)); 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate } /* end thr_create */ 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate int 289*7c478bd9Sstevel@tonic-gate pthread_create(pthread_t *new_thread_id, 290*7c478bd9Sstevel@tonic-gate const pthread_attr_t *attr, 291*7c478bd9Sstevel@tonic-gate void * (*real_func)(void *), 292*7c478bd9Sstevel@tonic-gate void *real_arg) 293*7c478bd9Sstevel@tonic-gate { 294*7c478bd9Sstevel@tonic-gate static tnf_pthread_create_func_t real_pthread_create = NULL; 295*7c478bd9Sstevel@tonic-gate args_t *arg_p; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate #ifdef VERYVERBOSE 298*7c478bd9Sstevel@tonic-gate fprintf(stderr, "hello from the interposed pthread_create parent\n"); 299*7c478bd9Sstevel@tonic-gate #endif 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* use dlsym to find the address of the "real" pthread_create func */ 302*7c478bd9Sstevel@tonic-gate if (real_pthread_create == NULL) { 303*7c478bd9Sstevel@tonic-gate real_pthread_create = (tnf_pthread_create_func_t) 304*7c478bd9Sstevel@tonic-gate dlsym(RTLD_NEXT, "pthread_create"); 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate assert(real_pthread_create); 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* set up the interposed argument block */ 309*7c478bd9Sstevel@tonic-gate arg_p = (args_t *)malloc(sizeof (args_t)); 310*7c478bd9Sstevel@tonic-gate assert(arg_p); 311*7c478bd9Sstevel@tonic-gate arg_p->real_func = real_func; 312*7c478bd9Sstevel@tonic-gate arg_p->real_arg = real_arg; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate return ((*real_pthread_create)(new_thread_id, attr, probestart, 315*7c478bd9Sstevel@tonic-gate (void *) arg_p)); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate } /* end pthread_create */ 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate void 320*7c478bd9Sstevel@tonic-gate thr_exit(void * status) 321*7c478bd9Sstevel@tonic-gate { 322*7c478bd9Sstevel@tonic-gate static tnf_thr_exit_func_t real_thr_exit = NULL; 323*7c478bd9Sstevel@tonic-gate /* use dlsym to find the address of the "real" pthread_create func */ 324*7c478bd9Sstevel@tonic-gate if (real_thr_exit == NULL) { 325*7c478bd9Sstevel@tonic-gate real_thr_exit = (tnf_thr_exit_func_t) 326*7c478bd9Sstevel@tonic-gate dlsym(RTLD_NEXT, "thr_exit"); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate assert(real_thr_exit); 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * Calling tnf_thread_disable() whenever a thread exits... 333*7c478bd9Sstevel@tonic-gate * This has the side-effect of unlocking our currently 334*7c478bd9Sstevel@tonic-gate * locked block in the trace buffer. This keeps a dying 335*7c478bd9Sstevel@tonic-gate * thread from taking a block with it when it dies, but 336*7c478bd9Sstevel@tonic-gate * it means that we won't be able to trace events from 337*7c478bd9Sstevel@tonic-gate * the thread-specific data destructors. We will lose 338*7c478bd9Sstevel@tonic-gate * out on any events a thread spits out AFTER is calls thr_exit(). 339*7c478bd9Sstevel@tonic-gate * This code was added to fix a bug where tracing breaks when trying 340*7c478bd9Sstevel@tonic-gate * to trace a program with large numbers of thread-ids. 341*7c478bd9Sstevel@tonic-gate * 342*7c478bd9Sstevel@tonic-gate * Addendum: 343*7c478bd9Sstevel@tonic-gate * Now you can't get events for thr_exit using an interposition library. 344*7c478bd9Sstevel@tonic-gate * Since thr_exit is a really helpful event, this is a problem. 345*7c478bd9Sstevel@tonic-gate * Also, breaking this interposition will probably break 346*7c478bd9Sstevel@tonic-gate * BAT, the DevPro TNF perf tool. 347*7c478bd9Sstevel@tonic-gate * 348*7c478bd9Sstevel@tonic-gate * Addendum: 349*7c478bd9Sstevel@tonic-gate * Correction: You can get interposition events if the interposition 350*7c478bd9Sstevel@tonic-gate * library comes BEFORE libtnfprobe.so. But not, if the interp. 351*7c478bd9Sstevel@tonic-gate * library comes AFTER libtnfprobe.so. This is a more difficult 352*7c478bd9Sstevel@tonic-gate * constraint that it might sound like because of the following: 353*7c478bd9Sstevel@tonic-gate * The tnfctl functional interface and the prex command line 354*7c478bd9Sstevel@tonic-gate * interface provide convenience features where you can supply 355*7c478bd9Sstevel@tonic-gate * a character string argument which will be put into LD_PRELOAD 356*7c478bd9Sstevel@tonic-gate * for you. Unfortunately, this string gets appended AFTER 357*7c478bd9Sstevel@tonic-gate * libtnfprobe.so by the tnfctl library(and also hence by the 358*7c478bd9Sstevel@tonic-gate * prex -l option). 359*7c478bd9Sstevel@tonic-gate * Luckily, when libtnfprobe is added by the tnfctl library, it is 360*7c478bd9Sstevel@tonic-gate * added AFTER an existing contents of the LD_PRELOAD variable. 361*7c478bd9Sstevel@tonic-gate * 362*7c478bd9Sstevel@tonic-gate * Therefore, if you are using an interposition library to collect 363*7c478bd9Sstevel@tonic-gate * thr_exit and pthread_exit events, THEN you should NOT use 'prex -l' 364*7c478bd9Sstevel@tonic-gate * or the 'ld_preload' argument to tnfctl_exec_open(), instead, you 365*7c478bd9Sstevel@tonic-gate * should be sure to put the interposition library into the LD_PRELOAD 366*7c478bd9Sstevel@tonic-gate * variable yourself. 367*7c478bd9Sstevel@tonic-gate * 368*7c478bd9Sstevel@tonic-gate */ 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate tnf_thread_disable(); 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate ((*real_thr_exit)(status)); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate void 376*7c478bd9Sstevel@tonic-gate pthread_exit(void * status) 377*7c478bd9Sstevel@tonic-gate { 378*7c478bd9Sstevel@tonic-gate static tnf_pthread_exit_func_t real_pthread_exit = NULL; 379*7c478bd9Sstevel@tonic-gate /* use dlsym to find the address of the "real" pthread_create func */ 380*7c478bd9Sstevel@tonic-gate if (real_pthread_exit == NULL) { 381*7c478bd9Sstevel@tonic-gate real_pthread_exit = (tnf_pthread_exit_func_t) 382*7c478bd9Sstevel@tonic-gate dlsym(RTLD_NEXT, "pthread_exit"); 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate assert(real_pthread_exit); 385*7c478bd9Sstevel@tonic-gate /* see the comment in thr_exit about tnf_thread_disable() */ 386*7c478bd9Sstevel@tonic-gate tnf_thread_disable(); 387*7c478bd9Sstevel@tonic-gate ((*real_pthread_exit)(status)); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate /* 391*7c478bd9Sstevel@tonic-gate * function to be interposed in front of _resume. We invalidate the 392*7c478bd9Sstevel@tonic-gate * schedule record in case the lwpid changes the next time this 393*7c478bd9Sstevel@tonic-gate * thread is scheduled. 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate #pragma weak _resume_ret = _tnf_resume_ret 397*7c478bd9Sstevel@tonic-gate void 398*7c478bd9Sstevel@tonic-gate _tnf_resume_ret(void *arg1) 399*7c478bd9Sstevel@tonic-gate { 400*7c478bd9Sstevel@tonic-gate static void (*real_resume_ret)(void *) = NULL; 401*7c478bd9Sstevel@tonic-gate tnf_ops_t *ops; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate if (real_resume_ret == NULL) { 404*7c478bd9Sstevel@tonic-gate real_resume_ret = (void (*)(void *)) dlsym(RTLD_NEXT, 405*7c478bd9Sstevel@tonic-gate "_resume_ret"); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate assert(real_resume_ret); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate ops = tnf_get_ops(); 410*7c478bd9Sstevel@tonic-gate if (ops) { 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * invalidate the schedule record. This forces it 413*7c478bd9Sstevel@tonic-gate * to get re-initialized with the new lwpid the next 414*7c478bd9Sstevel@tonic-gate * time this thread gets scheduled 415*7c478bd9Sstevel@tonic-gate */ 416*7c478bd9Sstevel@tonic-gate if (ops->schedule.lwpid != _lwp_self()) 417*7c478bd9Sstevel@tonic-gate ops->schedule.record_p = 0; 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate real_resume_ret(arg1); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate /* 424*7c478bd9Sstevel@tonic-gate * Functions to be interposed in front of fork and fork1. 425*7c478bd9Sstevel@tonic-gate * 426*7c478bd9Sstevel@tonic-gate * NOTE: we can't handle vfork, because the child would ruin the parent's 427*7c478bd9Sstevel@tonic-gate * data structures. We therefore don't interpose, letting the child's 428*7c478bd9Sstevel@tonic-gate * events appear as though they were the parent's. A slightly cleaner 429*7c478bd9Sstevel@tonic-gate * way to handle vfork would be to interpose on vfork separately to 430*7c478bd9Sstevel@tonic-gate * change the pid and anything else needed to show any events caused 431*7c478bd9Sstevel@tonic-gate * by the child as its events, and then interpose on the exec's as 432*7c478bd9Sstevel@tonic-gate * well to set things back to the way they should be for the parent. 433*7c478bd9Sstevel@tonic-gate * But this is a lot of work, and it makes almost no difference, since the 434*7c478bd9Sstevel@tonic-gate * child typically exec's very quickly after a vfork. 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate #pragma weak fork = _tnf_fork 438*7c478bd9Sstevel@tonic-gate pid_t 439*7c478bd9Sstevel@tonic-gate _tnf_fork(void) 440*7c478bd9Sstevel@tonic-gate { 441*7c478bd9Sstevel@tonic-gate static fork_t real_fork = NULL; 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate if (real_fork == NULL) { 444*7c478bd9Sstevel@tonic-gate real_fork = (fork_t)dlsym(RTLD_NEXT, "fork"); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate assert(real_fork); 447*7c478bd9Sstevel@tonic-gate return (common_fork(real_fork)); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate #pragma weak fork1 = _tnf_fork1 451*7c478bd9Sstevel@tonic-gate pid_t 452*7c478bd9Sstevel@tonic-gate _tnf_fork1(void) 453*7c478bd9Sstevel@tonic-gate { 454*7c478bd9Sstevel@tonic-gate static fork_t real_fork = NULL; 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate if (real_fork == NULL) { 457*7c478bd9Sstevel@tonic-gate real_fork = (fork_t)dlsym(RTLD_NEXT, "fork1"); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate assert(real_fork); 460*7c478bd9Sstevel@tonic-gate return (common_fork(real_fork)); 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate #ifdef sparc 464*7c478bd9Sstevel@tonic-gate /* 465*7c478bd9Sstevel@tonic-gate * Function to be interposed in front of thr_stksegment 466*7c478bd9Sstevel@tonic-gate * _tnf_thr_stksegment() - used to hide the probestart() allocated data 467*7c478bd9Sstevel@tonic-gate * on the thread stack, ensuring that the caller receives a pointer to the 468*7c478bd9Sstevel@tonic-gate * true bottom (ie, usable) portion of the stack, and the size thereof. 469*7c478bd9Sstevel@tonic-gate * 470*7c478bd9Sstevel@tonic-gate * NOTE: On sparc systems, failure to allow for the presense of tnf data 471*7c478bd9Sstevel@tonic-gate * on the stack would cause TNF probes to fail across doorfs calls. The 472*7c478bd9Sstevel@tonic-gate * i386 version of door_return decides to "skip over some slop", so no 473*7c478bd9Sstevel@tonic-gate * interpose function is required for x86; if the 512 byte 'slop skip' 474*7c478bd9Sstevel@tonic-gate * is ever removed from the i386 door_return, then it will also need 475*7c478bd9Sstevel@tonic-gate * interpose function intervention. 476*7c478bd9Sstevel@tonic-gate */ 477*7c478bd9Sstevel@tonic-gate #pragma weak thr_stksegment = _tnf_thr_stksegment 478*7c478bd9Sstevel@tonic-gate static int 479*7c478bd9Sstevel@tonic-gate _tnf_thr_stksegment(stack_t *s) 480*7c478bd9Sstevel@tonic-gate { 481*7c478bd9Sstevel@tonic-gate static tnf_thr_stksegment_func_t real_thr_stksegment = NULL; 482*7c478bd9Sstevel@tonic-gate int err; 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate #ifdef VERYVERBOSE 485*7c478bd9Sstevel@tonic-gate fprintf(stderr, "hello from the interposed thr_stksegment\n"); 486*7c478bd9Sstevel@tonic-gate #endif 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate if (real_thr_stksegment == NULL) { 489*7c478bd9Sstevel@tonic-gate real_thr_stksegment = (tnf_thr_stksegment_func_t) 490*7c478bd9Sstevel@tonic-gate dlsym(RTLD_NEXT, "thr_stksegment"); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate assert(real_thr_stksegment); 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate err = ((*real_thr_stksegment)(s)); 495*7c478bd9Sstevel@tonic-gate if (err == 0) { 496*7c478bd9Sstevel@tonic-gate s->ss_sp = (void *)((caddr_t)s->ss_sp - tnf_probe_dsize); 497*7c478bd9Sstevel@tonic-gate s->ss_size -= tnf_probe_dsize; 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate return (err); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate #endif /* sparc */ 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 504*7c478bd9Sstevel@tonic-gate /* ----------------------- Private Functions ---------------------- */ 505*7c478bd9Sstevel@tonic-gate /* ---------------------------------------------------------------- */ 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * tnf_probe_getfunc() - default test function if libthread is not 509*7c478bd9Sstevel@tonic-gate * present 510*7c478bd9Sstevel@tonic-gate */ 511*7c478bd9Sstevel@tonic-gate static tnf_ops_t * 512*7c478bd9Sstevel@tonic-gate tnf_probe_getfunc(void) 513*7c478bd9Sstevel@tonic-gate { 514*7c478bd9Sstevel@tonic-gate /* test function to be used if libthread is not linked in */ 515*7c478bd9Sstevel@tonic-gate #ifdef DEBUGFUNCS 516*7c478bd9Sstevel@tonic-gate { 517*7c478bd9Sstevel@tonic-gate char tmp_buf[512]; 518*7c478bd9Sstevel@tonic-gate (void) sprintf(tmp_buf, "tnf_probe_getfunc: \n"); 519*7c478bd9Sstevel@tonic-gate (void) write(2, tmp_buf, strlen(tmp_buf)); 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate #endif 522*7c478bd9Sstevel@tonic-gate return (tpd); 523*7c478bd9Sstevel@tonic-gate } /* end tnf_probe_getfunc */ 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate /* 527*7c478bd9Sstevel@tonic-gate * probestart() - this function is called as the start_func by the 528*7c478bd9Sstevel@tonic-gate * interposed thr_create() and pthread_create(). It calls the real start 529*7c478bd9Sstevel@tonic-gate * function. 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate static void * 533*7c478bd9Sstevel@tonic-gate probestart(void * arg) 534*7c478bd9Sstevel@tonic-gate { 535*7c478bd9Sstevel@tonic-gate args_t *args_p = (args_t *)arg; 536*7c478bd9Sstevel@tonic-gate start_func_t real_func; 537*7c478bd9Sstevel@tonic-gate void *real_arg; 538*7c478bd9Sstevel@tonic-gate tnf_ops_t ops; /* allocated on stack */ 539*7c478bd9Sstevel@tonic-gate void *real_retval; 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate #ifdef VERYVERBOSE 542*7c478bd9Sstevel@tonic-gate fprintf(stderr, "hello from the interposed thr_create child\n"); 543*7c478bd9Sstevel@tonic-gate #endif 544*7c478bd9Sstevel@tonic-gate #ifdef sparc 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * if the size of the probe data has not yet been calculated, 547*7c478bd9Sstevel@tonic-gate * initialize a jmpbuffer and calculate the amount of stack space 548*7c478bd9Sstevel@tonic-gate * used by probestart: %fp - %sp from jmp_buf 549*7c478bd9Sstevel@tonic-gate * Not expecting anything to actually longjmp here, so that is 550*7c478bd9Sstevel@tonic-gate * handled as an error condition. 551*7c478bd9Sstevel@tonic-gate */ 552*7c478bd9Sstevel@tonic-gate if (tnf_probe_dsize == 0) { 553*7c478bd9Sstevel@tonic-gate jmp_buf tnf_jmpbuf; 554*7c478bd9Sstevel@tonic-gate if (setjmp(tnf_jmpbuf) != 0) { 555*7c478bd9Sstevel@tonic-gate (void) write(2, 556*7c478bd9Sstevel@tonic-gate "probestart: unexpected longjmp\n", 32); 557*7c478bd9Sstevel@tonic-gate assert(0); 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate tnf_probe_dsize = (size_t)(tnf_jmpbuf[3] - tnf_jmpbuf[1]); 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate #endif /* sparc */ 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate /* initialize ops */ 564*7c478bd9Sstevel@tonic-gate (void) memset(&ops, 0, sizeof (ops)); /* zero ops */ 565*7c478bd9Sstevel@tonic-gate ops.mode = TNF_ALLOC_REUSABLE; 566*7c478bd9Sstevel@tonic-gate ops.alloc = tnfw_b_alloc; 567*7c478bd9Sstevel@tonic-gate ops.commit = tnfw_b_xcommit; 568*7c478bd9Sstevel@tonic-gate ops.rollback = tnfw_b_xabort; 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate /* copy (and free) the allocated arg block */ 571*7c478bd9Sstevel@tonic-gate real_func = args_p->real_func; 572*7c478bd9Sstevel@tonic-gate real_arg = args_p->real_arg; 573*7c478bd9Sstevel@tonic-gate free(args_p); 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate /* paranoia: thr_probe_setup should be defined */ 576*7c478bd9Sstevel@tonic-gate assert(thr_probe_setup != 0); 577*7c478bd9Sstevel@tonic-gate if (thr_probe_setup != 0) thr_probe_setup(&ops); 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate #ifdef VERYVERBOSE 580*7c478bd9Sstevel@tonic-gate fprintf(stderr, "in middle of interposed start procedure\n"); 581*7c478bd9Sstevel@tonic-gate #endif 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate real_retval = (*real_func)(real_arg); 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* 586*7c478bd9Sstevel@tonic-gate * we need to write a NULL into the tpd pointer to disable 587*7c478bd9Sstevel@tonic-gate * tracing for this thread. 588*7c478bd9Sstevel@tonic-gate * CAUTION: never make this function tail recursive because 589*7c478bd9Sstevel@tonic-gate * tpd is allocated on stack. 590*7c478bd9Sstevel@tonic-gate */ 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* This should be handled by the call to tnf_thread_disable() */ 593*7c478bd9Sstevel@tonic-gate /* if (thr_probe_setup != 0) */ 594*7c478bd9Sstevel@tonic-gate /* thr_probe_setup(NULL); */ 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate /* see the comment in thr_exit about tnf_thread_disable */ 597*7c478bd9Sstevel@tonic-gate tnf_thread_disable(); 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate return (real_retval); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate } /* end probestart */ 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate static thread_key_t tpd_key; 605*7c478bd9Sstevel@tonic-gate static int key_created = 0; 606*7c478bd9Sstevel@tonic-gate static tnf_ops_t *stashed_tpd = NULL; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate /* 609*7c478bd9Sstevel@tonic-gate * tnf_thread_disable: API to disable a thread 610*7c478bd9Sstevel@tonic-gate */ 611*7c478bd9Sstevel@tonic-gate void 612*7c478bd9Sstevel@tonic-gate tnf_thread_disable(void) 613*7c478bd9Sstevel@tonic-gate { 614*7c478bd9Sstevel@tonic-gate tnf_ops_t *ops; 615*7c478bd9Sstevel@tonic-gate static mutex_t keylock = DEFAULTMUTEX; 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate if (thr_probe_setup != 0) { 618*7c478bd9Sstevel@tonic-gate /* threaded client */ 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate if (!key_created) { 621*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&keylock); 622*7c478bd9Sstevel@tonic-gate if (!key_created) { 623*7c478bd9Sstevel@tonic-gate /* REMIND: destructor function ? */ 624*7c478bd9Sstevel@tonic-gate (void) thr_keycreate(&tpd_key, NULL); 625*7c478bd9Sstevel@tonic-gate key_created++; 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&keylock); 628*7c478bd9Sstevel@tonic-gate } 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate /* get the tpd */ 631*7c478bd9Sstevel@tonic-gate ops = thr_probe_getfunc_addr(); 632*7c478bd9Sstevel@tonic-gate /* check ops to ensure function is idempotent */ 633*7c478bd9Sstevel@tonic-gate if (ops != NULL) { 634*7c478bd9Sstevel@tonic-gate /* unlock currently held blocks */ 635*7c478bd9Sstevel@tonic-gate tnfw_b_release_block(&ops->wcb); 636*7c478bd9Sstevel@tonic-gate /* disable the thread */ 637*7c478bd9Sstevel@tonic-gate thr_probe_setup(NULL); 638*7c478bd9Sstevel@tonic-gate /* stash the tpd */ 639*7c478bd9Sstevel@tonic-gate (void) thr_setspecific(tpd_key, ops); 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate } else { 642*7c478bd9Sstevel@tonic-gate /* non-threaded client */ 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate /* get the tpd */ 645*7c478bd9Sstevel@tonic-gate ops = tnf_probe_getfunc(); 646*7c478bd9Sstevel@tonic-gate if (ops != NULL) { 647*7c478bd9Sstevel@tonic-gate /* disable the process */ 648*7c478bd9Sstevel@tonic-gate probe_setup(NULL); 649*7c478bd9Sstevel@tonic-gate /* stash the tpd */ 650*7c478bd9Sstevel@tonic-gate stashed_tpd = ops; 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate /* 656*7c478bd9Sstevel@tonic-gate * tnf_thread_enable: API to enable a thread 657*7c478bd9Sstevel@tonic-gate */ 658*7c478bd9Sstevel@tonic-gate void 659*7c478bd9Sstevel@tonic-gate tnf_thread_enable(void) 660*7c478bd9Sstevel@tonic-gate { 661*7c478bd9Sstevel@tonic-gate tnf_ops_t *ops; 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate if (thr_probe_setup != 0) { 664*7c478bd9Sstevel@tonic-gate /* threaded client */ 665*7c478bd9Sstevel@tonic-gate 666*7c478bd9Sstevel@tonic-gate if (key_created) { 667*7c478bd9Sstevel@tonic-gate (void) thr_getspecific(tpd_key, (void *)&ops); 668*7c478bd9Sstevel@tonic-gate if (ops) { 669*7c478bd9Sstevel@tonic-gate thr_probe_setup(ops); 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate } else { 673*7c478bd9Sstevel@tonic-gate /* non-threaded client */ 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate ops = stashed_tpd; 676*7c478bd9Sstevel@tonic-gate if (ops) { 677*7c478bd9Sstevel@tonic-gate probe_setup(ops); 678*7c478bd9Sstevel@tonic-gate } 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * common_fork - code that is common among the interpositions of 684*7c478bd9Sstevel@tonic-gate * fork, fork1, and vfork 685*7c478bd9Sstevel@tonic-gate */ 686*7c478bd9Sstevel@tonic-gate static pid_t 687*7c478bd9Sstevel@tonic-gate common_fork(fork_t real_fork) 688*7c478bd9Sstevel@tonic-gate { 689*7c478bd9Sstevel@tonic-gate pid_t retval; 690*7c478bd9Sstevel@tonic-gate tnf_ops_t *ops; 691*7c478bd9Sstevel@tonic-gate tnf_tag_data_t *metatag_data; 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate #ifdef DEBUGFUNCS 694*7c478bd9Sstevel@tonic-gate { 695*7c478bd9Sstevel@tonic-gate char tmp_buf[512]; 696*7c478bd9Sstevel@tonic-gate (void) sprintf(tmp_buf, "in interposed fork: \n"); 697*7c478bd9Sstevel@tonic-gate (void) write(2, tmp_buf, strlen(tmp_buf)); 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate #endif 700*7c478bd9Sstevel@tonic-gate if ((_tnfw_b_control->tnf_state == TNFW_B_NOBUFFER) && 701*7c478bd9Sstevel@tonic-gate (tnf_trace_file_name[0] != '\0')) { 702*7c478bd9Sstevel@tonic-gate /* 703*7c478bd9Sstevel@tonic-gate * if no buffer has been allocated yet, and prex plugged in 704*7c478bd9Sstevel@tonic-gate * name... 705*7c478bd9Sstevel@tonic-gate */ 706*7c478bd9Sstevel@tonic-gate ops = tnf_get_ops(); 707*7c478bd9Sstevel@tonic-gate if (ops == NULL) { 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate * get it from stashed location 710*7c478bd9Sstevel@tonic-gate * don't enable thread though 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate if (thr_probe_setup != 0) { 713*7c478bd9Sstevel@tonic-gate /* threaded client */ 714*7c478bd9Sstevel@tonic-gate if (key_created) { 715*7c478bd9Sstevel@tonic-gate (void) thr_getspecific(tpd_key, 716*7c478bd9Sstevel@tonic-gate (void *)&ops); 717*7c478bd9Sstevel@tonic-gate } 718*7c478bd9Sstevel@tonic-gate } else { 719*7c478bd9Sstevel@tonic-gate /* non-threaded client */ 720*7c478bd9Sstevel@tonic-gate ops = stashed_tpd; 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate /* 725*7c478bd9Sstevel@tonic-gate * ops shouldn't be NULL. But, if it is, then we don't 726*7c478bd9Sstevel@tonic-gate * initialize tracing. In the child, tracing will be 727*7c478bd9Sstevel@tonic-gate * set to broken. 728*7c478bd9Sstevel@tonic-gate */ 729*7c478bd9Sstevel@tonic-gate if (ops) { 730*7c478bd9Sstevel@tonic-gate /* initialize tracing */ 731*7c478bd9Sstevel@tonic-gate ops->busy = 1; 732*7c478bd9Sstevel@tonic-gate metatag_data = TAG_DATA(tnf_struct_type); 733*7c478bd9Sstevel@tonic-gate metatag_data->tag_desc(ops, metatag_data); 734*7c478bd9Sstevel@tonic-gate /* commit the data */ 735*7c478bd9Sstevel@tonic-gate (void) ops->commit(&(ops->wcb)); 736*7c478bd9Sstevel@tonic-gate ops->busy = 0; 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate } 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate retval = real_fork(); 741*7c478bd9Sstevel@tonic-gate if (retval == 0) { 742*7c478bd9Sstevel@tonic-gate /* child process */ 743*7c478bd9Sstevel@tonic-gate _tnfw_b_control->tnf_pid = getpid(); 744*7c478bd9Sstevel@tonic-gate if ((_tnfw_b_control->tnf_state == TNFW_B_NOBUFFER) && 745*7c478bd9Sstevel@tonic-gate (tnf_trace_file_name[0] != '\0')) { 746*7c478bd9Sstevel@tonic-gate /* 747*7c478bd9Sstevel@tonic-gate * race condition, prex attached after condition was 748*7c478bd9Sstevel@tonic-gate * checked in parent, so both parent and child point at 749*7c478bd9Sstevel@tonic-gate * the same file name and will overwrite each other. 750*7c478bd9Sstevel@tonic-gate * So, we set tracing to broken in child. We could 751*7c478bd9Sstevel@tonic-gate * invent a new state called RACE and use prex to 752*7c478bd9Sstevel@tonic-gate * reset it, if needed... 753*7c478bd9Sstevel@tonic-gate */ 754*7c478bd9Sstevel@tonic-gate tnf_trace_file_name[0] = '\0'; 755*7c478bd9Sstevel@tonic-gate _tnfw_b_control->tnf_state = TNFW_B_BROKEN; 756*7c478bd9Sstevel@tonic-gate } else if (_tnfw_b_control->tnf_state == TNFW_B_RUNNING) { 757*7c478bd9Sstevel@tonic-gate /* normal expected condition */ 758*7c478bd9Sstevel@tonic-gate _tnfw_b_control->tnf_state = TNFW_B_FORKED; 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate return (retval); 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate /* 765*7c478bd9Sstevel@tonic-gate * tnf_threaded_test 766*7c478bd9Sstevel@tonic-gate */ 767*7c478bd9Sstevel@tonic-gate /*ARGSUSED0*/ 768*7c478bd9Sstevel@tonic-gate static void * 769*7c478bd9Sstevel@tonic-gate tnf_threaded_test(void *dummy, tnf_probe_control_t *probe_p, 770*7c478bd9Sstevel@tonic-gate tnf_probe_setup_t *set_p) 771*7c478bd9Sstevel@tonic-gate { 772*7c478bd9Sstevel@tonic-gate tnf_ops_t *tpd_p; 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate tpd_p = thr_probe_getfunc_addr(); 775*7c478bd9Sstevel@tonic-gate if (tpd_p) { 776*7c478bd9Sstevel@tonic-gate return (probe_p->alloc_func(tpd_p, probe_p, set_p)); 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate return (NULL); 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate /* 783*7c478bd9Sstevel@tonic-gate * tnf_non_threaded_test 784*7c478bd9Sstevel@tonic-gate */ 785*7c478bd9Sstevel@tonic-gate /*ARGSUSED0*/ 786*7c478bd9Sstevel@tonic-gate static void * 787*7c478bd9Sstevel@tonic-gate tnf_non_threaded_test(void *dummy, tnf_probe_control_t *probe_p, 788*7c478bd9Sstevel@tonic-gate tnf_probe_setup_t *set_p) 789*7c478bd9Sstevel@tonic-gate { 790*7c478bd9Sstevel@tonic-gate tnf_ops_t *tpd_p; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate tpd_p = tnf_probe_getfunc(); 793*7c478bd9Sstevel@tonic-gate if (tpd_p) { 794*7c478bd9Sstevel@tonic-gate return (probe_p->alloc_func(tpd_p, probe_p, set_p)); 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate return (NULL); 797*7c478bd9Sstevel@tonic-gate } 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate /* 800*7c478bd9Sstevel@tonic-gate * tnf_get_ops() returns the ops pointer (thread-private data), or NULL 801*7c478bd9Sstevel@tonic-gate * if tracing is disabled for this thread. 802*7c478bd9Sstevel@tonic-gate */ 803*7c478bd9Sstevel@tonic-gate static tnf_ops_t * 804*7c478bd9Sstevel@tonic-gate tnf_get_ops() 805*7c478bd9Sstevel@tonic-gate { 806*7c478bd9Sstevel@tonic-gate tnf_context_t *test_func_p = &thr_probe_getfunc_addr; 807*7c478bd9Sstevel@tonic-gate tnf_context_t test_func; 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate /* 810*7c478bd9Sstevel@tonic-gate * IMPORTANT: this test to see whether thr_probe_getfunc_addr 811*7c478bd9Sstevel@tonic-gate * is bound is tricky. The compiler currently has a bug 812*7c478bd9Sstevel@tonic-gate * (1263684) that causes the test to be optimized away unless 813*7c478bd9Sstevel@tonic-gate * coded with an intermediate pointer (test_func_p). This 814*7c478bd9Sstevel@tonic-gate * causes the process to SEGV when the variable is not bound. 815*7c478bd9Sstevel@tonic-gate */ 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate test_func = test_func_p ? *test_func_p : tnf_probe_getfunc; 818*7c478bd9Sstevel@tonic-gate return ((*test_func)()); 819*7c478bd9Sstevel@tonic-gate } 820