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 47struct pr_func_args { 48 tnfctl_probe_op_t func_p; 49 void *calldata; 50}; 51 52tnfctl_errcode_t _tnfctl_destructor_wrapper(tnfctl_handle_t *, 53 prbctlref_t *, void *); 54tnfctl_errcode_t _tnfctl_creator_wrapper(tnfctl_handle_t *, 55 prbctlref_t *, void *); 56static tnfctl_errcode_t apply_func(tnfctl_handle_t *, prbctlref_t *, void *); 57static tnfctl_errcode_t check_operation(tnfctl_handle_t *, tnfctl_probe_t *); 58 59tnfctl_errcode_t 60tnfctl_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 93tnfctl_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 102tnfctl_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 114tnfctl_errcode_t 115tnfctl_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 127tnfctl_errcode_t 128tnfctl_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 165end_of_func: 166 /*LINTED statement has no consequent: else*/ 167 UNLOCK(hndl, release_lock); 168 return (prexstat); 169} 170 171tnfctl_errcode_t 172tnfctl_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 228end_of_func: 229 /*LINTED statement has no consequent: else*/ 230 UNLOCK(hndl, release_lock); 231 return (prexstat); 232} 233 234static tnfctl_errcode_t 235check_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 258tnfctl_errcode_t 259tnfctl_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)); 277end_of_func: 278 /*LINTED statement has no consequent: else*/ 279 UNLOCK(hndl, release_lock); 280 return (prexstat); 281} 282 283tnfctl_errcode_t 284tnfctl_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)); 303end_of_func: 304 /*LINTED statement has no consequent: else*/ 305 UNLOCK(hndl, release_lock); 306 return (prexstat); 307} 308 309tnfctl_errcode_t 310tnfctl_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 329end_of_func: 330 /*LINTED statement has no consequent: else*/ 331 UNLOCK(hndl, release_lock); 332 return (prexstat); 333} 334 335tnfctl_errcode_t 336tnfctl_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 356end_of_func: 357 /*LINTED statement has no consequent: else*/ 358 UNLOCK(hndl, release_lock); 359 return (prexstat); 360} 361 362tnfctl_errcode_t 363tnfctl_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 408end_of_func: 409 /*LINTED statement has no consequent: else*/ 410 UNLOCK(hndl, release_lock); 411 return (prexstat); 412} 413 414tnfctl_errcode_t 415tnfctl_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 438end_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 */ 448static tnfctl_errcode_t 449apply_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