xref: /titanic_44/usr/src/lib/libtnfctl/open.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1994, by Sun Microsytems, Inc.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * Interfaces that return a tnfctl handle back to client (except for
30*7c478bd9Sstevel@tonic-gate  * tnfctl_internal_open()) and helper functions for these interfaces.
31*7c478bd9Sstevel@tonic-gate  * Also has buffer alloc, buffer dealloc, and trace attributes retrieval
32*7c478bd9Sstevel@tonic-gate  * interfaces.
33*7c478bd9Sstevel@tonic-gate  */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
36*7c478bd9Sstevel@tonic-gate #include "kernel_int.h"
37*7c478bd9Sstevel@tonic-gate #include "dbg.h"
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
40*7c478bd9Sstevel@tonic-gate #include <unistd.h>
41*7c478bd9Sstevel@tonic-gate #include <signal.h>
42*7c478bd9Sstevel@tonic-gate #include <errno.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp);
45*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t step_to_end_of_exec(tnfctl_handle_t *hndl);
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate  * invokes the target program and executes it till the run time linker (rtld)
49*7c478bd9Sstevel@tonic-gate  * has loaded in the shared objects (but before any .init sections are
50*7c478bd9Sstevel@tonic-gate  * executed).  Returns a pointer to a tnfctl handle.
51*7c478bd9Sstevel@tonic-gate  */
52*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
53*7c478bd9Sstevel@tonic-gate tnfctl_exec_open(const char *pgm_name, char * const *args,  char * const *envp,
54*7c478bd9Sstevel@tonic-gate 		const char *ld_preload,
55*7c478bd9Sstevel@tonic-gate 		const char *libtnfprobe_path,
56*7c478bd9Sstevel@tonic-gate 		tnfctl_handle_t **ret_val)
57*7c478bd9Sstevel@tonic-gate {
58*7c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
59*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p = NULL;
60*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
61*7c478bd9Sstevel@tonic-gate 	uintptr_t	dbgaddr;
62*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	prbstat = prb_child_create(pgm_name, args, ld_preload, libtnfprobe_path,
65*7c478bd9Sstevel@tonic-gate 					envp, &proc_p);
66*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
67*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
68*7c478bd9Sstevel@tonic-gate 	}
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
71*7c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
72*7c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
73*7c478bd9Sstevel@tonic-gate 		(void) prb_proc_close(proc_p);
74*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
75*7c478bd9Sstevel@tonic-gate 	}
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 	hdl->proc_p = proc_p;
78*7c478bd9Sstevel@tonic-gate 	hdl->mode = DIRECT_MODE;
79*7c478bd9Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	/* use native /proc on this target */
82*7c478bd9Sstevel@tonic-gate 	hdl->p_read = _tnfctl_read_targ;
83*7c478bd9Sstevel@tonic-gate 	hdl->p_write = _tnfctl_write_targ;
84*7c478bd9Sstevel@tonic-gate 	hdl->p_obj_iter = _tnfctl_loadobj_iter;
85*7c478bd9Sstevel@tonic-gate 	hdl->p_getpid = _tnfctl_pid_get;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	/*
88*7c478bd9Sstevel@tonic-gate 	 * get the address of DT_DEBUG and send it in to prb_ layer.
89*7c478bd9Sstevel@tonic-gate 	 * This is needed before before prb_rtld_sync() can be called.
90*7c478bd9Sstevel@tonic-gate 	 */
91*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
92*7c478bd9Sstevel@tonic-gate 	if (prexstat)
93*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	prb_dbgaddr(proc_p, dbgaddr);
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	/* sync up to rtld sync point */
98*7c478bd9Sstevel@tonic-gate 	prbstat = prb_rtld_sync_if_needed(proc_p);
99*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
100*7c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_map_to_errcode(prbstat);
101*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
102*7c478bd9Sstevel@tonic-gate 	}
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	/* initialize state in handle */
105*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
106*7c478bd9Sstevel@tonic-gate 	if (prexstat)
107*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
110*7c478bd9Sstevel@tonic-gate 	if (prexstat)
111*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
114*7c478bd9Sstevel@tonic-gate 	/* Successful return */
115*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate failure_ret:
118*7c478bd9Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
119*7c478bd9Sstevel@tonic-gate 	free(hdl);
120*7c478bd9Sstevel@tonic-gate 	return (prexstat);
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate /*
125*7c478bd9Sstevel@tonic-gate  * attaches to a running process.  If the process is in the beginning
126*7c478bd9Sstevel@tonic-gate  * of an exec(2) system call (which is how tnfctl_continue() returns on exec),
127*7c478bd9Sstevel@tonic-gate  * it steps the process till the end of the the exec. If the process hasn't
128*7c478bd9Sstevel@tonic-gate  * reached the rtld sync point, the process is continued until it does
129*7c478bd9Sstevel@tonic-gate  * reach it.  Returns a pointer to a tnfctl handle.
130*7c478bd9Sstevel@tonic-gate  */
131*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
132*7c478bd9Sstevel@tonic-gate tnfctl_pid_open(pid_t pid, tnfctl_handle_t **ret_val)
133*7c478bd9Sstevel@tonic-gate {
134*7c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
135*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p = NULL;
136*7c478bd9Sstevel@tonic-gate 	uintptr_t	dbgaddr;
137*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
138*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	prexstat = attach_pid(pid, &proc_p);
141*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
142*7c478bd9Sstevel@tonic-gate 		return (prexstat);
143*7c478bd9Sstevel@tonic-gate 	}
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
146*7c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
147*7c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
148*7c478bd9Sstevel@tonic-gate 		(void) prb_proc_close(proc_p);
149*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	hdl->proc_p = proc_p;
153*7c478bd9Sstevel@tonic-gate 	hdl->mode = DIRECT_MODE;
154*7c478bd9Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	/* use native /proc on this target */
157*7c478bd9Sstevel@tonic-gate 	hdl->p_read = _tnfctl_read_targ;
158*7c478bd9Sstevel@tonic-gate 	hdl->p_write = _tnfctl_write_targ;
159*7c478bd9Sstevel@tonic-gate 	hdl->p_obj_iter = _tnfctl_loadobj_iter;
160*7c478bd9Sstevel@tonic-gate 	hdl->p_getpid = _tnfctl_pid_get;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	/*
163*7c478bd9Sstevel@tonic-gate 	 * Since tnfctl_continue() returns when a process does an exec
164*7c478bd9Sstevel@tonic-gate 	 * and leaves the process stopped at the beginning of exec, we
165*7c478bd9Sstevel@tonic-gate 	 * have to be sure to catch this case.
166*7c478bd9Sstevel@tonic-gate 	 */
167*7c478bd9Sstevel@tonic-gate 	prexstat = step_to_end_of_exec(hdl);
168*7c478bd9Sstevel@tonic-gate 	/* proc_p could be side effected by step_to_end_of_exec() */
169*7c478bd9Sstevel@tonic-gate 	proc_p = hdl->proc_p;
170*7c478bd9Sstevel@tonic-gate 	if (prexstat)
171*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 	/*
174*7c478bd9Sstevel@tonic-gate 	 * get the address of DT_DEBUG and send it in to prb_ layer.
175*7c478bd9Sstevel@tonic-gate 	 */
176*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
177*7c478bd9Sstevel@tonic-gate 	if (prexstat)
178*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	prb_dbgaddr(proc_p, dbgaddr);
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	/* sync up to rtld sync point if target is not there yet */
183*7c478bd9Sstevel@tonic-gate 	prbstat = prb_rtld_sync_if_needed(proc_p);
184*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
185*7c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_map_to_errcode(prbstat);
186*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
187*7c478bd9Sstevel@tonic-gate 	}
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	/* initialize state in handle */
190*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
191*7c478bd9Sstevel@tonic-gate 	if (prexstat)
192*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	/* set state in target indicating we're tracing externally */
195*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
196*7c478bd9Sstevel@tonic-gate 	if (prexstat)
197*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	/* Sucessful return */
202*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate failure_ret:
205*7c478bd9Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
206*7c478bd9Sstevel@tonic-gate 	free(hdl);
207*7c478bd9Sstevel@tonic-gate 	return (prexstat);
208*7c478bd9Sstevel@tonic-gate }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate  * open a process for tracing without using native /proc on it.  The client
212*7c478bd9Sstevel@tonic-gate  * provides a set of callback functions which encapsulate the /proc
213*7c478bd9Sstevel@tonic-gate  * functionality we need.  Returns a pointer to a tnfctl handle.
214*7c478bd9Sstevel@tonic-gate  */
215*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
216*7c478bd9Sstevel@tonic-gate tnfctl_indirect_open(void *prochandle, tnfctl_ind_config_t *config,
217*7c478bd9Sstevel@tonic-gate 		tnfctl_handle_t **ret_val)
218*7c478bd9Sstevel@tonic-gate {
219*7c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
220*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
223*7c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
224*7c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
225*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	hdl->proc_p = prochandle;
229*7c478bd9Sstevel@tonic-gate 	hdl->mode = INDIRECT_MODE;
230*7c478bd9Sstevel@tonic-gate 	hdl->called_exit = B_FALSE;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	/* initialize callback functions */
233*7c478bd9Sstevel@tonic-gate 	hdl->p_read = config->p_read;
234*7c478bd9Sstevel@tonic-gate 	hdl->p_write = config->p_write;
235*7c478bd9Sstevel@tonic-gate 	hdl->p_obj_iter = config->p_obj_iter;
236*7c478bd9Sstevel@tonic-gate 	hdl->p_getpid = config->p_getpid;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	/* initialize state in handle */
239*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_set_state(hdl);
240*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
241*7c478bd9Sstevel@tonic-gate 		free(hdl);
242*7c478bd9Sstevel@tonic-gate 		return (prexstat);
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 	/* set state in target indicating we're tracing externally */
245*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_external_getlock(hdl);
246*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
247*7c478bd9Sstevel@tonic-gate 	    free(hdl);
248*7c478bd9Sstevel@tonic-gate 	    return (prexstat);
249*7c478bd9Sstevel@tonic-gate 	}
250*7c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
251*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
252*7c478bd9Sstevel@tonic-gate }
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate /*
255*7c478bd9Sstevel@tonic-gate  * Returns a pointer to a tnfctl handle that can do kernel trace control
256*7c478bd9Sstevel@tonic-gate  * and kernel probe control.
257*7c478bd9Sstevel@tonic-gate  */
258*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
259*7c478bd9Sstevel@tonic-gate tnfctl_kernel_open(tnfctl_handle_t **ret_val)
260*7c478bd9Sstevel@tonic-gate {
261*7c478bd9Sstevel@tonic-gate 	tnfctl_handle_t	*hdl;
262*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	/* allocate hdl and zero fill */
265*7c478bd9Sstevel@tonic-gate 	hdl = calloc(1, sizeof (*hdl));
266*7c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
267*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_ALLOCFAIL);
268*7c478bd9Sstevel@tonic-gate 	}
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	/* initialize kernel tracing */
271*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_prbk_init(hdl);
272*7c478bd9Sstevel@tonic-gate 	if (prexstat)
273*7c478bd9Sstevel@tonic-gate 		return (prexstat);
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	hdl->mode = KERNEL_MODE;
276*7c478bd9Sstevel@tonic-gate 	hdl->targ_pid = 0;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/* initialize function pointers that can be stuffed into a probe */
279*7c478bd9Sstevel@tonic-gate 	_tnfctl_prbk_get_other_funcs(&hdl->allocfunc, &hdl->commitfunc,
280*7c478bd9Sstevel@tonic-gate 		&hdl->rollbackfunc, &hdl->endfunc);
281*7c478bd9Sstevel@tonic-gate 	_tnfctl_prbk_test_func(&hdl->testfunc);
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	/* find the probes in the kernel */
284*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_refresh_kernel(hdl);
285*7c478bd9Sstevel@tonic-gate 	if (prexstat)
286*7c478bd9Sstevel@tonic-gate 		return (prexstat);
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	*ret_val = hdl;
289*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
290*7c478bd9Sstevel@tonic-gate }
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate /*
293*7c478bd9Sstevel@tonic-gate  * Returns the trace attributes to the client.  Since there can be
294*7c478bd9Sstevel@tonic-gate  * only one controlling agent on a target at a time, our cached information
295*7c478bd9Sstevel@tonic-gate  * is correct and we don't have to actually retrieve any information
296*7c478bd9Sstevel@tonic-gate  * from the target.
297*7c478bd9Sstevel@tonic-gate  */
298*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
299*7c478bd9Sstevel@tonic-gate tnfctl_trace_attrs_get(tnfctl_handle_t *hdl, tnfctl_trace_attrs_t *attrs)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	boolean_t		release_lock;
302*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
305*7c478bd9Sstevel@tonic-gate 	LOCK_SYNC(hdl, prexstat, release_lock);
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	attrs->targ_pid = hdl->targ_pid;
308*7c478bd9Sstevel@tonic-gate 	attrs->trace_file_name = hdl->trace_file_name;
309*7c478bd9Sstevel@tonic-gate 	attrs->trace_buf_size = hdl->trace_buf_size;
310*7c478bd9Sstevel@tonic-gate 	attrs->trace_min_size = hdl->trace_min_size;
311*7c478bd9Sstevel@tonic-gate 	attrs->trace_buf_state = hdl->trace_buf_state;
312*7c478bd9Sstevel@tonic-gate 	attrs->trace_state = hdl->trace_state;
313*7c478bd9Sstevel@tonic-gate 	attrs->filter_state = hdl->kpidfilter_state;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/*LINTED statement has no consequent: else*/
316*7c478bd9Sstevel@tonic-gate 	UNLOCK(hdl, release_lock);
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate /*
323*7c478bd9Sstevel@tonic-gate  * Allocate a trace buffer of the specified name and size.
324*7c478bd9Sstevel@tonic-gate  */
325*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
326*7c478bd9Sstevel@tonic-gate tnfctl_buffer_alloc(tnfctl_handle_t *hdl, const char *trace_file_name,
327*7c478bd9Sstevel@tonic-gate 			uint_t trace_file_size)
328*7c478bd9Sstevel@tonic-gate {
329*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	if (hdl->mode == KERNEL_MODE) {
332*7c478bd9Sstevel@tonic-gate 		/* trace_file_name is ignored in kernel mode */
333*7c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_prbk_buffer_alloc(hdl, trace_file_size);
334*7c478bd9Sstevel@tonic-gate 		if (prexstat)
335*7c478bd9Sstevel@tonic-gate 			return (prexstat);
336*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	/* Not KERNEL_MODE */
340*7c478bd9Sstevel@tonic-gate 	if (hdl->trace_file_name != NULL) {
341*7c478bd9Sstevel@tonic-gate 		/* buffer already allocated */
342*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BUFEXISTS);
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_create_tracefile(hdl, trace_file_name,
346*7c478bd9Sstevel@tonic-gate 						trace_file_size);
347*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
348*7c478bd9Sstevel@tonic-gate 		return (prexstat);
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate /*
355*7c478bd9Sstevel@tonic-gate  * Deallocate the trace buffer - only works for kernel mode
356*7c478bd9Sstevel@tonic-gate  */
357*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
358*7c478bd9Sstevel@tonic-gate tnfctl_buffer_dealloc(tnfctl_handle_t *hdl)
359*7c478bd9Sstevel@tonic-gate {
360*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t prexstat;
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	if (hdl->mode != KERNEL_MODE)
363*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BADARG);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	/* KERNEL_MODE */
366*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_prbk_buffer_dealloc(hdl);
367*7c478bd9Sstevel@tonic-gate 	if (prexstat)
368*7c478bd9Sstevel@tonic-gate 		return (prexstat);
369*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate /*
374*7c478bd9Sstevel@tonic-gate  * Helper function for attaching to a target process
375*7c478bd9Sstevel@tonic-gate  */
376*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
377*7c478bd9Sstevel@tonic-gate attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp)
378*7c478bd9Sstevel@tonic-gate {
379*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
380*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	if (getpid() == pid)
383*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BADARG);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	/* check if pid is valid */
386*7c478bd9Sstevel@tonic-gate 	if ((kill(pid, 0) == -1) && errno == ESRCH) {
387*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NOPROCESS);
388*7c478bd9Sstevel@tonic-gate 	}
389*7c478bd9Sstevel@tonic-gate 	/* open up /proc fd */
390*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_open(pid, proc_pp);
391*7c478bd9Sstevel@tonic-gate 	if (prbstat)
392*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	proc_p = *proc_pp;
395*7c478bd9Sstevel@tonic-gate 	/*
396*7c478bd9Sstevel@tonic-gate 	 * default is to run-on-last-close.  In case we cannot sync with
397*7c478bd9Sstevel@tonic-gate 	 * target, we don't want to kill the target.
398*7c478bd9Sstevel@tonic-gate 	 */
399*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_setrlc(proc_p, B_TRUE);
400*7c478bd9Sstevel@tonic-gate 	if (prbstat)
401*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
402*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_setklc(proc_p, B_FALSE);
403*7c478bd9Sstevel@tonic-gate 	if (prbstat)
404*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	/* stop process */
407*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_stop(proc_p);
408*7c478bd9Sstevel@tonic-gate 	if (prbstat)
409*7c478bd9Sstevel@tonic-gate 		goto failure_ret;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	/* Sucessful return */
412*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate failure_ret:
415*7c478bd9Sstevel@tonic-gate 	(void) prb_proc_close(proc_p);
416*7c478bd9Sstevel@tonic-gate 	return (_tnfctl_map_to_errcode(prbstat));
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate /*
420*7c478bd9Sstevel@tonic-gate  * Checks if target is at the beginning of an exec system call.  If so,
421*7c478bd9Sstevel@tonic-gate  * it runs it till the end of the exec system call.  It takes care of
422*7c478bd9Sstevel@tonic-gate  * the case where you're about to exec a setuid program.
423*7c478bd9Sstevel@tonic-gate  * CAUTION: could side effect hndl->proc_p
424*7c478bd9Sstevel@tonic-gate  */
425*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
426*7c478bd9Sstevel@tonic-gate step_to_end_of_exec(tnfctl_handle_t *hndl)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p, *oldproc_p;
429*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat, tempstat;
430*7c478bd9Sstevel@tonic-gate 	int		pid;
431*7c478bd9Sstevel@tonic-gate 	prb_proc_state_t	pstate;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	proc_p = hndl->proc_p;
434*7c478bd9Sstevel@tonic-gate 	pid = hndl->p_getpid(proc_p);
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &pstate);
437*7c478bd9Sstevel@tonic-gate 	if (prbstat)
438*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
439*7c478bd9Sstevel@tonic-gate 	if (!(pstate.ps_issysentry && (pstate.ps_syscallnum == SYS_exec ||
440*7c478bd9Sstevel@tonic-gate 			pstate.ps_syscallnum == SYS_execve))) {
441*7c478bd9Sstevel@tonic-gate 		/* not stopped at beginning of exec system call */
442*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_NONE);
443*7c478bd9Sstevel@tonic-gate 	}
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	/* we are stopped at beginning of exec system call */
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	/* REMIND: do we have to wait on SYS_exec also ? */
448*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD);
449*7c478bd9Sstevel@tonic-gate 	if (prbstat)
450*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_cont(proc_p);
453*7c478bd9Sstevel@tonic-gate 	if (prbstat)
454*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
457*7c478bd9Sstevel@tonic-gate 	switch (prbstat) {
458*7c478bd9Sstevel@tonic-gate 	case PRB_STATUS_OK:
459*7c478bd9Sstevel@tonic-gate 		break;
460*7c478bd9Sstevel@tonic-gate 	case EAGAIN:
461*7c478bd9Sstevel@tonic-gate 		/*
462*7c478bd9Sstevel@tonic-gate 		 * If we had exec'ed a setuid/setgid program PIOCWSTOP
463*7c478bd9Sstevel@tonic-gate 		 * will return EAGAIN.  Reopen the 'fd' and try again.
464*7c478bd9Sstevel@tonic-gate 		 * Read the last section of /proc man page - we reopen first
465*7c478bd9Sstevel@tonic-gate 		 * and then close the old fd.
466*7c478bd9Sstevel@tonic-gate 		 */
467*7c478bd9Sstevel@tonic-gate 		oldproc_p = proc_p;
468*7c478bd9Sstevel@tonic-gate 		tempstat = prb_proc_reopen(pid, &proc_p);
469*7c478bd9Sstevel@tonic-gate 		if (tempstat) {
470*7c478bd9Sstevel@tonic-gate 			/* here EACCES means exec'ed a setuid/setgid program */
471*7c478bd9Sstevel@tonic-gate 			return (_tnfctl_map_to_errcode(tempstat));
472*7c478bd9Sstevel@tonic-gate 		}
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 		prb_proc_close(oldproc_p);
475*7c478bd9Sstevel@tonic-gate 		hndl->proc_p = proc_p;
476*7c478bd9Sstevel@tonic-gate 		break;
477*7c478bd9Sstevel@tonic-gate 	default:
478*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &pstate);
482*7c478bd9Sstevel@tonic-gate 	if (prbstat)
483*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	if (!(pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_execve))) {
486*7c478bd9Sstevel@tonic-gate 		/* unexpected condition */
487*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(ENOENT));
488*7c478bd9Sstevel@tonic-gate 	}
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	/* clear old interest mask */
491*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_DEL);
492*7c478bd9Sstevel@tonic-gate 	if (prbstat)
493*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
494*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
495*7c478bd9Sstevel@tonic-gate }
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
499*7c478bd9Sstevel@tonic-gate _tnfctl_external_getlock(tnfctl_handle_t *hdl)
500*7c478bd9Sstevel@tonic-gate {
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
503*7c478bd9Sstevel@tonic-gate 	prb_status_t		prbstat;
504*7c478bd9Sstevel@tonic-gate 	uintptr_t		targ_symbol_ptr;
505*7c478bd9Sstevel@tonic-gate 	int			internal_tracing_on;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_sym_find(hdl, TNFCTL_INTERNAL_TRACEFLAG,
508*7c478bd9Sstevel@tonic-gate 	&targ_symbol_ptr);
509*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
510*7c478bd9Sstevel@tonic-gate 	/* no libtnfctl in target: success */
511*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
512*7c478bd9Sstevel@tonic-gate 	}
513*7c478bd9Sstevel@tonic-gate 	prbstat = hdl->p_read(hdl->proc_p, targ_symbol_ptr,
514*7c478bd9Sstevel@tonic-gate 	&internal_tracing_on, sizeof (internal_tracing_on));
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
517*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_map_to_errcode(prbstat);
518*7c478bd9Sstevel@tonic-gate 	goto failure_ret;
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate 	if (internal_tracing_on) {
521*7c478bd9Sstevel@tonic-gate 	/* target process being traced internally */
522*7c478bd9Sstevel@tonic-gate 	prexstat = TNFCTL_ERR_BUSY;
523*7c478bd9Sstevel@tonic-gate 	goto failure_ret;
524*7c478bd9Sstevel@tonic-gate 	}
525*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_sym_find(hdl, TNFCTL_EXTERNAL_TRACEDPID,
526*7c478bd9Sstevel@tonic-gate 	&targ_symbol_ptr);
527*7c478bd9Sstevel@tonic-gate 	if (prexstat) {
528*7c478bd9Sstevel@tonic-gate 	/* this shouldn't happen. we know we have libtnfctl */
529*7c478bd9Sstevel@tonic-gate 	goto failure_ret;
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 	prbstat = hdl->p_write(hdl->proc_p, targ_symbol_ptr,
532*7c478bd9Sstevel@tonic-gate 	&(hdl->targ_pid), sizeof (hdl->targ_pid));
533*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
534*7c478bd9Sstevel@tonic-gate 	prexstat = _tnfctl_map_to_errcode(prbstat);
535*7c478bd9Sstevel@tonic-gate 	goto failure_ret;
536*7c478bd9Sstevel@tonic-gate 	}
537*7c478bd9Sstevel@tonic-gate 	/* success */
538*7c478bd9Sstevel@tonic-gate 	DBG((void) fprintf(stderr, "_tnfctl_external_getlock: ok to trace %d\n",
539*7c478bd9Sstevel@tonic-gate 	hdl->targ_pid));
540*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate failure_ret:
543*7c478bd9Sstevel@tonic-gate 	return (prexstat);
544*7c478bd9Sstevel@tonic-gate }
545