/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 (c) 1994, by Sun Microsytems, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Load object and probe discovery in target process. This file is
* not exercised for kernel probes.
*/
#ifndef DEBUG
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <fcntl.h>
#include <assert.h>
#include "tnfctl_int.h"
#include "kernel_int.h"
#include "dbg.h"
/*
* Defines - Project private interfaces
*/
/*
* Typedefs
*/
typedef struct link_args {
char *la_probename;
int ret_val;
} link_args_t;
typedef struct link_args2 {
char *la_probename;
} link_args2_t;
static int per_loadobj(void *, const tnfctl_ind_obj_info_t *, void *);
const tnfctl_ind_obj_info_t *);
static void free_obj_fields(objlist_t *);
/*
* sync up our library list with that of the run time linker's
* Returns an event indicating if a dlopen or dlclose happened.
*/
enum event_op_t *dl_evt)
{
int miscstat;
/* reset old and new of current objects */
}
/* read in object list */
/* reset libs_changed global var to indicated sync up done */
if (miscstat) {
/*
* for INDIRECT_MODE or INTERNAL_MODE, we should never get
* called when linkmaps are not consistent, so this is a real
* error - return without setting lmap_ok.
*/
return (TNFCTL_ERR_INTERNAL);
/*
* in DIRECT_MODE:
* caller needs to call tnfctl_continue on BADLMAPSTATE
* XXXX - the cast from int to prb_status_t is ok as
* we know we are in DIRECT_MODE and we are calling our
* own loadobject iterator function.
*/
}
/*
* find out about dlopens or dlcloses - In direct mode, there
* can only be one since we monitor all dl activity. The dl_evt
* field is only used by tnfctl_continue(). In proc_service
* mode or internal mode, the new_probe member indicates new probes
* correctly.
*/
break;
}
break;
}
}
/*
* reset new_probe field only if there was a dlopen or dlclose
*/
}
}
return (TNFCTL_ERR_NONE);
}
/*
* search through all libraries and discover all probes in target
* This function assumes all objects have been found and marked as
* appropriate (new, old, or neither)
*/
{
int num_probes, j;
while (cur_obj) {
/* dlclosed library : stitch out probes in target */
"sunw%verbosity 1; sunw%debug 'lib dlclosed'",
if (prexstat)
return (prexstat);
/* remove this object from linked list */
else
continue;
}
/* dlopened library : read in probes */
if (prexstat)
return (prexstat);
if (num_probes) {
sizeof (prbctlref_t));
return (TNFCTL_ERR_ALLOCFAIL);
if (prexstat)
return (prexstat);
/* increment num_probes */
if (prexstat)
return (prexstat);
}
}
}
#if 0
}
#endif
/* call create_func for client data if we saw new probes */
continue;
/* new object */
}
}
}
return (TNFCTL_ERR_NONE);
}
/*
* _tnfctl_free_objs_and_probes() - cleans up objects and probes
*/
void
{
while (obj) {
}
}
/*
* Free members of objlist_t
*/
static void
{
int i;
if (probe_p->attr_string)
if (probe_p->probe_handle)
}
}
/*
* _tnfctl_probes_traverse() - iterate over all probes by calling the
* callback function supplied.
*/
{
int j;
/*LINTED statement has no consequent: else*/
if (prexstat) {
/*LINTED statement has no consequent: else*/
return (prexstat);
}
}
}
/*LINTED statement has no consequent: else*/
return (TNFCTL_ERR_NONE);
}
/*
* function that is called by loadobject iterator function for every
* loadobject. If a new loadobject, add it to to our list.
*/
static int
{
/* loadobject already exists */
/* no need to close the objfd because iterator func will */
/* successful return */
return (0);
}
/* add new loadobject */
return (1);
/* may have to actually open the fd */
return (1);
} else {
/* dup the fd because iterator function will close it */
return (1);
}
entry_p->min_probe_num = 0;
} else {
/* add to end of list */
while (next_p) {
}
/* cur_p now points to last element on list */
}
return (0);
}
/*
* check if this loadobject already exists in our linked list.
*/
static objlist_t *
{
return (obj);
}
return (NULL);
}
/*
* find the number of probes in a loadobject
*/
static tnfctl_errcode_t
{
&search_info);
if (prexstat)
return (prexstat);
return (TNFCTL_ERR_NONE);
}
/*
* discover all probes in a loadobject and read it into our array.
*/
static tnfctl_errcode_t
{
&search_info);
if (prexstat)
return (prexstat);
return (TNFCTL_ERR_NONE);
}
/*
* checks if this relocation entry is a probe and if so,
* increments a counter for every probe seen
*/
/*ARGSUSED*/
static tnfctl_errcode_t
{
}
return (TNFCTL_ERR_NONE);
}
/*
* checks if this relocation entry is a probe and if so, reads in info
* on this probe
*/
/*ARGSUSED*/
static tnfctl_errcode_t
{
int miscstat;
return (TNFCTL_ERR_NONE);
/* found a probe */
/* read in probe structure */
if (miscstat) {
"read_a_probe: read from target failed: %d\n",
miscstat));
return (TNFCTL_ERR_INTERNAL);
}
/*
* dereference the attrs (read it into our address space only for
* working copy)
*/
if (prexstat) {
"read_a_probe: _tnfctl_readstr_targ (attrs) failed: %s\n",
return (prexstat);
}
"sunw%verbosity 1; sunw%debug 'found a probe'",
/* create probe handle */
return (TNFCTL_ERR_ALLOCFAIL);
/* link in probe handle into chain off tnfctl_handle_t */
/*
* if this is a "virgin" probe, set up probe to initial state
* REMIND: Could defer this target write till we link the probes
* together in target process in link_targ_obj_probes() i.e.
* do the "write" only once.
*/
/*
* update the probe in target to its initial state
* Since the probe is disabled, it is ok to write it one
* write command as opposed to updating each word individually
*/
if (miscstat)
return (TNFCTL_ERR_INTERNAL);
}
return (TNFCTL_ERR_NONE);
}
/*
* Link all the probes in a linked list in the target image in specified
* object. Also, link probes from previous object and next object into
* this list. The only
* reason this is needed is because internally in the process,
* tnf_probe_notify() that is called from libthread walks through all
* probes substituting the test function
* REMIND: find a way that we don't have to walk through probes internally.
*/
static tnfctl_errcode_t
{
int i;
int miscstat;
/* find previous object that has probes */
}
/* find next object with probes */
}
/* link probes (except for last one) in order */
&next_probe, sizeof (next_probe));
if (miscstat)
return (TNFCTL_ERR_INTERNAL);
}
if (prev_w_probes == NULL) {
/* adding as first object in list */
} else {
}
/* point next_addr to first probe in this object */
&next_probe, sizeof (next_probe));
if (miscstat)
return (TNFCTL_ERR_INTERNAL);
/* link last probe in object */
if (next_w_probes == NULL)
next_probe = NULL;
else {
}
&next_probe, sizeof (next_probe));
if (miscstat)
return (TNFCTL_ERR_INTERNAL);
return (TNFCTL_ERR_NONE);
}
/*
* An object has been closed. Stitch probes around this object in
* target image.
*/
static tnfctl_errcode_t
{
int miscstat;
/* find previous object that has probes */
}
/* find next object with probes */
}
if (next_w_probes == NULL)
next_probe = NULL;
else {
}
if (prev_w_probes == NULL) {
/* removing first object in list */
} else {
}
/* point next_addr to next_probe */
&next_probe, sizeof (next_probe));
if (miscstat)
return (TNFCTL_ERR_INTERNAL);
return (TNFCTL_ERR_NONE);
}
/*
* _tnfctl_flush_a_probe() - write a changed probe into the target process'
* address space.
*/
{
int miscstat;
/*
* For internal control:
* There is *no race* for finding the test function (between the time
* we call find_test_func() and the time we assign it to a probe),
* because tnfctl_internal_open() cannot be called from an init section
* (look at man page of tnfctl_internal_open()). And, after the init
* section of libthread has run, we will always use the MT test
* function.
*/
if (prexstat)
return (prexstat);
} else {
if (miscstat)
return (TNFCTL_ERR_INTERNAL);
}
return (TNFCTL_ERR_NONE);
}