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