xref: /titanic_50/usr/src/lib/libtnfctl/continue.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 1994,2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * interface to continue a target process (DIRECT_MODE) and helper
31*7c478bd9Sstevel@tonic-gate  * functions needed by this routine.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
35*7c478bd9Sstevel@tonic-gate #include "prb_proc.h"
36*7c478bd9Sstevel@tonic-gate #include "dbg.h"
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
40*7c478bd9Sstevel@tonic-gate #include <errno.h>
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t _tnfctl_continue(tnfctl_handle_t *hndl,
43*7c478bd9Sstevel@tonic-gate     tnfctl_event_t *evt, sigset_t *oldmask, boolean_t watch_forks);
44*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t enable_target_state(tnfctl_handle_t *hndl,
45*7c478bd9Sstevel@tonic-gate     boolean_t watch_forks);
46*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t disable_target_state(tnfctl_handle_t *hndl);
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * continue the target process and return the evt it stopped on.
50*7c478bd9Sstevel@tonic-gate  * If child_hndl is set and we see a fork, return a handle on child
51*7c478bd9Sstevel@tonic-gate  * process.
52*7c478bd9Sstevel@tonic-gate  */
53*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t
54*7c478bd9Sstevel@tonic-gate tnfctl_continue(tnfctl_handle_t *hndl, tnfctl_event_t *evt,
55*7c478bd9Sstevel@tonic-gate 		tnfctl_handle_t **child_hndl)
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
58*7c478bd9Sstevel@tonic-gate 	prb_status_t		prbstat;
59*7c478bd9Sstevel@tonic-gate 	boolean_t		lmapok = B_FALSE;
60*7c478bd9Sstevel@tonic-gate 	boolean_t		watch_forks;
61*7c478bd9Sstevel@tonic-gate 	/* set my_evt to something other than TNFCTL_EVENT_TARGGONE */
62*7c478bd9Sstevel@tonic-gate 	tnfctl_event_t		my_evt = TNFCTL_EVENT_EINTR;
63*7c478bd9Sstevel@tonic-gate 	enum event_op_t		dl_evt;
64*7c478bd9Sstevel@tonic-gate 	sigset_t		newmask, oldmask;
65*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t		*proc_p;
66*7c478bd9Sstevel@tonic-gate 	prgreg_t		reg0, reg1;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	/* this interface only works for DIRECT_MODE clients */
69*7c478bd9Sstevel@tonic-gate 	if (hndl->mode != DIRECT_MODE)
70*7c478bd9Sstevel@tonic-gate 		return (TNFCTL_ERR_BADARG);
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 	proc_p = hndl->proc_p;
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 	if (sigfillset(&newmask) == -1)
75*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 	watch_forks = (child_hndl != NULL);
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	/*
80*7c478bd9Sstevel@tonic-gate 	 * XXXX block all signals.  Synchronous signals like SEGV that
81*7c478bd9Sstevel@tonic-gate 	 * the user could catch and handle will now result in a core dump.
82*7c478bd9Sstevel@tonic-gate 	 * But, this is very unlikely for 2 reasons - most users don't try
83*7c478bd9Sstevel@tonic-gate 	 * to handle synchronous signals - it usually just aborts the process.
84*7c478bd9Sstevel@tonic-gate 	 * And, secondly, the code until we return the original mask is the
85*7c478bd9Sstevel@tonic-gate 	 * place where this synchronous signal would be generated - and, it
86*7c478bd9Sstevel@tonic-gate 	 * is not very much code.
87*7c478bd9Sstevel@tonic-gate 	 */
88*7c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) == -1)
89*7c478bd9Sstevel@tonic-gate 		return (tnfctl_status_map(errno));
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	/*
92*7c478bd9Sstevel@tonic-gate 	 * Target is stopped on entry because tnfctl_continue()
93*7c478bd9Sstevel@tonic-gate 	 * only returns with a stopped target.
94*7c478bd9Sstevel@tonic-gate 	 */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	/* target process shouldn't be stopped when link maps are incosistent */
97*7c478bd9Sstevel@tonic-gate 	while (lmapok == B_FALSE) {
98*7c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_continue(hndl, &my_evt, &oldmask,
99*7c478bd9Sstevel@tonic-gate 		    watch_forks);
100*7c478bd9Sstevel@tonic-gate 		if (prexstat) {
101*7c478bd9Sstevel@tonic-gate 			if (my_evt == TNFCTL_EVENT_TARGGONE ||
102*7c478bd9Sstevel@tonic-gate 			    my_evt == TNFCTL_EVENT_EXIT) {
103*7c478bd9Sstevel@tonic-gate 				/*
104*7c478bd9Sstevel@tonic-gate 				 * target exited - free obj list and probe
105*7c478bd9Sstevel@tonic-gate 				 * list so that we keep our internal state
106*7c478bd9Sstevel@tonic-gate 				 * correct, else probe control interfaces will
107*7c478bd9Sstevel@tonic-gate 				 * have wrong information.
108*7c478bd9Sstevel@tonic-gate 				 */
109*7c478bd9Sstevel@tonic-gate 			    DBG(fprintf(stderr, "target is gone\n"));
110*7c478bd9Sstevel@tonic-gate 				_tnfctl_free_objs_and_probes(hndl);
111*7c478bd9Sstevel@tonic-gate 				*evt = my_evt;
112*7c478bd9Sstevel@tonic-gate 				return (TNFCTL_ERR_NONE);
113*7c478bd9Sstevel@tonic-gate 			} else if (my_evt == TNFCTL_EVENT_EXEC) {
114*7c478bd9Sstevel@tonic-gate 				*evt = my_evt;
115*7c478bd9Sstevel@tonic-gate 				return (TNFCTL_ERR_NONE);
116*7c478bd9Sstevel@tonic-gate 			} else if (prexstat == TNFCTL_ERR_FILENOTFOUND) {
117*7c478bd9Sstevel@tonic-gate 				return (TNFCTL_ERR_NOPROCESS);
118*7c478bd9Sstevel@tonic-gate 			} else {
119*7c478bd9Sstevel@tonic-gate 				return (prexstat);
120*7c478bd9Sstevel@tonic-gate 			}
121*7c478bd9Sstevel@tonic-gate 		}
122*7c478bd9Sstevel@tonic-gate 		if (my_evt == TNFCTL_EVENT_FORK) {
123*7c478bd9Sstevel@tonic-gate 	/*
124*7c478bd9Sstevel@tonic-gate 	 * sanity check.  we should only get here if child_hndl is set
125*7c478bd9Sstevel@tonic-gate 	 */
126*7c478bd9Sstevel@tonic-gate 		    if (child_hndl) {
127*7c478bd9Sstevel@tonic-gate 			    *evt = my_evt;
128*7c478bd9Sstevel@tonic-gate 			    prbstat = prb_proc_get_r0_r1(proc_p,
129*7c478bd9Sstevel@tonic-gate 				&reg0, &reg1);
130*7c478bd9Sstevel@tonic-gate 			    if (prbstat) {
131*7c478bd9Sstevel@tonic-gate 				prexstat = _tnfctl_map_to_errcode(prbstat);
132*7c478bd9Sstevel@tonic-gate 				return (prexstat);
133*7c478bd9Sstevel@tonic-gate 			    }
134*7c478bd9Sstevel@tonic-gate 			    prexstat = tnfctl_pid_open((pid_t)reg0,
135*7c478bd9Sstevel@tonic-gate 						child_hndl);
136*7c478bd9Sstevel@tonic-gate 			    disable_target_state(*child_hndl);
137*7c478bd9Sstevel@tonic-gate 			    return (prexstat);
138*7c478bd9Sstevel@tonic-gate 			}
139*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_NONE);
140*7c478bd9Sstevel@tonic-gate 		}
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 		/*
143*7c478bd9Sstevel@tonic-gate 		 * update state in handle
144*7c478bd9Sstevel@tonic-gate 		 * REMIND: Only need to call _tnfctl_refresh_process on
145*7c478bd9Sstevel@tonic-gate 		 * dlopen or dlclose.  Need to take out other functionality
146*7c478bd9Sstevel@tonic-gate 		 * of refresh_process into a separate function that should
147*7c478bd9Sstevel@tonic-gate 		 * be called here.
148*7c478bd9Sstevel@tonic-gate 		 */
149*7c478bd9Sstevel@tonic-gate 		prexstat = _tnfctl_refresh_process(hndl, &lmapok, &dl_evt);
150*7c478bd9Sstevel@tonic-gate 		if (prexstat && (lmapok == B_TRUE))
151*7c478bd9Sstevel@tonic-gate 			return (prexstat);
152*7c478bd9Sstevel@tonic-gate 		prexstat = TNFCTL_ERR_NONE;
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 	*evt = my_evt;
155*7c478bd9Sstevel@tonic-gate 	/* see if we have more detail about the event */
156*7c478bd9Sstevel@tonic-gate 	if (dl_evt == EVT_OPEN)
157*7c478bd9Sstevel@tonic-gate 		*evt = TNFCTL_EVENT_DLOPEN;
158*7c478bd9Sstevel@tonic-gate 	else if (dl_evt == EVT_CLOSE)
159*7c478bd9Sstevel@tonic-gate 		*evt = TNFCTL_EVENT_DLCLOSE;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
162*7c478bd9Sstevel@tonic-gate }
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate /*
165*7c478bd9Sstevel@tonic-gate  * Continues target and waits for it to stop.
166*7c478bd9Sstevel@tonic-gate  *	warning: This routine returns TNFCTL_EVENT_DLOPEN for any kind of
167*7c478bd9Sstevel@tonic-gate  *	dl activity.  Up to the caller to determine the actual DL event.
168*7c478bd9Sstevel@tonic-gate  */
169*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
170*7c478bd9Sstevel@tonic-gate _tnfctl_continue(tnfctl_handle_t *hndl, tnfctl_event_t *evt, sigset_t *oldmask,
171*7c478bd9Sstevel@tonic-gate     boolean_t watch_forks)
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	prexstat;
174*7c478bd9Sstevel@tonic-gate 	tnfctl_errcode_t	ret_prexstat = TNFCTL_ERR_NONE;
175*7c478bd9Sstevel@tonic-gate 	prb_status_t		prbstat, prbstat2;
176*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t		*proc_p;
177*7c478bd9Sstevel@tonic-gate 	prb_proc_state_t 	state;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	proc_p = hndl->proc_p;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	/* set up state before we run process */
182*7c478bd9Sstevel@tonic-gate 	prexstat = enable_target_state(hndl, watch_forks);
183*7c478bd9Sstevel@tonic-gate 	if (prexstat)
184*7c478bd9Sstevel@tonic-gate 		return (prexstat);
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate again:
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	/* resume target */
189*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_cont(proc_p);
190*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
191*7c478bd9Sstevel@tonic-gate 		ret_prexstat = _tnfctl_map_to_errcode(prbstat);
192*7c478bd9Sstevel@tonic-gate 		goto end_of_func;
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	/* wait on target to stop (standby) */
196*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_wait(proc_p, B_TRUE, oldmask);
197*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
198*7c478bd9Sstevel@tonic-gate 		if (prbstat == EINTR) {
199*7c478bd9Sstevel@tonic-gate 			*evt = TNFCTL_EVENT_EINTR;
200*7c478bd9Sstevel@tonic-gate 			prbstat2 = prb_proc_stop(proc_p);
201*7c478bd9Sstevel@tonic-gate 			if (prbstat2) {
202*7c478bd9Sstevel@tonic-gate 				ret_prexstat = _tnfctl_map_to_errcode(prbstat2);
203*7c478bd9Sstevel@tonic-gate 				goto end_of_func;
204*7c478bd9Sstevel@tonic-gate 			}
205*7c478bd9Sstevel@tonic-gate 		} else if (prbstat == ENOENT) {
206*7c478bd9Sstevel@tonic-gate 			/* target process finished */
207*7c478bd9Sstevel@tonic-gate 			if (hndl->called_exit)
208*7c478bd9Sstevel@tonic-gate 				*evt = TNFCTL_EVENT_EXIT;
209*7c478bd9Sstevel@tonic-gate 			else
210*7c478bd9Sstevel@tonic-gate 				*evt = TNFCTL_EVENT_TARGGONE;
211*7c478bd9Sstevel@tonic-gate 			/* return directly - process no longer around */
212*7c478bd9Sstevel@tonic-gate 			return (TNFCTL_ERR_INTERNAL);
213*7c478bd9Sstevel@tonic-gate 		} else {
214*7c478bd9Sstevel@tonic-gate 			ret_prexstat = _tnfctl_map_to_errcode(prbstat);
215*7c478bd9Sstevel@tonic-gate 			goto end_of_func;
216*7c478bd9Sstevel@tonic-gate 		}
217*7c478bd9Sstevel@tonic-gate 	}
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_state(proc_p, &state);
220*7c478bd9Sstevel@tonic-gate 	if (prbstat) {
221*7c478bd9Sstevel@tonic-gate 		ret_prexstat = _tnfctl_map_to_errcode(prbstat);
222*7c478bd9Sstevel@tonic-gate 		goto end_of_func;
223*7c478bd9Sstevel@tonic-gate 	}
224*7c478bd9Sstevel@tonic-gate 	if (state.ps_isbptfault) {
225*7c478bd9Sstevel@tonic-gate 		/* dlopen or dlclose */
226*7c478bd9Sstevel@tonic-gate 		prbstat = prb_rtld_advance(proc_p);
227*7c478bd9Sstevel@tonic-gate 		if (prbstat) {
228*7c478bd9Sstevel@tonic-gate 			ret_prexstat = _tnfctl_map_to_errcode(prbstat);
229*7c478bd9Sstevel@tonic-gate 			goto end_of_func;
230*7c478bd9Sstevel@tonic-gate 		}
231*7c478bd9Sstevel@tonic-gate 		/*
232*7c478bd9Sstevel@tonic-gate 		 * actually don't know if it is a dlopen or dlclose yet.
233*7c478bd9Sstevel@tonic-gate 		 * But, we return dlopen here.  Up to the caller to determine
234*7c478bd9Sstevel@tonic-gate 		 * which one it actually is.
235*7c478bd9Sstevel@tonic-gate 		 */
236*7c478bd9Sstevel@tonic-gate 		*evt = TNFCTL_EVENT_DLOPEN;
237*7c478bd9Sstevel@tonic-gate 	} else
238*7c478bd9Sstevel@tonic-gate 	    if (state.ps_issysentry) {
239*7c478bd9Sstevel@tonic-gate 		switch (state.ps_syscallnum) {
240*7c478bd9Sstevel@tonic-gate 		case SYS_exec:
241*7c478bd9Sstevel@tonic-gate 		case SYS_execve:
242*7c478bd9Sstevel@tonic-gate 		    *evt = TNFCTL_EVENT_EXEC;
243*7c478bd9Sstevel@tonic-gate 		    ret_prexstat = TNFCTL_ERR_INTERNAL;
244*7c478bd9Sstevel@tonic-gate 		    break;
245*7c478bd9Sstevel@tonic-gate 		case SYS_exit:
246*7c478bd9Sstevel@tonic-gate 		    hndl->called_exit = B_TRUE;
247*7c478bd9Sstevel@tonic-gate 		    goto again;
248*7c478bd9Sstevel@tonic-gate 		default:
249*7c478bd9Sstevel@tonic-gate 		    break;
250*7c478bd9Sstevel@tonic-gate 		}
251*7c478bd9Sstevel@tonic-gate 	    } else if (state.ps_issysexit) {
252*7c478bd9Sstevel@tonic-gate 		    switch (state.ps_syscallnum) {
253*7c478bd9Sstevel@tonic-gate 		    case SYS_forkall:
254*7c478bd9Sstevel@tonic-gate 		    case SYS_vfork:
255*7c478bd9Sstevel@tonic-gate 		    case SYS_fork1:
256*7c478bd9Sstevel@tonic-gate 			*evt = TNFCTL_EVENT_FORK;
257*7c478bd9Sstevel@tonic-gate 			break;
258*7c478bd9Sstevel@tonic-gate 		    default:
259*7c478bd9Sstevel@tonic-gate 			break;
260*7c478bd9Sstevel@tonic-gate 		    }
261*7c478bd9Sstevel@tonic-gate 		}
262*7c478bd9Sstevel@tonic-gate end_of_func:
263*7c478bd9Sstevel@tonic-gate 	/*
264*7c478bd9Sstevel@tonic-gate 	 * disable all our sycall tracing and bpt setup in process when it
265*7c478bd9Sstevel@tonic-gate 	 * is stopped, so that even if the controlling process aborts,
266*7c478bd9Sstevel@tonic-gate 	 * the target could continue running
267*7c478bd9Sstevel@tonic-gate 	 */
268*7c478bd9Sstevel@tonic-gate 	prexstat = disable_target_state(hndl);
269*7c478bd9Sstevel@tonic-gate 	if (prexstat)
270*7c478bd9Sstevel@tonic-gate 		return (prexstat);
271*7c478bd9Sstevel@tonic-gate 	return (ret_prexstat);
272*7c478bd9Sstevel@tonic-gate }
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate /*
275*7c478bd9Sstevel@tonic-gate  * enable the system call tracing and dl activity tracing
276*7c478bd9Sstevel@tonic-gate  */
277*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
278*7c478bd9Sstevel@tonic-gate enable_target_state(tnfctl_handle_t *hndl, boolean_t watch_forks)
279*7c478bd9Sstevel@tonic-gate {
280*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
281*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	proc_p = hndl->proc_p;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	/* trace exec */
286*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_execve, PRB_SYS_ADD);
287*7c478bd9Sstevel@tonic-gate 	if (prbstat)
288*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
289*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_exec, PRB_SYS_ADD);
290*7c478bd9Sstevel@tonic-gate 	if (prbstat)
291*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
292*7c478bd9Sstevel@tonic-gate 	/* trace exit */
293*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
294*7c478bd9Sstevel@tonic-gate 	if (prbstat)
295*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
296*7c478bd9Sstevel@tonic-gate 	/* trace fork if the caller requests */
297*7c478bd9Sstevel@tonic-gate 	if (watch_forks) {
298*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_exit(proc_p, SYS_forkall, PRB_SYS_ADD);
299*7c478bd9Sstevel@tonic-gate 		if (prbstat)
300*7c478bd9Sstevel@tonic-gate 			return (_tnfctl_map_to_errcode(prbstat));
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_exit(proc_p, SYS_vfork, PRB_SYS_ADD);
303*7c478bd9Sstevel@tonic-gate 		if (prbstat)
304*7c478bd9Sstevel@tonic-gate 			return (_tnfctl_map_to_errcode(prbstat));
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_exit(proc_p, SYS_fork1, PRB_SYS_ADD);
307*7c478bd9Sstevel@tonic-gate 		if (prbstat)
308*7c478bd9Sstevel@tonic-gate 			return (_tnfctl_map_to_errcode(prbstat));
309*7c478bd9Sstevel@tonic-gate 		prbstat = prb_proc_setfork(proc_p, B_TRUE);
310*7c478bd9Sstevel@tonic-gate 		if (prbstat)
311*7c478bd9Sstevel@tonic-gate 			return (_tnfctl_map_to_errcode(prbstat));
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 	/*
314*7c478bd9Sstevel@tonic-gate 	 * tracing flags for fork and exec will get unset when
315*7c478bd9Sstevel@tonic-gate 	 * process stops. see disable_target_state()
316*7c478bd9Sstevel@tonic-gate 	 */
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	/* setup process to stop during dlopen() or dlclose() */
319*7c478bd9Sstevel@tonic-gate 	prbstat = prb_rtld_stalk(proc_p);
320*7c478bd9Sstevel@tonic-gate 	return (_tnfctl_map_to_errcode(prbstat));
321*7c478bd9Sstevel@tonic-gate }
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate /*
324*7c478bd9Sstevel@tonic-gate  * disable the system call tracing and dl activity tracing
325*7c478bd9Sstevel@tonic-gate  */
326*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
327*7c478bd9Sstevel@tonic-gate disable_target_state(tnfctl_handle_t *hndl)
328*7c478bd9Sstevel@tonic-gate {
329*7c478bd9Sstevel@tonic-gate 	prb_status_t	prbstat;
330*7c478bd9Sstevel@tonic-gate 	prb_proc_ctl_t	*proc_p;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	proc_p = hndl->proc_p;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	/* remove the stalking breakpoint while the process is stopped */
335*7c478bd9Sstevel@tonic-gate 	prbstat = prb_rtld_unstalk(proc_p);
336*7c478bd9Sstevel@tonic-gate 	if (prbstat)
337*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	/* remove the exec, exit and fork tracing while stopped */
340*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_execve, PRB_SYS_DEL);
341*7c478bd9Sstevel@tonic-gate 	if (prbstat)
342*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
343*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_exec, PRB_SYS_DEL);
344*7c478bd9Sstevel@tonic-gate 	if (prbstat)
345*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
346*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL);
347*7c478bd9Sstevel@tonic-gate 	if (prbstat)
348*7c478bd9Sstevel@tonic-gate 		return (_tnfctl_map_to_errcode(prbstat));
349*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_forkall, PRB_SYS_DEL);
350*7c478bd9Sstevel@tonic-gate 	if (prbstat)
351*7c478bd9Sstevel@tonic-gate 	    return (_tnfctl_map_to_errcode(prbstat));
352*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_vfork, PRB_SYS_DEL);
353*7c478bd9Sstevel@tonic-gate 	if (prbstat)
354*7c478bd9Sstevel@tonic-gate 	    return (_tnfctl_map_to_errcode(prbstat));
355*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_exit(proc_p, SYS_fork1, PRB_SYS_DEL);
356*7c478bd9Sstevel@tonic-gate 	if (prbstat)
357*7c478bd9Sstevel@tonic-gate 	    return (_tnfctl_map_to_errcode(prbstat));
358*7c478bd9Sstevel@tonic-gate 	prbstat = prb_proc_setfork(proc_p, B_FALSE);
359*7c478bd9Sstevel@tonic-gate 	if (prbstat)
360*7c478bd9Sstevel@tonic-gate 	    return (_tnfctl_map_to_errcode(prbstat));
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	return (TNFCTL_ERR_NONE);
363*7c478bd9Sstevel@tonic-gate }
364