diff options
Diffstat (limited to 'usr/src/lib/libtnfctl/internal.c')
-rw-r--r-- | usr/src/lib/libtnfctl/internal.c | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/usr/src/lib/libtnfctl/internal.c b/usr/src/lib/libtnfctl/internal.c deleted file mode 100644 index dbe97fc714..0000000000 --- a/usr/src/lib/libtnfctl/internal.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Implements the routines that are needed only for internal process - * control. - */ - -#ifndef DEBUG -#define NDEBUG 1 -#endif - -#include "tnfctl_int.h" -#include "kernel_int.h" -#include "dbg.h" - -#include <stdio.h> -#include <sys/types.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <link.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/param.h> -#include <sys/procfs.h> -#include <assert.h> -#include <dlfcn.h> - -static int inprocess_read(void *ignore, - uintptr_t addr, void *buf, size_t size); -static int inprocess_write(void *ignore, - uintptr_t addr, void *buf, size_t size); -static pid_t inprocess_getpid(void *ignore); -static tnfctl_errcode_t inprocess_get_dtdebug(void *hndl, uintptr_t *ret_val); -static int inprocess_loadobj_iter(void *opq, tnfctl_ind_obj_f *obj_func, - void *cd); - -/* - * Cause interposition on dlclose() and dlopen() - */ -#pragma weak dlclose = _tnfctl_dlclose - -#pragma weak dlopen = _tnfctl_dlopen - -/* - * The lock used to protect the _tnfctl_internal_tracing_flag variable. - * - */ -mutex_t _tnfctl_internalguard_lock = DEFAULTMUTEX; -boolean_t _tnfctl_internal_tracing_flag = 0; -pid_t _tnfctl_externally_traced_pid = NOPID; - -/* - * Returns a pointer to a tnfctl handle that can do in process probe control. - */ -tnfctl_errcode_t -tnfctl_internal_open(tnfctl_handle_t **ret_val) -{ - tnfctl_handle_t *hdl; - tnfctl_errcode_t prexstat; - uintptr_t dbgaddr; - - /* allocate hdl and zero fill */ - hdl = calloc(1, sizeof (*hdl)); - if (hdl == NULL) { - return (TNFCTL_ERR_ALLOCFAIL); - } - - hdl->mode = INTERNAL_MODE; - hdl->called_exit = B_FALSE; - - /* plug in inprocess call back functions */ - hdl->p_read = inprocess_read; - hdl->p_write = inprocess_write; - hdl->p_obj_iter = inprocess_loadobj_iter; - hdl->p_getpid = inprocess_getpid; - - /* - * get the address of DT_DEBUG and store it in proc_p - * (the handle on the same process is the dbg address) - */ - prexstat = inprocess_get_dtdebug(hdl, &dbgaddr); - if (prexstat) { - free(hdl); - return (prexstat); - } - hdl->proc_p = (void *) dbgaddr; - - /* initialize state in handle */ - prexstat = _tnfctl_set_state(hdl); - if (prexstat) { - free(hdl); - return (prexstat); - } - /* see if process is already being traced */ - prexstat = _tnfctl_internal_getlock(); - if (prexstat) { - free(hdl); - return (prexstat); - } - *ret_val = hdl; - return (TNFCTL_ERR_NONE); -} - -/* - * reads a block of memory from the same address space. - */ -static int -inprocess_read(void *ignore, uintptr_t addr, void *buf, size_t size) -{ - - DBG_TNF_PROBE_2(inprocess_read_1, "libtnfctl", "sunw%verbosity 3;", - tnf_long, num_bytes, size, - tnf_opaque, from_address, addr); - - (void) memcpy(buf, (void *) addr, size); - return (0); -} - -/* - * writes a block of memory to the same address space. - */ -static int -inprocess_write(void *ignore, uintptr_t addr, void *buf, size_t size) -{ - - DBG_TNF_PROBE_2(inprocess_write_1, "libtnfctl", "sunw%verbosity 3;", - tnf_long, num_bytes, size, - tnf_opaque, to_address, addr); - - (void) memcpy((void *)addr, buf, size); - return (0); -} - -/* - * returns the pid of the process. - */ -static pid_t -inprocess_getpid(void *ignore) -{ - return (getpid()); -} -extern Elf3264_Dyn _DYNAMIC; - -/* - * returns the address of the DT_DEBUG field in the _DYNAMIC array - * of the same address space. - */ -static tnfctl_errcode_t -inprocess_get_dtdebug(void *hndl, uintptr_t *ret_val) -{ - Elf3264_Dyn *dyn = &_DYNAMIC; - Elf3264_Dyn *dp; - - for (dp = dyn; dp->d_tag != DT_NULL; dp++) { - if (dp->d_tag == DT_DEBUG) { - *ret_val = (uintptr_t) dp; - return (TNFCTL_ERR_NONE); - } - } - return (TNFCTL_ERR_INTERNAL); -} - -#define PROCFORMAT "/proc/%d" - -/* - * iterate over all loadobjects in the same address space calling the - * callback function "obj_func". - */ -static int -inprocess_loadobj_iter(void *opq, tnfctl_ind_obj_f *obj_func, void *cd) -{ - Elf3264_Dyn *dtdebug = opq; - struct r_debug *r_dbg; - struct link_map *lmap; - char path[MAXPATHLEN]; - int procfd; - tnfctl_ind_obj_info_t loadobj; - int retval = 0; /* sucessful return */ - - DBG_TNF_PROBE_0(inprocess_loadobj_iter_start, "libtnfctl", - "start inprocess_loadobj_iter; sunw%verbosity 1"); - - r_dbg = (struct r_debug *)dtdebug->d_un.d_ptr; - - DBG_TNF_PROBE_1(inprocess_loadobj_iter_1, "libtnfctl", - "sunw%verbosity 1", - tnf_string, link_map_state, - (r_dbg->r_state == RT_CONSISTENT) ? "RT_CONSISTENT" : - (r_dbg->r_state == RT_ADD) ? "RT_ADD" : "RT_DELETE"); - - /* bail if link map is not consistent */ - if (r_dbg->r_state != RT_CONSISTENT) - return (1); - - (void) sprintf(path, PROCFORMAT, (int) getpid()); - - /* - * opening /proc readonly, so debuggers can still run - * We use /proc in order to get fd on the object. - */ - procfd = open(path, O_RDONLY); - if (procfd == -1) - return (1); - - for (lmap = r_dbg->r_map; lmap; lmap = lmap->l_next) { - loadobj.text_base = lmap->l_addr; - loadobj.data_base = lmap->l_addr; - loadobj.objname = lmap->l_name; - /* - * client of this interface should deal with -1 for objfd, - * so no error checking is needed on this ioctl - */ - loadobj.objfd = ioctl(procfd, PIOCOPENM, &(lmap->l_addr)); - - retval = obj_func(opq, &loadobj, cd); - - /* close the fd */ - if (loadobj.objfd != -1) - close(loadobj.objfd); - - /* check for error */ - if (retval == 1) - goto end_of_func; - } - -end_of_func: - close(procfd); - - DBG_TNF_PROBE_0(inprocess_loadobj_iter_end, "libtnfctl", - "end inprocess_loadobj_iter; sunw%verbosity 1"); - return (retval); -} - -/* - * The lock that prevents a thread from accessing our cached library list - * and a dlopen or dlclose happening at the same time in another thread. - */ -mutex_t _tnfctl_lmap_lock = DEFAULTMUTEX; - -/* - * The flag that indicates that the library list has changed via a - * dlopen or dlclose. - */ -boolean_t _tnfctl_libs_changed = B_FALSE; - -/* - * Thread id of the owner of the lock in order to implement a - * recursive lock i.e. no deadlock if the same thread tries to lock - * a lock it already holds. - */ -static thread_t lock_holder = 0; /* XXX - no tid with 0 */ - -#define LMAP_LOCK (&_tnfctl_lmap_lock) - -/* - * dlclose interposition with a recursive lock so that a .fini section - * can recursively call dlopen or dlclose while holding _tnfctl_lmap_lock - * This interposition serializes access to rtld's loadobject list and - * also updates the flag _tnfctl_libs_changed to indicate a change in - * the library list. This flag is checked by operations that update - * probes so that it can sync up with the new library list and potential - * new/deleted probes. - */ -int -_tnfctl_dlclose(void *handle) -{ - static int (*real_dlclose)(void *handle) = NULL; - int retval; - thread_t tid; - - if (real_dlclose == NULL) { - real_dlclose = (int (*)(void *)) dlsym(RTLD_NEXT, "dlclose"); - } - assert(real_dlclose); - - if (mutex_trylock(LMAP_LOCK) != 0) { - /* don't have lock */ - tid = thr_self(); - if (tid == lock_holder) { - /* recursive dlopen/dlclose by same thread */ - return ((*real_dlclose)(handle)); - } - /* not a recursive dlopen/dlclose - wait on lock */ - mutex_lock(LMAP_LOCK); - } - - /* lock is held now */ - lock_holder = thr_self(); - retval = (*real_dlclose)(handle); - - /* - * reset lock_holder so that if _tnfctl_lmap_lock is held by some - * other part of the code, we don't assume it is a recursive - * dlopen/dlclose - */ - lock_holder = 0; - _tnfctl_libs_changed = B_TRUE; - mutex_unlock(LMAP_LOCK); - - return (retval); -} - -/* - * dlopen interposition with a recursive lock so that a .init section - * can recursively call dlopen or dlclose while holding _tnfctl_lmap_lock - * This interposition serializes access to rtld's loadobject list and - * also updates the flag _tnfctl_libs_changed to indicate a change in - * the library list. This flag is checked by operations that update - * probes so that it can sync up with the new library list and potential - * new/deleted probes. - */ -void * -_tnfctl_dlopen(const char *pathname, int mode) -{ - static void * (*real_dlopen)(const char *, int) = NULL; - void *retval; - thread_t tid; - - if (real_dlopen == NULL) { - real_dlopen = (void * (*)(const char *, int)) - dlsym(RTLD_NEXT, "dlopen"); - } - assert(real_dlopen); - - if (mutex_trylock(LMAP_LOCK) != 0) { - /* don't have lock */ - tid = thr_self(); - if (tid == lock_holder) { - /* recursive dlopen/dlclose by same thread */ - return ((*real_dlopen)(pathname, mode)); - } - /* not a recursive dlopen/dlclose - wait on lock */ - mutex_lock(LMAP_LOCK); - } - - /* lock is held now */ - lock_holder = thr_self(); - retval = (*real_dlopen)(pathname, mode); - - /* - * reset lock_holder so that if _tnfctl_lmap_lock is held by some - * other part of the code, we don't assume it is a recursive - * dlopen/dlclose - */ - lock_holder = 0; - _tnfctl_libs_changed = B_TRUE; - mutex_unlock(LMAP_LOCK); - - return (retval); -} - -tnfctl_errcode_t -_tnfctl_internal_getlock() -{ - mutex_lock(&_tnfctl_internalguard_lock); - if (_tnfctl_internal_tracing_flag == 1) { - /* internal trace control active */ - mutex_unlock(&_tnfctl_internalguard_lock); - return (TNFCTL_ERR_BUSY); - } - _tnfctl_internal_tracing_flag = 1; - if (_tnfctl_externally_traced_pid == getpid()) { - /* external trace control is active */ - _tnfctl_internal_tracing_flag = 0; - mutex_unlock(&_tnfctl_internalguard_lock); - return (TNFCTL_ERR_BUSY); - } - DBG((void) fprintf(stderr, "_tnfctl_internal_getlock: ok to trace %d\n", - getpid())); - mutex_unlock(&_tnfctl_internalguard_lock); - return (TNFCTL_ERR_NONE); -} |