xref: /titanic_51/usr/src/lib/libtnfctl/open.c (revision 8fd04b8338ed5093ec2d1e668fa620b7de44c177)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*8fd04b83SRoger A. Faulkner  * Common Development and Distribution License (the "License").
6*8fd04b83SRoger A. Faulkner  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate 
22*8fd04b83SRoger A. Faulkner /*
23*8fd04b83SRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24*8fd04b83SRoger A. Faulkner  * Use is subject to license terms.
25*8fd04b83SRoger A. Faulkner  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Interfaces that return a tnfctl handle back to client (except for
297c478bd9Sstevel@tonic-gate  * tnfctl_internal_open()) and helper functions for these interfaces.
307c478bd9Sstevel@tonic-gate  * Also has buffer alloc, buffer dealloc, and trace attributes retrieval
317c478bd9Sstevel@tonic-gate  * interfaces.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
357c478bd9Sstevel@tonic-gate #include "kernel_int.h"
367c478bd9Sstevel@tonic-gate #include "dbg.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
397c478bd9Sstevel@tonic-gate #include <unistd.h>
407c478bd9Sstevel@tonic-gate #include <signal.h>
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static tnfctl_errcode_t attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp);
447c478bd9Sstevel@tonic-gate static tnfctl_errcode_t step_to_end_of_exec(tnfctl_handle_t *hndl);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * invokes the target program and executes it till the run time linker (rtld)
487c478bd9Sstevel@tonic-gate  * has loaded in the shared objects (but before any .init sections are
497c478bd9Sstevel@tonic-gate  * executed).  Returns a pointer to a tnfctl handle.
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate tnfctl_errcode_t
527c478bd9Sstevel@tonic-gate tnfctl_exec_open(const char *pgm_name, char * const *args,  char * const *envp,
537c478bd9Sstevel@tonic-gate 		const char *ld_preload,
547c478bd9Sstevel@tonic-gate 		const char *libtnfprobe_path,
557c478bd9Sstevel@tonic-gate 		tnfctl_handle_t **ret_val)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
587c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p = NULL;
597c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
607c478bd9Sstevel@tonic-gate 	uintptr_t	dbgaddr;
617c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	prbstat = prb_child_create(pgm_name, args, ld_preload, libtnfprobe_path,
647c478bd9Sstevel@tonic-gate 	    envp, &proc_p);
657c478bd9Sstevel@tonic-gate 	if (prbstat) {
667c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
677c478bd9Sstevel@tonic-gate 	}
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
707c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
717c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
727c478bd9Sstevel@tonic-gate 		(void) prb_proc_close(proc_p);
737c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	hdl->proc_p = proc_p;
777c478bd9Sstevel@tonic-gate 	hdl->mode = DIRECT_MODE;
787c478bd9Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	/* use native /proc on this target */
817c478bd9Sstevel@tonic-gate 	hdl->p_read = _tnfctl_read_targ;
827c478bd9Sstevel@tonic-gate 	hdl->p_write = _tnfctl_write_targ;
837c478bd9Sstevel@tonic-gate 	hdl->p_obj_iter = _tnfctl_loadobj_iter;
847c478bd9Sstevel@tonic-gate 	hdl->p_getpid = _tnfctl_pid_get;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	/*
877c478bd9Sstevel@tonic-gate 	 * get the address of DT_DEBUG and send it in to prb_ layer.
887c478bd9Sstevel@tonic-gate 	 * This is needed before before prb_rtld_sync() can be called.
897c478bd9Sstevel@tonic-gate 	 */
907c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
917c478bd9Sstevel@tonic-gate 	if (prexstat)
927c478bd9Sstevel@tonic-gate 		goto failure_ret;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	prb_dbgaddr(proc_p, dbgaddr);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/* sync up to rtld sync point */
977c478bd9Sstevel@tonic-gate 	prbstat = prb_rtld_sync_if_needed(proc_p);
987c478bd9Sstevel@tonic-gate 	if (prbstat) {
997c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_map_to_errcode(prbstat);
1007c478bd9Sstevel@tonic-gate 		goto failure_ret;
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	/* initialize state in handle */
1047c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
1057c478bd9Sstevel@tonic-gate 	if (prexstat)
1067c478bd9Sstevel@tonic-gate 		goto failure_ret;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
1097c478bd9Sstevel@tonic-gate 	if (prexstat)
1107c478bd9Sstevel@tonic-gate 		goto failure_ret;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
1137c478bd9Sstevel@tonic-gate 	/* Successful return */
1147c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate failure_ret:
1177c478bd9Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
1187c478bd9Sstevel@tonic-gate 	free(hdl);
1197c478bd9Sstevel@tonic-gate 	return (prexstat);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate  * attaches to a running process.  If the process is in the beginning
1257c478bd9Sstevel@tonic-gate  * of an exec(2) system call (which is how tnfctl_continue() returns on exec),
1267c478bd9Sstevel@tonic-gate  * it steps the process till the end of the the exec. If the process hasn't
1277c478bd9Sstevel@tonic-gate  * reached the rtld sync point, the process is continued until it does
1287c478bd9Sstevel@tonic-gate  * reach it.  Returns a pointer to a tnfctl handle.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate tnfctl_errcode_t
1317c478bd9Sstevel@tonic-gate tnfctl_pid_open(pid_t pid, tnfctl_handle_t **ret_val)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
1347c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p = NULL;
1357c478bd9Sstevel@tonic-gate 	uintptr_t	dbgaddr;
1367c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
1377c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	prexstat = attach_pid(pid, &proc_p);
1407c478bd9Sstevel@tonic-gate 	if (prexstat) {
1417c478bd9Sstevel@tonic-gate 		return (prexstat);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
1457c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
1467c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
1477c478bd9Sstevel@tonic-gate 		(void) prb_proc_close(proc_p);
1487c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	hdl->proc_p = proc_p;
1527c478bd9Sstevel@tonic-gate 	hdl->mode = DIRECT_MODE;
1537c478bd9Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* use native /proc on this target */
1567c478bd9Sstevel@tonic-gate 	hdl->p_read = _tnfctl_read_targ;
1577c478bd9Sstevel@tonic-gate 	hdl->p_write = _tnfctl_write_targ;
1587c478bd9Sstevel@tonic-gate 	hdl->p_obj_iter = _tnfctl_loadobj_iter;
1597c478bd9Sstevel@tonic-gate 	hdl->p_getpid = _tnfctl_pid_get;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	/*
1627c478bd9Sstevel@tonic-gate 	 * Since tnfctl_continue() returns when a process does an exec
1637c478bd9Sstevel@tonic-gate 	 * and leaves the process stopped at the beginning of exec, we
1647c478bd9Sstevel@tonic-gate 	 * have to be sure to catch this case.
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 	prexstat = step_to_end_of_exec(hdl);
1677c478bd9Sstevel@tonic-gate 	/* proc_p could be side effected by step_to_end_of_exec() */
1687c478bd9Sstevel@tonic-gate 	proc_p = hdl->proc_p;
1697c478bd9Sstevel@tonic-gate 	if (prexstat)
1707c478bd9Sstevel@tonic-gate 		goto failure_ret;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/*
1737c478bd9Sstevel@tonic-gate 	 * get the address of DT_DEBUG and send it in to prb_ layer.
1747c478bd9Sstevel@tonic-gate 	 */
1757c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
1767c478bd9Sstevel@tonic-gate 	if (prexstat)
1777c478bd9Sstevel@tonic-gate 		goto failure_ret;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	prb_dbgaddr(proc_p, dbgaddr);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/* sync up to rtld sync point if target is not there yet */
1827c478bd9Sstevel@tonic-gate 	prbstat = prb_rtld_sync_if_needed(proc_p);
1837c478bd9Sstevel@tonic-gate 	if (prbstat) {
1847c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_map_to_errcode(prbstat);
1857c478bd9Sstevel@tonic-gate 		goto failure_ret;
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	/* initialize state in handle */
1897c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
1907c478bd9Sstevel@tonic-gate 	if (prexstat)
1917c478bd9Sstevel@tonic-gate 		goto failure_ret;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/* set state in target indicating we're tracing externally */
1947c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
1957c478bd9Sstevel@tonic-gate 	if (prexstat)
1967c478bd9Sstevel@tonic-gate 		goto failure_ret;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/* Sucessful return */
2017c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate failure_ret:
2047c478bd9Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
2057c478bd9Sstevel@tonic-gate 	free(hdl);
2067c478bd9Sstevel@tonic-gate 	return (prexstat);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate  * open a process for tracing without using native /proc on it.  The client
2117c478bd9Sstevel@tonic-gate  * provides a set of callback functions which encapsulate the /proc
2127c478bd9Sstevel@tonic-gate  * functionality we need.  Returns a pointer to a tnfctl handle.
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate tnfctl_errcode_t
2157c478bd9Sstevel@tonic-gate tnfctl_indirect_open(void *prochandle, tnfctl_ind_config_t *config,
2167c478bd9Sstevel@tonic-gate 		tnfctl_handle_t **ret_val)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
2197c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
2227c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
2237c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
2247c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	hdl->proc_p = prochandle;
2287c478bd9Sstevel@tonic-gate 	hdl->mode = INDIRECT_MODE;
2297c478bd9Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/* initialize callback functions */
2327c478bd9Sstevel@tonic-gate 	hdl->p_read = config->p_read;
2337c478bd9Sstevel@tonic-gate 	hdl->p_write = config->p_write;
2347c478bd9Sstevel@tonic-gate 	hdl->p_obj_iter = config->p_obj_iter;
2357c478bd9Sstevel@tonic-gate 	hdl->p_getpid = config->p_getpid;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/* initialize state in handle */
2387c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
2397c478bd9Sstevel@tonic-gate 	if (prexstat) {
2407c478bd9Sstevel@tonic-gate 		free(hdl);
2417c478bd9Sstevel@tonic-gate 		return (prexstat);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	/* set state in target indicating we're tracing externally */
2447c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
2457c478bd9Sstevel@tonic-gate 	if (prexstat) {
2467c478bd9Sstevel@tonic-gate 		free(hdl);
2477c478bd9Sstevel@tonic-gate 		return (prexstat);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
2507c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Returns a pointer to a tnfctl handle that can do kernel trace control
2557c478bd9Sstevel@tonic-gate  * and kernel probe control.
2567c478bd9Sstevel@tonic-gate  */
2577c478bd9Sstevel@tonic-gate tnfctl_errcode_t
2587c478bd9Sstevel@tonic-gate tnfctl_kernel_open(tnfctl_handle_t **ret_val)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
2617c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
2647c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
2657c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
2667c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/* initialize kernel tracing */
2707c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_prbk_init(hdl);
2717c478bd9Sstevel@tonic-gate 	if (prexstat)
2727c478bd9Sstevel@tonic-gate 		return (prexstat);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	hdl->mode = KERNEL_MODE;
2757c478bd9Sstevel@tonic-gate 	hdl->targ_pid = 0;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	/* initialize function pointers that can be stuffed into a probe */
2787c478bd9Sstevel@tonic-gate 	_tnfctl_prbk_get_other_funcs(&hdl->allocfunc, &hdl->commitfunc,
2797c478bd9Sstevel@tonic-gate 	    &hdl->rollbackfunc, &hdl->endfunc);
2807c478bd9Sstevel@tonic-gate 	_tnfctl_prbk_test_func(&hdl->testfunc);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	/* find the probes in the kernel */
2837c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_refresh_kernel(hdl);
2847c478bd9Sstevel@tonic-gate 	if (prexstat)
2857c478bd9Sstevel@tonic-gate 		return (prexstat);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
2887c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate  * Returns the trace attributes to the client.  Since there can be
2937c478bd9Sstevel@tonic-gate  * only one controlling agent on a target at a time, our cached information
2947c478bd9Sstevel@tonic-gate  * is correct and we don't have to actually retrieve any information
2957c478bd9Sstevel@tonic-gate  * from the target.
2967c478bd9Sstevel@tonic-gate  */
2977c478bd9Sstevel@tonic-gate tnfctl_errcode_t
2987c478bd9Sstevel@tonic-gate tnfctl_trace_attrs_get(tnfctl_handle_t *hdl, tnfctl_trace_attrs_t *attrs)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 	boolean_t		release_lock;
3017c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
3047c478bd9Sstevel@tonic-gate 	LOCK_SYNC(hdl, prexstat, release_lock);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	attrs->targ_pid = hdl->targ_pid;
3077c478bd9Sstevel@tonic-gate 	attrs->trace_file_name = hdl->trace_file_name;
3087c478bd9Sstevel@tonic-gate 	attrs->trace_buf_size = hdl->trace_buf_size;
3097c478bd9Sstevel@tonic-gate 	attrs->trace_min_size = hdl->trace_min_size;
3107c478bd9Sstevel@tonic-gate 	attrs->trace_buf_state = hdl->trace_buf_state;
3117c478bd9Sstevel@tonic-gate 	attrs->trace_state = hdl->trace_state;
3127c478bd9Sstevel@tonic-gate 	attrs->filter_state = hdl->kpidfilter_state;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
3157c478bd9Sstevel@tonic-gate 	UNLOCK(hdl, release_lock);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * Allocate a trace buffer of the specified name and size.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate tnfctl_errcode_t
3257c478bd9Sstevel@tonic-gate tnfctl_buffer_alloc(tnfctl_handle_t *hdl, const char *trace_file_name,
3267c478bd9Sstevel@tonic-gate 			uint_t trace_file_size)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (hdl->mode == KERNEL_MODE) {
3317c478bd9Sstevel@tonic-gate 		/* trace_file_name is ignored in kernel mode */
3327c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_prbk_buffer_alloc(hdl, trace_file_size);
3337c478bd9Sstevel@tonic-gate 		if (prexstat)
3347c478bd9Sstevel@tonic-gate 			return (prexstat);
3357c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	/* Not KERNEL_MODE */
3397c478bd9Sstevel@tonic-gate 	if (hdl->trace_file_name != NULL) {
3407c478bd9Sstevel@tonic-gate 		/* buffer already allocated */
3417c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BUFEXISTS);
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_create_tracefile(hdl, trace_file_name,
3457c478bd9Sstevel@tonic-gate 	    trace_file_size);
3467c478bd9Sstevel@tonic-gate 	if (prexstat) {
3477c478bd9Sstevel@tonic-gate 		return (prexstat);
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate  * Deallocate the trace buffer - only works for kernel mode
3557c478bd9Sstevel@tonic-gate  */
3567c478bd9Sstevel@tonic-gate tnfctl_errcode_t
3577c478bd9Sstevel@tonic-gate tnfctl_buffer_dealloc(tnfctl_handle_t *hdl)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	if (hdl->mode != KERNEL_MODE)
3627c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BADARG);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/* KERNEL_MODE */
3657c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_prbk_buffer_dealloc(hdl);
3667c478bd9Sstevel@tonic-gate 	if (prexstat)
3677c478bd9Sstevel@tonic-gate 		return (prexstat);
3687c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /*
3737c478bd9Sstevel@tonic-gate  * Helper function for attaching to a target process
3747c478bd9Sstevel@tonic-gate  */
3757c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
3767c478bd9Sstevel@tonic-gate attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
3797c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (getpid() == pid)
3827c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BADARG);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	/* check if pid is valid */
3857c478bd9Sstevel@tonic-gate 	if ((kill(pid, 0) == -1) && errno == ESRCH) {
3867c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NOPROCESS);
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 	/* open up /proc fd */
3897c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_open(pid, proc_pp);
3907c478bd9Sstevel@tonic-gate 	if (prbstat)
3917c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	proc_p = *proc_pp;
3947c478bd9Sstevel@tonic-gate 	/*
3957c478bd9Sstevel@tonic-gate 	 * default is to run-on-last-close.  In case we cannot sync with
3967c478bd9Sstevel@tonic-gate 	 * target, we don't want to kill the target.
3977c478bd9Sstevel@tonic-gate 	 */
3987c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_setrlc(proc_p, B_TRUE);
3997c478bd9Sstevel@tonic-gate 	if (prbstat)
4007c478bd9Sstevel@tonic-gate 		goto failure_ret;
4017c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_setklc(proc_p, B_FALSE);
4027c478bd9Sstevel@tonic-gate 	if (prbstat)
4037c478bd9Sstevel@tonic-gate 		goto failure_ret;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	/* stop process */
4067c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_stop(proc_p);
4077c478bd9Sstevel@tonic-gate 	if (prbstat)
4087c478bd9Sstevel@tonic-gate 		goto failure_ret;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	/* Sucessful return */
4117c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate failure_ret:
4147c478bd9Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
4157c478bd9Sstevel@tonic-gate 	return (_tnfctl_map_to_errcode(prbstat));
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate  * Checks if target is at the beginning of an exec system call.  If so,
4207c478bd9Sstevel@tonic-gate  * it runs it till the end of the exec system call.  It takes care of
4217c478bd9Sstevel@tonic-gate  * the case where you're about to exec a setuid program.
4227c478bd9Sstevel@tonic-gate  * CAUTION: could side effect hndl->proc_p
4237c478bd9Sstevel@tonic-gate  */
4247c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
4257c478bd9Sstevel@tonic-gate step_to_end_of_exec(tnfctl_handle_t *hndl)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p, *oldproc_p;
4287c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat, tempstat;
4297c478bd9Sstevel@tonic-gate 	int		pid;
4307c478bd9Sstevel@tonic-gate 	prb_proc_state_t	pstate;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	proc_p = hndl->proc_p;
4337c478bd9Sstevel@tonic-gate 	pid = hndl->p_getpid(proc_p);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &pstate);
4367c478bd9Sstevel@tonic-gate 	if (prbstat)
4377c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
438*8fd04b83SRoger A. Faulkner 	if (!(pstate.ps_issysentry && pstate.ps_syscallnum == SYS_execve)) {
4397c478bd9Sstevel@tonic-gate 		/* not stopped at beginning of exec system call */
4407c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/* we are stopped at beginning of exec system call */
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD);
4467c478bd9Sstevel@tonic-gate 	if (prbstat)
4477c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_cont(proc_p);
4507c478bd9Sstevel@tonic-gate 	if (prbstat)
4517c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
4547c478bd9Sstevel@tonic-gate 	switch (prbstat) {
4557c478bd9Sstevel@tonic-gate 	case PRB_STATUS_OK:
4567c478bd9Sstevel@tonic-gate 		break;
4577c478bd9Sstevel@tonic-gate 	case EAGAIN:
4587c478bd9Sstevel@tonic-gate 		/*
4597c478bd9Sstevel@tonic-gate 		 * If we had exec'ed a setuid/setgid program PIOCWSTOP
4607c478bd9Sstevel@tonic-gate 		 * will return EAGAIN.  Reopen the 'fd' and try again.
4617c478bd9Sstevel@tonic-gate 		 * Read the last section of /proc man page - we reopen first
4627c478bd9Sstevel@tonic-gate 		 * and then close the old fd.
4637c478bd9Sstevel@tonic-gate 		 */
4647c478bd9Sstevel@tonic-gate 		oldproc_p = proc_p;
4657c478bd9Sstevel@tonic-gate 		tempstat = prb_proc_reopen(pid, &proc_p);
4667c478bd9Sstevel@tonic-gate 		if (tempstat) {
4677c478bd9Sstevel@tonic-gate 			/* here EACCES means exec'ed a setuid/setgid program */
4687c478bd9Sstevel@tonic-gate 			return (_tnfctl_map_to_errcode(tempstat));
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		prb_proc_close(oldproc_p);
4727c478bd9Sstevel@tonic-gate 		hndl->proc_p = proc_p;
4737c478bd9Sstevel@tonic-gate 		break;
4747c478bd9Sstevel@tonic-gate 	default:
4757c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &pstate);
4797c478bd9Sstevel@tonic-gate 	if (prbstat)
4807c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4817c478bd9Sstevel@tonic-gate 
482*8fd04b83SRoger A. Faulkner 	if (!(pstate.ps_issysexit && pstate.ps_syscallnum == SYS_execve)) {
4837c478bd9Sstevel@tonic-gate 		/* unexpected condition */
4847c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(ENOENT));
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/* clear old interest mask */
4887c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_DEL);
4897c478bd9Sstevel@tonic-gate 	if (prbstat)
4907c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4917c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate tnfctl_errcode_t
4967c478bd9Sstevel@tonic-gate _tnfctl_external_getlock(tnfctl_handle_t *hdl)
4977c478bd9Sstevel@tonic-gate {
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
5007c478bd9Sstevel@tonic-gate 	prb_status_t		prbstat;
5017c478bd9Sstevel@tonic-gate 	uintptr_t		targ_symbol_ptr;
5027c478bd9Sstevel@tonic-gate 	int			internal_tracing_on;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_sym_find(hdl, TNFCTL_INTERNAL_TRACEFLAG,
5057c478bd9Sstevel@tonic-gate 	    &targ_symbol_ptr);
5067c478bd9Sstevel@tonic-gate 	if (prexstat) {
5077c478bd9Sstevel@tonic-gate 	/* no libtnfctl in target: success */
5087c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 	prbstat = hdl->p_read(hdl->proc_p, targ_symbol_ptr,
5117c478bd9Sstevel@tonic-gate 	    &internal_tracing_on, sizeof (internal_tracing_on));
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (prbstat) {
5147c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_map_to_errcode(prbstat);
5157c478bd9Sstevel@tonic-gate 	goto failure_ret;
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 	if (internal_tracing_on) {
5187c478bd9Sstevel@tonic-gate 	/* target process being traced internally */
5197c478bd9Sstevel@tonic-gate 	prexstat = TNFCTL_ERR_BUSY;
5207c478bd9Sstevel@tonic-gate 	goto failure_ret;
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_sym_find(hdl, TNFCTL_EXTERNAL_TRACEDPID,
5237c478bd9Sstevel@tonic-gate 	    &targ_symbol_ptr);
5247c478bd9Sstevel@tonic-gate 	if (prexstat) {
5257c478bd9Sstevel@tonic-gate 	/* this shouldn't happen. we know we have libtnfctl */
5267c478bd9Sstevel@tonic-gate 	goto failure_ret;
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 	prbstat = hdl->p_write(hdl->proc_p, targ_symbol_ptr,
5297c478bd9Sstevel@tonic-gate 	    &(hdl->targ_pid), sizeof (hdl->targ_pid));
5307c478bd9Sstevel@tonic-gate 	if (prbstat) {
5317c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_map_to_errcode(prbstat);
5327c478bd9Sstevel@tonic-gate 	goto failure_ret;
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 	/* success */
5357c478bd9Sstevel@tonic-gate 	DBG((void) fprintf(stderr, "_tnfctl_external_getlock: ok to trace %d\n",
5367c478bd9Sstevel@tonic-gate 	    hdl->targ_pid));
5377c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate failure_ret:
5407c478bd9Sstevel@tonic-gate 	return (prexstat);
5417c478bd9Sstevel@tonic-gate }
542