17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright (c) 1994, by Sun Microsytems, Inc.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate/*
277c478bdstevel@tonic-gate * Load object and probe discovery in target process.  This file is
287c478bdstevel@tonic-gate * not exercised for kernel probes.
297c478bdstevel@tonic-gate */
307c478bdstevel@tonic-gate
317c478bdstevel@tonic-gate#ifndef DEBUG
327c478bdstevel@tonic-gate#define	NDEBUG	1
337c478bdstevel@tonic-gate#endif
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gate#include <stdio.h>
367c478bdstevel@tonic-gate#include <stdlib.h>
377c478bdstevel@tonic-gate#include <unistd.h>
387c478bdstevel@tonic-gate#include <string.h>
397c478bdstevel@tonic-gate#include <stddef.h>
407c478bdstevel@tonic-gate#include <sys/types.h>
417c478bdstevel@tonic-gate#include <sys/stat.h>
427c478bdstevel@tonic-gate#include <fcntl.h>
437c478bdstevel@tonic-gate#include <assert.h>
447c478bdstevel@tonic-gate
457c478bdstevel@tonic-gate#include "tnfctl_int.h"
467c478bdstevel@tonic-gate#include "kernel_int.h"
477c478bdstevel@tonic-gate#include "dbg.h"
487c478bdstevel@tonic-gate
497c478bdstevel@tonic-gate/*
507c478bdstevel@tonic-gate * Defines - Project private interfaces
517c478bdstevel@tonic-gate */
527c478bdstevel@tonic-gate
537c478bdstevel@tonic-gate#define	PROBE_SYMBOL	"__tnf_probe_version_1"
547c478bdstevel@tonic-gate
557c478bdstevel@tonic-gate/*
567c478bdstevel@tonic-gate * Typedefs
577c478bdstevel@tonic-gate */
587c478bdstevel@tonic-gate
597c478bdstevel@tonic-gatetypedef struct link_args {
607c478bdstevel@tonic-gate	char		*la_probename;
617c478bdstevel@tonic-gate	int		ret_val;
627c478bdstevel@tonic-gate} link_args_t;
637c478bdstevel@tonic-gate
647c478bdstevel@tonic-gatetypedef struct link_args2 {
657c478bdstevel@tonic-gate	tnfctl_handle_t	*la_hndl;
667c478bdstevel@tonic-gate	char		*la_probename;
677c478bdstevel@tonic-gate	objlist_t	*la_obj;
687c478bdstevel@tonic-gate	ulong_t		la_index;
697c478bdstevel@tonic-gate	ulong_t		la_base;
707c478bdstevel@tonic-gate} link_args2_t;
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gatestatic int per_loadobj(void *, const tnfctl_ind_obj_info_t *, void *);
737c478bdstevel@tonic-gatestatic objlist_t *loadobj_find(tnfctl_handle_t *,
747c478bdstevel@tonic-gate			const tnfctl_ind_obj_info_t *);
757c478bdstevel@tonic-gatestatic tnfctl_errcode_t get_num_probes(tnfctl_handle_t *, objlist_t *, int *);
767c478bdstevel@tonic-gatestatic tnfctl_errcode_t read_probes_in_obj(tnfctl_handle_t *, objlist_t *,
777c478bdstevel@tonic-gate		ulong_t, ulong_t);
787c478bdstevel@tonic-gatestatic void free_obj_fields(objlist_t *);
797c478bdstevel@tonic-gatestatic tnfctl_errcode_t count_probes(char *, uintptr_t, void *,
807c478bdstevel@tonic-gate					tnfctl_elf_search_t *);
817c478bdstevel@tonic-gatestatic tnfctl_errcode_t read_a_probe(char *, uintptr_t, void *,
827c478bdstevel@tonic-gate					tnfctl_elf_search_t *);
837c478bdstevel@tonic-gatestatic tnfctl_errcode_t link_targ_obj_probes(tnfctl_handle_t *, objlist_t *);
847c478bdstevel@tonic-gatestatic tnfctl_errcode_t unlink_targ_obj_probes(tnfctl_handle_t *, objlist_t *);
857c478bdstevel@tonic-gate
867c478bdstevel@tonic-gate/*
877c478bdstevel@tonic-gate * sync up our library list with that of the run time linker's
887c478bdstevel@tonic-gate * Returns an event indicating if a dlopen or dlclose happened.
897c478bdstevel@tonic-gate */
907c478bdstevel@tonic-gatetnfctl_errcode_t
917c478bdstevel@tonic-gate_tnfctl_lmap_update(tnfctl_handle_t *hndl, boolean_t *lmap_ok,
927c478bdstevel@tonic-gate				enum event_op_t *dl_evt)
937c478bdstevel@tonic-gate{
947c478bdstevel@tonic-gate	int		miscstat;
957c478bdstevel@tonic-gate	objlist_t	*cur_obj;
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gate	*lmap_ok = B_TRUE;
987c478bdstevel@tonic-gate
997c478bdstevel@tonic-gate	/* reset old and new of current objects */
1007c478bdstevel@tonic-gate	for (cur_obj = hndl->objlist; cur_obj; cur_obj = cur_obj->next) {
1017c478bdstevel@tonic-gate		cur_obj->old = B_TRUE;
1027c478bdstevel@tonic-gate		cur_obj->new = B_FALSE;
1037c478bdstevel@tonic-gate	}
1047c478bdstevel@tonic-gate
1057c478bdstevel@tonic-gate	/* read in object list */
1067c478bdstevel@tonic-gate	miscstat = hndl->p_obj_iter(hndl->proc_p, per_loadobj, hndl);
1077c478bdstevel@tonic-gate	/* reset libs_changed global var to indicated sync up done */
1087c478bdstevel@tonic-gate	_tnfctl_libs_changed = B_FALSE;
1097c478bdstevel@tonic-gate	if (miscstat) {
1107c478bdstevel@tonic-gate		/*
1117c478bdstevel@tonic-gate		 * for INDIRECT_MODE or INTERNAL_MODE, we should never get
1127c478bdstevel@tonic-gate		 * called when linkmaps are not consistent, so this is a real
1137c478bdstevel@tonic-gate		 * error - return without setting lmap_ok.
1147c478bdstevel@tonic-gate		 */
1157c478bdstevel@tonic-gate		if ((hndl->mode == INDIRECT_MODE) ||
1167c478bdstevel@tonic-gate				(hndl->mode == INTERNAL_MODE))
1177c478bdstevel@tonic-gate			return (TNFCTL_ERR_INTERNAL);
1187c478bdstevel@tonic-gate
1197c478bdstevel@tonic-gate		assert(hndl->mode == DIRECT_MODE);
1207c478bdstevel@tonic-gate		/*
1217c478bdstevel@tonic-gate		 * in DIRECT_MODE:
1227c478bdstevel@tonic-gate		 * caller needs to call tnfctl_continue on BADLMAPSTATE
1237c478bdstevel@tonic-gate		 * XXXX - the cast from int to prb_status_t is ok as
1247c478bdstevel@tonic-gate		 * we know we are in DIRECT_MODE and we are calling our
1257c478bdstevel@tonic-gate		 * own loadobject iterator function.
1267c478bdstevel@tonic-gate		 */
1277c478bdstevel@tonic-gate		if ((prb_status_t) miscstat == PRB_STATUS_BADLMAPSTATE)
1287c478bdstevel@tonic-gate			*lmap_ok = B_FALSE;
1297c478bdstevel@tonic-gate		return (_tnfctl_map_to_errcode((prb_status_t) miscstat));
1307c478bdstevel@tonic-gate	}
1317c478bdstevel@tonic-gate
1327c478bdstevel@tonic-gate	/*
1337c478bdstevel@tonic-gate	 * find out about dlopens or dlcloses - In direct mode, there
1347c478bdstevel@tonic-gate	 * can only be one since we monitor all dl activity.  The dl_evt
1357c478bdstevel@tonic-gate	 * field is only used by tnfctl_continue().  In proc_service
1367c478bdstevel@tonic-gate	 * mode or internal mode, the new_probe member indicates new probes
1377c478bdstevel@tonic-gate	 * correctly.
1387c478bdstevel@tonic-gate	 */
1397c478bdstevel@tonic-gate	*dl_evt = EVT_NONE;
1407c478bdstevel@tonic-gate	for (cur_obj = hndl->objlist; cur_obj; cur_obj = cur_obj->next) {
1417c478bdstevel@tonic-gate		if (cur_obj->old == B_TRUE) {
1427c478bdstevel@tonic-gate			*dl_evt = EVT_CLOSE;
1437c478bdstevel@tonic-gate			break;
1447c478bdstevel@tonic-gate		}
1457c478bdstevel@tonic-gate		if (cur_obj->new == B_TRUE) {
1467c478bdstevel@tonic-gate			*dl_evt = EVT_OPEN;
1477c478bdstevel@tonic-gate			break;
1487c478bdstevel@tonic-gate		}
1497c478bdstevel@tonic-gate	}
1507c478bdstevel@tonic-gate
1517c478bdstevel@tonic-gate	/*
1527c478bdstevel@tonic-gate	 * reset new_probe field only if there was a dlopen or dlclose
1537c478bdstevel@tonic-gate	 */
1547c478bdstevel@tonic-gate	if (*dl_evt != EVT_NONE) {
1557c478bdstevel@tonic-gate		for (cur_obj = hndl->objlist; cur_obj;
1567c478bdstevel@tonic-gate				cur_obj = cur_obj->next) {
1577c478bdstevel@tonic-gate			cur_obj->new_probe = cur_obj->new;
1587c478bdstevel@tonic-gate		}
1597c478bdstevel@tonic-gate	}
1607c478bdstevel@tonic-gate
1617c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
1627c478bdstevel@tonic-gate}
1637c478bdstevel@tonic-gate
1647c478bdstevel@tonic-gate
1657c478bdstevel@tonic-gate/*
1667c478bdstevel@tonic-gate * search through all libraries and discover all probes in target
1677c478bdstevel@tonic-gate * This function assumes all objects have been found and marked as
1687c478bdstevel@tonic-gate * appropriate (new, old, or neither)
1697c478bdstevel@tonic-gate */
1707c478bdstevel@tonic-gatetnfctl_errcode_t
1717c478bdstevel@tonic-gate_tnfctl_find_all_probes(tnfctl_handle_t *hndl)
1727c478bdstevel@tonic-gate{
1737c478bdstevel@tonic-gate	tnfctl_errcode_t	prexstat;
1747c478bdstevel@tonic-gate	int		num_probes, j;
1757c478bdstevel@tonic-gate	objlist_t	*cur_obj, *prev_obj, *tmp_obj;
1767c478bdstevel@tonic-gate	boolean_t	saw_new_probes = B_FALSE;
1777c478bdstevel@tonic-gate
1787c478bdstevel@tonic-gate	prev_obj = NULL;
1797c478bdstevel@tonic-gate	cur_obj = hndl->objlist;
1807c478bdstevel@tonic-gate	while (cur_obj) {
1817c478bdstevel@tonic-gate		if (cur_obj->old == B_TRUE) {
1827c478bdstevel@tonic-gate			/* dlclosed library : stitch out probes in target */
1837c478bdstevel@tonic-gate
1847c478bdstevel@tonic-gate			DBG_TNF_PROBE_3(_tnfctl_find_all_probes_1, "libtnfctl",
1857c478bdstevel@tonic-gate				"sunw%verbosity 1; sunw%debug 'lib dlclosed'",
1867c478bdstevel@tonic-gate				tnf_opaque, lib_baseaddr, cur_obj->baseaddr,
1877c478bdstevel@tonic-gate				tnf_string, lib_name, cur_obj->objname,
1887c478bdstevel@tonic-gate				tnf_long, lib_fd, cur_obj->objfd);
1897c478bdstevel@tonic-gate
1907c478bdstevel@tonic-gate			prexstat = unlink_targ_obj_probes(hndl, cur_obj);
1917c478bdstevel@tonic-gate			if (prexstat)
1927c478bdstevel@tonic-gate				return (prexstat);
1937c478bdstevel@tonic-gate			free_obj_fields(cur_obj);
1947c478bdstevel@tonic-gate			/* remove this object from linked list */
1957c478bdstevel@tonic-gate			tmp_obj = cur_obj;
1967c478bdstevel@tonic-gate			cur_obj = cur_obj->next;
1977c478bdstevel@tonic-gate			if (prev_obj == NULL)
1987c478bdstevel@tonic-gate				hndl->objlist = cur_obj;
1997c478bdstevel@tonic-gate			else
2007c478bdstevel@tonic-gate				prev_obj->next = cur_obj;
2017c478bdstevel@tonic-gate			free(tmp_obj);
2027c478bdstevel@tonic-gate			continue;
2037c478bdstevel@tonic-gate		}
2047c478bdstevel@tonic-gate
2057c478bdstevel@tonic-gate		if (cur_obj->new == B_TRUE) {
2067c478bdstevel@tonic-gate			/* dlopened library : read in probes */
2077c478bdstevel@tonic-gate			prexstat = get_num_probes(hndl, cur_obj, &num_probes);
2087c478bdstevel@tonic-gate			if (prexstat)
2097c478bdstevel@tonic-gate				return (prexstat);
2107c478bdstevel@tonic-gate			if (num_probes) {
2117c478bdstevel@tonic-gate				saw_new_probes = B_TRUE;
2127c478bdstevel@tonic-gate				cur_obj->probes = malloc(num_probes *
2137c478bdstevel@tonic-gate					sizeof (prbctlref_t));
2147c478bdstevel@tonic-gate				if (cur_obj->probes == NULL)
2157c478bdstevel@tonic-gate					return (TNFCTL_ERR_ALLOCFAIL);
2167c478bdstevel@tonic-gate				prexstat = read_probes_in_obj(hndl, cur_obj,
2177c478bdstevel@tonic-gate					num_probes, hndl->num_probes);
2187c478bdstevel@tonic-gate				if (prexstat)
2197c478bdstevel@tonic-gate					return (prexstat);
2207c478bdstevel@tonic-gate				cur_obj->min_probe_num = hndl->num_probes;
2217c478bdstevel@tonic-gate				/* increment num_probes */
2227c478bdstevel@tonic-gate				hndl->num_probes += num_probes;
2237c478bdstevel@tonic-gate				cur_obj->probecnt = num_probes;
2247c478bdstevel@tonic-gate				prexstat = link_targ_obj_probes(hndl, cur_obj);
2257c478bdstevel@tonic-gate				if (prexstat)
2267c478bdstevel@tonic-gate					return (prexstat);
2277c478bdstevel@tonic-gate			}
2287c478bdstevel@tonic-gate		}
2297c478bdstevel@tonic-gate		prev_obj = cur_obj;
2307c478bdstevel@tonic-gate		cur_obj = cur_obj->next;
2317c478bdstevel@tonic-gate	}
2327c478bdstevel@tonic-gate
2337c478bdstevel@tonic-gate#if 0
2347c478bdstevel@tonic-gate	for (cur_obj = hndl->objlist; cur_obj; cur_obj = cur_obj->next) {
2357c478bdstevel@tonic-gate			(void) fprintf(stderr, "%s 0x%08x %s fd=%d\n",
2367c478bdstevel@tonic-gate				(cur_obj->new) ? "*" : " ",
2377c478bdstevel@tonic-gate				cur_obj->baseaddr, cur_obj->objname,
2387c478bdstevel@tonic-gate				cur_obj->objfd);
2397c478bdstevel@tonic-gate	}
2407c478bdstevel@tonic-gate#endif
2417c478bdstevel@tonic-gate
2427c478bdstevel@tonic-gate	/* call create_func for client data if we saw new probes */
2437c478bdstevel@tonic-gate	if (saw_new_probes && hndl->create_func) {
2447c478bdstevel@tonic-gate		for (cur_obj = hndl->objlist; cur_obj;
2457c478bdstevel@tonic-gate						cur_obj = cur_obj->next) {
2467c478bdstevel@tonic-gate			tnfctl_probe_t *probe_handle;
2477c478bdstevel@tonic-gate
2487c478bdstevel@tonic-gate			if (cur_obj->new == B_FALSE)
2497c478bdstevel@tonic-gate				continue;
2507c478bdstevel@tonic-gate			/* new object */
2517c478bdstevel@tonic-gate			for (j = 0; j < cur_obj->probecnt; j++) {
2527c478bdstevel@tonic-gate				probe_handle = cur_obj->probes[j].probe_handle;
2537c478bdstevel@tonic-gate				probe_handle->client_registered_data =
2547c478bdstevel@tonic-gate					hndl->create_func(hndl, probe_handle);
2557c478bdstevel@tonic-gate			}
2567c478bdstevel@tonic-gate		}
2577c478bdstevel@tonic-gate	}
2587c478bdstevel@tonic-gate
2597c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
2607c478bdstevel@tonic-gate}
2617c478bdstevel@tonic-gate
2627c478bdstevel@tonic-gate/*
2637c478bdstevel@tonic-gate * _tnfctl_free_objs_and_probes() - cleans up objects and probes
2647c478bdstevel@tonic-gate */
2657c478bdstevel@tonic-gatevoid
2667c478bdstevel@tonic-gate_tnfctl_free_objs_and_probes(tnfctl_handle_t *hndl)
2677c478bdstevel@tonic-gate{
2687c478bdstevel@tonic-gate	objlist_t *obj, *tmp;
2697c478bdstevel@tonic-gate
2707c478bdstevel@tonic-gate	obj = hndl->objlist;
2717c478bdstevel@tonic-gate	while (obj) {
2727c478bdstevel@tonic-gate		free_obj_fields(obj);
2737c478bdstevel@tonic-gate		tmp = obj;
2747c478bdstevel@tonic-gate		obj = obj->next;
2757c478bdstevel@tonic-gate		free(tmp);
2767c478bdstevel@tonic-gate	}
2777c478bdstevel@tonic-gate	hndl->objlist = NULL;
2787c478bdstevel@tonic-gate}
2797c478bdstevel@tonic-gate
2807c478bdstevel@tonic-gate/*
2817c478bdstevel@tonic-gate * Free members of objlist_t
2827c478bdstevel@tonic-gate */
2837c478bdstevel@tonic-gatestatic void
2847c478bdstevel@tonic-gatefree_obj_fields(objlist_t *obj)
2857c478bdstevel@tonic-gate{
2867c478bdstevel@tonic-gate	int i;
2877c478bdstevel@tonic-gate	prbctlref_t *probe_p;
2887c478bdstevel@tonic-gate
2897c478bdstevel@tonic-gate	for (i = 0; i < obj->probecnt; i++) {
2907c478bdstevel@tonic-gate		probe_p = &(obj->probes[i]);
2917c478bdstevel@tonic-gate		if (probe_p->attr_string)
2927c478bdstevel@tonic-gate			free(probe_p->attr_string);
2937c478bdstevel@tonic-gate		if (probe_p->probe_handle)
2947c478bdstevel@tonic-gate			probe_p->probe_handle->valid = B_FALSE;
2957c478bdstevel@tonic-gate	}
2967c478bdstevel@tonic-gate	if (obj->probes)
2977c478bdstevel@tonic-gate		free(obj->probes);
2987c478bdstevel@tonic-gate	obj->probecnt = 0;
2997c478bdstevel@tonic-gate	if (obj->objname)
3007c478bdstevel@tonic-gate		free(obj->objname);
3017c478bdstevel@tonic-gate	if (obj->objfd != -1)
3027c478bdstevel@tonic-gate		close(obj->objfd);
3037c478bdstevel@tonic-gate}
3047c478bdstevel@tonic-gate
3057c478bdstevel@tonic-gate/*
3067c478bdstevel@tonic-gate * _tnfctl_probes_traverse() - iterate over all probes by calling the
3077c478bdstevel@tonic-gate * callback function supplied.
3087c478bdstevel@tonic-gate */
3097c478bdstevel@tonic-gatetnfctl_errcode_t
3107c478bdstevel@tonic-gate_tnfctl_probes_traverse(tnfctl_handle_t *hndl,
3117c478bdstevel@tonic-gate	_tnfctl_traverse_probe_func_t func_p, void *calldata_p)
3127c478bdstevel@tonic-gate{
3137c478bdstevel@tonic-gate	tnfctl_errcode_t	prexstat;
3147c478bdstevel@tonic-gate	boolean_t	release_lock;
3157c478bdstevel@tonic-gate	objlist_t	*obj;
3167c478bdstevel@tonic-gate	int		j;
3177c478bdstevel@tonic-gate
3187c478bdstevel@tonic-gate	/*LINTED statement has no consequent: else*/
3197c478bdstevel@tonic-gate	LOCK_SYNC(hndl, prexstat, release_lock);
3207c478bdstevel@tonic-gate
3217c478bdstevel@tonic-gate	for (obj = hndl->objlist; obj; obj = obj->next) {
3227c478bdstevel@tonic-gate		for (j = 0; j < obj->probecnt; j++) {
3237c478bdstevel@tonic-gate			prexstat = (*func_p) (hndl, &(obj->probes[j]),
3247c478bdstevel@tonic-gate							calldata_p);
3257c478bdstevel@tonic-gate			if (prexstat) {
3267c478bdstevel@tonic-gate				/*LINTED statement has no consequent: else*/
3277c478bdstevel@tonic-gate				UNLOCK(hndl, release_lock);
3287c478bdstevel@tonic-gate				return (prexstat);
3297c478bdstevel@tonic-gate			}
3307c478bdstevel@tonic-gate		}
3317c478bdstevel@tonic-gate	}
3327c478bdstevel@tonic-gate
3337c478bdstevel@tonic-gate	/*LINTED statement has no consequent: else*/
3347c478bdstevel@tonic-gate	UNLOCK(hndl, release_lock);
3357c478bdstevel@tonic-gate
3367c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
3377c478bdstevel@tonic-gate}
3387c478bdstevel@tonic-gate
3397c478bdstevel@tonic-gate/*
3407c478bdstevel@tonic-gate * function that is called by loadobject iterator function for every
3417c478bdstevel@tonic-gate * loadobject.  If a new loadobject, add it to to our list.
3427c478bdstevel@tonic-gate */
3437c478bdstevel@tonic-gatestatic int
3447c478bdstevel@tonic-gateper_loadobj(void *proc_p, const tnfctl_ind_obj_info_t *obj, void *cd)
3457c478bdstevel@tonic-gate{
3467c478bdstevel@tonic-gate	tnfctl_handle_t	*hndl = cd;
3477c478bdstevel@tonic-gate	objlist_t	*entry_p, *cur_p, *next_p;
3487c478bdstevel@tonic-gate
3497c478bdstevel@tonic-gate	if (entry_p = loadobj_find(hndl, obj)) {
3507c478bdstevel@tonic-gate		/* loadobject already exists */
3517c478bdstevel@tonic-gate		entry_p->old = B_FALSE;
3527c478bdstevel@tonic-gate		/* no need to close the objfd because iterator func will */
3537c478bdstevel@tonic-gate
3547c478bdstevel@tonic-gate		/* successful return */
3557c478bdstevel@tonic-gate		return (0);
3567c478bdstevel@tonic-gate	}
3577c478bdstevel@tonic-gate
3587c478bdstevel@tonic-gate	/* add new loadobject */
3597c478bdstevel@tonic-gate	entry_p = calloc(1, sizeof (objlist_t));
3607c478bdstevel@tonic-gate
3617c478bdstevel@tonic-gate	entry_p->old = B_FALSE;
3627c478bdstevel@tonic-gate	entry_p->new = B_TRUE;
3637c478bdstevel@tonic-gate	entry_p->new_probe = B_TRUE;
3647c478bdstevel@tonic-gate	entry_p->objname = strdup(obj->objname);
3657c478bdstevel@tonic-gate	if (entry_p->objname == NULL)
3667c478bdstevel@tonic-gate		return (1);
3677c478bdstevel@tonic-gate	entry_p->baseaddr = obj->text_base;
3687c478bdstevel@tonic-gate	/* may have to actually open the fd */
3697c478bdstevel@tonic-gate	if (obj->objfd == -1) {
3707c478bdstevel@tonic-gate		entry_p->objfd = open(obj->objname, O_RDONLY);
3717c478bdstevel@tonic-gate		if (entry_p->objfd == -1)
3727c478bdstevel@tonic-gate			return (1);
3737c478bdstevel@tonic-gate	} else {
3747c478bdstevel@tonic-gate		/* dup the fd because iterator function will close it */
3757c478bdstevel@tonic-gate		entry_p->objfd = dup(obj->objfd);
3767c478bdstevel@tonic-gate		if (entry_p->objfd == -1)
3777c478bdstevel@tonic-gate			return (1);
3787c478bdstevel@tonic-gate	}
3797c478bdstevel@tonic-gate
3807c478bdstevel@tonic-gate	entry_p->min_probe_num = 0;
3817c478bdstevel@tonic-gate	entry_p->probecnt = 0;
3827c478bdstevel@tonic-gate	entry_p->probes = NULL;
3837c478bdstevel@tonic-gate	entry_p->next = NULL;
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate	if (hndl->objlist == NULL) {
3867c478bdstevel@tonic-gate		hndl->objlist = entry_p;
3877c478bdstevel@tonic-gate	} else {
3887c478bdstevel@tonic-gate		/* add to end of list */
3897c478bdstevel@tonic-gate		next_p = hndl->objlist;
3907c478bdstevel@tonic-gate		while (next_p) {
3917c478bdstevel@tonic-gate			cur_p = next_p;
3927c478bdstevel@tonic-gate			next_p = next_p->next;
3937c478bdstevel@tonic-gate		}
3947c478bdstevel@tonic-gate		/* cur_p now points to last element on list */
3957c478bdstevel@tonic-gate		cur_p->next = entry_p;
3967c478bdstevel@tonic-gate	}
3977c478bdstevel@tonic-gate
3987c478bdstevel@tonic-gate	return (0);
3997c478bdstevel@tonic-gate}
4007c478bdstevel@tonic-gate
4017c478bdstevel@tonic-gate/*
4027c478bdstevel@tonic-gate * check if this loadobject already exists in our linked list.
4037c478bdstevel@tonic-gate */
4047c478bdstevel@tonic-gatestatic objlist_t *
4057c478bdstevel@tonic-gateloadobj_find(tnfctl_handle_t *hndl, const tnfctl_ind_obj_info_t *this_obj)
4067c478bdstevel@tonic-gate{
4077c478bdstevel@tonic-gate	objlist_t *obj;
4087c478bdstevel@tonic-gate
4097c478bdstevel@tonic-gate	for (obj = hndl->objlist; obj; obj = obj->next) {
4107c478bdstevel@tonic-gate		if (obj->baseaddr == this_obj->text_base)
4117c478bdstevel@tonic-gate			return (obj);
4127c478bdstevel@tonic-gate	}
4137c478bdstevel@tonic-gate	return (NULL);
4147c478bdstevel@tonic-gate}
4157c478bdstevel@tonic-gate
4167c478bdstevel@tonic-gate/*
4177c478bdstevel@tonic-gate * find the number of probes in a loadobject
4187c478bdstevel@tonic-gate */
4197c478bdstevel@tonic-gatestatic tnfctl_errcode_t
4207c478bdstevel@tonic-gateget_num_probes(tnfctl_handle_t *hndl, objlist_t *obj, int *num_probes)
4217c478bdstevel@tonic-gate{
4227c478bdstevel@tonic-gate	tnfctl_errcode_t	prexstat;
4237c478bdstevel@tonic-gate	link_args_t	largs;
4247c478bdstevel@tonic-gate	tnfctl_elf_search_t search_info;
4257c478bdstevel@tonic-gate
4267c478bdstevel@tonic-gate	DBG_TNF_PROBE_0(get_num_probes_1, "libtnfctl", "sunw%verbosity 1");
4277c478bdstevel@tonic-gate
4287c478bdstevel@tonic-gate	largs.la_probename = PROBE_SYMBOL;
4297c478bdstevel@tonic-gate	largs.ret_val = 0;
4307c478bdstevel@tonic-gate
4317c478bdstevel@tonic-gate	search_info.section_func = _tnfctl_traverse_rela;
4327c478bdstevel@tonic-gate	search_info.record_func = count_probes;
4337c478bdstevel@tonic-gate	search_info.record_data = &largs;
4347c478bdstevel@tonic-gate
4357c478bdstevel@tonic-gate	prexstat = _tnfctl_traverse_object(obj->objfd, obj->baseaddr,
4367c478bdstevel@tonic-gate						&search_info);
4377c478bdstevel@tonic-gate	if (prexstat)
4387c478bdstevel@tonic-gate		return (prexstat);
4397c478bdstevel@tonic-gate
4407c478bdstevel@tonic-gate	DBG_TNF_PROBE_2(get_num_probes_2, "libtnfctl", "sunw%verbosity 1",
4417c478bdstevel@tonic-gate			tnf_long, num_probes, largs.ret_val,
4427c478bdstevel@tonic-gate			tnf_string, obj_name, obj->objname);
4437c478bdstevel@tonic-gate
4447c478bdstevel@tonic-gate	*num_probes = largs.ret_val;
4457c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
4467c478bdstevel@tonic-gate}
4477c478bdstevel@tonic-gate
4487c478bdstevel@tonic-gate/*
4497c478bdstevel@tonic-gate * discover all probes in a loadobject and read it into our array.
4507c478bdstevel@tonic-gate */
4517c478bdstevel@tonic-gatestatic tnfctl_errcode_t
4527c478bdstevel@tonic-gateread_probes_in_obj(tnfctl_handle_t *hndl, objlist_t *obj, ulong_t num_probes,
4537c478bdstevel@tonic-gate			ulong_t probe_base_num)
4547c478bdstevel@tonic-gate{
4557c478bdstevel@tonic-gate	tnfctl_errcode_t	prexstat;
4567c478bdstevel@tonic-gate	link_args2_t	largs2;
4577c478bdstevel@tonic-gate	tnfctl_elf_search_t search_info;
4587c478bdstevel@tonic-gate
4597c478bdstevel@tonic-gate	DBG_TNF_PROBE_0(read_probes_in_obj_1, "libtnfctl", "sunw%verbosity 2");
4607c478bdstevel@tonic-gate
4617c478bdstevel@tonic-gate	largs2.la_hndl = hndl;
4627c478bdstevel@tonic-gate	largs2.la_probename = PROBE_SYMBOL;
4637c478bdstevel@tonic-gate	largs2.la_obj = obj;
4647c478bdstevel@tonic-gate	largs2.la_index = 0;
4657c478bdstevel@tonic-gate	largs2.la_base = probe_base_num;
4667c478bdstevel@tonic-gate
4677c478bdstevel@tonic-gate	search_info.section_func = _tnfctl_traverse_rela;
4687c478bdstevel@tonic-gate	search_info.record_func = read_a_probe;
4697c478bdstevel@tonic-gate	search_info.record_data = &largs2;
4707c478bdstevel@tonic-gate
4717c478bdstevel@tonic-gate	prexstat = _tnfctl_traverse_object(obj->objfd, obj->baseaddr,
4727c478bdstevel@tonic-gate						&search_info);
4737c478bdstevel@tonic-gate	if (prexstat)
4747c478bdstevel@tonic-gate		return (prexstat);
4757c478bdstevel@tonic-gate
4767c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
4777c478bdstevel@tonic-gate}
4787c478bdstevel@tonic-gate
4797c478bdstevel@tonic-gate/*
4807c478bdstevel@tonic-gate * checks if this relocation entry is a probe and if so,
4817c478bdstevel@tonic-gate * increments a counter for every probe seen
4827c478bdstevel@tonic-gate */
4837c478bdstevel@tonic-gate/*ARGSUSED*/
4847c478bdstevel@tonic-gatestatic tnfctl_errcode_t
4857c478bdstevel@tonic-gatecount_probes(char *name, uintptr_t addr, void *rel_entry,
4867c478bdstevel@tonic-gate	tnfctl_elf_search_t * search_info_p)
4877c478bdstevel@tonic-gate{
4887c478bdstevel@tonic-gate	link_args_t	*largs_p = (link_args_t *) search_info_p->record_data;
4897c478bdstevel@tonic-gate
4907c478bdstevel@tonic-gate	if (strcmp(name, largs_p->la_probename) == 0) {
4917c478bdstevel@tonic-gate		largs_p->ret_val++;
4927c478bdstevel@tonic-gate	}
4937c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
4947c478bdstevel@tonic-gate}
4957c478bdstevel@tonic-gate
4967c478bdstevel@tonic-gate/*
4977c478bdstevel@tonic-gate * checks if this relocation entry is a probe and if so, reads in info
4987c478bdstevel@tonic-gate * on this probe
4997c478bdstevel@tonic-gate */
5007c478bdstevel@tonic-gate/*ARGSUSED*/
5017c478bdstevel@tonic-gatestatic tnfctl_errcode_t
5027c478bdstevel@tonic-gateread_a_probe(char *name, uintptr_t addr, void *rel_entry,
5037c478bdstevel@tonic-gate	tnfctl_elf_search_t * search_info_p)
5047c478bdstevel@tonic-gate{
5057c478bdstevel@tonic-gate	link_args2_t	*largs2_p = (link_args2_t *) search_info_p->record_data;
5067c478bdstevel@tonic-gate	ulong_t		index = largs2_p->la_index;
5077c478bdstevel@tonic-gate	prbctlref_t	*prbctl_p;
5087c478bdstevel@tonic-gate	tnfctl_handle_t	*hndl = largs2_p->la_hndl;
5097c478bdstevel@tonic-gate	tnfctl_errcode_t	prexstat;
5107c478bdstevel@tonic-gate	int		miscstat;
5117c478bdstevel@tonic-gate	uintptr_t	attrs;
5127c478bdstevel@tonic-gate
5137c478bdstevel@tonic-gate	assert((hndl->mode == INTERNAL_MODE) ?
5147c478bdstevel@tonic-gate		(MUTEX_HELD(&_tnfctl_lmap_lock)) : 1);
5157c478bdstevel@tonic-gate
5167c478bdstevel@tonic-gate	if (strcmp(name, largs2_p->la_probename) != 0)
5177c478bdstevel@tonic-gate		return (TNFCTL_ERR_NONE);
5187c478bdstevel@tonic-gate
5197c478bdstevel@tonic-gate	/* found a probe */
5207c478bdstevel@tonic-gate	prbctl_p = &(largs2_p->la_obj->probes[index]);
5217c478bdstevel@tonic-gate	prbctl_p->addr = addr;
5227c478bdstevel@tonic-gate	prbctl_p->probe_id = largs2_p->la_base + index;
5237c478bdstevel@tonic-gate	prbctl_p->obj = largs2_p->la_obj;
5247c478bdstevel@tonic-gate	largs2_p->la_index++;
5257c478bdstevel@tonic-gate
5267c478bdstevel@tonic-gate	/* read in probe structure */
5277c478bdstevel@tonic-gate	miscstat = hndl->p_read(hndl->proc_p, addr,
5287c478bdstevel@tonic-gate		&prbctl_p->wrkprbctl, sizeof (prbctl_p->wrkprbctl));
5297c478bdstevel@tonic-gate	if (miscstat) {
5307c478bdstevel@tonic-gate		DBG((void) fprintf(stderr,
5317c478bdstevel@tonic-gate			"read_a_probe: read from target failed: %d\n",
5327c478bdstevel@tonic-gate			miscstat));
5337c478bdstevel@tonic-gate		return (TNFCTL_ERR_INTERNAL);
5347c478bdstevel@tonic-gate	}
5357c478bdstevel@tonic-gate
5367c478bdstevel@tonic-gate	/*
5377c478bdstevel@tonic-gate	 * dereference the attrs (read it into our address space only for
5387c478bdstevel@tonic-gate	 * working copy)
5397c478bdstevel@tonic-gate	 */
5407c478bdstevel@tonic-gate	attrs = (uintptr_t) prbctl_p->wrkprbctl.attrs;
5417c478bdstevel@tonic-gate	prexstat = _tnfctl_readstr_targ(hndl, attrs, &prbctl_p->attr_string);
5427c478bdstevel@tonic-gate	if (prexstat) {
5437c478bdstevel@tonic-gate		DBG((void) fprintf(stderr,
5447c478bdstevel@tonic-gate		    "read_a_probe: _tnfctl_readstr_targ (attrs) failed: %s\n",
5457c478bdstevel@tonic-gate				tnfctl_strerror(prexstat)));
5467c478bdstevel@tonic-gate		return (prexstat);
5477c478bdstevel@tonic-gate	}
5487c478bdstevel@tonic-gate
5497c478bdstevel@tonic-gate	DBG_TNF_PROBE_1(read_a_probe_2, "libtnfctl",
5507c478bdstevel@tonic-gate		"sunw%verbosity 1; sunw%debug 'found a probe'",
5517c478bdstevel@tonic-gate		tnf_string, probe, prbctl_p->attr_string);
5527c478bdstevel@tonic-gate
5537c478bdstevel@tonic-gate	/* create probe handle */
5547c478bdstevel@tonic-gate	prbctl_p->probe_handle = calloc(1, sizeof (tnfctl_probe_t));
5557c478bdstevel@tonic-gate	if (prbctl_p->probe_handle == NULL)
5567c478bdstevel@tonic-gate		return (TNFCTL_ERR_ALLOCFAIL);
5577c478bdstevel@tonic-gate	prbctl_p->probe_handle->valid = B_TRUE;
5587c478bdstevel@tonic-gate	prbctl_p->probe_handle->probe_p = prbctl_p;
5597c478bdstevel@tonic-gate	/* link in probe handle into chain off tnfctl_handle_t */
5607c478bdstevel@tonic-gate	prbctl_p->probe_handle->next = hndl->probe_handle_list_head;
5617c478bdstevel@tonic-gate	hndl->probe_handle_list_head = prbctl_p->probe_handle;
5627c478bdstevel@tonic-gate
5637c478bdstevel@tonic-gate	/*
5647c478bdstevel@tonic-gate	 * if this is a "virgin" probe, set up probe to initial state
5657c478bdstevel@tonic-gate	 * REMIND: Could defer this target write till we link the probes
5667c478bdstevel@tonic-gate	 * together in target process in link_targ_obj_probes() i.e.
5677c478bdstevel@tonic-gate	 * do the "write" only once.
5687c478bdstevel@tonic-gate	 */
5697c478bdstevel@tonic-gate	if (prbctl_p->wrkprbctl.commit_func == NULL) {
5707c478bdstevel@tonic-gate		prbctl_p->wrkprbctl.probe_func =
5717c478bdstevel@tonic-gate				(tnf_probe_func_t) hndl->endfunc;
5727c478bdstevel@tonic-gate		prbctl_p->wrkprbctl.commit_func =
5737c478bdstevel@tonic-gate				(tnf_probe_func_t) hndl->commitfunc;
5747c478bdstevel@tonic-gate		prbctl_p->wrkprbctl.alloc_func =
5757c478bdstevel@tonic-gate				(tnf_probe_alloc_func_t) hndl->allocfunc;
5767c478bdstevel@tonic-gate		/*
5777c478bdstevel@tonic-gate		 * update the probe in target to its initial state
5787c478bdstevel@tonic-gate		 * Since the probe is disabled, it is ok to write it one
5797c478bdstevel@tonic-gate		 * write command as opposed to updating each word individually
5807c478bdstevel@tonic-gate		 */
5817c478bdstevel@tonic-gate		miscstat = hndl->p_write(hndl->proc_p, addr,
5827c478bdstevel@tonic-gate			&prbctl_p->wrkprbctl, sizeof (prbctl_p->wrkprbctl));
5837c478bdstevel@tonic-gate		if (miscstat)
5847c478bdstevel@tonic-gate			return (TNFCTL_ERR_INTERNAL);
5857c478bdstevel@tonic-gate	}
5867c478bdstevel@tonic-gate
5877c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
5887c478bdstevel@tonic-gate}
5897c478bdstevel@tonic-gate
5907c478bdstevel@tonic-gate/*
5917c478bdstevel@tonic-gate * Link all the probes in a linked list in the target image in specified
5927c478bdstevel@tonic-gate * object.  Also, link probes from previous object and next object into
5937c478bdstevel@tonic-gate * this list.  The only
5947c478bdstevel@tonic-gate * reason this is needed is because internally in the process,
5957c478bdstevel@tonic-gate * tnf_probe_notify() that is called from libthread walks through all
5967c478bdstevel@tonic-gate * probes substituting the test function
5977c478bdstevel@tonic-gate * REMIND: find a way that we don't have to walk through probes internally.
5987c478bdstevel@tonic-gate */
5997c478bdstevel@tonic-gatestatic tnfctl_errcode_t
6007c478bdstevel@tonic-gatelink_targ_obj_probes(tnfctl_handle_t *hndl, objlist_t *cur)
6017c478bdstevel@tonic-gate{
6027c478bdstevel@tonic-gate	int i;
6037c478bdstevel@tonic-gate	prbctlref_t *probe_p;
6047c478bdstevel@tonic-gate	tnf_probe_control_t *next_probe;
6057c478bdstevel@tonic-gate	int miscstat;
6067c478bdstevel@tonic-gate	objlist_t *cur_tmp, *prev_w_probes, *next_w_probes;
6077c478bdstevel@tonic-gate	uintptr_t next_addr;
6087c478bdstevel@tonic-gate
6097c478bdstevel@tonic-gate	/* find previous object that has probes */
6107c478bdstevel@tonic-gate	prev_w_probes = NULL;
6117c478bdstevel@tonic-gate	cur_tmp = hndl->objlist;
6127c478bdstevel@tonic-gate	while (cur_tmp != cur) {
6137c478bdstevel@tonic-gate		if (cur_tmp->probecnt != 0)
6147c478bdstevel@tonic-gate			prev_w_probes = cur_tmp;
6157c478bdstevel@tonic-gate		cur_tmp = cur_tmp->next;
6167c478bdstevel@tonic-gate	}
6177c478bdstevel@tonic-gate
6187c478bdstevel@tonic-gate	/* find next object with probes */
6197c478bdstevel@tonic-gate	next_w_probes = NULL;
6207c478bdstevel@tonic-gate	cur_tmp = cur->next;
6217c478bdstevel@tonic-gate	while (cur_tmp != NULL) {
6227c478bdstevel@tonic-gate		if (cur_tmp->probecnt != 0)
6237c478bdstevel@tonic-gate			next_w_probes = cur_tmp;
6247c478bdstevel@tonic-gate		cur_tmp = cur_tmp->next;
6257c478bdstevel@tonic-gate	}
6267c478bdstevel@tonic-gate
6277c478bdstevel@tonic-gate	/* link probes (except for last one) in order */
6287c478bdstevel@tonic-gate	for (i = 0; i < (cur->probecnt - 1); i++) {
6297c478bdstevel@tonic-gate		probe_p = &(cur->probes[i]);
6307c478bdstevel@tonic-gate		next_probe = (tnf_probe_control_t *) cur->probes[i+1].addr;
6317c478bdstevel@tonic-gate		probe_p->wrkprbctl.next = next_probe;
6327c478bdstevel@tonic-gate		miscstat = hndl->p_write(hndl->proc_p, probe_p->addr +
6337c478bdstevel@tonic-gate				offsetof(struct tnf_probe_control, next),
6347c478bdstevel@tonic-gate				&next_probe, sizeof (next_probe));
6357c478bdstevel@tonic-gate		if (miscstat)
6367c478bdstevel@tonic-gate			return (TNFCTL_ERR_INTERNAL);
6377c478bdstevel@tonic-gate	}
6387c478bdstevel@tonic-gate
6397c478bdstevel@tonic-gate	next_probe = (tnf_probe_control_t *) cur->probes[0].addr;
6407c478bdstevel@tonic-gate	if (prev_w_probes == NULL) {
6417c478bdstevel@tonic-gate		/* adding as first object in list */
6427c478bdstevel@tonic-gate		next_addr = hndl->probelist_head;
6437c478bdstevel@tonic-gate	} else {
6447c478bdstevel@tonic-gate		probe_p = &(prev_w_probes->probes[prev_w_probes->probecnt - 1]);
6457c478bdstevel@tonic-gate		probe_p->wrkprbctl.next = next_probe;
6467c478bdstevel@tonic-gate		next_addr = probe_p->addr +
6477c478bdstevel@tonic-gate				offsetof(struct tnf_probe_control, next);
6487c478bdstevel@tonic-gate	}
6497c478bdstevel@tonic-gate
6507c478bdstevel@tonic-gate	/* point next_addr to first probe in this object */
6517c478bdstevel@tonic-gate	miscstat = hndl->p_write(hndl->proc_p, next_addr,
6527c478bdstevel@tonic-gate			&next_probe, sizeof (next_probe));
6537c478bdstevel@tonic-gate	if (miscstat)
6547c478bdstevel@tonic-gate		return (TNFCTL_ERR_INTERNAL);
6557c478bdstevel@tonic-gate
6567c478bdstevel@tonic-gate	/* link last probe in object */
6577c478bdstevel@tonic-gate	if (next_w_probes == NULL)
6587c478bdstevel@tonic-gate		next_probe = NULL;
6597c478bdstevel@tonic-gate	else {
6607c478bdstevel@tonic-gate		next_probe = (tnf_probe_control_t *)
6617c478bdstevel@tonic-gate				next_w_probes->probes[0].addr;
6627c478bdstevel@tonic-gate	}
6637c478bdstevel@tonic-gate	probe_p = &(cur->probes[cur->probecnt - 1]);
6647c478bdstevel@tonic-gate	probe_p->wrkprbctl.next = next_probe;
6657c478bdstevel@tonic-gate	miscstat = hndl->p_write(hndl->proc_p, probe_p->addr +
6667c478bdstevel@tonic-gate			offsetof(struct tnf_probe_control, next),
6677c478bdstevel@tonic-gate			&next_probe, sizeof (next_probe));
6687c478bdstevel@tonic-gate	if (miscstat)
6697c478bdstevel@tonic-gate		return (TNFCTL_ERR_INTERNAL);
6707c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
6717c478bdstevel@tonic-gate}
6727c478bdstevel@tonic-gate
6737c478bdstevel@tonic-gate/*
6747c478bdstevel@tonic-gate * An object has been closed.  Stitch probes around this object in
6757c478bdstevel@tonic-gate * target image.
6767c478bdstevel@tonic-gate */
6777c478bdstevel@tonic-gatestatic tnfctl_errcode_t
6787c478bdstevel@tonic-gateunlink_targ_obj_probes(tnfctl_handle_t *hndl, objlist_t *cur)
6797c478bdstevel@tonic-gate{
6807c478bdstevel@tonic-gate	prbctlref_t *probe_p;
6817c478bdstevel@tonic-gate	tnf_probe_control_t *next_probe;
6827c478bdstevel@tonic-gate	int miscstat;
6837c478bdstevel@tonic-gate	objlist_t *cur_tmp, *prev_w_probes, *next_w_probes;
6847c478bdstevel@tonic-gate	uintptr_t next_addr;
6857c478bdstevel@tonic-gate
6867c478bdstevel@tonic-gate	/* find previous object that has probes */
6877c478bdstevel@tonic-gate	prev_w_probes = NULL;
6887c478bdstevel@tonic-gate	cur_tmp = hndl->objlist;
6897c478bdstevel@tonic-gate	while (cur_tmp != cur) {
6907c478bdstevel@tonic-gate		if (cur_tmp->probecnt != 0)
6917c478bdstevel@tonic-gate			prev_w_probes = cur_tmp;
6927c478bdstevel@tonic-gate		cur_tmp = cur_tmp->next;
6937c478bdstevel@tonic-gate	}
6947c478bdstevel@tonic-gate
6957c478bdstevel@tonic-gate	/* find next object with probes */
6967c478bdstevel@tonic-gate	next_w_probes = NULL;
6977c478bdstevel@tonic-gate	cur_tmp = cur->next;
6987c478bdstevel@tonic-gate	while (cur_tmp != NULL) {
6997c478bdstevel@tonic-gate		if (cur_tmp->probecnt != 0)
7007c478bdstevel@tonic-gate			next_w_probes = cur_tmp;
7017c478bdstevel@tonic-gate		cur_tmp = cur_tmp->next;
7027c478bdstevel@tonic-gate	}
7037c478bdstevel@tonic-gate
7047c478bdstevel@tonic-gate	if (next_w_probes == NULL)
7057c478bdstevel@tonic-gate		next_probe = NULL;
7067c478bdstevel@tonic-gate	else {
7077c478bdstevel@tonic-gate		next_probe = (tnf_probe_control_t *)
7087c478bdstevel@tonic-gate				next_w_probes->probes[0].addr;
7097c478bdstevel@tonic-gate	}
7107c478bdstevel@tonic-gate
7117c478bdstevel@tonic-gate	if (prev_w_probes == NULL) {
7127c478bdstevel@tonic-gate		/* removing first object in list */
7137c478bdstevel@tonic-gate		next_addr = hndl->probelist_head;
7147c478bdstevel@tonic-gate	} else {
7157c478bdstevel@tonic-gate		probe_p = &(prev_w_probes->probes[prev_w_probes->probecnt - 1]);
7167c478bdstevel@tonic-gate		probe_p->wrkprbctl.next = next_probe;
7177c478bdstevel@tonic-gate		next_addr = probe_p->addr +
7187c478bdstevel@tonic-gate				offsetof(struct tnf_probe_control, next);
7197c478bdstevel@tonic-gate	}
7207c478bdstevel@tonic-gate
7217c478bdstevel@tonic-gate	/* point next_addr to next_probe */
7227c478bdstevel@tonic-gate	miscstat = hndl->p_write(hndl->proc_p, next_addr,
7237c478bdstevel@tonic-gate			&next_probe, sizeof (next_probe));
7247c478bdstevel@tonic-gate	if (miscstat)
7257c478bdstevel@tonic-gate		return (TNFCTL_ERR_INTERNAL);
7267c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
7277c478bdstevel@tonic-gate}
7287c478bdstevel@tonic-gate
7297c478bdstevel@tonic-gate/*
7307c478bdstevel@tonic-gate * _tnfctl_flush_a_probe() - write a changed probe into the target process'
7317c478bdstevel@tonic-gate * address space.
7327c478bdstevel@tonic-gate */
7337c478bdstevel@tonic-gatetnfctl_errcode_t
7347c478bdstevel@tonic-gate_tnfctl_flush_a_probe(tnfctl_handle_t *hndl, prbctlref_t *ref_p, size_t offset,
7357c478bdstevel@tonic-gate			size_t size)
7367c478bdstevel@tonic-gate{
7377c478bdstevel@tonic-gate	tnfctl_errcode_t	prexstat;
7387c478bdstevel@tonic-gate	int			miscstat;
7397c478bdstevel@tonic-gate
7407c478bdstevel@tonic-gate	/*
7417c478bdstevel@tonic-gate	 * For internal control:
7427c478bdstevel@tonic-gate	 * There is *no race* for finding the test function (between the time
7437c478bdstevel@tonic-gate	 * we call find_test_func() and the time we assign it to a probe),
7447c478bdstevel@tonic-gate	 * because tnfctl_internal_open() cannot be called from an init section
7457c478bdstevel@tonic-gate	 * (look at man page of tnfctl_internal_open()).  And, after the init
7467c478bdstevel@tonic-gate	 * section of libthread has run, we will always use the MT test
7477c478bdstevel@tonic-gate	 * function.
7487c478bdstevel@tonic-gate	 */
7497c478bdstevel@tonic-gate
7507c478bdstevel@tonic-gate	if (hndl->mode == KERNEL_MODE) {
7517c478bdstevel@tonic-gate		prexstat = _tnfctl_prbk_flush(hndl, ref_p);
7527c478bdstevel@tonic-gate		if (prexstat)
7537c478bdstevel@tonic-gate			return (prexstat);
7547c478bdstevel@tonic-gate	} else {
7557c478bdstevel@tonic-gate		miscstat = hndl->p_write(hndl->proc_p,
7567c478bdstevel@tonic-gate			ref_p->addr + offset,
7577c478bdstevel@tonic-gate			((char *)&(ref_p->wrkprbctl)) + offset, size);
7587c478bdstevel@tonic-gate		if (miscstat)
7597c478bdstevel@tonic-gate			return (TNFCTL_ERR_INTERNAL);
7607c478bdstevel@tonic-gate	}
7617c478bdstevel@tonic-gate
7627c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
7637c478bdstevel@tonic-gate}
764