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