xref: /titanic_50/usr/src/lib/libtnfctl/probes_ext.c (revision 10d63b7db37a83b39c7f511cf9426c9d03ea0760)
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