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
tnfctl_register_funcs(tnfctl_handle_t * hndl,void * (* create_func)(tnfctl_handle_t *,tnfctl_probe_t *),void (* destroy_func)(void *))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
_tnfctl_destructor_wrapper(tnfctl_handle_t * hndl,prbctlref_t * probe,void * cd)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
_tnfctl_creator_wrapper(tnfctl_handle_t * hndl,prbctlref_t * probe,void * cd)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
tnfctl_probe_apply(tnfctl_handle_t * hndl,tnfctl_probe_op_t func_p,void * calldata)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
tnfctl_probe_apply_ids(tnfctl_handle_t * hndl,ulong_t probe_count,ulong_t * probe_ids,tnfctl_probe_op_t func_p,void * calldata)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
tnfctl_probe_state_get(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl,tnfctl_probe_state_t * state_p)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
check_operation(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl)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
tnfctl_probe_enable(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl,void * cd)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
tnfctl_probe_disable(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl,void * cd)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
tnfctl_probe_trace(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl,void * cd)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
tnfctl_probe_untrace(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl,void * cd)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
tnfctl_probe_connect(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl,const char * lib_base_name,const char * func)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
tnfctl_probe_disconnect_all(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_hndl,void * cd)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
apply_func(tnfctl_handle_t * hndl,prbctlref_t * probe,void * cd)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