17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright (c) 1994, by Sun Microsytems, Inc.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate/*
277c478bdstevel@tonic-gate * Interfaces to control kernel tracing and kernel probes
287c478bdstevel@tonic-gate */
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate#ifndef DEBUG
317c478bdstevel@tonic-gate#define	NDEBUG	1
327c478bdstevel@tonic-gate#endif
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate#include <stdio.h>
357c478bdstevel@tonic-gate#include <stdlib.h>
367c478bdstevel@tonic-gate#include <unistd.h>
377c478bdstevel@tonic-gate#include <string.h>	/* for strerror() */
387c478bdstevel@tonic-gate#include <sys/types.h>
397c478bdstevel@tonic-gate#include <sys/stat.h>
407c478bdstevel@tonic-gate#include <sys/tnf.h>
417c478bdstevel@tonic-gate#include <fcntl.h>
427c478bdstevel@tonic-gate#include <errno.h>
437c478bdstevel@tonic-gate#include <signal.h>
447c478bdstevel@tonic-gate#include <assert.h>
457c478bdstevel@tonic-gate
467c478bdstevel@tonic-gate#include "tnfctl_int.h"
477c478bdstevel@tonic-gate#include "kernel_int.h"
487c478bdstevel@tonic-gate
497c478bdstevel@tonic-gate/* The TNF pseudo-device */
507c478bdstevel@tonic-gate#define	TNFDRIVER	"/dev/tnfctl"
517c478bdstevel@tonic-gate
527c478bdstevel@tonic-gate/* Dummy "test" function  -- just used to flag enabled probes */
537c478bdstevel@tonic-gate#define	PRBK_DUMMY_TEST	((tnf_probe_test_func_t) 4)
547c478bdstevel@tonic-gate
557c478bdstevel@tonic-gate/* Dummy "commit" function -- just used to flag trace enabled */
567c478bdstevel@tonic-gate#define	PRBK_DUMMY_COMMIT ((tnf_probe_func_t) 8)
577c478bdstevel@tonic-gate
587c478bdstevel@tonic-gate/* Dummy "rollback" function -- just used to flag trace disabled */
597c478bdstevel@tonic-gate#define	PRBK_DUMMY_ROLLBACK ((tnf_probe_func_t) 12)
607c478bdstevel@tonic-gate
617c478bdstevel@tonic-gate/* Dummy "end" function */
627c478bdstevel@tonic-gate#define	PRBK_DUMMY_END ((uintptr_t) 16)
637c478bdstevel@tonic-gate
647c478bdstevel@tonic-gate/* Dummy "alloc" function */
657c478bdstevel@tonic-gate#define	PRBK_DUMMY_ALLOC ((uintptr_t) 20)
667c478bdstevel@tonic-gate
677c478bdstevel@tonic-gate/* Minimum and maximum allowed buffer sizes. */
687c478bdstevel@tonic-gate/* XXX -- maximum should be some function of physmem. */
697c478bdstevel@tonic-gate#define	KERNEL_MINBUF_SIZE	(128 * 1024)
707c478bdstevel@tonic-gate#define	KERNEL_MAXBUF_SIZE	(128 * 1024 * 1024)
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gatestatic tnfctl_errcode_t prbk_get_buf_attrs(tnfctl_handle_t *hdl);
737c478bdstevel@tonic-gatestatic tnfctl_errcode_t alloc_probe_space(tnfctl_handle_t *hndl, int maxprobe);
747c478bdstevel@tonic-gate
757c478bdstevel@tonic-gate/*
767c478bdstevel@tonic-gate * Initialize the kernel interface:  Open the TNF control device,
777c478bdstevel@tonic-gate * and determine the current kernel probes state, including the
787c478bdstevel@tonic-gate * current pidfilter list.
797c478bdstevel@tonic-gate */
807c478bdstevel@tonic-gatetnfctl_errcode_t
817c478bdstevel@tonic-gate_tnfctl_prbk_init(tnfctl_handle_t *hdl)
827c478bdstevel@tonic-gate{
837c478bdstevel@tonic-gate	tnfctl_errcode_t prexstat;
847c478bdstevel@tonic-gate	tifiocstate_t kstate;
857c478bdstevel@tonic-gate	int kfd;
867c478bdstevel@tonic-gate
877c478bdstevel@tonic-gate	kfd = open(TNFDRIVER, O_RDWR);
887c478bdstevel@tonic-gate	if (kfd < 0) {
897c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
907c478bdstevel@tonic-gate	}
917c478bdstevel@tonic-gate	if (ioctl(kfd, TIFIOCGSTATE, &kstate) < 0)
927c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
937c478bdstevel@tonic-gate
947c478bdstevel@tonic-gate	hdl->kfd = kfd;
957c478bdstevel@tonic-gate	hdl->kpidfilter_state = kstate.pidfilter_mode;
967c478bdstevel@tonic-gate	hdl->trace_state = !kstate.trace_stopped;
977c478bdstevel@tonic-gate	hdl->trace_min_size = KERNEL_MINBUF_SIZE;
987c478bdstevel@tonic-gate	prexstat = prbk_get_buf_attrs(hdl);
997c478bdstevel@tonic-gate	if (prexstat)
1007c478bdstevel@tonic-gate		return (prexstat);
1017c478bdstevel@tonic-gate
1027c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
1037c478bdstevel@tonic-gate}
1047c478bdstevel@tonic-gate
1057c478bdstevel@tonic-gate/*
1067c478bdstevel@tonic-gate * Close the TNF control device.
1077c478bdstevel@tonic-gate */
1087c478bdstevel@tonic-gatetnfctl_errcode_t
1097c478bdstevel@tonic-gate_tnfctl_prbk_close(tnfctl_handle_t *hdl)
1107c478bdstevel@tonic-gate{
1117c478bdstevel@tonic-gate	if (hdl == NULL)
1127c478bdstevel@tonic-gate		return (TNFCTL_ERR_NONE);
1137c478bdstevel@tonic-gate
1147c478bdstevel@tonic-gate	if (close(hdl->kfd) == -1) {
1157c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
1167c478bdstevel@tonic-gate	}
1177c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
1187c478bdstevel@tonic-gate}
1197c478bdstevel@tonic-gate
1207c478bdstevel@tonic-gate/*
1217c478bdstevel@tonic-gate * Returns function addresses that can be plugged into function pointers
1227c478bdstevel@tonic-gate * in kernel probes.  These are actually dummy values that get
1237c478bdstevel@tonic-gate * interpreted by a routine in this file when a probe is flushed.
1247c478bdstevel@tonic-gate */
1257c478bdstevel@tonic-gatevoid
1267c478bdstevel@tonic-gate_tnfctl_prbk_get_other_funcs(uintptr_t *allocp, uintptr_t *commitp,
1277c478bdstevel@tonic-gate	uintptr_t *rollbackp, uintptr_t *endp)
1287c478bdstevel@tonic-gate{
1297c478bdstevel@tonic-gate	*allocp = PRBK_DUMMY_ALLOC;
1307c478bdstevel@tonic-gate	*commitp = (uintptr_t) PRBK_DUMMY_COMMIT;
1317c478bdstevel@tonic-gate	*rollbackp = (uintptr_t) PRBK_DUMMY_ROLLBACK;
1327c478bdstevel@tonic-gate	*endp = PRBK_DUMMY_END;
1337c478bdstevel@tonic-gate}
1347c478bdstevel@tonic-gate
1357c478bdstevel@tonic-gate
1367c478bdstevel@tonic-gate/*
1377c478bdstevel@tonic-gate * Returns test function address
1387c478bdstevel@tonic-gate */
1397c478bdstevel@tonic-gatevoid
1407c478bdstevel@tonic-gate_tnfctl_prbk_test_func(uintptr_t *outp)
1417c478bdstevel@tonic-gate{
1427c478bdstevel@tonic-gate	*outp = (uintptr_t) PRBK_DUMMY_TEST;
1437c478bdstevel@tonic-gate}
1447c478bdstevel@tonic-gate
1457c478bdstevel@tonic-gate/*
1467c478bdstevel@tonic-gate * Allocate a trace buffer.  Check for reasonable size; reject if there's
1477c478bdstevel@tonic-gate * already a buffer.
1487c478bdstevel@tonic-gate */
1497c478bdstevel@tonic-gatetnfctl_errcode_t
1507c478bdstevel@tonic-gate_tnfctl_prbk_buffer_alloc(tnfctl_handle_t *hdl, int size)
1517c478bdstevel@tonic-gate{
1527c478bdstevel@tonic-gate	tifiocstate_t bufstat;
1537c478bdstevel@tonic-gate	tnfctl_errcode_t prexstat;
1547c478bdstevel@tonic-gate	int saved_val;
1557c478bdstevel@tonic-gate
1567c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCGSTATE, &bufstat) < 0) {
1577c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
1587c478bdstevel@tonic-gate	}
1597c478bdstevel@tonic-gate	if (bufstat.buffer_state != TIFIOCBUF_NONE) {
1607c478bdstevel@tonic-gate		return (TNFCTL_ERR_BUFEXISTS);
1617c478bdstevel@tonic-gate	}
1627c478bdstevel@tonic-gate	if (size < KERNEL_MINBUF_SIZE) {
1637c478bdstevel@tonic-gate		return (TNFCTL_ERR_SIZETOOSMALL);
1647c478bdstevel@tonic-gate	} else if (size > KERNEL_MAXBUF_SIZE) {
1657c478bdstevel@tonic-gate		/* REMIND: make this an error ? */
1667c478bdstevel@tonic-gate		size = KERNEL_MAXBUF_SIZE;
1677c478bdstevel@tonic-gate	}
1687c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCALLOCBUF, size) < 0) {
1697c478bdstevel@tonic-gate		saved_val = errno;
1707c478bdstevel@tonic-gate		(void) prbk_get_buf_attrs(hdl);
1717c478bdstevel@tonic-gate		return (tnfctl_status_map(saved_val));
1727c478bdstevel@tonic-gate	}
1737c478bdstevel@tonic-gate
1747c478bdstevel@tonic-gate	prexstat = prbk_get_buf_attrs(hdl);
1757c478bdstevel@tonic-gate	if (prexstat)
1767c478bdstevel@tonic-gate		return (prexstat);
1777c478bdstevel@tonic-gate
1787c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
1797c478bdstevel@tonic-gate}
1807c478bdstevel@tonic-gate
1817c478bdstevel@tonic-gate/*
1827c478bdstevel@tonic-gate * Deallocate the kernel's trace buffer.
1837c478bdstevel@tonic-gate */
1847c478bdstevel@tonic-gatetnfctl_errcode_t
1857c478bdstevel@tonic-gate_tnfctl_prbk_buffer_dealloc(tnfctl_handle_t *hdl)
1867c478bdstevel@tonic-gate{
1877c478bdstevel@tonic-gate	tifiocstate_t bufstat;
1887c478bdstevel@tonic-gate	tnfctl_errcode_t prexstat;
1897c478bdstevel@tonic-gate	int saved_val;
1907c478bdstevel@tonic-gate
1917c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCGSTATE, &bufstat) < 0) {
1927c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
1937c478bdstevel@tonic-gate	}
1947c478bdstevel@tonic-gate	if (bufstat.buffer_state == TIFIOCBUF_NONE) {
1957c478bdstevel@tonic-gate		return (TNFCTL_ERR_NOBUF);
1967c478bdstevel@tonic-gate	}
1977c478bdstevel@tonic-gate
1987c478bdstevel@tonic-gate	if (bufstat.buffer_state == TIFIOCBUF_OK && !bufstat.trace_stopped) {
1997c478bdstevel@tonic-gate		return (TNFCTL_ERR_BADDEALLOC);
2007c478bdstevel@tonic-gate	}
2017c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCDEALLOCBUF) < 0) {
2027c478bdstevel@tonic-gate		saved_val = errno;
2037c478bdstevel@tonic-gate		(void) prbk_get_buf_attrs(hdl);
2047c478bdstevel@tonic-gate		return (tnfctl_status_map(saved_val));
2057c478bdstevel@tonic-gate	}
2067c478bdstevel@tonic-gate
2077c478bdstevel@tonic-gate	prexstat = prbk_get_buf_attrs(hdl);
2087c478bdstevel@tonic-gate	if (prexstat)
2097c478bdstevel@tonic-gate		return (prexstat);
2107c478bdstevel@tonic-gate
2117c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
2127c478bdstevel@tonic-gate}
2137c478bdstevel@tonic-gate
2147c478bdstevel@tonic-gate/*
2157c478bdstevel@tonic-gate * Turns kernel global tracing on or off.
2167c478bdstevel@tonic-gate */
2177c478bdstevel@tonic-gatetnfctl_errcode_t
2187c478bdstevel@tonic-gate_tnfctl_prbk_set_tracing(tnfctl_handle_t *hdl, boolean_t onoff)
2197c478bdstevel@tonic-gate{
2207c478bdstevel@tonic-gate	if (hdl->trace_state != onoff &&
2217c478bdstevel@tonic-gate	    ioctl(hdl->kfd, TIFIOCSTRACING, onoff) < 0) {
2227c478bdstevel@tonic-gate		if (errno == ENOMEM && onoff)
2237c478bdstevel@tonic-gate			return (TNFCTL_ERR_NOBUF);
2247c478bdstevel@tonic-gate		else
2257c478bdstevel@tonic-gate			return (tnfctl_status_map(errno));
2267c478bdstevel@tonic-gate	}
2277c478bdstevel@tonic-gate	hdl->trace_state = onoff;
2287c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
2297c478bdstevel@tonic-gate}
2307c478bdstevel@tonic-gate
2317c478bdstevel@tonic-gate/*
2327c478bdstevel@tonic-gate * Turn process filter mode on or off.  The process filter is maintained
2337c478bdstevel@tonic-gate * even when process filtering is off, but has no effect:  all processes
2347c478bdstevel@tonic-gate * are traced.
2357c478bdstevel@tonic-gate */
2367c478bdstevel@tonic-gatetnfctl_errcode_t
2377c478bdstevel@tonic-gate_tnfctl_prbk_set_pfilter_mode(tnfctl_handle_t *hdl, boolean_t onoff)
2387c478bdstevel@tonic-gate{
2397c478bdstevel@tonic-gate	if (hdl->kpidfilter_state != onoff &&
2407c478bdstevel@tonic-gate	    ioctl(hdl->kfd, TIFIOCSPIDFILTER, onoff) < 0) {
2417c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
2427c478bdstevel@tonic-gate	}
2437c478bdstevel@tonic-gate	hdl->kpidfilter_state = onoff;
2447c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
2457c478bdstevel@tonic-gate}
2467c478bdstevel@tonic-gate
2477c478bdstevel@tonic-gate/*
2487c478bdstevel@tonic-gate * Return the process filter list.
2497c478bdstevel@tonic-gate */
2507c478bdstevel@tonic-gatetnfctl_errcode_t
2517c478bdstevel@tonic-gate_tnfctl_prbk_get_pfilter_list(tnfctl_handle_t *hdl, pid_t **ret_list_p,
2527c478bdstevel@tonic-gate				int *ret_count)
2537c478bdstevel@tonic-gate{
2547c478bdstevel@tonic-gate	tifiocstate_t kstate;
2557c478bdstevel@tonic-gate	int *filterset;
2567c478bdstevel@tonic-gate	int i;
2577c478bdstevel@tonic-gate	pid_t *ret_list;
2587c478bdstevel@tonic-gate
2597c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCGSTATE, &kstate) < 0)
2607c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
2617c478bdstevel@tonic-gate
2627c478bdstevel@tonic-gate	if (kstate.pidfilter_size == 0) {
2637c478bdstevel@tonic-gate		*ret_count = 0;
2647c478bdstevel@tonic-gate		*ret_list_p = NULL;
2657c478bdstevel@tonic-gate		return (TNFCTL_ERR_NONE);
2667c478bdstevel@tonic-gate	}
2677c478bdstevel@tonic-gate
2687c478bdstevel@tonic-gate	filterset = (int *) malloc((kstate.pidfilter_size + 1) *
2697c478bdstevel@tonic-gate					sizeof (pid_t));
2707c478bdstevel@tonic-gate	if (filterset == NULL)
2717c478bdstevel@tonic-gate		return (TNFCTL_ERR_ALLOCFAIL);
2727c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCPIDFILTERGET, filterset) < 0)
2737c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate	/* filterset[0] contains size of array */
2767c478bdstevel@tonic-gate	ret_list = malloc(filterset[0] * sizeof (pid_t));
2777c478bdstevel@tonic-gate	if (ret_list == NULL)
2787c478bdstevel@tonic-gate		return (TNFCTL_ERR_ALLOCFAIL);
2797c478bdstevel@tonic-gate
2807c478bdstevel@tonic-gate	for (i = 1; i <= filterset[0]; ++i)
2817c478bdstevel@tonic-gate		ret_list[i - 1] = filterset[i];
2827c478bdstevel@tonic-gate
2837c478bdstevel@tonic-gate	*ret_count = filterset[0];
2847c478bdstevel@tonic-gate	(void) free(filterset);
2857c478bdstevel@tonic-gate	*ret_list_p = ret_list;
2867c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
2877c478bdstevel@tonic-gate}
2887c478bdstevel@tonic-gate
2897c478bdstevel@tonic-gate/*
2907c478bdstevel@tonic-gate * Add the pid to the process filter list.
2917c478bdstevel@tonic-gate * check whether it's already in the filter list,
2927c478bdstevel@tonic-gate * and whether the process exists.
2937c478bdstevel@tonic-gate */
2947c478bdstevel@tonic-gatetnfctl_errcode_t
2957c478bdstevel@tonic-gate_tnfctl_prbk_pfilter_add(tnfctl_handle_t *hdl, pid_t pid_to_add)
2967c478bdstevel@tonic-gate{
2977c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCSPIDON, pid_to_add) < 0) {
2987c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
2997c478bdstevel@tonic-gate	}
3007c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
3017c478bdstevel@tonic-gate}
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate/*
3047c478bdstevel@tonic-gate * Drop the pid from the process filter list.
3057c478bdstevel@tonic-gate */
3067c478bdstevel@tonic-gatetnfctl_errcode_t
3077c478bdstevel@tonic-gate_tnfctl_prbk_pfilter_delete(tnfctl_handle_t *hdl, pid_t pid_to_del)
3087c478bdstevel@tonic-gate{
3097c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCSPIDOFF, pid_to_del) < 0) {
3107c478bdstevel@tonic-gate		if (errno == ESRCH) {
3117c478bdstevel@tonic-gate			return (TNFCTL_ERR_NOPROCESS);
3127c478bdstevel@tonic-gate		} else {
3137c478bdstevel@tonic-gate			return (tnfctl_status_map(errno));
3147c478bdstevel@tonic-gate		}
3157c478bdstevel@tonic-gate	}
3167c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
3177c478bdstevel@tonic-gate}
3187c478bdstevel@tonic-gate
3197c478bdstevel@tonic-gate/*
3207c478bdstevel@tonic-gate * get the buffer attributes - side effect tnfctl handle
3217c478bdstevel@tonic-gate */
3227c478bdstevel@tonic-gatestatic tnfctl_errcode_t
3237c478bdstevel@tonic-gateprbk_get_buf_attrs(tnfctl_handle_t *hdl)
3247c478bdstevel@tonic-gate{
3257c478bdstevel@tonic-gate	tifiocstate_t bufstat;
3267c478bdstevel@tonic-gate
3277c478bdstevel@tonic-gate	if (ioctl(hdl->kfd, TIFIOCGSTATE, &bufstat) < 0) {
3287c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
3297c478bdstevel@tonic-gate	}
3307c478bdstevel@tonic-gate
3317c478bdstevel@tonic-gate	hdl->trace_file_name = NULL;
3327c478bdstevel@tonic-gate	hdl->trace_buf_size = bufstat.buffer_size;
3337c478bdstevel@tonic-gate	if (bufstat.buffer_state == TIFIOCBUF_NONE)
3347c478bdstevel@tonic-gate		hdl->trace_buf_state = TNFCTL_BUF_NONE;
3357c478bdstevel@tonic-gate	else if (bufstat.buffer_state == TIFIOCBUF_BROKEN)
3367c478bdstevel@tonic-gate		hdl->trace_buf_state = TNFCTL_BUF_BROKEN;
3377c478bdstevel@tonic-gate	else
3387c478bdstevel@tonic-gate		hdl->trace_buf_state = TNFCTL_BUF_OK;
3397c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
3407c478bdstevel@tonic-gate}
3417c478bdstevel@tonic-gate
3427c478bdstevel@tonic-gate/*
3437c478bdstevel@tonic-gate * "Flush" a probe:  i.e., sync up the kernel state with the
3447c478bdstevel@tonic-gate * (desired) state stored in our data structure.
3457c478bdstevel@tonic-gate */
3467c478bdstevel@tonic-gatetnfctl_errcode_t
3477c478bdstevel@tonic-gate_tnfctl_prbk_flush(tnfctl_handle_t *hndl, prbctlref_t *p)
3487c478bdstevel@tonic-gate{
3497c478bdstevel@tonic-gate	tnf_probevals_t probebuf;
3507c478bdstevel@tonic-gate
3517c478bdstevel@tonic-gate	probebuf.probenum = p->probe_id;
3527c478bdstevel@tonic-gate	probebuf.enabled = (p->wrkprbctl.test_func != NULL);
3537c478bdstevel@tonic-gate	probebuf.traced = (p->wrkprbctl.commit_func == PRBK_DUMMY_COMMIT);
3547c478bdstevel@tonic-gate	if (ioctl(hndl->kfd, TIFIOCSPROBEVALS, &probebuf) < 0)
3557c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
3567c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
3577c478bdstevel@tonic-gate}
3587c478bdstevel@tonic-gate
3597c478bdstevel@tonic-gate/*
3607c478bdstevel@tonic-gate * Refresh our understanding of the existing probes in the kernel.
3617c478bdstevel@tonic-gate */
3627c478bdstevel@tonic-gatetnfctl_errcode_t
3637c478bdstevel@tonic-gate_tnfctl_refresh_kernel(tnfctl_handle_t *hndl)
3647c478bdstevel@tonic-gate{
3657c478bdstevel@tonic-gate	int maxprobe, i;
3667c478bdstevel@tonic-gate	int pos;
3677c478bdstevel@tonic-gate	tnfctl_errcode_t prexstat;
3687c478bdstevel@tonic-gate	tnf_probevals_t probebuf;
3697c478bdstevel@tonic-gate	objlist_t *obj_p;
3707c478bdstevel@tonic-gate	prbctlref_t *p = NULL;
3717c478bdstevel@tonic-gate
3727c478bdstevel@tonic-gate	prexstat = prbk_get_buf_attrs(hndl);
3737c478bdstevel@tonic-gate	if (prexstat)
3747c478bdstevel@tonic-gate		return (prexstat);
3757c478bdstevel@tonic-gate	/*
3767c478bdstevel@tonic-gate	 * Here is where you'd set obj_p->new to B_FALSE and obj_p->old to
3777c478bdstevel@tonic-gate	 * B_TRUE for all existing objects.  We currently don't need
3787c478bdstevel@tonic-gate	 * it until we get modload/unload working correctly with probes
3797c478bdstevel@tonic-gate	 */
3807c478bdstevel@tonic-gate	if (ioctl(hndl->kfd, TIFIOCGMAXPROBE, &maxprobe) < 0)
3817c478bdstevel@tonic-gate		return (tnfctl_status_map(errno));
3827c478bdstevel@tonic-gate	if (maxprobe == hndl->num_probes) {
3837c478bdstevel@tonic-gate		/* XXX Inadequate in the presence of module unloading */
3847c478bdstevel@tonic-gate		return (TNFCTL_ERR_NONE);
3857c478bdstevel@tonic-gate	}
3867c478bdstevel@tonic-gate
3877c478bdstevel@tonic-gate	prexstat = alloc_probe_space(hndl, maxprobe);
3887c478bdstevel@tonic-gate	if (prexstat)
3897c478bdstevel@tonic-gate		return (prexstat);
3907c478bdstevel@tonic-gate
3917c478bdstevel@tonic-gate	obj_p = hndl->objlist;
3927c478bdstevel@tonic-gate	assert((obj_p != NULL) && (obj_p->probes != NULL));
3937c478bdstevel@tonic-gate
3947c478bdstevel@tonic-gate	for (i = 1; i <= maxprobe; ++i) {
3957c478bdstevel@tonic-gate
3967c478bdstevel@tonic-gate		if (i >= (obj_p->min_probe_num + obj_p->probecnt)) {
3977c478bdstevel@tonic-gate			obj_p = obj_p->next;
3987c478bdstevel@tonic-gate		}
3997c478bdstevel@tonic-gate
4007c478bdstevel@tonic-gate		/* make sure we are in the correct object */
4017c478bdstevel@tonic-gate		assert(obj_p != NULL);
4027c478bdstevel@tonic-gate		assert((i >= obj_p->min_probe_num) &&
4037c478bdstevel@tonic-gate			(i < (obj_p->min_probe_num + obj_p->probecnt)));
4047c478bdstevel@tonic-gate
4057c478bdstevel@tonic-gate		/* get a pointer to correct probe */
4067c478bdstevel@tonic-gate		pos = i - obj_p->min_probe_num;
4077c478bdstevel@tonic-gate		p = &(obj_p->probes[pos]);
4087c478bdstevel@tonic-gate		assert((p != NULL) && (p->probe_id == i) && (p->probe_handle));
4097c478bdstevel@tonic-gate
4107c478bdstevel@tonic-gate		probebuf.probenum = i;
4117c478bdstevel@tonic-gate		if (ioctl(hndl->kfd, TIFIOCGPROBEVALS, &probebuf) < 0) {
4127c478bdstevel@tonic-gate			if (errno == ENOENT) {
4137c478bdstevel@tonic-gate				/*
4147c478bdstevel@tonic-gate				 * This probe has vanished due to a module
4157c478bdstevel@tonic-gate				 * unload.
4167c478bdstevel@tonic-gate				 */
4177c478bdstevel@tonic-gate				p->probe_handle->valid = B_FALSE;
4187c478bdstevel@tonic-gate			} else {
4197c478bdstevel@tonic-gate				return (tnfctl_status_map(errno));
4207c478bdstevel@tonic-gate			}
4217c478bdstevel@tonic-gate		} else {
4227c478bdstevel@tonic-gate			if (p->probe_handle->valid == B_FALSE) {
4237c478bdstevel@tonic-gate				/*
4247c478bdstevel@tonic-gate				 * seeing this probe for the first time
4257c478bdstevel@tonic-gate				 * (alloc_probe_space() initialized this
4267c478bdstevel@tonic-gate				 * "valid" field to B_FALSE)
4277c478bdstevel@tonic-gate				 */
4287c478bdstevel@tonic-gate				/* Update our info about this probe */
4297c478bdstevel@tonic-gate				p->wrkprbctl.test_func = (probebuf.enabled) ?
4307c478bdstevel@tonic-gate					PRBK_DUMMY_TEST : NULL;
4317c478bdstevel@tonic-gate				p->wrkprbctl.commit_func = (probebuf.traced) ?
4327c478bdstevel@tonic-gate					PRBK_DUMMY_COMMIT : PRBK_DUMMY_ROLLBACK;
4337c478bdstevel@tonic-gate				p->probe_handle->valid = B_TRUE;
4347c478bdstevel@tonic-gate				if (probebuf.attrsize < sizeof (probebuf))
4357c478bdstevel@tonic-gate					probebuf.attrsize = sizeof (probebuf);
4367c478bdstevel@tonic-gate				p->attr_string = malloc(probebuf.attrsize);
4377c478bdstevel@tonic-gate				if (p->attr_string == NULL)
4387c478bdstevel@tonic-gate					return (TNFCTL_ERR_ALLOCFAIL);
4397c478bdstevel@tonic-gate				/*
4407c478bdstevel@tonic-gate				 * NOTE: the next statement is a structure
4417c478bdstevel@tonic-gate				 * copy and *not* a pointer assignment
4427c478bdstevel@tonic-gate				 */
4437c478bdstevel@tonic-gate/* LINTED pointer cast may result in improper alignment */
4447c478bdstevel@tonic-gate				*(tnf_probevals_t *) p->attr_string = probebuf;
4457c478bdstevel@tonic-gate				if (ioctl(hndl->kfd, TIFIOCGPROBESTRING,
4467c478bdstevel@tonic-gate						p->attr_string) < 0)
4477c478bdstevel@tonic-gate					return (tnfctl_status_map(errno));
4487c478bdstevel@tonic-gate				if (hndl->create_func) {
4497c478bdstevel@tonic-gate				    p->probe_handle->client_registered_data =
4507c478bdstevel@tonic-gate					hndl->create_func(hndl,
4517c478bdstevel@tonic-gate						p->probe_handle);
4527c478bdstevel@tonic-gate				}
4537c478bdstevel@tonic-gate			}
4547c478bdstevel@tonic-gate		}
4557c478bdstevel@tonic-gate	}
4567c478bdstevel@tonic-gate	hndl->num_probes = maxprobe;
4577c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
4587c478bdstevel@tonic-gate}
4597c478bdstevel@tonic-gate
4607c478bdstevel@tonic-gate/*
4617c478bdstevel@tonic-gate * check if there are any new probes in the kernel that we aren't aware of.
4627c478bdstevel@tonic-gate * If so, allocate space for those probes in our data structure.
4637c478bdstevel@tonic-gate */
4647c478bdstevel@tonic-gatestatic tnfctl_errcode_t
4657c478bdstevel@tonic-gatealloc_probe_space(tnfctl_handle_t *hndl, int maxprobe)
4667c478bdstevel@tonic-gate{
4677c478bdstevel@tonic-gate	objlist_t **o_pp;
4687c478bdstevel@tonic-gate	objlist_t *obj_p, *nobj_p;
4697c478bdstevel@tonic-gate	int min_probe_num, i;
4707c478bdstevel@tonic-gate	prbctlref_t *probe_p;
4717c478bdstevel@tonic-gate
4727c478bdstevel@tonic-gate	/* we know that: hndl->maxprobe != maxprobe */
4737c478bdstevel@tonic-gate	obj_p = hndl->objlist;
4747c478bdstevel@tonic-gate	if (obj_p == NULL) {
4757c478bdstevel@tonic-gate		/* no objects allocated */
4767c478bdstevel@tonic-gate		o_pp = &(hndl->objlist);
4777c478bdstevel@tonic-gate		min_probe_num = 1;
4787c478bdstevel@tonic-gate	} else {
4797c478bdstevel@tonic-gate		/* find last object */
4807c478bdstevel@tonic-gate		while (obj_p->next != NULL) {
4817c478bdstevel@tonic-gate			/* reset new_probe field on modload/unload */
4827c478bdstevel@tonic-gate			obj_p->new_probe = B_FALSE;
4837c478bdstevel@tonic-gate			obj_p = obj_p->next;
4847c478bdstevel@tonic-gate		}
4857c478bdstevel@tonic-gate		o_pp = &(obj_p->next);
4867c478bdstevel@tonic-gate		min_probe_num = obj_p->min_probe_num + obj_p->probecnt;
4877c478bdstevel@tonic-gate	}
4887c478bdstevel@tonic-gate
4897c478bdstevel@tonic-gate	nobj_p = calloc(1, sizeof (objlist_t));
4907c478bdstevel@tonic-gate	if (nobj_p == NULL)
4917c478bdstevel@tonic-gate		return (TNFCTL_ERR_ALLOCFAIL);
4927c478bdstevel@tonic-gate	/* add to the linked list */
4937c478bdstevel@tonic-gate	*o_pp = nobj_p;
4947c478bdstevel@tonic-gate	/* NULL, B_FALSE, or 0's not explicitly initialized */
4957c478bdstevel@tonic-gate	nobj_p->new_probe = B_TRUE;
4967c478bdstevel@tonic-gate	nobj_p->new = B_TRUE;
4977c478bdstevel@tonic-gate	nobj_p->objfd = -1;
4987c478bdstevel@tonic-gate	nobj_p->min_probe_num = min_probe_num;
4997c478bdstevel@tonic-gate	nobj_p->probecnt = maxprobe - min_probe_num + 1;
5007c478bdstevel@tonic-gate	nobj_p->probes = calloc(nobj_p->probecnt,  sizeof (prbctlref_t));
5017c478bdstevel@tonic-gate	if (nobj_p->probes == NULL) {
5027c478bdstevel@tonic-gate		free(nobj_p);
5037c478bdstevel@tonic-gate		return (TNFCTL_ERR_ALLOCFAIL);
5047c478bdstevel@tonic-gate	}
5057c478bdstevel@tonic-gate
5067c478bdstevel@tonic-gate	probe_p = &(nobj_p->probes[0]);
5077c478bdstevel@tonic-gate	for (i = min_probe_num; i <= maxprobe; i++) {
5087c478bdstevel@tonic-gate		probe_p->obj = nobj_p;
5097c478bdstevel@tonic-gate		probe_p->probe_id = i;
5107c478bdstevel@tonic-gate		probe_p->probe_handle = calloc(1, sizeof (tnfctl_probe_t));
5117c478bdstevel@tonic-gate		if (probe_p->probe_handle == NULL) {
5127c478bdstevel@tonic-gate			if (nobj_p->probes)
5137c478bdstevel@tonic-gate				free(nobj_p->probes);
5147c478bdstevel@tonic-gate			free(nobj_p);
5157c478bdstevel@tonic-gate			return (TNFCTL_ERR_ALLOCFAIL);
5167c478bdstevel@tonic-gate		}
5177c478bdstevel@tonic-gate		probe_p->probe_handle->valid = B_FALSE;
5187c478bdstevel@tonic-gate		probe_p->probe_handle->probe_p = probe_p;
5197c478bdstevel@tonic-gate		/* link in probe handle into chain off tnfctl_handle_t */
5207c478bdstevel@tonic-gate		probe_p->probe_handle->next = hndl->probe_handle_list_head;
5217c478bdstevel@tonic-gate		hndl->probe_handle_list_head = probe_p->probe_handle;
5227c478bdstevel@tonic-gate
5237c478bdstevel@tonic-gate		probe_p++;
5247c478bdstevel@tonic-gate	}
5257c478bdstevel@tonic-gate
5267c478bdstevel@tonic-gate	hndl->num_probes = maxprobe;
5277c478bdstevel@tonic-gate	return (TNFCTL_ERR_NONE);
5287c478bdstevel@tonic-gate}
529