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 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <string.h> /* for strerror() */ 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <sys/tnf.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 #include <locale.h> 38 39 #include "prbk.h" 40 41 #include <tnf/tnfctl.h> 42 43 extern tnfctl_handle_t *g_hndl; 44 45 typedef struct _pidlist { 46 pid_t pid; 47 struct _pidlist *next; 48 } pidlist_t; 49 50 static boolean_t check_kernelmode(tnfctl_trace_attrs_t *attrs_p); 51 52 static boolean_t 53 check_kernelmode(tnfctl_trace_attrs_t *attrs_p) 54 { 55 extern int g_kernelmode; 56 tnfctl_errcode_t err; 57 58 if (!g_kernelmode) { 59 (void) fprintf(stderr, gettext( 60 "This command is only available " 61 "in kernel mode (prex invoked with the -k flag)\n")); 62 return (B_TRUE); 63 } 64 if (attrs_p) { 65 err = tnfctl_trace_attrs_get(g_hndl, attrs_p); 66 if (err) { 67 (void) fprintf(stderr, gettext( 68 "error on checking trace attributes : %s\n"), 69 tnfctl_strerror(err)); 70 return (B_TRUE); 71 } 72 } 73 return (B_FALSE); 74 } 75 76 /* 77 * Print trace buffer status (is one allocated, and if so, how big is it. 78 */ 79 void 80 prbk_buffer_list() 81 { 82 tnfctl_trace_attrs_t attrs; 83 84 if (check_kernelmode(&attrs)) 85 return; 86 if (attrs.trace_buf_state == TNFCTL_BUF_NONE) { 87 (void) printf(gettext("No trace buffer allocated\n")); 88 } else { 89 (void) printf(gettext("Trace buffer size is %d bytes\n"), 90 attrs.trace_buf_size); 91 if (attrs.trace_buf_state == TNFCTL_BUF_BROKEN) { 92 (void) printf(gettext("Tracing system has failed -- " 93 "tracing suspended\n")); 94 } 95 } 96 } 97 98 99 /* 100 * Allocate a trace buffer. Check for reasonable size; reject if there's 101 * already a buffer. 102 */ 103 void 104 prbk_buffer_alloc(int size) 105 { 106 tnfctl_errcode_t err; 107 tnfctl_trace_attrs_t attrs; 108 109 if (check_kernelmode(&attrs)) 110 return; 111 112 if (attrs.trace_buf_state != TNFCTL_BUF_NONE) { 113 (void) fprintf(stderr, 114 gettext("There is already a buffer allocated\n")); 115 return; 116 } 117 if (size < attrs.trace_min_size) { 118 (void) fprintf(stderr, gettext( 119 "Size %d is less than the minimum buffer size of %d -- " 120 "buffer size set to %d bytes\n"), 121 size, attrs.trace_min_size, attrs.trace_min_size); 122 size = attrs.trace_min_size; 123 } 124 125 err = tnfctl_buffer_alloc(g_hndl, NULL, size); 126 if (err) { 127 (void) fprintf(stderr, 128 gettext("error in allocating buffer: %s\n"), 129 tnfctl_strerror(err)); 130 return; 131 } 132 133 /* get the trace attributes again */ 134 if (check_kernelmode(&attrs)) 135 return; 136 (void) printf(gettext("Buffer of size %d bytes allocated\n"), 137 attrs.trace_buf_size); 138 } 139 140 141 /* 142 * Deallocate the kernel's trace buffer. 143 */ 144 void 145 prbk_buffer_dealloc() 146 { 147 tnfctl_errcode_t err; 148 149 if (check_kernelmode(NULL)) 150 return; 151 152 err = tnfctl_buffer_dealloc(g_hndl); 153 switch (err) { 154 case (TNFCTL_ERR_NONE): 155 (void) printf(gettext("buffer deallocated\n")); 156 break; 157 case (TNFCTL_ERR_NOBUF): 158 (void) fprintf(stderr, 159 gettext("There is no buffer to deallocate\n")); 160 break; 161 case (TNFCTL_ERR_BADDEALLOC): 162 (void) fprintf(stderr, 163 gettext("Can't deallocate the buffer when " 164 "tracing is active\n")); 165 break; 166 default: 167 (void) fprintf(stderr, 168 gettext("error in deleting buffer: %s\n"), 169 tnfctl_strerror(err)); 170 break; 171 } 172 } 173 174 175 /* 176 * Process filter routines. 177 * 178 * Process id sets are encoded as "pidlists": a linked list of pids. 179 * In a feeble attempt at encapsulation, the pidlist_t type is private 180 * to this file; prexgram.y manipulates pidlists only as opaque handles. 181 */ 182 183 /* 184 * Add the given pid (new) to the pidlist (pl). 185 */ 186 void * 187 prbk_pidlist_add(void *pl, int new) 188 189 { 190 pidlist_t *npl = (pidlist_t *) malloc(sizeof (*npl)); 191 192 if (npl == NULL) { 193 (void) fprintf(stderr, 194 gettext("Out of memory -- can't process pid %d\n"), 195 new); 196 return (pl); 197 } 198 npl->next = pl; 199 npl->pid = new; 200 return (npl); 201 } 202 203 /* 204 * Add the pids in the given pidlist to the process filter list. 205 * For each pid, check whether it's already in the filter list, 206 * and whether the process exists. 207 */ 208 void 209 prbk_pfilter_add(void *pl) 210 { 211 pidlist_t *ppl = (pidlist_t *) pl; 212 pidlist_t *tmp; 213 tnfctl_errcode_t err; 214 215 if (check_kernelmode(NULL)) 216 return; 217 while (ppl != NULL) { 218 err = tnfctl_filter_list_add(g_hndl, ppl->pid); 219 if (err) { 220 (void) fprintf(stderr, gettext("Process %ld: %s\n"), 221 ppl->pid, tnfctl_strerror(err)); 222 } 223 tmp = ppl; 224 ppl = ppl->next; 225 free(tmp); 226 } 227 } 228 229 /* 230 * Drop the pids in the given pidlist from the process filter list. 231 * For each pid, complain if it's not in the process filter list; 232 * and if the process no longer exists (and hence has already implicitly 233 * been dropped from the process filter list), say so. 234 */ 235 void 236 prbk_pfilter_drop(void *pl) 237 { 238 pidlist_t *ppl = (pidlist_t *) pl; 239 pidlist_t *tmp; 240 tnfctl_errcode_t err; 241 242 if (check_kernelmode(NULL)) 243 return; 244 245 while (ppl != NULL) { 246 tmp = ppl; 247 err = tnfctl_filter_list_delete(g_hndl, tmp->pid); 248 switch (err) { 249 case (TNFCTL_ERR_NONE): 250 break; 251 case (TNFCTL_ERR_BADARG): 252 (void) fprintf(stderr, 253 gettext("Process %ld is not being traced\n"), 254 tmp->pid); 255 break; 256 case (TNFCTL_ERR_NOPROCESS): 257 (void) printf(gettext("Process %ld has exited\n"), 258 tmp->pid); 259 break; 260 default: 261 (void) fprintf(stderr, gettext("Process %ld: %s\n"), 262 tmp->pid, tnfctl_strerror(err)); 263 break; 264 } 265 ppl = ppl->next; 266 free(tmp); 267 } 268 } 269 270 /* 271 * Turn process filter mode on or off. The process filter is maintained 272 * even when process filtering is off, but has no effect: all processes 273 * are traced. 274 */ 275 void 276 prbk_set_pfilter_mode(boolean_t onoff) 277 { 278 tnfctl_errcode_t err; 279 280 if (check_kernelmode(NULL)) 281 return; 282 err = tnfctl_filter_state_set(g_hndl, onoff); 283 if (err) { 284 (void) fprintf(stderr, gettext("pfilter: %s\n"), 285 tnfctl_strerror(err)); 286 } 287 } 288 289 290 /* 291 * Report whether process filter mode is currently on or off, and 292 * dump the current process filter set. 293 */ 294 void 295 prbk_show_pfilter_mode() 296 { 297 tnfctl_errcode_t err; 298 tnfctl_trace_attrs_t attrs; 299 pid_t *pids_p; 300 int i, pid_count; 301 pid_t *cur_pid; 302 303 if (check_kernelmode(&attrs)) 304 return; 305 (void) printf(gettext("Process filtering is %s\n"), 306 attrs.filter_state ? "on" : "off"); 307 err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count); 308 if (err) { 309 (void) fprintf(stderr, 310 gettext("error in getting process filter list: %s\n"), 311 tnfctl_strerror(err)); 312 return; 313 } 314 (void) printf(gettext("Process filter set is ")); 315 if (pid_count == 0) 316 (void) printf("empty.\n"); 317 else { 318 (void) printf("{"); 319 cur_pid = pids_p; 320 for (i = 0; i < pid_count; i++, cur_pid++) { 321 (void) printf("%ld%s", *cur_pid, 322 (i != (pid_count - 1)) ? ", " : "}\n"); 323 } 324 } 325 } 326 327 /* 328 * Check for process filtering on with empty pid filter. 329 */ 330 void 331 prbk_warn_pfilter_empty(void) 332 { 333 tnfctl_errcode_t err; 334 pid_t *pids_p; 335 int pid_count; 336 tnfctl_trace_attrs_t attrs; 337 338 if (check_kernelmode(&attrs)) 339 return; 340 if (attrs.filter_state) { 341 err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count); 342 if (err) { 343 (void) fprintf(stderr, 344 gettext("error in getting process filter list: %s\n"), 345 tnfctl_strerror(err)); 346 return; 347 } 348 if (!pid_count) 349 (void) fprintf(stderr, 350 gettext("Warning: Process filtering on, \ 351 but pid filter list is empty\n")); 352 } 353 } 354 355 356 /* 357 * Turn kernel tracing on or off. 358 */ 359 void 360 prbk_set_tracing(boolean_t onoff) 361 { 362 tnfctl_errcode_t err; 363 364 if (check_kernelmode(NULL)) 365 return; 366 367 err = tnfctl_trace_state_set(g_hndl, onoff); 368 if (err) { 369 (void) fprintf(stderr, 370 gettext("error in setting tracing state: %s\n"), 371 tnfctl_strerror(err)); 372 } 373 } 374 375 /* 376 * Show whether kernel tracing is currently on or off. 377 */ 378 void 379 prbk_show_tracing() 380 { 381 tnfctl_trace_attrs_t attrs; 382 383 if (check_kernelmode(&attrs)) 384 return; 385 (void) printf(gettext("Tracing is %s\n"), 386 attrs.trace_state ? "on" : "off"); 387 } 388