xref: /titanic_52/usr/src/lib/libtnfctl/kernel_int.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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  * Interfaces to control kernel tracing and kernel probes
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #ifndef DEBUG
33*7c478bd9Sstevel@tonic-gate #define	NDEBUG	1
34*7c478bd9Sstevel@tonic-gate #endif
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #include <stdio.h>
37*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
38*7c478bd9Sstevel@tonic-gate #include <unistd.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>	/* for strerror() */
40*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/tnf.h>
43*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <signal.h>
46*7c478bd9Sstevel@tonic-gate #include <assert.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
49*7c478bd9Sstevel@tonic-gate #include "kernel_int.h"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /* The TNF pseudo-device */
52*7c478bd9Sstevel@tonic-gate #define	TNFDRIVER	"/dev/tnfctl"
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate /* Dummy "test" function  -- just used to flag enabled probes */
55*7c478bd9Sstevel@tonic-gate #define	PRBK_DUMMY_TEST	((tnf_probe_test_func_t) 4)
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /* Dummy "commit" function -- just used to flag trace enabled */
58*7c478bd9Sstevel@tonic-gate #define	PRBK_DUMMY_COMMIT ((tnf_probe_func_t) 8)
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /* Dummy "rollback" function -- just used to flag trace disabled */
61*7c478bd9Sstevel@tonic-gate #define	PRBK_DUMMY_ROLLBACK ((tnf_probe_func_t) 12)
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate /* Dummy "end" function */
64*7c478bd9Sstevel@tonic-gate #define	PRBK_DUMMY_END ((uintptr_t) 16)
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /* Dummy "alloc" function */
67*7c478bd9Sstevel@tonic-gate #define	PRBK_DUMMY_ALLOC ((uintptr_t) 20)
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /* Minimum and maximum allowed buffer sizes. */
70*7c478bd9Sstevel@tonic-gate /* XXX -- maximum should be some function of physmem. */
71*7c478bd9Sstevel@tonic-gate #define	KERNEL_MINBUF_SIZE	(128 * 1024)
72*7c478bd9Sstevel@tonic-gate #define	KERNEL_MAXBUF_SIZE	(128 * 1024 * 1024)
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t prbk_get_buf_attrs(tnfctl_handle_t *hdl);
75*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t alloc_probe_space(tnfctl_handle_t *hndl, int maxprobe);
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate /*
78*7c478bd9Sstevel@tonic-gate  * Initialize the kernel interface:  Open the TNF control device,
79*7c478bd9Sstevel@tonic-gate  * and determine the current kernel probes state, including the
80*7c478bd9Sstevel@tonic-gate  * current pidfilter list.
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
83*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_init(tnfctl_handle_t *hdl)
84*7c478bd9Sstevel@tonic-gate {
85*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
86*7c478bd9Sstevel@tonic-gate 	tifiocstate_t kstate;
87*7c478bd9Sstevel@tonic-gate 	int kfd;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	kfd = open(TNFDRIVER, O_RDWR);
90*7c478bd9Sstevel@tonic-gate 	if (kfd < 0) {
91*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
92*7c478bd9Sstevel@tonic-gate 	}
93*7c478bd9Sstevel@tonic-gate 	if (ioctl(kfd, TIFIOCGSTATE, &kstate) < 0)
94*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	hdl->kfd = kfd;
97*7c478bd9Sstevel@tonic-gate 	hdl->kpidfilter_state = kstate.pidfilter_mode;
98*7c478bd9Sstevel@tonic-gate 	hdl->trace_state = !kstate.trace_stopped;
99*7c478bd9Sstevel@tonic-gate 	hdl->trace_min_size = KERNEL_MINBUF_SIZE;
100*7c478bd9Sstevel@tonic-gate 	prexstat = prbk_get_buf_attrs(hdl);
101*7c478bd9Sstevel@tonic-gate 	if (prexstat)
102*7c478bd9Sstevel@tonic-gate 		return (prexstat);
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * Close the TNF control device.
109*7c478bd9Sstevel@tonic-gate  */
110*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
111*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_close(tnfctl_handle_t *hdl)
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	if (hdl == NULL)
114*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if (close(hdl->kfd) == -1) {
117*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * Returns function addresses that can be plugged into function pointers
124*7c478bd9Sstevel@tonic-gate  * in kernel probes.  These are actually dummy values that get
125*7c478bd9Sstevel@tonic-gate  * interpreted by a routine in this file when a probe is flushed.
126*7c478bd9Sstevel@tonic-gate  */
127*7c478bd9Sstevel@tonic-gate void
128*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_get_other_funcs(uintptr_t *allocp, uintptr_t *commitp,
129*7c478bd9Sstevel@tonic-gate 	uintptr_t *rollbackp, uintptr_t *endp)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	*allocp = PRBK_DUMMY_ALLOC;
132*7c478bd9Sstevel@tonic-gate 	*commitp = (uintptr_t) PRBK_DUMMY_COMMIT;
133*7c478bd9Sstevel@tonic-gate 	*rollbackp = (uintptr_t) PRBK_DUMMY_ROLLBACK;
134*7c478bd9Sstevel@tonic-gate 	*endp = PRBK_DUMMY_END;
135*7c478bd9Sstevel@tonic-gate }
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate /*
139*7c478bd9Sstevel@tonic-gate  * Returns test function address
140*7c478bd9Sstevel@tonic-gate  */
141*7c478bd9Sstevel@tonic-gate void
142*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_test_func(uintptr_t *outp)
143*7c478bd9Sstevel@tonic-gate {
144*7c478bd9Sstevel@tonic-gate 	*outp = (uintptr_t) PRBK_DUMMY_TEST;
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * Allocate a trace buffer.  Check for reasonable size; reject if there's
149*7c478bd9Sstevel@tonic-gate  * already a buffer.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
152*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_buffer_alloc(tnfctl_handle_t *hdl, int size)
153*7c478bd9Sstevel@tonic-gate {
154*7c478bd9Sstevel@tonic-gate 	tifiocstate_t bufstat;
155*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
156*7c478bd9Sstevel@tonic-gate 	int saved_val;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCGSTATE, &bufstat) < 0) {
159*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 	if (bufstat.buffer_state != TIFIOCBUF_NONE) {
162*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BUFEXISTS);
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 	if (size < KERNEL_MINBUF_SIZE) {
165*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_SIZETOOSMALL);
166*7c478bd9Sstevel@tonic-gate 	} else if (size > KERNEL_MAXBUF_SIZE) {
167*7c478bd9Sstevel@tonic-gate 		/* REMIND: make this an error ? */
168*7c478bd9Sstevel@tonic-gate 		size = KERNEL_MAXBUF_SIZE;
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCALLOCBUF, size) < 0) {
171*7c478bd9Sstevel@tonic-gate 		saved_val = errno;
172*7c478bd9Sstevel@tonic-gate 		(void) prbk_get_buf_attrs(hdl);
173*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(saved_val));
174*7c478bd9Sstevel@tonic-gate 	}
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	prexstat = prbk_get_buf_attrs(hdl);
177*7c478bd9Sstevel@tonic-gate 	if (prexstat)
178*7c478bd9Sstevel@tonic-gate 		return (prexstat);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate /*
184*7c478bd9Sstevel@tonic-gate  * Deallocate the kernel's trace buffer.
185*7c478bd9Sstevel@tonic-gate  */
186*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
187*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_buffer_dealloc(tnfctl_handle_t *hdl)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	tifiocstate_t bufstat;
190*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
191*7c478bd9Sstevel@tonic-gate 	int saved_val;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCGSTATE, &bufstat) < 0) {
194*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate 	if (bufstat.buffer_state == TIFIOCBUF_NONE) {
197*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NOBUF);
198*7c478bd9Sstevel@tonic-gate 	}
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	if (bufstat.buffer_state == TIFIOCBUF_OK && !bufstat.trace_stopped) {
201*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BADDEALLOC);
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCDEALLOCBUF) < 0) {
204*7c478bd9Sstevel@tonic-gate 		saved_val = errno;
205*7c478bd9Sstevel@tonic-gate 		(void) prbk_get_buf_attrs(hdl);
206*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(saved_val));
207*7c478bd9Sstevel@tonic-gate 	}
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	prexstat = prbk_get_buf_attrs(hdl);
210*7c478bd9Sstevel@tonic-gate 	if (prexstat)
211*7c478bd9Sstevel@tonic-gate 		return (prexstat);
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate /*
217*7c478bd9Sstevel@tonic-gate  * Turns kernel global tracing on or off.
218*7c478bd9Sstevel@tonic-gate  */
219*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
220*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_set_tracing(tnfctl_handle_t *hdl, boolean_t onoff)
221*7c478bd9Sstevel@tonic-gate {
222*7c478bd9Sstevel@tonic-gate 	if (hdl->trace_state != onoff &&
223*7c478bd9Sstevel@tonic-gate 	    ioctl(hdl->kfd, TIFIOCSTRACING, onoff) < 0) {
224*7c478bd9Sstevel@tonic-gate 		if (errno == ENOMEM && onoff)
225*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NOBUF);
226*7c478bd9Sstevel@tonic-gate 		else
227*7c478bd9Sstevel@tonic-gate 			return (tnfctl_status_map(errno));
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 	hdl->trace_state = onoff;
230*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
231*7c478bd9Sstevel@tonic-gate }
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate /*
234*7c478bd9Sstevel@tonic-gate  * Turn process filter mode on or off.  The process filter is maintained
235*7c478bd9Sstevel@tonic-gate  * even when process filtering is off, but has no effect:  all processes
236*7c478bd9Sstevel@tonic-gate  * are traced.
237*7c478bd9Sstevel@tonic-gate  */
238*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
239*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_set_pfilter_mode(tnfctl_handle_t *hdl, boolean_t onoff)
240*7c478bd9Sstevel@tonic-gate {
241*7c478bd9Sstevel@tonic-gate 	if (hdl->kpidfilter_state != onoff &&
242*7c478bd9Sstevel@tonic-gate 	    ioctl(hdl->kfd, TIFIOCSPIDFILTER, onoff) < 0) {
243*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
244*7c478bd9Sstevel@tonic-gate 	}
245*7c478bd9Sstevel@tonic-gate 	hdl->kpidfilter_state = onoff;
246*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
247*7c478bd9Sstevel@tonic-gate }
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate /*
250*7c478bd9Sstevel@tonic-gate  * Return the process filter list.
251*7c478bd9Sstevel@tonic-gate  */
252*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
253*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_get_pfilter_list(tnfctl_handle_t *hdl, pid_t **ret_list_p,
254*7c478bd9Sstevel@tonic-gate 				int *ret_count)
255*7c478bd9Sstevel@tonic-gate {
256*7c478bd9Sstevel@tonic-gate 	tifiocstate_t kstate;
257*7c478bd9Sstevel@tonic-gate 	int *filterset;
258*7c478bd9Sstevel@tonic-gate 	int i;
259*7c478bd9Sstevel@tonic-gate 	pid_t *ret_list;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCGSTATE, &kstate) < 0)
262*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	if (kstate.pidfilter_size == 0) {
265*7c478bd9Sstevel@tonic-gate 		*ret_count = 0;
266*7c478bd9Sstevel@tonic-gate 		*ret_list_p = NULL;
267*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
268*7c478bd9Sstevel@tonic-gate 	}
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	filterset = (int *) malloc((kstate.pidfilter_size + 1) *
271*7c478bd9Sstevel@tonic-gate 					sizeof (pid_t));
272*7c478bd9Sstevel@tonic-gate 	if (filterset == NULL)
273*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
274*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCPIDFILTERGET, filterset) < 0)
275*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	/* filterset[0] contains size of array */
278*7c478bd9Sstevel@tonic-gate 	ret_list = malloc(filterset[0] * sizeof (pid_t));
279*7c478bd9Sstevel@tonic-gate 	if (ret_list == NULL)
280*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	for (i = 1; i <= filterset[0]; ++i)
283*7c478bd9Sstevel@tonic-gate 		ret_list[i - 1] = filterset[i];
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	*ret_count = filterset[0];
286*7c478bd9Sstevel@tonic-gate 	(void) free(filterset);
287*7c478bd9Sstevel@tonic-gate 	*ret_list_p = ret_list;
288*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
289*7c478bd9Sstevel@tonic-gate }
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate /*
292*7c478bd9Sstevel@tonic-gate  * Add the pid to the process filter list.
293*7c478bd9Sstevel@tonic-gate  * check whether it's already in the filter list,
294*7c478bd9Sstevel@tonic-gate  * and whether the process exists.
295*7c478bd9Sstevel@tonic-gate  */
296*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
297*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_pfilter_add(tnfctl_handle_t *hdl, pid_t pid_to_add)
298*7c478bd9Sstevel@tonic-gate {
299*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCSPIDON, pid_to_add) < 0) {
300*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
303*7c478bd9Sstevel@tonic-gate }
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate /*
306*7c478bd9Sstevel@tonic-gate  * Drop the pid from the process filter list.
307*7c478bd9Sstevel@tonic-gate  */
308*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
309*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_pfilter_delete(tnfctl_handle_t *hdl, pid_t pid_to_del)
310*7c478bd9Sstevel@tonic-gate {
311*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCSPIDOFF, pid_to_del) < 0) {
312*7c478bd9Sstevel@tonic-gate 		if (errno == ESRCH) {
313*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NOPROCESS);
314*7c478bd9Sstevel@tonic-gate 		} else {
315*7c478bd9Sstevel@tonic-gate 			return (tnfctl_status_map(errno));
316*7c478bd9Sstevel@tonic-gate 		}
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate /*
322*7c478bd9Sstevel@tonic-gate  * get the buffer attributes - side effect tnfctl handle
323*7c478bd9Sstevel@tonic-gate  */
324*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
325*7c478bd9Sstevel@tonic-gate prbk_get_buf_attrs(tnfctl_handle_t *hdl)
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	tifiocstate_t bufstat;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	if (ioctl(hdl->kfd, TIFIOCGSTATE, &bufstat) < 0) {
330*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
331*7c478bd9Sstevel@tonic-gate 	}
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	hdl->trace_file_name = NULL;
334*7c478bd9Sstevel@tonic-gate 	hdl->trace_buf_size = bufstat.buffer_size;
335*7c478bd9Sstevel@tonic-gate 	if (bufstat.buffer_state == TIFIOCBUF_NONE)
336*7c478bd9Sstevel@tonic-gate 		hdl->trace_buf_state = TNFCTL_BUF_NONE;
337*7c478bd9Sstevel@tonic-gate 	else if (bufstat.buffer_state == TIFIOCBUF_BROKEN)
338*7c478bd9Sstevel@tonic-gate 		hdl->trace_buf_state = TNFCTL_BUF_BROKEN;
339*7c478bd9Sstevel@tonic-gate 	else
340*7c478bd9Sstevel@tonic-gate 		hdl->trace_buf_state = TNFCTL_BUF_OK;
341*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
342*7c478bd9Sstevel@tonic-gate }
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate /*
345*7c478bd9Sstevel@tonic-gate  * "Flush" a probe:  i.e., sync up the kernel state with the
346*7c478bd9Sstevel@tonic-gate  * (desired) state stored in our data structure.
347*7c478bd9Sstevel@tonic-gate  */
348*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
349*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_flush(tnfctl_handle_t *hndl, prbctlref_t *p)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	tnf_probevals_t probebuf;
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	probebuf.probenum = p->probe_id;
354*7c478bd9Sstevel@tonic-gate 	probebuf.enabled = (p->wrkprbctl.test_func != NULL);
355*7c478bd9Sstevel@tonic-gate 	probebuf.traced = (p->wrkprbctl.commit_func == PRBK_DUMMY_COMMIT);
356*7c478bd9Sstevel@tonic-gate 	if (ioctl(hndl->kfd, TIFIOCSPROBEVALS, &probebuf) < 0)
357*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
358*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
359*7c478bd9Sstevel@tonic-gate }
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate /*
362*7c478bd9Sstevel@tonic-gate  * Refresh our understanding of the existing probes in the kernel.
363*7c478bd9Sstevel@tonic-gate  */
364*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
365*7c478bd9Sstevel@tonic-gate _tnfctl_refresh_kernel(tnfctl_handle_t *hndl)
366*7c478bd9Sstevel@tonic-gate {
367*7c478bd9Sstevel@tonic-gate 	int maxprobe, i;
368*7c478bd9Sstevel@tonic-gate 	int pos;
369*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
370*7c478bd9Sstevel@tonic-gate 	tnf_probevals_t probebuf;
371*7c478bd9Sstevel@tonic-gate 	objlist_t *obj_p;
372*7c478bd9Sstevel@tonic-gate 	prbctlref_t *p = NULL;
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	prexstat = prbk_get_buf_attrs(hndl);
375*7c478bd9Sstevel@tonic-gate 	if (prexstat)
376*7c478bd9Sstevel@tonic-gate 		return (prexstat);
377*7c478bd9Sstevel@tonic-gate 	/*
378*7c478bd9Sstevel@tonic-gate 	 * Here is where you'd set obj_p->new to B_FALSE and obj_p->old to
379*7c478bd9Sstevel@tonic-gate 	 * B_TRUE for all existing objects.  We currently don't need
380*7c478bd9Sstevel@tonic-gate 	 * it until we get modload/unload working correctly with probes
381*7c478bd9Sstevel@tonic-gate 	 */
382*7c478bd9Sstevel@tonic-gate 	if (ioctl(hndl->kfd, TIFIOCGMAXPROBE, &maxprobe) < 0)
383*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
384*7c478bd9Sstevel@tonic-gate 	if (maxprobe == hndl->num_probes) {
385*7c478bd9Sstevel@tonic-gate 		/* XXX Inadequate in the presence of module unloading */
386*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	prexstat = alloc_probe_space(hndl, maxprobe);
390*7c478bd9Sstevel@tonic-gate 	if (prexstat)
391*7c478bd9Sstevel@tonic-gate 		return (prexstat);
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	NOTE(NO_COMPETING_THREADS_NOW)
394*7c478bd9Sstevel@tonic-gate 	obj_p = hndl->objlist;
395*7c478bd9Sstevel@tonic-gate 	NOTE(COMPETING_THREADS_NOW)
396*7c478bd9Sstevel@tonic-gate 	assert((obj_p != NULL) && (obj_p->probes != NULL));
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	for (i = 1; i <= maxprobe; ++i) {
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 		if (i >= (obj_p->min_probe_num + obj_p->probecnt)) {
401*7c478bd9Sstevel@tonic-gate 			obj_p = obj_p->next;
402*7c478bd9Sstevel@tonic-gate 		}
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 		/* make sure we are in the correct object */
405*7c478bd9Sstevel@tonic-gate 		assert(obj_p != NULL);
406*7c478bd9Sstevel@tonic-gate 		assert((i >= obj_p->min_probe_num) &&
407*7c478bd9Sstevel@tonic-gate 			(i < (obj_p->min_probe_num + obj_p->probecnt)));
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 		/* get a pointer to correct probe */
410*7c478bd9Sstevel@tonic-gate 		pos = i - obj_p->min_probe_num;
411*7c478bd9Sstevel@tonic-gate 		p = &(obj_p->probes[pos]);
412*7c478bd9Sstevel@tonic-gate 		assert((p != NULL) && (p->probe_id == i) && (p->probe_handle));
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 		probebuf.probenum = i;
415*7c478bd9Sstevel@tonic-gate 		if (ioctl(hndl->kfd, TIFIOCGPROBEVALS, &probebuf) < 0) {
416*7c478bd9Sstevel@tonic-gate 			if (errno == ENOENT) {
417*7c478bd9Sstevel@tonic-gate 				/*
418*7c478bd9Sstevel@tonic-gate 				 * This probe has vanished due to a module
419*7c478bd9Sstevel@tonic-gate 				 * unload.
420*7c478bd9Sstevel@tonic-gate 				 */
421*7c478bd9Sstevel@tonic-gate 				p->probe_handle->valid = B_FALSE;
422*7c478bd9Sstevel@tonic-gate 			} else {
423*7c478bd9Sstevel@tonic-gate 				return (tnfctl_status_map(errno));
424*7c478bd9Sstevel@tonic-gate 			}
425*7c478bd9Sstevel@tonic-gate 		} else {
426*7c478bd9Sstevel@tonic-gate 			if (p->probe_handle->valid == B_FALSE) {
427*7c478bd9Sstevel@tonic-gate 				/*
428*7c478bd9Sstevel@tonic-gate 				 * seeing this probe for the first time
429*7c478bd9Sstevel@tonic-gate 				 * (alloc_probe_space() initialized this
430*7c478bd9Sstevel@tonic-gate 				 * "valid" field to B_FALSE)
431*7c478bd9Sstevel@tonic-gate 				 */
432*7c478bd9Sstevel@tonic-gate 				/* Update our info about this probe */
433*7c478bd9Sstevel@tonic-gate 				p->wrkprbctl.test_func = (probebuf.enabled) ?
434*7c478bd9Sstevel@tonic-gate 					PRBK_DUMMY_TEST : NULL;
435*7c478bd9Sstevel@tonic-gate 				p->wrkprbctl.commit_func = (probebuf.traced) ?
436*7c478bd9Sstevel@tonic-gate 					PRBK_DUMMY_COMMIT : PRBK_DUMMY_ROLLBACK;
437*7c478bd9Sstevel@tonic-gate 				p->probe_handle->valid = B_TRUE;
438*7c478bd9Sstevel@tonic-gate 				if (probebuf.attrsize < sizeof (probebuf))
439*7c478bd9Sstevel@tonic-gate 					probebuf.attrsize = sizeof (probebuf);
440*7c478bd9Sstevel@tonic-gate 				p->attr_string = malloc(probebuf.attrsize);
441*7c478bd9Sstevel@tonic-gate 				if (p->attr_string == NULL)
442*7c478bd9Sstevel@tonic-gate 					return (TNFCTL_ERR_ALLOCFAIL);
443*7c478bd9Sstevel@tonic-gate 				/*
444*7c478bd9Sstevel@tonic-gate 				 * NOTE: the next statement is a structure
445*7c478bd9Sstevel@tonic-gate 				 * copy and *not* a pointer assignment
446*7c478bd9Sstevel@tonic-gate 				 */
447*7c478bd9Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */
448*7c478bd9Sstevel@tonic-gate 				*(tnf_probevals_t *) p->attr_string = probebuf;
449*7c478bd9Sstevel@tonic-gate 				if (ioctl(hndl->kfd, TIFIOCGPROBESTRING,
450*7c478bd9Sstevel@tonic-gate 						p->attr_string) < 0)
451*7c478bd9Sstevel@tonic-gate 					return (tnfctl_status_map(errno));
452*7c478bd9Sstevel@tonic-gate 				if (hndl->create_func) {
453*7c478bd9Sstevel@tonic-gate 				    p->probe_handle->client_registered_data =
454*7c478bd9Sstevel@tonic-gate 					hndl->create_func(hndl,
455*7c478bd9Sstevel@tonic-gate 						p->probe_handle);
456*7c478bd9Sstevel@tonic-gate 				}
457*7c478bd9Sstevel@tonic-gate 			}
458*7c478bd9Sstevel@tonic-gate 		}
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 	hndl->num_probes = maxprobe;
461*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
462*7c478bd9Sstevel@tonic-gate }
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate /*
465*7c478bd9Sstevel@tonic-gate  * check if there are any new probes in the kernel that we aren't aware of.
466*7c478bd9Sstevel@tonic-gate  * If so, allocate space for those probes in our data structure.
467*7c478bd9Sstevel@tonic-gate  */
468*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
469*7c478bd9Sstevel@tonic-gate alloc_probe_space(tnfctl_handle_t *hndl, int maxprobe)
470*7c478bd9Sstevel@tonic-gate {
471*7c478bd9Sstevel@tonic-gate 	objlist_t **o_pp;
472*7c478bd9Sstevel@tonic-gate 	objlist_t *obj_p, *nobj_p;
473*7c478bd9Sstevel@tonic-gate 	int min_probe_num, i;
474*7c478bd9Sstevel@tonic-gate 	prbctlref_t *probe_p;
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	/* we know that: hndl->maxprobe != maxprobe */
477*7c478bd9Sstevel@tonic-gate 	NOTE(NO_COMPETING_THREADS_NOW)
478*7c478bd9Sstevel@tonic-gate 	obj_p = hndl->objlist;
479*7c478bd9Sstevel@tonic-gate 	NOTE(COMPETING_THREADS_NOW)
480*7c478bd9Sstevel@tonic-gate 	if (obj_p == NULL) {
481*7c478bd9Sstevel@tonic-gate 		/* no objects allocated */
482*7c478bd9Sstevel@tonic-gate 		o_pp = &(hndl->objlist);
483*7c478bd9Sstevel@tonic-gate 		min_probe_num = 1;
484*7c478bd9Sstevel@tonic-gate 	} else {
485*7c478bd9Sstevel@tonic-gate 		/* find last object */
486*7c478bd9Sstevel@tonic-gate 		while (obj_p->next != NULL) {
487*7c478bd9Sstevel@tonic-gate 			/* reset new_probe field on modload/unload */
488*7c478bd9Sstevel@tonic-gate 			obj_p->new_probe = B_FALSE;
489*7c478bd9Sstevel@tonic-gate 			obj_p = obj_p->next;
490*7c478bd9Sstevel@tonic-gate 		}
491*7c478bd9Sstevel@tonic-gate 		o_pp = &(obj_p->next);
492*7c478bd9Sstevel@tonic-gate 		min_probe_num = obj_p->min_probe_num + obj_p->probecnt;
493*7c478bd9Sstevel@tonic-gate 	}
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	nobj_p = calloc(1, sizeof (objlist_t));
496*7c478bd9Sstevel@tonic-gate 	if (nobj_p == NULL)
497*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
498*7c478bd9Sstevel@tonic-gate 	/* add to the linked list */
499*7c478bd9Sstevel@tonic-gate 	*o_pp = nobj_p;
500*7c478bd9Sstevel@tonic-gate 	/* NULL, B_FALSE, or 0's not explicitly initialized */
501*7c478bd9Sstevel@tonic-gate 	nobj_p->new_probe = B_TRUE;
502*7c478bd9Sstevel@tonic-gate 	nobj_p->new = B_TRUE;
503*7c478bd9Sstevel@tonic-gate 	nobj_p->objfd = -1;
504*7c478bd9Sstevel@tonic-gate 	nobj_p->min_probe_num = min_probe_num;
505*7c478bd9Sstevel@tonic-gate 	nobj_p->probecnt = maxprobe - min_probe_num + 1;
506*7c478bd9Sstevel@tonic-gate 	nobj_p->probes = calloc(nobj_p->probecnt,  sizeof (prbctlref_t));
507*7c478bd9Sstevel@tonic-gate 	if (nobj_p->probes == NULL) {
508*7c478bd9Sstevel@tonic-gate 		free(nobj_p);
509*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	probe_p = &(nobj_p->probes[0]);
513*7c478bd9Sstevel@tonic-gate 	for (i = min_probe_num; i <= maxprobe; i++) {
514*7c478bd9Sstevel@tonic-gate 		NOTE(NO_COMPETING_THREADS_NOW)
515*7c478bd9Sstevel@tonic-gate 		probe_p->obj = nobj_p;
516*7c478bd9Sstevel@tonic-gate 		NOTE(COMPETING_THREADS_NOW)
517*7c478bd9Sstevel@tonic-gate 		probe_p->probe_id = i;
518*7c478bd9Sstevel@tonic-gate 		probe_p->probe_handle = calloc(1, sizeof (tnfctl_probe_t));
519*7c478bd9Sstevel@tonic-gate 		if (probe_p->probe_handle == NULL) {
520*7c478bd9Sstevel@tonic-gate 			if (nobj_p->probes)
521*7c478bd9Sstevel@tonic-gate 				free(nobj_p->probes);
522*7c478bd9Sstevel@tonic-gate 			free(nobj_p);
523*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_ALLOCFAIL);
524*7c478bd9Sstevel@tonic-gate 		}
525*7c478bd9Sstevel@tonic-gate 		probe_p->probe_handle->valid = B_FALSE;
526*7c478bd9Sstevel@tonic-gate 		probe_p->probe_handle->probe_p = probe_p;
527*7c478bd9Sstevel@tonic-gate 		/* link in probe handle into chain off tnfctl_handle_t */
528*7c478bd9Sstevel@tonic-gate 		probe_p->probe_handle->next = hndl->probe_handle_list_head;
529*7c478bd9Sstevel@tonic-gate 		hndl->probe_handle_list_head = probe_p->probe_handle;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 		probe_p++;
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	hndl->num_probes = maxprobe;
535*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
536*7c478bd9Sstevel@tonic-gate }
537