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
_tnfctl_lmap_update(tnfctl_handle_t * hndl,boolean_t * lmap_ok,enum event_op_t * dl_evt)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
_tnfctl_find_all_probes(tnfctl_handle_t * hndl)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
_tnfctl_free_objs_and_probes(tnfctl_handle_t * hndl)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
free_obj_fields(objlist_t * obj)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
_tnfctl_probes_traverse(tnfctl_handle_t * hndl,_tnfctl_traverse_probe_func_t func_p,void * calldata_p)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
per_loadobj(void * proc_p,const tnfctl_ind_obj_info_t * obj,void * cd)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 *
loadobj_find(tnfctl_handle_t * hndl,const tnfctl_ind_obj_info_t * this_obj)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
get_num_probes(tnfctl_handle_t * hndl,objlist_t * obj,int * num_probes)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
read_probes_in_obj(tnfctl_handle_t * hndl,objlist_t * obj,ulong_t num_probes,ulong_t probe_base_num)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
count_probes(char * name,uintptr_t addr,void * rel_entry,tnfctl_elf_search_t * search_info_p)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
read_a_probe(char * name,uintptr_t addr,void * rel_entry,tnfctl_elf_search_t * search_info_p)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
link_targ_obj_probes(tnfctl_handle_t * hndl,objlist_t * cur)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
unlink_targ_obj_probes(tnfctl_handle_t * hndl,objlist_t * cur)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
_tnfctl_flush_a_probe(tnfctl_handle_t * hndl,prbctlref_t * ref_p,size_t offset,size_t size)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