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 * Published interfaces for probe control. 30 */ 31 32 #ifndef DEBUG 33 #define NDEBUG 1 34 #endif 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <unistd.h> 39 #include <string.h> 40 #include <assert.h> 41 #include <stddef.h> 42 43 #include "tnfctl_int.h" 44 #include "kernel_int.h" 45 #include "dbg.h" 46 47 struct pr_func_args { 48 tnfctl_probe_op_t func_p; 49 void *calldata; 50 }; 51 52 tnfctl_errcode_t _tnfctl_destructor_wrapper(tnfctl_handle_t *, 53 prbctlref_t *, void *); 54 tnfctl_errcode_t _tnfctl_creator_wrapper(tnfctl_handle_t *, 55 prbctlref_t *, void *); 56 static tnfctl_errcode_t apply_func(tnfctl_handle_t *, prbctlref_t *, void *); 57 static tnfctl_errcode_t check_operation(tnfctl_handle_t *, tnfctl_probe_t *); 58 59 tnfctl_errcode_t 60 tnfctl_register_funcs(tnfctl_handle_t *hndl, 61 void *(*create_func)(tnfctl_handle_t *, tnfctl_probe_t *), 62 void (*destroy_func)(void *)) 63 { 64 tnfctl_errcode_t prexstat; 65 66 if (hndl->destroy_func) { 67 /* 68 * not the first time the register_funcs() is being called 69 * First call currently registered destroy_func on all 70 * probes 71 */ 72 prexstat = _tnfctl_probes_traverse(hndl, 73 _tnfctl_destructor_wrapper, NULL); 74 if (prexstat) 75 return (prexstat); 76 } 77 78 /* set up new creator and destructor functions */ 79 hndl->create_func = create_func; 80 hndl->destroy_func = destroy_func; 81 82 /* call new creator function for all current probes */ 83 if (create_func) { 84 prexstat = _tnfctl_probes_traverse(hndl, 85 _tnfctl_creator_wrapper, NULL); 86 if (prexstat) 87 return (prexstat); 88 } 89 90 return (TNFCTL_ERR_NONE); 91 } 92 93 tnfctl_errcode_t 94 _tnfctl_destructor_wrapper(tnfctl_handle_t *hndl, prbctlref_t *probe, void *cd) 95 { 96 assert(hndl->destroy_func); 97 hndl->destroy_func(probe->probe_handle->client_registered_data); 98 99 return (TNFCTL_ERR_NONE); 100 } 101 102 tnfctl_errcode_t 103 _tnfctl_creator_wrapper(tnfctl_handle_t *hndl, prbctlref_t *probe, void *cd) 104 { 105 tnfctl_probe_t *p_handle; 106 107 assert(hndl->create_func); 108 p_handle = probe->probe_handle; 109 p_handle->client_registered_data = hndl->create_func(hndl, p_handle); 110 111 return (TNFCTL_ERR_NONE); 112 } 113 114 tnfctl_errcode_t 115 tnfctl_probe_apply(tnfctl_handle_t *hndl, tnfctl_probe_op_t func_p, 116 void *calldata) 117 { 118 struct pr_func_args pr_args; 119 tnfctl_errcode_t prexstat; 120 121 pr_args.func_p = func_p; 122 pr_args.calldata = calldata; 123 prexstat = _tnfctl_probes_traverse(hndl, apply_func, &pr_args); 124 return (prexstat); 125 } 126 127 tnfctl_errcode_t 128 tnfctl_probe_apply_ids(tnfctl_handle_t *hndl, ulong_t probe_count, 129 ulong_t *probe_ids, tnfctl_probe_op_t func_p, 130 void *calldata) 131 { 132 ulong_t *id_p; 133 ulong_t i, pos; 134 objlist_t *obj_p; 135 prbctlref_t *probe; 136 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 137 boolean_t release_lock; 138 139 /*LINTED statement has no consequent: else*/ 140 LOCK_SYNC(hndl, prexstat, release_lock); 141 142 /* select probes based on numbers */ 143 id_p = probe_ids; 144 for (i = 0; i < probe_count; i++, id_p++) { 145 obj_p = hndl->objlist; 146 while (obj_p) { 147 if ((*id_p >= obj_p->min_probe_num) && 148 (*id_p < (obj_p->min_probe_num + 149 obj_p->probecnt))) { 150 break; 151 } 152 obj_p = obj_p->next; 153 } 154 if (obj_p == NULL) { 155 prexstat = TNFCTL_ERR_INVALIDPROBE; 156 goto end_of_func; 157 } 158 pos = *id_p - obj_p->min_probe_num; 159 probe = &(obj_p->probes[pos]); 160 prexstat = func_p(hndl, probe->probe_handle, calldata); 161 if (prexstat) 162 goto end_of_func; 163 } 164 165 end_of_func: 166 /*LINTED statement has no consequent: else*/ 167 UNLOCK(hndl, release_lock); 168 return (prexstat); 169 } 170 171 tnfctl_errcode_t 172 tnfctl_probe_state_get(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl, 173 tnfctl_probe_state_t *state_p) 174 { 175 tnf_probe_control_t *prbctl_p; 176 boolean_t release_lock; 177 tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 178 char **func_names; 179 uintptr_t *func_addrs; 180 181 if (hndl->mode == KERNEL_MODE) { 182 prexstat = _tnfctl_refresh_kernel(hndl); 183 if (prexstat) 184 return (prexstat); 185 } 186 187 /*LINTED statement has no consequent: else*/ 188 LOCK_SYNC(hndl, prexstat, release_lock); 189 190 if (probe_hndl->valid == B_FALSE) { 191 prexstat = TNFCTL_ERR_INVALIDPROBE; 192 goto end_of_func; 193 } 194 195 state_p->id = probe_hndl->probe_p->probe_id; 196 state_p->attr_string = probe_hndl->probe_p->attr_string; 197 198 prbctl_p = &probe_hndl->probe_p->wrkprbctl; 199 state_p->enabled = (prbctl_p->test_func) ? B_TRUE : B_FALSE; 200 state_p->traced = (prbctl_p->commit_func == 201 (tnf_probe_func_t) hndl->commitfunc) ? B_TRUE : B_FALSE; 202 state_p->new_probe = probe_hndl->probe_p->obj->new_probe; 203 state_p->obj_name = probe_hndl->probe_p->obj->objname; 204 state_p->client_registered_data = probe_hndl->client_registered_data; 205 206 if (hndl->mode == KERNEL_MODE) { 207 state_p->func_names = NULL; 208 state_p->func_addrs = NULL; 209 /* skip code upto label */ 210 goto end_of_func; 211 } 212 213 /* process mode - get the probe functions */ 214 prexstat = _tnfctl_comb_decode(hndl, (uintptr_t) prbctl_p->probe_func, 215 &func_names, &func_addrs); 216 if (prexstat) 217 goto end_of_func; 218 219 /* if there are any probe functions */ 220 if (func_names[0] != NULL) { 221 state_p->func_names = (const char * const *) func_names; 222 state_p->func_addrs = func_addrs; 223 } else { 224 state_p->func_names = NULL; 225 state_p->func_addrs = NULL; 226 } 227 228 end_of_func: 229 /*LINTED statement has no consequent: else*/ 230 UNLOCK(hndl, release_lock); 231 return (prexstat); 232 } 233 234 static tnfctl_errcode_t 235 check_operation(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl) 236 { 237 tnfctl_errcode_t prexstat; 238 239 if (hndl->mode == KERNEL_MODE) { 240 prexstat = _tnfctl_refresh_kernel(hndl); 241 if (prexstat) 242 return (prexstat); 243 } else if (hndl->trace_buf_state == TNFCTL_BUF_NONE) { 244 /* process tracing */ 245 return (TNFCTL_ERR_NOBUF); 246 } 247 248 if (hndl->trace_buf_state == TNFCTL_BUF_BROKEN) 249 return (TNFCTL_ERR_BUFBROKEN); 250 251 if (probe_hndl->valid == B_FALSE) { 252 return (TNFCTL_ERR_INVALIDPROBE); 253 } 254 255 return (TNFCTL_ERR_NONE); 256 } 257 258 tnfctl_errcode_t 259 tnfctl_probe_enable(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl, void *cd) 260 { 261 tnf_probe_control_t *prbctl_p; 262 boolean_t release_lock; 263 tnfctl_errcode_t prexstat; 264 265 /*LINTED statement has no consequent: else*/ 266 LOCK_SYNC(hndl, prexstat, release_lock); 267 268 prexstat = check_operation(hndl, probe_hndl); 269 if (prexstat) 270 goto end_of_func; 271 272 prbctl_p = &probe_hndl->probe_p->wrkprbctl; 273 prbctl_p->test_func = (tnf_probe_test_func_t) hndl->testfunc; 274 prexstat = _tnfctl_flush_a_probe(hndl, probe_hndl->probe_p, 275 offsetof(struct tnf_probe_control, test_func), 276 sizeof (tnf_probe_test_func_t)); 277 end_of_func: 278 /*LINTED statement has no consequent: else*/ 279 UNLOCK(hndl, release_lock); 280 return (prexstat); 281 } 282 283 tnfctl_errcode_t 284 tnfctl_probe_disable(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl, 285 void *cd) 286 { 287 tnf_probe_control_t *prbctl_p; 288 boolean_t release_lock; 289 tnfctl_errcode_t prexstat; 290 291 /*LINTED statement has no consequent: else*/ 292 LOCK_SYNC(hndl, prexstat, release_lock); 293 294 prexstat = check_operation(hndl, probe_hndl); 295 if (prexstat) 296 goto end_of_func; 297 298 prbctl_p = &probe_hndl->probe_p->wrkprbctl; 299 prbctl_p->test_func = (tnf_probe_test_func_t) NULL; 300 prexstat = _tnfctl_flush_a_probe(hndl, probe_hndl->probe_p, 301 offsetof(struct tnf_probe_control, test_func), 302 sizeof (tnf_probe_test_func_t)); 303 end_of_func: 304 /*LINTED statement has no consequent: else*/ 305 UNLOCK(hndl, release_lock); 306 return (prexstat); 307 } 308 309 tnfctl_errcode_t 310 tnfctl_probe_trace(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl, void *cd) 311 { 312 tnf_probe_control_t *prbctl_p; 313 boolean_t release_lock; 314 tnfctl_errcode_t prexstat; 315 316 /*LINTED statement has no consequent: else*/ 317 LOCK_SYNC(hndl, prexstat, release_lock); 318 319 prexstat = check_operation(hndl, probe_hndl); 320 if (prexstat) 321 goto end_of_func; 322 323 prbctl_p = &probe_hndl->probe_p->wrkprbctl; 324 prbctl_p->commit_func = (tnf_probe_func_t) hndl->commitfunc; 325 prexstat = _tnfctl_flush_a_probe(hndl, probe_hndl->probe_p, 326 offsetof(struct tnf_probe_control, commit_func), 327 sizeof (tnf_probe_func_t)); 328 329 end_of_func: 330 /*LINTED statement has no consequent: else*/ 331 UNLOCK(hndl, release_lock); 332 return (prexstat); 333 } 334 335 tnfctl_errcode_t 336 tnfctl_probe_untrace(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl, 337 void *cd) 338 { 339 tnf_probe_control_t *prbctl_p; 340 boolean_t release_lock; 341 tnfctl_errcode_t prexstat; 342 343 /*LINTED statement has no consequent: else*/ 344 LOCK_SYNC(hndl, prexstat, release_lock); 345 346 prexstat = check_operation(hndl, probe_hndl); 347 if (prexstat) 348 goto end_of_func; 349 350 prbctl_p = &probe_hndl->probe_p->wrkprbctl; 351 prbctl_p->commit_func = (tnf_probe_func_t) hndl->rollbackfunc; 352 prexstat = _tnfctl_flush_a_probe(hndl, probe_hndl->probe_p, 353 offsetof(struct tnf_probe_control, commit_func), 354 sizeof (tnf_probe_func_t)); 355 356 end_of_func: 357 /*LINTED statement has no consequent: else*/ 358 UNLOCK(hndl, release_lock); 359 return (prexstat); 360 } 361 362 tnfctl_errcode_t 363 tnfctl_probe_connect(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl, 364 const char *lib_base_name, const char *func) 365 { 366 tnf_probe_control_t *prbctl_p; 367 boolean_t release_lock; 368 tnfctl_errcode_t prexstat; 369 uintptr_t func_addr; 370 uintptr_t comb; 371 372 if (hndl->mode == KERNEL_MODE) 373 return (TNFCTL_ERR_BADARG); 374 375 /*LINTED statement has no consequent: else*/ 376 LOCK_SYNC(hndl, prexstat, release_lock); 377 378 prexstat = check_operation(hndl, probe_hndl); 379 if (prexstat) 380 goto end_of_func; 381 382 if (func == NULL) { 383 prexstat = TNFCTL_ERR_NONE; 384 goto end_of_func; 385 } 386 387 if (lib_base_name) { 388 prexstat = _tnfctl_sym_obj_find(hndl, lib_base_name, func, 389 &func_addr); 390 } else { 391 prexstat = _tnfctl_sym_find(hndl, func, &func_addr); 392 } 393 /* check if function address was found */ 394 if (prexstat) 395 goto end_of_func; 396 397 prbctl_p = &probe_hndl->probe_p->wrkprbctl; 398 prexstat = _tnfctl_comb_build(hndl, PRB_COMB_CHAIN, 399 func_addr, (uintptr_t) prbctl_p->probe_func, 400 &comb); 401 if (prexstat) 402 goto end_of_func; 403 prbctl_p->probe_func = (tnf_probe_func_t) comb; 404 prexstat = _tnfctl_flush_a_probe(hndl, probe_hndl->probe_p, 405 offsetof(struct tnf_probe_control, probe_func), 406 sizeof (tnf_probe_func_t)); 407 408 end_of_func: 409 /*LINTED statement has no consequent: else*/ 410 UNLOCK(hndl, release_lock); 411 return (prexstat); 412 } 413 414 tnfctl_errcode_t 415 tnfctl_probe_disconnect_all(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_hndl, 416 void *cd) 417 { 418 tnf_probe_control_t *prbctl_p; 419 boolean_t release_lock; 420 tnfctl_errcode_t prexstat; 421 422 if (hndl->mode == KERNEL_MODE) 423 return (TNFCTL_ERR_BADARG); 424 425 /*LINTED statement has no consequent: else*/ 426 LOCK_SYNC(hndl, prexstat, release_lock); 427 428 prexstat = check_operation(hndl, probe_hndl); 429 if (prexstat) 430 goto end_of_func; 431 432 prbctl_p = &probe_hndl->probe_p->wrkprbctl; 433 prbctl_p->probe_func = (tnf_probe_func_t) hndl->endfunc; 434 prexstat = _tnfctl_flush_a_probe(hndl, probe_hndl->probe_p, 435 offsetof(struct tnf_probe_control, probe_func), 436 sizeof (tnf_probe_func_t)); 437 438 end_of_func: 439 /*LINTED statement has no consequent: else*/ 440 UNLOCK(hndl, release_lock); 441 return (prexstat); 442 } 443 444 /* 445 * Important that this function be tail recursive to minimize depth 446 * of call chain that is called for every probe 447 */ 448 static tnfctl_errcode_t 449 apply_func(tnfctl_handle_t *hndl, prbctlref_t *probe, void *cd) 450 { 451 struct pr_func_args *args = cd; 452 tnfctl_errcode_t prexstat; 453 454 /* Call function only if match_func returns true */ 455 prexstat = (*(args->func_p))(hndl, probe->probe_handle, args->calldata); 456 return (prexstat); 457 } 458