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