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 (c) 1994,1999 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 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 * Implements the routines that are needed only for internal process 31*7c478bd9Sstevel@tonic-gate * control. 32*7c478bd9Sstevel@tonic-gate */ 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 35*7c478bd9Sstevel@tonic-gate #define NDEBUG 1 36*7c478bd9Sstevel@tonic-gate #endif 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h" 39*7c478bd9Sstevel@tonic-gate #include "kernel_int.h" 40*7c478bd9Sstevel@tonic-gate #include "dbg.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <stdio.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 44*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 45*7c478bd9Sstevel@tonic-gate #include <unistd.h> 46*7c478bd9Sstevel@tonic-gate #include <string.h> 47*7c478bd9Sstevel@tonic-gate #include <link.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 49*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 52*7c478bd9Sstevel@tonic-gate #include <assert.h> 53*7c478bd9Sstevel@tonic-gate #include <dlfcn.h> 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate static int inprocess_read(void *ignore, 56*7c478bd9Sstevel@tonic-gate uintptr_t addr, void *buf, size_t size); 57*7c478bd9Sstevel@tonic-gate static int inprocess_write(void *ignore, 58*7c478bd9Sstevel@tonic-gate uintptr_t addr, void *buf, size_t size); 59*7c478bd9Sstevel@tonic-gate static pid_t inprocess_getpid(void *ignore); 60*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t inprocess_get_dtdebug(void *hndl, uintptr_t *ret_val); 61*7c478bd9Sstevel@tonic-gate static int inprocess_loadobj_iter(void *opq, tnfctl_ind_obj_f *obj_func, 62*7c478bd9Sstevel@tonic-gate void *cd); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Cause interposition on _dlclose(), dlclose(), _dlopen(), and dlopen() 66*7c478bd9Sstevel@tonic-gate */ 67*7c478bd9Sstevel@tonic-gate #pragma weak _dlclose = _tnfctl_dlclose 68*7c478bd9Sstevel@tonic-gate #pragma weak dlclose = _tnfctl_dlclose 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate #pragma weak _dlopen = _tnfctl_dlopen 71*7c478bd9Sstevel@tonic-gate #pragma weak dlopen = _tnfctl_dlopen 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * The lock used to protect the _tnfctl_internal_tracing_flag variable. 75*7c478bd9Sstevel@tonic-gate * 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate mutex_t _tnfctl_internalguard_lock = DEFAULTMUTEX; 78*7c478bd9Sstevel@tonic-gate boolean_t _tnfctl_internal_tracing_flag = 0; 79*7c478bd9Sstevel@tonic-gate pid_t _tnfctl_externally_traced_pid = NOPID; 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * Returns a pointer to a tnfctl handle that can do in process probe control. 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 85*7c478bd9Sstevel@tonic-gate tnfctl_internal_open(tnfctl_handle_t **ret_val) 86*7c478bd9Sstevel@tonic-gate { 87*7c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl; 88*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 89*7c478bd9Sstevel@tonic-gate uintptr_t dbgaddr; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */ 92*7c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl)); 93*7c478bd9Sstevel@tonic-gate if (hdl == NULL) { 94*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 95*7c478bd9Sstevel@tonic-gate } 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate hdl->mode = INTERNAL_MODE; 98*7c478bd9Sstevel@tonic-gate hdl->called_exit = B_FALSE; 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* plug in inprocess call back functions */ 101*7c478bd9Sstevel@tonic-gate hdl->p_read = inprocess_read; 102*7c478bd9Sstevel@tonic-gate hdl->p_write = inprocess_write; 103*7c478bd9Sstevel@tonic-gate hdl->p_obj_iter = inprocess_loadobj_iter; 104*7c478bd9Sstevel@tonic-gate hdl->p_getpid = inprocess_getpid; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate /* 107*7c478bd9Sstevel@tonic-gate * get the address of DT_DEBUG and store it in proc_p 108*7c478bd9Sstevel@tonic-gate * (the handle on the same process is the dbg address) 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate prexstat = inprocess_get_dtdebug(hdl, &dbgaddr); 111*7c478bd9Sstevel@tonic-gate if (prexstat) { 112*7c478bd9Sstevel@tonic-gate free(hdl); 113*7c478bd9Sstevel@tonic-gate return (prexstat); 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate hdl->proc_p = (void *) dbgaddr; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* initialize state in handle */ 118*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_set_state(hdl); 119*7c478bd9Sstevel@tonic-gate if (prexstat) { 120*7c478bd9Sstevel@tonic-gate free(hdl); 121*7c478bd9Sstevel@tonic-gate return (prexstat); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate /* see if process is already being traced */ 124*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_internal_getlock(); 125*7c478bd9Sstevel@tonic-gate if (prexstat) { 126*7c478bd9Sstevel@tonic-gate free(hdl); 127*7c478bd9Sstevel@tonic-gate return (prexstat); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate *ret_val = hdl; 130*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate /* 134*7c478bd9Sstevel@tonic-gate * reads a block of memory from the same address space. 135*7c478bd9Sstevel@tonic-gate */ 136*7c478bd9Sstevel@tonic-gate static int 137*7c478bd9Sstevel@tonic-gate inprocess_read(void *ignore, uintptr_t addr, void *buf, size_t size) 138*7c478bd9Sstevel@tonic-gate { 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_2(inprocess_read_1, "libtnfctl", "sunw%verbosity 3;", 141*7c478bd9Sstevel@tonic-gate tnf_long, num_bytes, size, 142*7c478bd9Sstevel@tonic-gate tnf_opaque, from_address, addr); 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate (void) memcpy(buf, (void *) addr, size); 145*7c478bd9Sstevel@tonic-gate return (0); 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * writes a block of memory to the same address space. 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate static int 152*7c478bd9Sstevel@tonic-gate inprocess_write(void *ignore, uintptr_t addr, void *buf, size_t size) 153*7c478bd9Sstevel@tonic-gate { 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_2(inprocess_write_1, "libtnfctl", "sunw%verbosity 3;", 156*7c478bd9Sstevel@tonic-gate tnf_long, num_bytes, size, 157*7c478bd9Sstevel@tonic-gate tnf_opaque, to_address, addr); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)addr, buf, size); 160*7c478bd9Sstevel@tonic-gate return (0); 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate /* 164*7c478bd9Sstevel@tonic-gate * returns the pid of the process. 165*7c478bd9Sstevel@tonic-gate */ 166*7c478bd9Sstevel@tonic-gate static pid_t 167*7c478bd9Sstevel@tonic-gate inprocess_getpid(void *ignore) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate return (getpid()); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate extern Elf3264_Dyn _DYNAMIC; 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate /* 174*7c478bd9Sstevel@tonic-gate * returns the address of the DT_DEBUG field in the _DYNAMIC array 175*7c478bd9Sstevel@tonic-gate * of the same address space. 176*7c478bd9Sstevel@tonic-gate */ 177*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 178*7c478bd9Sstevel@tonic-gate inprocess_get_dtdebug(void *hndl, uintptr_t *ret_val) 179*7c478bd9Sstevel@tonic-gate { 180*7c478bd9Sstevel@tonic-gate Elf3264_Dyn *dyn = &_DYNAMIC; 181*7c478bd9Sstevel@tonic-gate Elf3264_Dyn *dp; 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate for (dp = dyn; dp->d_tag != DT_NULL; dp++) { 184*7c478bd9Sstevel@tonic-gate if (dp->d_tag == DT_DEBUG) { 185*7c478bd9Sstevel@tonic-gate *ret_val = (uintptr_t) dp; 186*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate #define PROCFORMAT "/proc/%d" 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate /* 195*7c478bd9Sstevel@tonic-gate * iterate over all loadobjects in the same address space calling the 196*7c478bd9Sstevel@tonic-gate * callback function "obj_func". 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate static int 199*7c478bd9Sstevel@tonic-gate inprocess_loadobj_iter(void *opq, tnfctl_ind_obj_f *obj_func, void *cd) 200*7c478bd9Sstevel@tonic-gate { 201*7c478bd9Sstevel@tonic-gate Elf3264_Dyn *dtdebug = opq; 202*7c478bd9Sstevel@tonic-gate struct r_debug *r_dbg; 203*7c478bd9Sstevel@tonic-gate struct link_map *lmap; 204*7c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 205*7c478bd9Sstevel@tonic-gate int procfd; 206*7c478bd9Sstevel@tonic-gate tnfctl_ind_obj_info_t loadobj; 207*7c478bd9Sstevel@tonic-gate int retval = 0; /* sucessful return */ 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_0(inprocess_loadobj_iter_start, "libtnfctl", 210*7c478bd9Sstevel@tonic-gate "start inprocess_loadobj_iter; sunw%verbosity 1"); 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate r_dbg = (struct r_debug *)dtdebug->d_un.d_ptr; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_1(inprocess_loadobj_iter_1, "libtnfctl", 215*7c478bd9Sstevel@tonic-gate "sunw%verbosity 1", 216*7c478bd9Sstevel@tonic-gate tnf_string, link_map_state, 217*7c478bd9Sstevel@tonic-gate (r_dbg->r_state == RT_CONSISTENT) ? "RT_CONSISTENT" : 218*7c478bd9Sstevel@tonic-gate (r_dbg->r_state == RT_ADD) ? "RT_ADD" : "RT_DELETE"); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate /* bail if link map is not consistent */ 221*7c478bd9Sstevel@tonic-gate if (r_dbg->r_state != RT_CONSISTENT) 222*7c478bd9Sstevel@tonic-gate return (1); 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate (void) sprintf(path, PROCFORMAT, (int) getpid()); 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * opening /proc readonly, so debuggers can still run 228*7c478bd9Sstevel@tonic-gate * We use /proc in order to get fd on the object. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate procfd = open(path, O_RDONLY); 231*7c478bd9Sstevel@tonic-gate if (procfd == -1) 232*7c478bd9Sstevel@tonic-gate return (1); 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate for (lmap = r_dbg->r_map; lmap; lmap = lmap->l_next) { 235*7c478bd9Sstevel@tonic-gate loadobj.text_base = lmap->l_addr; 236*7c478bd9Sstevel@tonic-gate loadobj.data_base = lmap->l_addr; 237*7c478bd9Sstevel@tonic-gate loadobj.objname = lmap->l_name; 238*7c478bd9Sstevel@tonic-gate /* 239*7c478bd9Sstevel@tonic-gate * client of this interface should deal with -1 for objfd, 240*7c478bd9Sstevel@tonic-gate * so no error checking is needed on this ioctl 241*7c478bd9Sstevel@tonic-gate */ 242*7c478bd9Sstevel@tonic-gate loadobj.objfd = ioctl(procfd, PIOCOPENM, &(lmap->l_addr)); 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate retval = obj_func(opq, &loadobj, cd); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate /* close the fd */ 247*7c478bd9Sstevel@tonic-gate if (loadobj.objfd != -1) 248*7c478bd9Sstevel@tonic-gate close(loadobj.objfd); 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate /* check for error */ 251*7c478bd9Sstevel@tonic-gate if (retval == 1) 252*7c478bd9Sstevel@tonic-gate goto end_of_func; 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate end_of_func: 256*7c478bd9Sstevel@tonic-gate close(procfd); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_0(inprocess_loadobj_iter_end, "libtnfctl", 259*7c478bd9Sstevel@tonic-gate "end inprocess_loadobj_iter; sunw%verbosity 1"); 260*7c478bd9Sstevel@tonic-gate return (retval); 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate /* 264*7c478bd9Sstevel@tonic-gate * The lock that prevents a thread from accessing our cached library list 265*7c478bd9Sstevel@tonic-gate * and a dlopen or dlclose happening at the same time in another thread. 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate mutex_t _tnfctl_lmap_lock = DEFAULTMUTEX; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate /* 270*7c478bd9Sstevel@tonic-gate * The flag that indicates that the library list has changed via a 271*7c478bd9Sstevel@tonic-gate * dlopen or dlclose. 272*7c478bd9Sstevel@tonic-gate */ 273*7c478bd9Sstevel@tonic-gate boolean_t _tnfctl_libs_changed = B_FALSE; 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * Thread id of the owner of the lock in order to implement a 277*7c478bd9Sstevel@tonic-gate * recursive lock i.e. no deadlock if the same thread tries to lock 278*7c478bd9Sstevel@tonic-gate * a lock it already holds. 279*7c478bd9Sstevel@tonic-gate */ 280*7c478bd9Sstevel@tonic-gate static thread_t lock_holder = 0; /* XXX - no tid with 0 */ 281*7c478bd9Sstevel@tonic-gate NOTE(MUTEX_PROTECTS_DATA(warlock::lmap_lock, lock_holder)) 282*7c478bd9Sstevel@tonic-gate NOTE(DATA_READABLE_WITHOUT_LOCK(lock_holder)) 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate /* 285*7c478bd9Sstevel@tonic-gate * In the routines below, we will appear to use a different lock if we 286*7c478bd9Sstevel@tonic-gate * are running lock_lint/warlock. We define a macro to represent whichever 287*7c478bd9Sstevel@tonic-gate * lock is appropriate. 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate #if defined(__lock_lint) 290*7c478bd9Sstevel@tonic-gate #define LMAP_LOCK (&warlock_kludge->lmap_lock) 291*7c478bd9Sstevel@tonic-gate #else 292*7c478bd9Sstevel@tonic-gate #define LMAP_LOCK (&_tnfctl_lmap_lock) 293*7c478bd9Sstevel@tonic-gate #endif 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * dlclose interposition with a recursive lock so that a .fini section 297*7c478bd9Sstevel@tonic-gate * can recursively call dlopen or dlclose while holding _tnfctl_lmap_lock 298*7c478bd9Sstevel@tonic-gate * This interposition serializes access to rtld's loadobject list and 299*7c478bd9Sstevel@tonic-gate * also updates the flag _tnfctl_libs_changed to indicate a change in 300*7c478bd9Sstevel@tonic-gate * the library list. This flag is checked by operations that update 301*7c478bd9Sstevel@tonic-gate * probes so that it can sync up with the new library list and potential 302*7c478bd9Sstevel@tonic-gate * new/deleted probes. 303*7c478bd9Sstevel@tonic-gate */ 304*7c478bd9Sstevel@tonic-gate int 305*7c478bd9Sstevel@tonic-gate _tnfctl_dlclose(void *handle) 306*7c478bd9Sstevel@tonic-gate { 307*7c478bd9Sstevel@tonic-gate static int (*real_dlclose)(void *handle) = NULL; 308*7c478bd9Sstevel@tonic-gate int retval; 309*7c478bd9Sstevel@tonic-gate thread_t tid; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate if (real_dlclose == NULL) { 312*7c478bd9Sstevel@tonic-gate real_dlclose = (int (*)(void *)) dlsym(RTLD_NEXT, "dlclose"); 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate assert(real_dlclose); 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate if (mutex_trylock(LMAP_LOCK) != 0) { 317*7c478bd9Sstevel@tonic-gate /* don't have lock */ 318*7c478bd9Sstevel@tonic-gate tid = thr_self(); 319*7c478bd9Sstevel@tonic-gate if (tid == lock_holder) { 320*7c478bd9Sstevel@tonic-gate /* recursive dlopen/dlclose by same thread */ 321*7c478bd9Sstevel@tonic-gate return ((*real_dlclose)(handle)); 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate /* not a recursive dlopen/dlclose - wait on lock */ 324*7c478bd9Sstevel@tonic-gate mutex_lock(LMAP_LOCK); 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* lock is held now */ 328*7c478bd9Sstevel@tonic-gate lock_holder = thr_self(); 329*7c478bd9Sstevel@tonic-gate retval = (*real_dlclose)(handle); 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * reset lock_holder so that if _tnfctl_lmap_lock is held by some 333*7c478bd9Sstevel@tonic-gate * other part of the code, we don't assume it is a recursive 334*7c478bd9Sstevel@tonic-gate * dlopen/dlclose 335*7c478bd9Sstevel@tonic-gate */ 336*7c478bd9Sstevel@tonic-gate lock_holder = 0; 337*7c478bd9Sstevel@tonic-gate _tnfctl_libs_changed = B_TRUE; 338*7c478bd9Sstevel@tonic-gate mutex_unlock(LMAP_LOCK); 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate return (retval); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate /* 344*7c478bd9Sstevel@tonic-gate * dlopen interposition with a recursive lock so that a .init section 345*7c478bd9Sstevel@tonic-gate * can recursively call dlopen or dlclose while holding _tnfctl_lmap_lock 346*7c478bd9Sstevel@tonic-gate * This interposition serializes access to rtld's loadobject list and 347*7c478bd9Sstevel@tonic-gate * also updates the flag _tnfctl_libs_changed to indicate a change in 348*7c478bd9Sstevel@tonic-gate * the library list. This flag is checked by operations that update 349*7c478bd9Sstevel@tonic-gate * probes so that it can sync up with the new library list and potential 350*7c478bd9Sstevel@tonic-gate * new/deleted probes. 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate void * 353*7c478bd9Sstevel@tonic-gate _tnfctl_dlopen(const char *pathname, int mode) 354*7c478bd9Sstevel@tonic-gate { 355*7c478bd9Sstevel@tonic-gate static void * (*real_dlopen)(const char *, int) = NULL; 356*7c478bd9Sstevel@tonic-gate void *retval; 357*7c478bd9Sstevel@tonic-gate thread_t tid; 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate if (real_dlopen == NULL) { 360*7c478bd9Sstevel@tonic-gate real_dlopen = (void * (*)(const char *, int)) 361*7c478bd9Sstevel@tonic-gate dlsym(RTLD_NEXT, "dlopen"); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate assert(real_dlopen); 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate if (mutex_trylock(LMAP_LOCK) != 0) { 366*7c478bd9Sstevel@tonic-gate /* don't have lock */ 367*7c478bd9Sstevel@tonic-gate tid = thr_self(); 368*7c478bd9Sstevel@tonic-gate if (tid == lock_holder) { 369*7c478bd9Sstevel@tonic-gate /* recursive dlopen/dlclose by same thread */ 370*7c478bd9Sstevel@tonic-gate return ((*real_dlopen)(pathname, mode)); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate /* not a recursive dlopen/dlclose - wait on lock */ 373*7c478bd9Sstevel@tonic-gate mutex_lock(LMAP_LOCK); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate /* lock is held now */ 377*7c478bd9Sstevel@tonic-gate lock_holder = thr_self(); 378*7c478bd9Sstevel@tonic-gate retval = (*real_dlopen)(pathname, mode); 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate /* 381*7c478bd9Sstevel@tonic-gate * reset lock_holder so that if _tnfctl_lmap_lock is held by some 382*7c478bd9Sstevel@tonic-gate * other part of the code, we don't assume it is a recursive 383*7c478bd9Sstevel@tonic-gate * dlopen/dlclose 384*7c478bd9Sstevel@tonic-gate */ 385*7c478bd9Sstevel@tonic-gate lock_holder = 0; 386*7c478bd9Sstevel@tonic-gate _tnfctl_libs_changed = B_TRUE; 387*7c478bd9Sstevel@tonic-gate mutex_unlock(LMAP_LOCK); 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate return (retval); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 393*7c478bd9Sstevel@tonic-gate _tnfctl_internal_getlock() 394*7c478bd9Sstevel@tonic-gate { 395*7c478bd9Sstevel@tonic-gate mutex_lock(&_tnfctl_internalguard_lock); 396*7c478bd9Sstevel@tonic-gate if (_tnfctl_internal_tracing_flag == 1) { 397*7c478bd9Sstevel@tonic-gate /* internal trace control active */ 398*7c478bd9Sstevel@tonic-gate mutex_unlock(&_tnfctl_internalguard_lock); 399*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BUSY); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate _tnfctl_internal_tracing_flag = 1; 402*7c478bd9Sstevel@tonic-gate if (_tnfctl_externally_traced_pid == getpid()) { 403*7c478bd9Sstevel@tonic-gate /* external trace control is active */ 404*7c478bd9Sstevel@tonic-gate _tnfctl_internal_tracing_flag = 0; 405*7c478bd9Sstevel@tonic-gate mutex_unlock(&_tnfctl_internalguard_lock); 406*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BUSY); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, "_tnfctl_internal_getlock: ok to trace %d\n", 409*7c478bd9Sstevel@tonic-gate getpid())); 410*7c478bd9Sstevel@tonic-gate mutex_unlock(&_tnfctl_internalguard_lock); 411*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate #ifdef __lock_lint 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate /* 418*7c478bd9Sstevel@tonic-gate * dummy function for lock_lint (warlock) static lock analysis. 419*7c478bd9Sstevel@tonic-gate */ 420*7c478bd9Sstevel@tonic-gate int 421*7c478bd9Sstevel@tonic-gate warlock_dummy() 422*7c478bd9Sstevel@tonic-gate { 423*7c478bd9Sstevel@tonic-gate int (*fp)(); 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate return ((*fp)()); 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate #endif 429