xref: /onnv-gate/usr/src/lib/libtnfctl/open.c (revision 11798:1e7f1f154004)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*11798SRoger.Faulkner@Sun.COM  * Common Development and Distribution License (the "License").
6*11798SRoger.Faulkner@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*11798SRoger.Faulkner@Sun.COM 
220Sstevel@tonic-gate /*
23*11798SRoger.Faulkner@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24*11798SRoger.Faulkner@Sun.COM  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Interfaces that return a tnfctl handle back to client (except for
290Sstevel@tonic-gate  * tnfctl_internal_open()) and helper functions for these interfaces.
300Sstevel@tonic-gate  * Also has buffer alloc, buffer dealloc, and trace attributes retrieval
310Sstevel@tonic-gate  * interfaces.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include "tnfctl_int.h"
350Sstevel@tonic-gate #include "kernel_int.h"
360Sstevel@tonic-gate #include "dbg.h"
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <stdlib.h>
390Sstevel@tonic-gate #include <unistd.h>
400Sstevel@tonic-gate #include <signal.h>
410Sstevel@tonic-gate #include <errno.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static tnfctl_errcode_t attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp);
440Sstevel@tonic-gate static tnfctl_errcode_t step_to_end_of_exec(tnfctl_handle_t *hndl);
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * invokes the target program and executes it till the run time linker (rtld)
480Sstevel@tonic-gate  * has loaded in the shared objects (but before any .init sections are
490Sstevel@tonic-gate  * executed).  Returns a pointer to a tnfctl handle.
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_exec_open(const char * pgm_name,char * const * args,char * const * envp,const char * ld_preload,const char * libtnfprobe_path,tnfctl_handle_t ** ret_val)520Sstevel@tonic-gate tnfctl_exec_open(const char *pgm_name, char * const *args,  char * const *envp,
530Sstevel@tonic-gate 		const char *ld_preload,
540Sstevel@tonic-gate 		const char *libtnfprobe_path,
550Sstevel@tonic-gate 		tnfctl_handle_t **ret_val)
560Sstevel@tonic-gate {
570Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
580Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p = NULL;
590Sstevel@tonic-gate 	prb_status_t	prbstat;
600Sstevel@tonic-gate 	uintptr_t	dbgaddr;
610Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 	prbstat = prb_child_create(pgm_name, args, ld_preload, libtnfprobe_path,
64*11798SRoger.Faulkner@Sun.COM 	    envp, &proc_p);
650Sstevel@tonic-gate 	if (prbstat) {
660Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
670Sstevel@tonic-gate 	}
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	/* allocate hdl and zero fill */
700Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
710Sstevel@tonic-gate 	if (hdl == NULL) {
720Sstevel@tonic-gate 		(void) prb_proc_close(proc_p);
730Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
740Sstevel@tonic-gate 	}
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	hdl->proc_p = proc_p;
770Sstevel@tonic-gate 	hdl->mode = DIRECT_MODE;
780Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	/* use native /proc on this target */
810Sstevel@tonic-gate 	hdl->p_read = _tnfctl_read_targ;
820Sstevel@tonic-gate 	hdl->p_write = _tnfctl_write_targ;
830Sstevel@tonic-gate 	hdl->p_obj_iter = _tnfctl_loadobj_iter;
840Sstevel@tonic-gate 	hdl->p_getpid = _tnfctl_pid_get;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	/*
870Sstevel@tonic-gate 	 * get the address of DT_DEBUG and send it in to prb_ layer.
880Sstevel@tonic-gate 	 * This is needed before before prb_rtld_sync() can be called.
890Sstevel@tonic-gate 	 */
900Sstevel@tonic-gate 	prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
910Sstevel@tonic-gate 	if (prexstat)
920Sstevel@tonic-gate 		goto failure_ret;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	prb_dbgaddr(proc_p, dbgaddr);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	/* sync up to rtld sync point */
970Sstevel@tonic-gate 	prbstat = prb_rtld_sync_if_needed(proc_p);
980Sstevel@tonic-gate 	if (prbstat) {
990Sstevel@tonic-gate 		prexstat = _tnfctl_map_to_errcode(prbstat);
1000Sstevel@tonic-gate 		goto failure_ret;
1010Sstevel@tonic-gate 	}
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	/* initialize state in handle */
1040Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
1050Sstevel@tonic-gate 	if (prexstat)
1060Sstevel@tonic-gate 		goto failure_ret;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
1090Sstevel@tonic-gate 	if (prexstat)
1100Sstevel@tonic-gate 		goto failure_ret;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	*ret_val = hdl;
1130Sstevel@tonic-gate 	/* Successful return */
1140Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate failure_ret:
1170Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
1180Sstevel@tonic-gate 	free(hdl);
1190Sstevel@tonic-gate 	return (prexstat);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate  * attaches to a running process.  If the process is in the beginning
1250Sstevel@tonic-gate  * of an exec(2) system call (which is how tnfctl_continue() returns on exec),
1260Sstevel@tonic-gate  * it steps the process till the end of the the exec. If the process hasn't
1270Sstevel@tonic-gate  * reached the rtld sync point, the process is continued until it does
1280Sstevel@tonic-gate  * reach it.  Returns a pointer to a tnfctl handle.
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_pid_open(pid_t pid,tnfctl_handle_t ** ret_val)1310Sstevel@tonic-gate tnfctl_pid_open(pid_t pid, tnfctl_handle_t **ret_val)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
1340Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p = NULL;
1350Sstevel@tonic-gate 	uintptr_t	dbgaddr;
1360Sstevel@tonic-gate 	prb_status_t	prbstat;
1370Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	prexstat = attach_pid(pid, &proc_p);
1400Sstevel@tonic-gate 	if (prexstat) {
1410Sstevel@tonic-gate 		return (prexstat);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	/* allocate hdl and zero fill */
1450Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
1460Sstevel@tonic-gate 	if (hdl == NULL) {
1470Sstevel@tonic-gate 		(void) prb_proc_close(proc_p);
1480Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	hdl->proc_p = proc_p;
1520Sstevel@tonic-gate 	hdl->mode = DIRECT_MODE;
1530Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	/* use native /proc on this target */
1560Sstevel@tonic-gate 	hdl->p_read = _tnfctl_read_targ;
1570Sstevel@tonic-gate 	hdl->p_write = _tnfctl_write_targ;
1580Sstevel@tonic-gate 	hdl->p_obj_iter = _tnfctl_loadobj_iter;
1590Sstevel@tonic-gate 	hdl->p_getpid = _tnfctl_pid_get;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	/*
1620Sstevel@tonic-gate 	 * Since tnfctl_continue() returns when a process does an exec
1630Sstevel@tonic-gate 	 * and leaves the process stopped at the beginning of exec, we
1640Sstevel@tonic-gate 	 * have to be sure to catch this case.
1650Sstevel@tonic-gate 	 */
1660Sstevel@tonic-gate 	prexstat = step_to_end_of_exec(hdl);
1670Sstevel@tonic-gate 	/* proc_p could be side effected by step_to_end_of_exec() */
1680Sstevel@tonic-gate 	proc_p = hdl->proc_p;
1690Sstevel@tonic-gate 	if (prexstat)
1700Sstevel@tonic-gate 		goto failure_ret;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/*
1730Sstevel@tonic-gate 	 * get the address of DT_DEBUG and send it in to prb_ layer.
1740Sstevel@tonic-gate 	 */
1750Sstevel@tonic-gate 	prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
1760Sstevel@tonic-gate 	if (prexstat)
1770Sstevel@tonic-gate 		goto failure_ret;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	prb_dbgaddr(proc_p, dbgaddr);
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/* sync up to rtld sync point if target is not there yet */
1820Sstevel@tonic-gate 	prbstat = prb_rtld_sync_if_needed(proc_p);
1830Sstevel@tonic-gate 	if (prbstat) {
1840Sstevel@tonic-gate 		prexstat = _tnfctl_map_to_errcode(prbstat);
1850Sstevel@tonic-gate 		goto failure_ret;
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/* initialize state in handle */
1890Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
1900Sstevel@tonic-gate 	if (prexstat)
1910Sstevel@tonic-gate 		goto failure_ret;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/* set state in target indicating we're tracing externally */
1940Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
1950Sstevel@tonic-gate 	if (prexstat)
1960Sstevel@tonic-gate 		goto failure_ret;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	*ret_val = hdl;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* Sucessful return */
2010Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate failure_ret:
2040Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
2050Sstevel@tonic-gate 	free(hdl);
2060Sstevel@tonic-gate 	return (prexstat);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate  * open a process for tracing without using native /proc on it.  The client
2110Sstevel@tonic-gate  * provides a set of callback functions which encapsulate the /proc
2120Sstevel@tonic-gate  * functionality we need.  Returns a pointer to a tnfctl handle.
2130Sstevel@tonic-gate  */
2140Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_indirect_open(void * prochandle,tnfctl_ind_config_t * config,tnfctl_handle_t ** ret_val)2150Sstevel@tonic-gate tnfctl_indirect_open(void *prochandle, tnfctl_ind_config_t *config,
2160Sstevel@tonic-gate 		tnfctl_handle_t **ret_val)
2170Sstevel@tonic-gate {
2180Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
2190Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	/* allocate hdl and zero fill */
2220Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
2230Sstevel@tonic-gate 	if (hdl == NULL) {
2240Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	hdl->proc_p = prochandle;
2280Sstevel@tonic-gate 	hdl->mode = INDIRECT_MODE;
2290Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/* initialize callback functions */
2320Sstevel@tonic-gate 	hdl->p_read = config->p_read;
2330Sstevel@tonic-gate 	hdl->p_write = config->p_write;
2340Sstevel@tonic-gate 	hdl->p_obj_iter = config->p_obj_iter;
2350Sstevel@tonic-gate 	hdl->p_getpid = config->p_getpid;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	/* initialize state in handle */
2380Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
2390Sstevel@tonic-gate 	if (prexstat) {
2400Sstevel@tonic-gate 		free(hdl);
2410Sstevel@tonic-gate 		return (prexstat);
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 	/* set state in target indicating we're tracing externally */
2440Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
2450Sstevel@tonic-gate 	if (prexstat) {
246*11798SRoger.Faulkner@Sun.COM 		free(hdl);
247*11798SRoger.Faulkner@Sun.COM 		return (prexstat);
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 	*ret_val = hdl;
2500Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate  * Returns a pointer to a tnfctl handle that can do kernel trace control
2550Sstevel@tonic-gate  * and kernel probe control.
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_kernel_open(tnfctl_handle_t ** ret_val)2580Sstevel@tonic-gate tnfctl_kernel_open(tnfctl_handle_t **ret_val)
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
2610Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	/* allocate hdl and zero fill */
2640Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
2650Sstevel@tonic-gate 	if (hdl == NULL) {
2660Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	/* initialize kernel tracing */
2700Sstevel@tonic-gate 	prexstat = _tnfctl_prbk_init(hdl);
2710Sstevel@tonic-gate 	if (prexstat)
2720Sstevel@tonic-gate 		return (prexstat);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	hdl->mode = KERNEL_MODE;
2750Sstevel@tonic-gate 	hdl->targ_pid = 0;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/* initialize function pointers that can be stuffed into a probe */
2780Sstevel@tonic-gate 	_tnfctl_prbk_get_other_funcs(&hdl->allocfunc, &hdl->commitfunc,
279*11798SRoger.Faulkner@Sun.COM 	    &hdl->rollbackfunc, &hdl->endfunc);
2800Sstevel@tonic-gate 	_tnfctl_prbk_test_func(&hdl->testfunc);
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	/* find the probes in the kernel */
2830Sstevel@tonic-gate 	prexstat = _tnfctl_refresh_kernel(hdl);
2840Sstevel@tonic-gate 	if (prexstat)
2850Sstevel@tonic-gate 		return (prexstat);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	*ret_val = hdl;
2880Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate  * Returns the trace attributes to the client.  Since there can be
2930Sstevel@tonic-gate  * only one controlling agent on a target at a time, our cached information
2940Sstevel@tonic-gate  * is correct and we don't have to actually retrieve any information
2950Sstevel@tonic-gate  * from the target.
2960Sstevel@tonic-gate  */
2970Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_trace_attrs_get(tnfctl_handle_t * hdl,tnfctl_trace_attrs_t * attrs)2980Sstevel@tonic-gate tnfctl_trace_attrs_get(tnfctl_handle_t *hdl, tnfctl_trace_attrs_t *attrs)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	boolean_t		release_lock;
3010Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
3040Sstevel@tonic-gate 	LOCK_SYNC(hdl, prexstat, release_lock);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	attrs->targ_pid = hdl->targ_pid;
3070Sstevel@tonic-gate 	attrs->trace_file_name = hdl->trace_file_name;
3080Sstevel@tonic-gate 	attrs->trace_buf_size = hdl->trace_buf_size;
3090Sstevel@tonic-gate 	attrs->trace_min_size = hdl->trace_min_size;
3100Sstevel@tonic-gate 	attrs->trace_buf_state = hdl->trace_buf_state;
3110Sstevel@tonic-gate 	attrs->trace_state = hdl->trace_state;
3120Sstevel@tonic-gate 	attrs->filter_state = hdl->kpidfilter_state;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
3150Sstevel@tonic-gate 	UNLOCK(hdl, release_lock);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate /*
3220Sstevel@tonic-gate  * Allocate a trace buffer of the specified name and size.
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_buffer_alloc(tnfctl_handle_t * hdl,const char * trace_file_name,uint_t trace_file_size)3250Sstevel@tonic-gate tnfctl_buffer_alloc(tnfctl_handle_t *hdl, const char *trace_file_name,
3260Sstevel@tonic-gate 			uint_t trace_file_size)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (hdl->mode == KERNEL_MODE) {
3310Sstevel@tonic-gate 		/* trace_file_name is ignored in kernel mode */
3320Sstevel@tonic-gate 		prexstat = _tnfctl_prbk_buffer_alloc(hdl, trace_file_size);
3330Sstevel@tonic-gate 		if (prexstat)
3340Sstevel@tonic-gate 			return (prexstat);
3350Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/* Not KERNEL_MODE */
3390Sstevel@tonic-gate 	if (hdl->trace_file_name != NULL) {
3400Sstevel@tonic-gate 		/* buffer already allocated */
3410Sstevel@tonic-gate 		return (TNFCTL_ERR_BUFEXISTS);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	prexstat = _tnfctl_create_tracefile(hdl, trace_file_name,
345*11798SRoger.Faulkner@Sun.COM 	    trace_file_size);
3460Sstevel@tonic-gate 	if (prexstat) {
3470Sstevel@tonic-gate 		return (prexstat);
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate /*
3540Sstevel@tonic-gate  * Deallocate the trace buffer - only works for kernel mode
3550Sstevel@tonic-gate  */
3560Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_buffer_dealloc(tnfctl_handle_t * hdl)3570Sstevel@tonic-gate tnfctl_buffer_dealloc(tnfctl_handle_t *hdl)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	if (hdl->mode != KERNEL_MODE)
3620Sstevel@tonic-gate 		return (TNFCTL_ERR_BADARG);
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	/* KERNEL_MODE */
3650Sstevel@tonic-gate 	prexstat = _tnfctl_prbk_buffer_dealloc(hdl);
3660Sstevel@tonic-gate 	if (prexstat)
3670Sstevel@tonic-gate 		return (prexstat);
3680Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate  * Helper function for attaching to a target process
3740Sstevel@tonic-gate  */
3750Sstevel@tonic-gate static tnfctl_errcode_t
attach_pid(pid_t pid,prb_proc_ctl_t ** proc_pp)3760Sstevel@tonic-gate attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	prb_status_t	prbstat;
3790Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if (getpid() == pid)
3820Sstevel@tonic-gate 		return (TNFCTL_ERR_BADARG);
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/* check if pid is valid */
3850Sstevel@tonic-gate 	if ((kill(pid, 0) == -1) && errno == ESRCH) {
3860Sstevel@tonic-gate 		return (TNFCTL_ERR_NOPROCESS);
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 	/* open up /proc fd */
3890Sstevel@tonic-gate 	prbstat = prb_proc_open(pid, proc_pp);
3900Sstevel@tonic-gate 	if (prbstat)
3910Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	proc_p = *proc_pp;
3940Sstevel@tonic-gate 	/*
3950Sstevel@tonic-gate 	 * default is to run-on-last-close.  In case we cannot sync with
3960Sstevel@tonic-gate 	 * target, we don't want to kill the target.
3970Sstevel@tonic-gate 	 */
3980Sstevel@tonic-gate 	prbstat = prb_proc_setrlc(proc_p, B_TRUE);
3990Sstevel@tonic-gate 	if (prbstat)
4000Sstevel@tonic-gate 		goto failure_ret;
4010Sstevel@tonic-gate 	prbstat = prb_proc_setklc(proc_p, B_FALSE);
4020Sstevel@tonic-gate 	if (prbstat)
4030Sstevel@tonic-gate 		goto failure_ret;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	/* stop process */
4060Sstevel@tonic-gate 	prbstat = prb_proc_stop(proc_p);
4070Sstevel@tonic-gate 	if (prbstat)
4080Sstevel@tonic-gate 		goto failure_ret;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	/* Sucessful return */
4110Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate failure_ret:
4140Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
4150Sstevel@tonic-gate 	return (_tnfctl_map_to_errcode(prbstat));
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate  * Checks if target is at the beginning of an exec system call.  If so,
4200Sstevel@tonic-gate  * it runs it till the end of the exec system call.  It takes care of
4210Sstevel@tonic-gate  * the case where you're about to exec a setuid program.
4220Sstevel@tonic-gate  * CAUTION: could side effect hndl->proc_p
4230Sstevel@tonic-gate  */
4240Sstevel@tonic-gate static tnfctl_errcode_t
step_to_end_of_exec(tnfctl_handle_t * hndl)4250Sstevel@tonic-gate step_to_end_of_exec(tnfctl_handle_t *hndl)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p, *oldproc_p;
4280Sstevel@tonic-gate 	prb_status_t	prbstat, tempstat;
4290Sstevel@tonic-gate 	int		pid;
4300Sstevel@tonic-gate 	prb_proc_state_t	pstate;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	proc_p = hndl->proc_p;
4330Sstevel@tonic-gate 	pid = hndl->p_getpid(proc_p);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &pstate);
4360Sstevel@tonic-gate 	if (prbstat)
4370Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
438*11798SRoger.Faulkner@Sun.COM 	if (!(pstate.ps_issysentry && pstate.ps_syscallnum == SYS_execve)) {
4390Sstevel@tonic-gate 		/* not stopped at beginning of exec system call */
4400Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	/* we are stopped at beginning of exec system call */
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD);
4460Sstevel@tonic-gate 	if (prbstat)
4470Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	prbstat = prb_proc_cont(proc_p);
4500Sstevel@tonic-gate 	if (prbstat)
4510Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
4540Sstevel@tonic-gate 	switch (prbstat) {
4550Sstevel@tonic-gate 	case PRB_STATUS_OK:
4560Sstevel@tonic-gate 		break;
4570Sstevel@tonic-gate 	case EAGAIN:
4580Sstevel@tonic-gate 		/*
4590Sstevel@tonic-gate 		 * If we had exec'ed a setuid/setgid program PIOCWSTOP
4600Sstevel@tonic-gate 		 * will return EAGAIN.  Reopen the 'fd' and try again.
4610Sstevel@tonic-gate 		 * Read the last section of /proc man page - we reopen first
4620Sstevel@tonic-gate 		 * and then close the old fd.
4630Sstevel@tonic-gate 		 */
4640Sstevel@tonic-gate 		oldproc_p = proc_p;
4650Sstevel@tonic-gate 		tempstat = prb_proc_reopen(pid, &proc_p);
4660Sstevel@tonic-gate 		if (tempstat) {
4670Sstevel@tonic-gate 			/* here EACCES means exec'ed a setuid/setgid program */
4680Sstevel@tonic-gate 			return (_tnfctl_map_to_errcode(tempstat));
4690Sstevel@tonic-gate 		}
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 		prb_proc_close(oldproc_p);
4720Sstevel@tonic-gate 		hndl->proc_p = proc_p;
4730Sstevel@tonic-gate 		break;
4740Sstevel@tonic-gate 	default:
4750Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &pstate);
4790Sstevel@tonic-gate 	if (prbstat)
4800Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4810Sstevel@tonic-gate 
482*11798SRoger.Faulkner@Sun.COM 	if (!(pstate.ps_issysexit && pstate.ps_syscallnum == SYS_execve)) {
4830Sstevel@tonic-gate 		/* unexpected condition */
4840Sstevel@tonic-gate 		return (tnfctl_status_map(ENOENT));
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/* clear old interest mask */
4880Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_DEL);
4890Sstevel@tonic-gate 	if (prbstat)
4900Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
4910Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate tnfctl_errcode_t
_tnfctl_external_getlock(tnfctl_handle_t * hdl)4960Sstevel@tonic-gate _tnfctl_external_getlock(tnfctl_handle_t *hdl)
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
5000Sstevel@tonic-gate 	prb_status_t		prbstat;
5010Sstevel@tonic-gate 	uintptr_t		targ_symbol_ptr;
5020Sstevel@tonic-gate 	int			internal_tracing_on;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	prexstat = _tnfctl_sym_find(hdl, TNFCTL_INTERNAL_TRACEFLAG,
505*11798SRoger.Faulkner@Sun.COM 	    &targ_symbol_ptr);
5060Sstevel@tonic-gate 	if (prexstat) {
5070Sstevel@tonic-gate 	/* no libtnfctl in target: success */
5080Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 	prbstat = hdl->p_read(hdl->proc_p, targ_symbol_ptr,
511*11798SRoger.Faulkner@Sun.COM 	    &internal_tracing_on, sizeof (internal_tracing_on));
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	if (prbstat) {
5140Sstevel@tonic-gate 	prexstat = _tnfctl_map_to_errcode(prbstat);
5150Sstevel@tonic-gate 	goto failure_ret;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 	if (internal_tracing_on) {
5180Sstevel@tonic-gate 	/* target process being traced internally */
5190Sstevel@tonic-gate 	prexstat = TNFCTL_ERR_BUSY;
5200Sstevel@tonic-gate 	goto failure_ret;
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate 	prexstat = _tnfctl_sym_find(hdl, TNFCTL_EXTERNAL_TRACEDPID,
523*11798SRoger.Faulkner@Sun.COM 	    &targ_symbol_ptr);
5240Sstevel@tonic-gate 	if (prexstat) {
5250Sstevel@tonic-gate 	/* this shouldn't happen. we know we have libtnfctl */
5260Sstevel@tonic-gate 	goto failure_ret;
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 	prbstat = hdl->p_write(hdl->proc_p, targ_symbol_ptr,
529*11798SRoger.Faulkner@Sun.COM 	    &(hdl->targ_pid), sizeof (hdl->targ_pid));
5300Sstevel@tonic-gate 	if (prbstat) {
5310Sstevel@tonic-gate 	prexstat = _tnfctl_map_to_errcode(prbstat);
5320Sstevel@tonic-gate 	goto failure_ret;
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 	/* success */
5350Sstevel@tonic-gate 	DBG((void) fprintf(stderr, "_tnfctl_external_getlock: ok to trace %d\n",
536*11798SRoger.Faulkner@Sun.COM 	    hdl->targ_pid));
5370Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate failure_ret:
5400Sstevel@tonic-gate 	return (prexstat);
5410Sstevel@tonic-gate }
542