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