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