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