xref: /titanic_52/usr/src/lib/libtnfctl/probes.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, by Sun Microsytems, Inc.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * Load object and probe discovery in target process.  This file is
30*7c478bd9Sstevel@tonic-gate  * not exercised for kernel probes.
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #ifndef DEBUG
34*7c478bd9Sstevel@tonic-gate #define	NDEBUG	1
35*7c478bd9Sstevel@tonic-gate #endif
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <stdio.h>
38*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
39*7c478bd9Sstevel@tonic-gate #include <unistd.h>
40*7c478bd9Sstevel@tonic-gate #include <string.h>
41*7c478bd9Sstevel@tonic-gate #include <stddef.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
44*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
45*7c478bd9Sstevel@tonic-gate #include <assert.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
48*7c478bd9Sstevel@tonic-gate #include "kernel_int.h"
49*7c478bd9Sstevel@tonic-gate #include "dbg.h"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * Defines - Project private interfaces
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #define	PROBE_SYMBOL	"__tnf_probe_version_1"
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /*
58*7c478bd9Sstevel@tonic-gate  * Typedefs
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate typedef struct link_args {
62*7c478bd9Sstevel@tonic-gate 	char		*la_probename;
63*7c478bd9Sstevel@tonic-gate 	int		ret_val;
64*7c478bd9Sstevel@tonic-gate } link_args_t;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate typedef struct link_args2 {
67*7c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*la_hndl;
68*7c478bd9Sstevel@tonic-gate 	char		*la_probename;
69*7c478bd9Sstevel@tonic-gate 	objlist_t	*la_obj;
70*7c478bd9Sstevel@tonic-gate 	ulong_t		la_index;
71*7c478bd9Sstevel@tonic-gate 	ulong_t		la_base;
72*7c478bd9Sstevel@tonic-gate } link_args2_t;
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate NOTE(SCHEME_PROTECTS_DATA("always automatic", link_args link_args2))
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate static int per_loadobj(void *, const tnfctl_ind_obj_info_t *, void *);
77*7c478bd9Sstevel@tonic-gate static objlist_t *loadobj_find(tnfctl_handle_t *,
78*7c478bd9Sstevel@tonic-gate 			const tnfctl_ind_obj_info_t *);
79*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t get_num_probes(tnfctl_handle_t *, objlist_t *, int *);
80*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t read_probes_in_obj(tnfctl_handle_t *, objlist_t *,
81*7c478bd9Sstevel@tonic-gate 		ulong_t, ulong_t);
82*7c478bd9Sstevel@tonic-gate static void free_obj_fields(objlist_t *);
83*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t count_probes(char *, uintptr_t, void *,
84*7c478bd9Sstevel@tonic-gate 					tnfctl_elf_search_t *);
85*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t read_a_probe(char *, uintptr_t, void *,
86*7c478bd9Sstevel@tonic-gate 					tnfctl_elf_search_t *);
87*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t link_targ_obj_probes(tnfctl_handle_t *, objlist_t *);
88*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t unlink_targ_obj_probes(tnfctl_handle_t *, objlist_t *);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate /*
91*7c478bd9Sstevel@tonic-gate  * sync up our library list with that of the run time linker's
92*7c478bd9Sstevel@tonic-gate  * Returns an event indicating if a dlopen or dlclose happened.
93*7c478bd9Sstevel@tonic-gate  */
94*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
95*7c478bd9Sstevel@tonic-gate _tnfctl_lmap_update(tnfctl_handle_t *hndl, boolean_t *lmap_ok,
96*7c478bd9Sstevel@tonic-gate 				enum event_op_t *dl_evt)
97*7c478bd9Sstevel@tonic-gate {
98*7c478bd9Sstevel@tonic-gate 	int		miscstat;
99*7c478bd9Sstevel@tonic-gate 	objlist_t	*cur_obj;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	*lmap_ok = B_TRUE;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	/* reset old and new of current objects */
104*7c478bd9Sstevel@tonic-gate 	for (cur_obj = hndl->objlist; cur_obj; cur_obj = cur_obj->next) {
105*7c478bd9Sstevel@tonic-gate 		cur_obj->old = B_TRUE;
106*7c478bd9Sstevel@tonic-gate 		cur_obj->new = B_FALSE;
107*7c478bd9Sstevel@tonic-gate 	}
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	/* read in object list */
110*7c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_obj_iter(hndl->proc_p, per_loadobj, hndl);
111*7c478bd9Sstevel@tonic-gate 	/* reset libs_changed global var to indicated sync up done */
112*7c478bd9Sstevel@tonic-gate 	_tnfctl_libs_changed = B_FALSE;
113*7c478bd9Sstevel@tonic-gate 	if (miscstat) {
114*7c478bd9Sstevel@tonic-gate 		/*
115*7c478bd9Sstevel@tonic-gate 		 * for INDIRECT_MODE or INTERNAL_MODE, we should never get
116*7c478bd9Sstevel@tonic-gate 		 * called when linkmaps are not consistent, so this is a real
117*7c478bd9Sstevel@tonic-gate 		 * error - return without setting lmap_ok.
118*7c478bd9Sstevel@tonic-gate 		 */
119*7c478bd9Sstevel@tonic-gate 		if ((hndl->mode == INDIRECT_MODE) ||
120*7c478bd9Sstevel@tonic-gate 				(hndl->mode == INTERNAL_MODE))
121*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 		assert(hndl->mode == DIRECT_MODE);
124*7c478bd9Sstevel@tonic-gate 		/*
125*7c478bd9Sstevel@tonic-gate 		 * in DIRECT_MODE:
126*7c478bd9Sstevel@tonic-gate 		 * caller needs to call tnfctl_continue on BADLMAPSTATE
127*7c478bd9Sstevel@tonic-gate 		 * XXXX - the cast from int to prb_status_t is ok as
128*7c478bd9Sstevel@tonic-gate 		 * we know we are in DIRECT_MODE and we are calling our
129*7c478bd9Sstevel@tonic-gate 		 * own loadobject iterator function.
130*7c478bd9Sstevel@tonic-gate 		 */
131*7c478bd9Sstevel@tonic-gate 		if ((prb_status_t) miscstat == PRB_STATUS_BADLMAPSTATE)
132*7c478bd9Sstevel@tonic-gate 			*lmap_ok = B_FALSE;
133*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode((prb_status_t) miscstat));
134*7c478bd9Sstevel@tonic-gate 	}
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	/*
137*7c478bd9Sstevel@tonic-gate 	 * find out about dlopens or dlcloses - In direct mode, there
138*7c478bd9Sstevel@tonic-gate 	 * can only be one since we monitor all dl activity.  The dl_evt
139*7c478bd9Sstevel@tonic-gate 	 * field is only used by tnfctl_continue().  In proc_service
140*7c478bd9Sstevel@tonic-gate 	 * mode or internal mode, the new_probe member indicates new probes
141*7c478bd9Sstevel@tonic-gate 	 * correctly.
142*7c478bd9Sstevel@tonic-gate 	 */
143*7c478bd9Sstevel@tonic-gate 	*dl_evt = EVT_NONE;
144*7c478bd9Sstevel@tonic-gate 	for (cur_obj = hndl->objlist; cur_obj; cur_obj = cur_obj->next) {
145*7c478bd9Sstevel@tonic-gate 		if (cur_obj->old == B_TRUE) {
146*7c478bd9Sstevel@tonic-gate 			*dl_evt = EVT_CLOSE;
147*7c478bd9Sstevel@tonic-gate 			break;
148*7c478bd9Sstevel@tonic-gate 		}
149*7c478bd9Sstevel@tonic-gate 		if (cur_obj->new == B_TRUE) {
150*7c478bd9Sstevel@tonic-gate 			*dl_evt = EVT_OPEN;
151*7c478bd9Sstevel@tonic-gate 			break;
152*7c478bd9Sstevel@tonic-gate 		}
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	/*
156*7c478bd9Sstevel@tonic-gate 	 * reset new_probe field only if there was a dlopen or dlclose
157*7c478bd9Sstevel@tonic-gate 	 */
158*7c478bd9Sstevel@tonic-gate 	if (*dl_evt != EVT_NONE) {
159*7c478bd9Sstevel@tonic-gate 		for (cur_obj = hndl->objlist; cur_obj;
160*7c478bd9Sstevel@tonic-gate 				cur_obj = cur_obj->next) {
161*7c478bd9Sstevel@tonic-gate 			cur_obj->new_probe = cur_obj->new;
162*7c478bd9Sstevel@tonic-gate 		}
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
166*7c478bd9Sstevel@tonic-gate }
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate  * search through all libraries and discover all probes in target
171*7c478bd9Sstevel@tonic-gate  * This function assumes all objects have been found and marked as
172*7c478bd9Sstevel@tonic-gate  * appropriate (new, old, or neither)
173*7c478bd9Sstevel@tonic-gate  */
174*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
175*7c478bd9Sstevel@tonic-gate _tnfctl_find_all_probes(tnfctl_handle_t *hndl)
176*7c478bd9Sstevel@tonic-gate {
177*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
178*7c478bd9Sstevel@tonic-gate 	int		num_probes, j;
179*7c478bd9Sstevel@tonic-gate 	objlist_t	*cur_obj, *prev_obj, *tmp_obj;
180*7c478bd9Sstevel@tonic-gate 	boolean_t	saw_new_probes = B_FALSE;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	prev_obj = NULL;
183*7c478bd9Sstevel@tonic-gate 	cur_obj = hndl->objlist;
184*7c478bd9Sstevel@tonic-gate 	while (cur_obj) {
185*7c478bd9Sstevel@tonic-gate 		if (cur_obj->old == B_TRUE) {
186*7c478bd9Sstevel@tonic-gate 			/* dlclosed library : stitch out probes in target */
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 			DBG_TNF_PROBE_3(_tnfctl_find_all_probes_1, "libtnfctl",
189*7c478bd9Sstevel@tonic-gate 				"sunw%verbosity 1; sunw%debug 'lib dlclosed'",
190*7c478bd9Sstevel@tonic-gate 				tnf_opaque, lib_baseaddr, cur_obj->baseaddr,
191*7c478bd9Sstevel@tonic-gate 				tnf_string, lib_name, cur_obj->objname,
192*7c478bd9Sstevel@tonic-gate 				tnf_long, lib_fd, cur_obj->objfd);
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 			prexstat = unlink_targ_obj_probes(hndl, cur_obj);
195*7c478bd9Sstevel@tonic-gate 			if (prexstat)
196*7c478bd9Sstevel@tonic-gate 				return (prexstat);
197*7c478bd9Sstevel@tonic-gate 			free_obj_fields(cur_obj);
198*7c478bd9Sstevel@tonic-gate 			/* remove this object from linked list */
199*7c478bd9Sstevel@tonic-gate 			tmp_obj = cur_obj;
200*7c478bd9Sstevel@tonic-gate 			cur_obj = cur_obj->next;
201*7c478bd9Sstevel@tonic-gate 			if (prev_obj == NULL)
202*7c478bd9Sstevel@tonic-gate 				hndl->objlist = cur_obj;
203*7c478bd9Sstevel@tonic-gate 			else
204*7c478bd9Sstevel@tonic-gate 				prev_obj->next = cur_obj;
205*7c478bd9Sstevel@tonic-gate 			free(tmp_obj);
206*7c478bd9Sstevel@tonic-gate 			continue;
207*7c478bd9Sstevel@tonic-gate 		}
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 		if (cur_obj->new == B_TRUE) {
210*7c478bd9Sstevel@tonic-gate 			/* dlopened library : read in probes */
211*7c478bd9Sstevel@tonic-gate 			prexstat = get_num_probes(hndl, cur_obj, &num_probes);
212*7c478bd9Sstevel@tonic-gate 			if (prexstat)
213*7c478bd9Sstevel@tonic-gate 				return (prexstat);
214*7c478bd9Sstevel@tonic-gate 			if (num_probes) {
215*7c478bd9Sstevel@tonic-gate 				saw_new_probes = B_TRUE;
216*7c478bd9Sstevel@tonic-gate 				cur_obj->probes = malloc(num_probes *
217*7c478bd9Sstevel@tonic-gate 					sizeof (prbctlref_t));
218*7c478bd9Sstevel@tonic-gate 				if (cur_obj->probes == NULL)
219*7c478bd9Sstevel@tonic-gate 					return (TNFCTL_ERR_ALLOCFAIL);
220*7c478bd9Sstevel@tonic-gate 				prexstat = read_probes_in_obj(hndl, cur_obj,
221*7c478bd9Sstevel@tonic-gate 					num_probes, hndl->num_probes);
222*7c478bd9Sstevel@tonic-gate 				if (prexstat)
223*7c478bd9Sstevel@tonic-gate 					return (prexstat);
224*7c478bd9Sstevel@tonic-gate 				cur_obj->min_probe_num = hndl->num_probes;
225*7c478bd9Sstevel@tonic-gate 				/* increment num_probes */
226*7c478bd9Sstevel@tonic-gate 				hndl->num_probes += num_probes;
227*7c478bd9Sstevel@tonic-gate 				cur_obj->probecnt = num_probes;
228*7c478bd9Sstevel@tonic-gate 				prexstat = link_targ_obj_probes(hndl, cur_obj);
229*7c478bd9Sstevel@tonic-gate 				if (prexstat)
230*7c478bd9Sstevel@tonic-gate 					return (prexstat);
231*7c478bd9Sstevel@tonic-gate 			}
232*7c478bd9Sstevel@tonic-gate 		}
233*7c478bd9Sstevel@tonic-gate 		prev_obj = cur_obj;
234*7c478bd9Sstevel@tonic-gate 		cur_obj = cur_obj->next;
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate #if 0
238*7c478bd9Sstevel@tonic-gate 	for (cur_obj = hndl->objlist; cur_obj; cur_obj = cur_obj->next) {
239*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s 0x%08x %s fd=%d\n",
240*7c478bd9Sstevel@tonic-gate 				(cur_obj->new) ? "*" : " ",
241*7c478bd9Sstevel@tonic-gate 				cur_obj->baseaddr, cur_obj->objname,
242*7c478bd9Sstevel@tonic-gate 				cur_obj->objfd);
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate #endif
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	/* call create_func for client data if we saw new probes */
247*7c478bd9Sstevel@tonic-gate 	if (saw_new_probes && hndl->create_func) {
248*7c478bd9Sstevel@tonic-gate 		for (cur_obj = hndl->objlist; cur_obj;
249*7c478bd9Sstevel@tonic-gate 						cur_obj = cur_obj->next) {
250*7c478bd9Sstevel@tonic-gate 			tnfctl_probe_t *probe_handle;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 			if (cur_obj->new == B_FALSE)
253*7c478bd9Sstevel@tonic-gate 				continue;
254*7c478bd9Sstevel@tonic-gate 			/* new object */
255*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < cur_obj->probecnt; j++) {
256*7c478bd9Sstevel@tonic-gate 				probe_handle = cur_obj->probes[j].probe_handle;
257*7c478bd9Sstevel@tonic-gate 				probe_handle->client_registered_data =
258*7c478bd9Sstevel@tonic-gate 					hndl->create_func(hndl, probe_handle);
259*7c478bd9Sstevel@tonic-gate 			}
260*7c478bd9Sstevel@tonic-gate 		}
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
264*7c478bd9Sstevel@tonic-gate }
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate /*
267*7c478bd9Sstevel@tonic-gate  * _tnfctl_free_objs_and_probes() - cleans up objects and probes
268*7c478bd9Sstevel@tonic-gate  */
269*7c478bd9Sstevel@tonic-gate void
270*7c478bd9Sstevel@tonic-gate _tnfctl_free_objs_and_probes(tnfctl_handle_t *hndl)
271*7c478bd9Sstevel@tonic-gate {
272*7c478bd9Sstevel@tonic-gate 	objlist_t *obj, *tmp;
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	NOTE(NO_COMPETING_THREADS_NOW)
275*7c478bd9Sstevel@tonic-gate 	obj = hndl->objlist;
276*7c478bd9Sstevel@tonic-gate 	while (obj) {
277*7c478bd9Sstevel@tonic-gate 		free_obj_fields(obj);
278*7c478bd9Sstevel@tonic-gate 		tmp = obj;
279*7c478bd9Sstevel@tonic-gate 		obj = obj->next;
280*7c478bd9Sstevel@tonic-gate 		free(tmp);
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 	hndl->objlist = NULL;
283*7c478bd9Sstevel@tonic-gate 	NOTE(COMPETING_THREADS_NOW)
284*7c478bd9Sstevel@tonic-gate }
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate /*
287*7c478bd9Sstevel@tonic-gate  * Free members of objlist_t
288*7c478bd9Sstevel@tonic-gate  */
289*7c478bd9Sstevel@tonic-gate static void
290*7c478bd9Sstevel@tonic-gate free_obj_fields(objlist_t *obj)
291*7c478bd9Sstevel@tonic-gate {
292*7c478bd9Sstevel@tonic-gate 	int i;
293*7c478bd9Sstevel@tonic-gate 	prbctlref_t *probe_p;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < obj->probecnt; i++) {
296*7c478bd9Sstevel@tonic-gate 		probe_p = &(obj->probes[i]);
297*7c478bd9Sstevel@tonic-gate 		if (probe_p->attr_string)
298*7c478bd9Sstevel@tonic-gate 			free(probe_p->attr_string);
299*7c478bd9Sstevel@tonic-gate 		if (probe_p->probe_handle)
300*7c478bd9Sstevel@tonic-gate 			probe_p->probe_handle->valid = B_FALSE;
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 	if (obj->probes)
303*7c478bd9Sstevel@tonic-gate 		free(obj->probes);
304*7c478bd9Sstevel@tonic-gate 	obj->probecnt = 0;
305*7c478bd9Sstevel@tonic-gate 	if (obj->objname)
306*7c478bd9Sstevel@tonic-gate 		free(obj->objname);
307*7c478bd9Sstevel@tonic-gate 	if (obj->objfd != -1)
308*7c478bd9Sstevel@tonic-gate 		close(obj->objfd);
309*7c478bd9Sstevel@tonic-gate }
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate /*
312*7c478bd9Sstevel@tonic-gate  * _tnfctl_probes_traverse() - iterate over all probes by calling the
313*7c478bd9Sstevel@tonic-gate  * callback function supplied.
314*7c478bd9Sstevel@tonic-gate  */
315*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
316*7c478bd9Sstevel@tonic-gate _tnfctl_probes_traverse(tnfctl_handle_t *hndl,
317*7c478bd9Sstevel@tonic-gate 	_tnfctl_traverse_probe_func_t func_p, void *calldata_p)
318*7c478bd9Sstevel@tonic-gate {
319*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
320*7c478bd9Sstevel@tonic-gate 	boolean_t	release_lock;
321*7c478bd9Sstevel@tonic-gate 	objlist_t	*obj;
322*7c478bd9Sstevel@tonic-gate 	int		j;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
325*7c478bd9Sstevel@tonic-gate 	LOCK_SYNC(hndl, prexstat, release_lock);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	for (obj = hndl->objlist; obj; obj = obj->next) {
328*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < obj->probecnt; j++) {
329*7c478bd9Sstevel@tonic-gate 			prexstat = (*func_p) (hndl, &(obj->probes[j]),
330*7c478bd9Sstevel@tonic-gate 							calldata_p);
331*7c478bd9Sstevel@tonic-gate 			if (prexstat) {
332*7c478bd9Sstevel@tonic-gate 				/*LINTED statement has no consequent: else*/
333*7c478bd9Sstevel@tonic-gate 				UNLOCK(hndl, release_lock);
334*7c478bd9Sstevel@tonic-gate 				return (prexstat);
335*7c478bd9Sstevel@tonic-gate 			}
336*7c478bd9Sstevel@tonic-gate 		}
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
340*7c478bd9Sstevel@tonic-gate 	UNLOCK(hndl, release_lock);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
343*7c478bd9Sstevel@tonic-gate }
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate /*
346*7c478bd9Sstevel@tonic-gate  * function that is called by loadobject iterator function for every
347*7c478bd9Sstevel@tonic-gate  * loadobject.  If a new loadobject, add it to to our list.
348*7c478bd9Sstevel@tonic-gate  */
349*7c478bd9Sstevel@tonic-gate static int
350*7c478bd9Sstevel@tonic-gate per_loadobj(void *proc_p, const tnfctl_ind_obj_info_t *obj, void *cd)
351*7c478bd9Sstevel@tonic-gate {
352*7c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hndl = cd;
353*7c478bd9Sstevel@tonic-gate 	objlist_t	*entry_p, *cur_p, *next_p;
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	if (entry_p = loadobj_find(hndl, obj)) {
356*7c478bd9Sstevel@tonic-gate 		/* loadobject already exists */
357*7c478bd9Sstevel@tonic-gate 		entry_p->old = B_FALSE;
358*7c478bd9Sstevel@tonic-gate 		/* no need to close the objfd because iterator func will */
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 		/* successful return */
361*7c478bd9Sstevel@tonic-gate 		return (0);
362*7c478bd9Sstevel@tonic-gate 	}
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	/* add new loadobject */
365*7c478bd9Sstevel@tonic-gate 	entry_p = calloc(1, sizeof (objlist_t));
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	entry_p->old = B_FALSE;
368*7c478bd9Sstevel@tonic-gate 	entry_p->new = B_TRUE;
369*7c478bd9Sstevel@tonic-gate 	entry_p->new_probe = B_TRUE;
370*7c478bd9Sstevel@tonic-gate 	entry_p->objname = strdup(obj->objname);
371*7c478bd9Sstevel@tonic-gate 	if (entry_p->objname == NULL)
372*7c478bd9Sstevel@tonic-gate 		return (1);
373*7c478bd9Sstevel@tonic-gate 	entry_p->baseaddr = obj->text_base;
374*7c478bd9Sstevel@tonic-gate 	/* may have to actually open the fd */
375*7c478bd9Sstevel@tonic-gate 	if (obj->objfd == -1) {
376*7c478bd9Sstevel@tonic-gate 		entry_p->objfd = open(obj->objname, O_RDONLY);
377*7c478bd9Sstevel@tonic-gate 		if (entry_p->objfd == -1)
378*7c478bd9Sstevel@tonic-gate 			return (1);
379*7c478bd9Sstevel@tonic-gate 	} else {
380*7c478bd9Sstevel@tonic-gate 		/* dup the fd because iterator function will close it */
381*7c478bd9Sstevel@tonic-gate 		entry_p->objfd = dup(obj->objfd);
382*7c478bd9Sstevel@tonic-gate 		if (entry_p->objfd == -1)
383*7c478bd9Sstevel@tonic-gate 			return (1);
384*7c478bd9Sstevel@tonic-gate 	}
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	entry_p->min_probe_num = 0;
387*7c478bd9Sstevel@tonic-gate 	entry_p->probecnt = 0;
388*7c478bd9Sstevel@tonic-gate 	entry_p->probes = NULL;
389*7c478bd9Sstevel@tonic-gate 	entry_p->next = NULL;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	if (hndl->objlist == NULL) {
392*7c478bd9Sstevel@tonic-gate 		hndl->objlist = entry_p;
393*7c478bd9Sstevel@tonic-gate 	} else {
394*7c478bd9Sstevel@tonic-gate 		/* add to end of list */
395*7c478bd9Sstevel@tonic-gate 		next_p = hndl->objlist;
396*7c478bd9Sstevel@tonic-gate 		while (next_p) {
397*7c478bd9Sstevel@tonic-gate 			cur_p = next_p;
398*7c478bd9Sstevel@tonic-gate 			next_p = next_p->next;
399*7c478bd9Sstevel@tonic-gate 		}
400*7c478bd9Sstevel@tonic-gate 		/* cur_p now points to last element on list */
401*7c478bd9Sstevel@tonic-gate 		cur_p->next = entry_p;
402*7c478bd9Sstevel@tonic-gate 	}
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 	return (0);
405*7c478bd9Sstevel@tonic-gate }
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate /*
408*7c478bd9Sstevel@tonic-gate  * check if this loadobject already exists in our linked list.
409*7c478bd9Sstevel@tonic-gate  */
410*7c478bd9Sstevel@tonic-gate static objlist_t *
411*7c478bd9Sstevel@tonic-gate loadobj_find(tnfctl_handle_t *hndl, const tnfctl_ind_obj_info_t *this_obj)
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate 	objlist_t *obj;
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	for (obj = hndl->objlist; obj; obj = obj->next) {
416*7c478bd9Sstevel@tonic-gate 		if (obj->baseaddr == this_obj->text_base)
417*7c478bd9Sstevel@tonic-gate 			return (obj);
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 	return (NULL);
420*7c478bd9Sstevel@tonic-gate }
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate /*
423*7c478bd9Sstevel@tonic-gate  * find the number of probes in a loadobject
424*7c478bd9Sstevel@tonic-gate  */
425*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
426*7c478bd9Sstevel@tonic-gate get_num_probes(tnfctl_handle_t *hndl, objlist_t *obj, int *num_probes)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
429*7c478bd9Sstevel@tonic-gate 	link_args_t	largs;
430*7c478bd9Sstevel@tonic-gate 	tnfctl_elf_search_t search_info;
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(get_num_probes_1, "libtnfctl", "sunw%verbosity 1");
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	largs.la_probename = PROBE_SYMBOL;
435*7c478bd9Sstevel@tonic-gate 	largs.ret_val = 0;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	search_info.section_func = _tnfctl_traverse_rela;
438*7c478bd9Sstevel@tonic-gate 	search_info.record_func = count_probes;
439*7c478bd9Sstevel@tonic-gate 	search_info.record_data = &largs;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_traverse_object(obj->objfd, obj->baseaddr,
442*7c478bd9Sstevel@tonic-gate 						&search_info);
443*7c478bd9Sstevel@tonic-gate 	if (prexstat)
444*7c478bd9Sstevel@tonic-gate 		return (prexstat);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_2(get_num_probes_2, "libtnfctl", "sunw%verbosity 1",
447*7c478bd9Sstevel@tonic-gate 			tnf_long, num_probes, largs.ret_val,
448*7c478bd9Sstevel@tonic-gate 			tnf_string, obj_name, obj->objname);
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	*num_probes = largs.ret_val;
451*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate /*
455*7c478bd9Sstevel@tonic-gate  * discover all probes in a loadobject and read it into our array.
456*7c478bd9Sstevel@tonic-gate  */
457*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
458*7c478bd9Sstevel@tonic-gate read_probes_in_obj(tnfctl_handle_t *hndl, objlist_t *obj, ulong_t num_probes,
459*7c478bd9Sstevel@tonic-gate 			ulong_t probe_base_num)
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
462*7c478bd9Sstevel@tonic-gate 	link_args2_t	largs2;
463*7c478bd9Sstevel@tonic-gate 	tnfctl_elf_search_t search_info;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_0(read_probes_in_obj_1, "libtnfctl", "sunw%verbosity 2");
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	largs2.la_hndl = hndl;
468*7c478bd9Sstevel@tonic-gate 	largs2.la_probename = PROBE_SYMBOL;
469*7c478bd9Sstevel@tonic-gate 	largs2.la_obj = obj;
470*7c478bd9Sstevel@tonic-gate 	largs2.la_index = 0;
471*7c478bd9Sstevel@tonic-gate 	largs2.la_base = probe_base_num;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	search_info.section_func = _tnfctl_traverse_rela;
474*7c478bd9Sstevel@tonic-gate 	search_info.record_func = read_a_probe;
475*7c478bd9Sstevel@tonic-gate 	search_info.record_data = &largs2;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_traverse_object(obj->objfd, obj->baseaddr,
478*7c478bd9Sstevel@tonic-gate 						&search_info);
479*7c478bd9Sstevel@tonic-gate 	if (prexstat)
480*7c478bd9Sstevel@tonic-gate 		return (prexstat);
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate /*
486*7c478bd9Sstevel@tonic-gate  * checks if this relocation entry is a probe and if so,
487*7c478bd9Sstevel@tonic-gate  * increments a counter for every probe seen
488*7c478bd9Sstevel@tonic-gate  */
489*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
490*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
491*7c478bd9Sstevel@tonic-gate count_probes(char *name, uintptr_t addr, void *rel_entry,
492*7c478bd9Sstevel@tonic-gate 	tnfctl_elf_search_t * search_info_p)
493*7c478bd9Sstevel@tonic-gate {
494*7c478bd9Sstevel@tonic-gate 	link_args_t	*largs_p = (link_args_t *) search_info_p->record_data;
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, largs_p->la_probename) == 0) {
497*7c478bd9Sstevel@tonic-gate 		largs_p->ret_val++;
498*7c478bd9Sstevel@tonic-gate 	}
499*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
500*7c478bd9Sstevel@tonic-gate }
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate /*
503*7c478bd9Sstevel@tonic-gate  * checks if this relocation entry is a probe and if so, reads in info
504*7c478bd9Sstevel@tonic-gate  * on this probe
505*7c478bd9Sstevel@tonic-gate  */
506*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
507*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
508*7c478bd9Sstevel@tonic-gate read_a_probe(char *name, uintptr_t addr, void *rel_entry,
509*7c478bd9Sstevel@tonic-gate 	tnfctl_elf_search_t * search_info_p)
510*7c478bd9Sstevel@tonic-gate {
511*7c478bd9Sstevel@tonic-gate 	link_args2_t	*largs2_p = (link_args2_t *) search_info_p->record_data;
512*7c478bd9Sstevel@tonic-gate 	ulong_t		index = largs2_p->la_index;
513*7c478bd9Sstevel@tonic-gate 	prbctlref_t	*prbctl_p;
514*7c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hndl = largs2_p->la_hndl;
515*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
516*7c478bd9Sstevel@tonic-gate 	int		miscstat;
517*7c478bd9Sstevel@tonic-gate 	uintptr_t	attrs;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	assert((hndl->mode == INTERNAL_MODE) ?
520*7c478bd9Sstevel@tonic-gate 		(MUTEX_HELD(&_tnfctl_lmap_lock)) : 1);
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, largs2_p->la_probename) != 0)
523*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	/* found a probe */
526*7c478bd9Sstevel@tonic-gate 	prbctl_p = &(largs2_p->la_obj->probes[index]);
527*7c478bd9Sstevel@tonic-gate 	prbctl_p->addr = addr;
528*7c478bd9Sstevel@tonic-gate 	prbctl_p->probe_id = largs2_p->la_base + index;
529*7c478bd9Sstevel@tonic-gate 	prbctl_p->obj = largs2_p->la_obj;
530*7c478bd9Sstevel@tonic-gate 	largs2_p->la_index++;
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	/* read in probe structure */
533*7c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_read(hndl->proc_p, addr,
534*7c478bd9Sstevel@tonic-gate 		&prbctl_p->wrkprbctl, sizeof (prbctl_p->wrkprbctl));
535*7c478bd9Sstevel@tonic-gate 	if (miscstat) {
536*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
537*7c478bd9Sstevel@tonic-gate 			"read_a_probe: read from target failed: %d\n",
538*7c478bd9Sstevel@tonic-gate 			miscstat));
539*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_INTERNAL);
540*7c478bd9Sstevel@tonic-gate 	}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	/*
543*7c478bd9Sstevel@tonic-gate 	 * dereference the attrs (read it into our address space only for
544*7c478bd9Sstevel@tonic-gate 	 * working copy)
545*7c478bd9Sstevel@tonic-gate 	 */
546*7c478bd9Sstevel@tonic-gate 	attrs = (uintptr_t) prbctl_p->wrkprbctl.attrs;
547*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_readstr_targ(hndl, attrs, &prbctl_p->attr_string);
548*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
549*7c478bd9Sstevel@tonic-gate 		DBG((void) fprintf(stderr,
550*7c478bd9Sstevel@tonic-gate 		    "read_a_probe: _tnfctl_readstr_targ (attrs) failed: %s\n",
551*7c478bd9Sstevel@tonic-gate 				tnfctl_strerror(prexstat)));
552*7c478bd9Sstevel@tonic-gate 		return (prexstat);
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	DBG_TNF_PROBE_1(read_a_probe_2, "libtnfctl",
556*7c478bd9Sstevel@tonic-gate 		"sunw%verbosity 1; sunw%debug 'found a probe'",
557*7c478bd9Sstevel@tonic-gate 		tnf_string, probe, prbctl_p->attr_string);
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 	/* create probe handle */
560*7c478bd9Sstevel@tonic-gate 	prbctl_p->probe_handle = calloc(1, sizeof (tnfctl_probe_t));
561*7c478bd9Sstevel@tonic-gate 	if (prbctl_p->probe_handle == NULL)
562*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
563*7c478bd9Sstevel@tonic-gate 	prbctl_p->probe_handle->valid = B_TRUE;
564*7c478bd9Sstevel@tonic-gate 	prbctl_p->probe_handle->probe_p = prbctl_p;
565*7c478bd9Sstevel@tonic-gate 	/* link in probe handle into chain off tnfctl_handle_t */
566*7c478bd9Sstevel@tonic-gate 	prbctl_p->probe_handle->next = hndl->probe_handle_list_head;
567*7c478bd9Sstevel@tonic-gate 	hndl->probe_handle_list_head = prbctl_p->probe_handle;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	/*
570*7c478bd9Sstevel@tonic-gate 	 * if this is a "virgin" probe, set up probe to initial state
571*7c478bd9Sstevel@tonic-gate 	 * REMIND: Could defer this target write till we link the probes
572*7c478bd9Sstevel@tonic-gate 	 * together in target process in link_targ_obj_probes() i.e.
573*7c478bd9Sstevel@tonic-gate 	 * do the "write" only once.
574*7c478bd9Sstevel@tonic-gate 	 */
575*7c478bd9Sstevel@tonic-gate 	if (prbctl_p->wrkprbctl.commit_func == NULL) {
576*7c478bd9Sstevel@tonic-gate 		prbctl_p->wrkprbctl.probe_func =
577*7c478bd9Sstevel@tonic-gate 				(tnf_probe_func_t) hndl->endfunc;
578*7c478bd9Sstevel@tonic-gate 		prbctl_p->wrkprbctl.commit_func =
579*7c478bd9Sstevel@tonic-gate 				(tnf_probe_func_t) hndl->commitfunc;
580*7c478bd9Sstevel@tonic-gate 		prbctl_p->wrkprbctl.alloc_func =
581*7c478bd9Sstevel@tonic-gate 				(tnf_probe_alloc_func_t) hndl->allocfunc;
582*7c478bd9Sstevel@tonic-gate 		/*
583*7c478bd9Sstevel@tonic-gate 		 * update the probe in target to its initial state
584*7c478bd9Sstevel@tonic-gate 		 * Since the probe is disabled, it is ok to write it one
585*7c478bd9Sstevel@tonic-gate 		 * write command as opposed to updating each word individually
586*7c478bd9Sstevel@tonic-gate 		 */
587*7c478bd9Sstevel@tonic-gate 		miscstat = hndl->p_write(hndl->proc_p, addr,
588*7c478bd9Sstevel@tonic-gate 			&prbctl_p->wrkprbctl, sizeof (prbctl_p->wrkprbctl));
589*7c478bd9Sstevel@tonic-gate 		if (miscstat)
590*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
591*7c478bd9Sstevel@tonic-gate 	}
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
594*7c478bd9Sstevel@tonic-gate }
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate /*
597*7c478bd9Sstevel@tonic-gate  * Link all the probes in a linked list in the target image in specified
598*7c478bd9Sstevel@tonic-gate  * object.  Also, link probes from previous object and next object into
599*7c478bd9Sstevel@tonic-gate  * this list.  The only
600*7c478bd9Sstevel@tonic-gate  * reason this is needed is because internally in the process,
601*7c478bd9Sstevel@tonic-gate  * tnf_probe_notify() that is called from libthread walks through all
602*7c478bd9Sstevel@tonic-gate  * probes substituting the test function
603*7c478bd9Sstevel@tonic-gate  * REMIND: find a way that we don't have to walk through probes internally.
604*7c478bd9Sstevel@tonic-gate  */
605*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
606*7c478bd9Sstevel@tonic-gate link_targ_obj_probes(tnfctl_handle_t *hndl, objlist_t *cur)
607*7c478bd9Sstevel@tonic-gate {
608*7c478bd9Sstevel@tonic-gate 	int i;
609*7c478bd9Sstevel@tonic-gate 	prbctlref_t *probe_p;
610*7c478bd9Sstevel@tonic-gate 	tnf_probe_control_t *next_probe;
611*7c478bd9Sstevel@tonic-gate 	int miscstat;
612*7c478bd9Sstevel@tonic-gate 	objlist_t *cur_tmp, *prev_w_probes, *next_w_probes;
613*7c478bd9Sstevel@tonic-gate 	uintptr_t next_addr;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	/* find previous object that has probes */
616*7c478bd9Sstevel@tonic-gate 	prev_w_probes = NULL;
617*7c478bd9Sstevel@tonic-gate 	cur_tmp = hndl->objlist;
618*7c478bd9Sstevel@tonic-gate 	while (cur_tmp != cur) {
619*7c478bd9Sstevel@tonic-gate 		if (cur_tmp->probecnt != 0)
620*7c478bd9Sstevel@tonic-gate 			prev_w_probes = cur_tmp;
621*7c478bd9Sstevel@tonic-gate 		cur_tmp = cur_tmp->next;
622*7c478bd9Sstevel@tonic-gate 	}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	/* find next object with probes */
625*7c478bd9Sstevel@tonic-gate 	next_w_probes = NULL;
626*7c478bd9Sstevel@tonic-gate 	cur_tmp = cur->next;
627*7c478bd9Sstevel@tonic-gate 	while (cur_tmp != NULL) {
628*7c478bd9Sstevel@tonic-gate 		if (cur_tmp->probecnt != 0)
629*7c478bd9Sstevel@tonic-gate 			next_w_probes = cur_tmp;
630*7c478bd9Sstevel@tonic-gate 		cur_tmp = cur_tmp->next;
631*7c478bd9Sstevel@tonic-gate 	}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	/* link probes (except for last one) in order */
634*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (cur->probecnt - 1); i++) {
635*7c478bd9Sstevel@tonic-gate 		probe_p = &(cur->probes[i]);
636*7c478bd9Sstevel@tonic-gate 		next_probe = (tnf_probe_control_t *) cur->probes[i+1].addr;
637*7c478bd9Sstevel@tonic-gate 		probe_p->wrkprbctl.next = next_probe;
638*7c478bd9Sstevel@tonic-gate 		miscstat = hndl->p_write(hndl->proc_p, probe_p->addr +
639*7c478bd9Sstevel@tonic-gate 				offsetof(struct tnf_probe_control, next),
640*7c478bd9Sstevel@tonic-gate 				&next_probe, sizeof (next_probe));
641*7c478bd9Sstevel@tonic-gate 		if (miscstat)
642*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
643*7c478bd9Sstevel@tonic-gate 	}
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	next_probe = (tnf_probe_control_t *) cur->probes[0].addr;
646*7c478bd9Sstevel@tonic-gate 	if (prev_w_probes == NULL) {
647*7c478bd9Sstevel@tonic-gate 		/* adding as first object in list */
648*7c478bd9Sstevel@tonic-gate 		next_addr = hndl->probelist_head;
649*7c478bd9Sstevel@tonic-gate 	} else {
650*7c478bd9Sstevel@tonic-gate 		probe_p = &(prev_w_probes->probes[prev_w_probes->probecnt - 1]);
651*7c478bd9Sstevel@tonic-gate 		probe_p->wrkprbctl.next = next_probe;
652*7c478bd9Sstevel@tonic-gate 		next_addr = probe_p->addr +
653*7c478bd9Sstevel@tonic-gate 				offsetof(struct tnf_probe_control, next);
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	/* point next_addr to first probe in this object */
657*7c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_write(hndl->proc_p, next_addr,
658*7c478bd9Sstevel@tonic-gate 			&next_probe, sizeof (next_probe));
659*7c478bd9Sstevel@tonic-gate 	if (miscstat)
660*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_INTERNAL);
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	/* link last probe in object */
663*7c478bd9Sstevel@tonic-gate 	if (next_w_probes == NULL)
664*7c478bd9Sstevel@tonic-gate 		next_probe = NULL;
665*7c478bd9Sstevel@tonic-gate 	else {
666*7c478bd9Sstevel@tonic-gate 		next_probe = (tnf_probe_control_t *)
667*7c478bd9Sstevel@tonic-gate 				next_w_probes->probes[0].addr;
668*7c478bd9Sstevel@tonic-gate 	}
669*7c478bd9Sstevel@tonic-gate 	probe_p = &(cur->probes[cur->probecnt - 1]);
670*7c478bd9Sstevel@tonic-gate 	probe_p->wrkprbctl.next = next_probe;
671*7c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_write(hndl->proc_p, probe_p->addr +
672*7c478bd9Sstevel@tonic-gate 			offsetof(struct tnf_probe_control, next),
673*7c478bd9Sstevel@tonic-gate 			&next_probe, sizeof (next_probe));
674*7c478bd9Sstevel@tonic-gate 	if (miscstat)
675*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_INTERNAL);
676*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate /*
680*7c478bd9Sstevel@tonic-gate  * An object has been closed.  Stitch probes around this object in
681*7c478bd9Sstevel@tonic-gate  * target image.
682*7c478bd9Sstevel@tonic-gate  */
683*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
684*7c478bd9Sstevel@tonic-gate unlink_targ_obj_probes(tnfctl_handle_t *hndl, objlist_t *cur)
685*7c478bd9Sstevel@tonic-gate {
686*7c478bd9Sstevel@tonic-gate 	prbctlref_t *probe_p;
687*7c478bd9Sstevel@tonic-gate 	tnf_probe_control_t *next_probe;
688*7c478bd9Sstevel@tonic-gate 	int miscstat;
689*7c478bd9Sstevel@tonic-gate 	objlist_t *cur_tmp, *prev_w_probes, *next_w_probes;
690*7c478bd9Sstevel@tonic-gate 	uintptr_t next_addr;
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	/* find previous object that has probes */
693*7c478bd9Sstevel@tonic-gate 	prev_w_probes = NULL;
694*7c478bd9Sstevel@tonic-gate 	cur_tmp = hndl->objlist;
695*7c478bd9Sstevel@tonic-gate 	while (cur_tmp != cur) {
696*7c478bd9Sstevel@tonic-gate 		if (cur_tmp->probecnt != 0)
697*7c478bd9Sstevel@tonic-gate 			prev_w_probes = cur_tmp;
698*7c478bd9Sstevel@tonic-gate 		cur_tmp = cur_tmp->next;
699*7c478bd9Sstevel@tonic-gate 	}
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	/* find next object with probes */
702*7c478bd9Sstevel@tonic-gate 	next_w_probes = NULL;
703*7c478bd9Sstevel@tonic-gate 	cur_tmp = cur->next;
704*7c478bd9Sstevel@tonic-gate 	while (cur_tmp != NULL) {
705*7c478bd9Sstevel@tonic-gate 		if (cur_tmp->probecnt != 0)
706*7c478bd9Sstevel@tonic-gate 			next_w_probes = cur_tmp;
707*7c478bd9Sstevel@tonic-gate 		cur_tmp = cur_tmp->next;
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	if (next_w_probes == NULL)
711*7c478bd9Sstevel@tonic-gate 		next_probe = NULL;
712*7c478bd9Sstevel@tonic-gate 	else {
713*7c478bd9Sstevel@tonic-gate 		next_probe = (tnf_probe_control_t *)
714*7c478bd9Sstevel@tonic-gate 				next_w_probes->probes[0].addr;
715*7c478bd9Sstevel@tonic-gate 	}
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	if (prev_w_probes == NULL) {
718*7c478bd9Sstevel@tonic-gate 		/* removing first object in list */
719*7c478bd9Sstevel@tonic-gate 		next_addr = hndl->probelist_head;
720*7c478bd9Sstevel@tonic-gate 	} else {
721*7c478bd9Sstevel@tonic-gate 		probe_p = &(prev_w_probes->probes[prev_w_probes->probecnt - 1]);
722*7c478bd9Sstevel@tonic-gate 		probe_p->wrkprbctl.next = next_probe;
723*7c478bd9Sstevel@tonic-gate 		next_addr = probe_p->addr +
724*7c478bd9Sstevel@tonic-gate 				offsetof(struct tnf_probe_control, next);
725*7c478bd9Sstevel@tonic-gate 	}
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	/* point next_addr to next_probe */
728*7c478bd9Sstevel@tonic-gate 	miscstat = hndl->p_write(hndl->proc_p, next_addr,
729*7c478bd9Sstevel@tonic-gate 			&next_probe, sizeof (next_probe));
730*7c478bd9Sstevel@tonic-gate 	if (miscstat)
731*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_INTERNAL);
732*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
733*7c478bd9Sstevel@tonic-gate }
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate /*
736*7c478bd9Sstevel@tonic-gate  * _tnfctl_flush_a_probe() - write a changed probe into the target process'
737*7c478bd9Sstevel@tonic-gate  * address space.
738*7c478bd9Sstevel@tonic-gate  */
739*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
740*7c478bd9Sstevel@tonic-gate _tnfctl_flush_a_probe(tnfctl_handle_t *hndl, prbctlref_t *ref_p, size_t offset,
741*7c478bd9Sstevel@tonic-gate 			size_t size)
742*7c478bd9Sstevel@tonic-gate {
743*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
744*7c478bd9Sstevel@tonic-gate 	int			miscstat;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	/*
747*7c478bd9Sstevel@tonic-gate 	 * For internal control:
748*7c478bd9Sstevel@tonic-gate 	 * There is *no race* for finding the test function (between the time
749*7c478bd9Sstevel@tonic-gate 	 * we call find_test_func() and the time we assign it to a probe),
750*7c478bd9Sstevel@tonic-gate 	 * because tnfctl_internal_open() cannot be called from an init section
751*7c478bd9Sstevel@tonic-gate 	 * (look at man page of tnfctl_internal_open()).  And, after the init
752*7c478bd9Sstevel@tonic-gate 	 * section of libthread has run, we will always use the MT test
753*7c478bd9Sstevel@tonic-gate 	 * function.
754*7c478bd9Sstevel@tonic-gate 	 */
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	if (hndl->mode == KERNEL_MODE) {
757*7c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_prbk_flush(hndl, ref_p);
758*7c478bd9Sstevel@tonic-gate 		if (prexstat)
759*7c478bd9Sstevel@tonic-gate 			return (prexstat);
760*7c478bd9Sstevel@tonic-gate 	} else {
761*7c478bd9Sstevel@tonic-gate 		miscstat = hndl->p_write(hndl->proc_p,
762*7c478bd9Sstevel@tonic-gate 			ref_p->addr + offset,
763*7c478bd9Sstevel@tonic-gate 			((char *)&(ref_p->wrkprbctl)) + offset, size);
764*7c478bd9Sstevel@tonic-gate 		if (miscstat)
765*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
766*7c478bd9Sstevel@tonic-gate 	}
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
769*7c478bd9Sstevel@tonic-gate }
770