/*
* 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
* 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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Implements the routines that are needed only for internal process
* control.
*/
#ifndef DEBUG
#endif
#include "tnfctl_int.h"
#include "kernel_int.h"
#include "dbg.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <link.h>
#include <fcntl.h>
#include <assert.h>
#include <dlfcn.h>
static int inprocess_read(void *ignore,
static int inprocess_write(void *ignore,
void *cd);
/*
* Cause interposition on dlclose() and dlopen()
*/
/*
* The lock used to protect the _tnfctl_internal_tracing_flag variable.
*
*/
/*
* Returns a pointer to a tnfctl handle that can do in process probe control.
*/
{
/* allocate hdl and zero fill */
return (TNFCTL_ERR_ALLOCFAIL);
}
/* plug in inprocess call back functions */
/*
* get the address of DT_DEBUG and store it in proc_p
* (the handle on the same process is the dbg address)
*/
if (prexstat) {
return (prexstat);
}
/* initialize state in handle */
if (prexstat) {
return (prexstat);
}
/* see if process is already being traced */
if (prexstat) {
return (prexstat);
}
return (TNFCTL_ERR_NONE);
}
/*
* reads a block of memory from the same address space.
*/
static int
{
return (0);
}
/*
* writes a block of memory to the same address space.
*/
static int
{
return (0);
}
/*
* returns the pid of the process.
*/
static pid_t
{
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
{
return (TNFCTL_ERR_NONE);
}
}
return (TNFCTL_ERR_INTERNAL);
}
/*
* iterate over all loadobjects in the same address space calling the
* callback function "obj_func".
*/
static int
{
int procfd;
"start inprocess_loadobj_iter; sunw%verbosity 1");
"sunw%verbosity 1",
/* bail if link map is not consistent */
return (1);
/*
* opening /proc readonly, so debuggers can still run
* We use /proc in order to get fd on the object.
*/
if (procfd == -1)
return (1);
/*
* client of this interface should deal with -1 for objfd,
* so no error checking is needed on this ioctl
*/
/* close the fd */
/* check for error */
if (retval == 1)
goto end_of_func;
}
"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.
*/
/*
* The flag that indicates that the library list has changed via a
* dlopen or dlclose.
*/
/*
* 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.
*/
/*
* In the routines below, we will appear to use a different lock if we
* lock is appropriate.
*/
#if defined(__lock_lint)
#else
#define LMAP_LOCK (&_tnfctl_lmap_lock)
#endif
/*
* 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
*/
int
_tnfctl_dlclose(void *handle)
{
int retval;
if (real_dlclose == NULL) {
}
if (mutex_trylock(LMAP_LOCK) != 0) {
/* don't have lock */
if (tid == lock_holder) {
return ((*real_dlclose)(handle));
}
}
/* lock is held now */
lock_holder = thr_self();
/*
* 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
*/
lock_holder = 0;
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
*/
void *
{
static void * (*real_dlopen)(const char *, int) = NULL;
void *retval;
if (real_dlopen == NULL) {
real_dlopen = (void * (*)(const char *, int))
}
if (mutex_trylock(LMAP_LOCK) != 0) {
/* don't have lock */
if (tid == lock_holder) {
}
}
/* lock is held now */
lock_holder = thr_self();
/*
* 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
*/
lock_holder = 0;
return (retval);
}
{
if (_tnfctl_internal_tracing_flag == 1) {
/* internal trace control active */
return (TNFCTL_ERR_BUSY);
}
if (_tnfctl_externally_traced_pid == getpid()) {
/* external trace control is active */
return (TNFCTL_ERR_BUSY);
}
getpid()));
return (TNFCTL_ERR_NONE);
}
#ifdef __lock_lint
/*
* dummy function for lock_lint (warlock) static lock analysis.
*/
int
{
int (*fp)();
return ((*fp)());
}
#endif