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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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