4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * interface to continue a target process (DIRECT_MODE) and helper
29 * functions needed by this routine.
32 #include "tnfctl_int.h"
40 static tnfctl_errcode_t
_tnfctl_continue(tnfctl_handle_t
*hndl
,
41 tnfctl_event_t
*evt
, sigset_t
*oldmask
, boolean_t watch_forks
);
42 static tnfctl_errcode_t
enable_target_state(tnfctl_handle_t
*hndl
,
43 boolean_t watch_forks
);
44 static tnfctl_errcode_t
disable_target_state(tnfctl_handle_t
*hndl
);
47 * continue the target process and return the evt it stopped on.
48 * If child_hndl is set and we see a fork, return a handle on child
52 tnfctl_continue(tnfctl_handle_t
*hndl
, tnfctl_event_t
*evt
,
53 tnfctl_handle_t
**child_hndl
)
55 tnfctl_errcode_t prexstat
;
57 boolean_t lmapok
= B_FALSE
;
58 boolean_t watch_forks
;
59 /* set my_evt to something other than TNFCTL_EVENT_TARGGONE */
60 tnfctl_event_t my_evt
= TNFCTL_EVENT_EINTR
;
61 enum event_op_t dl_evt
;
62 sigset_t newmask
, oldmask
;
63 prb_proc_ctl_t
*proc_p
;
66 /* this interface only works for DIRECT_MODE clients */
67 if (hndl
->mode
!= DIRECT_MODE
)
68 return (TNFCTL_ERR_BADARG
);
70 proc_p
= hndl
->proc_p
;
72 if (sigfillset(&newmask
) == -1)
73 return (tnfctl_status_map(errno
));
75 watch_forks
= (child_hndl
!= NULL
);
78 * XXXX block all signals. Synchronous signals like SEGV that
79 * the user could catch and handle will now result in a core dump.
80 * But, this is very unlikely for 2 reasons - most users don't try
81 * to handle synchronous signals - it usually just aborts the process.
82 * And, secondly, the code until we return the original mask is the
83 * place where this synchronous signal would be generated - and, it
84 * is not very much code.
86 if (sigprocmask(SIG_BLOCK
, &newmask
, &oldmask
) == -1)
87 return (tnfctl_status_map(errno
));
90 * Target is stopped on entry because tnfctl_continue()
91 * only returns with a stopped target.
94 /* target process shouldn't be stopped when link maps are incosistent */
95 while (lmapok
== B_FALSE
) {
96 prexstat
= _tnfctl_continue(hndl
, &my_evt
, &oldmask
,
99 if (my_evt
== TNFCTL_EVENT_TARGGONE
||
100 my_evt
== TNFCTL_EVENT_EXIT
) {
102 * target exited - free obj list and probe
103 * list so that we keep our internal state
104 * correct, else probe control interfaces will
105 * have wrong information.
107 DBG(fprintf(stderr
, "target is gone\n"));
108 _tnfctl_free_objs_and_probes(hndl
);
110 return (TNFCTL_ERR_NONE
);
111 } else if (my_evt
== TNFCTL_EVENT_EXEC
) {
113 return (TNFCTL_ERR_NONE
);
114 } else if (prexstat
== TNFCTL_ERR_FILENOTFOUND
) {
115 return (TNFCTL_ERR_NOPROCESS
);
120 if (my_evt
== TNFCTL_EVENT_FORK
) {
122 * sanity check. we should only get here if child_hndl is set
126 prbstat
= prb_proc_get_r0_r1(proc_p
,
129 prexstat
= _tnfctl_map_to_errcode(prbstat
);
132 prexstat
= tnfctl_pid_open((pid_t
)reg0
,
134 disable_target_state(*child_hndl
);
137 return (TNFCTL_ERR_NONE
);
141 * update state in handle
142 * REMIND: Only need to call _tnfctl_refresh_process on
143 * dlopen or dlclose. Need to take out other functionality
144 * of refresh_process into a separate function that should
147 prexstat
= _tnfctl_refresh_process(hndl
, &lmapok
, &dl_evt
);
148 if (prexstat
&& (lmapok
== B_TRUE
))
150 prexstat
= TNFCTL_ERR_NONE
;
153 /* see if we have more detail about the event */
154 if (dl_evt
== EVT_OPEN
)
155 *evt
= TNFCTL_EVENT_DLOPEN
;
156 else if (dl_evt
== EVT_CLOSE
)
157 *evt
= TNFCTL_EVENT_DLCLOSE
;
159 return (TNFCTL_ERR_NONE
);
163 * Continues target and waits for it to stop.
164 * warning: This routine returns TNFCTL_EVENT_DLOPEN for any kind of
165 * dl activity. Up to the caller to determine the actual DL event.
167 static tnfctl_errcode_t
168 _tnfctl_continue(tnfctl_handle_t
*hndl
, tnfctl_event_t
*evt
, sigset_t
*oldmask
,
169 boolean_t watch_forks
)
171 tnfctl_errcode_t prexstat
;
172 tnfctl_errcode_t ret_prexstat
= TNFCTL_ERR_NONE
;
173 prb_status_t prbstat
, prbstat2
;
174 prb_proc_ctl_t
*proc_p
;
175 prb_proc_state_t state
;
177 proc_p
= hndl
->proc_p
;
179 /* set up state before we run process */
180 prexstat
= enable_target_state(hndl
, watch_forks
);
187 prbstat
= prb_proc_cont(proc_p
);
189 ret_prexstat
= _tnfctl_map_to_errcode(prbstat
);
193 /* wait on target to stop (standby) */
194 prbstat
= prb_proc_wait(proc_p
, B_TRUE
, oldmask
);
196 if (prbstat
== EINTR
) {
197 *evt
= TNFCTL_EVENT_EINTR
;
198 prbstat2
= prb_proc_stop(proc_p
);
200 ret_prexstat
= _tnfctl_map_to_errcode(prbstat2
);
203 } else if (prbstat
== ENOENT
) {
204 /* target process finished */
205 if (hndl
->called_exit
)
206 *evt
= TNFCTL_EVENT_EXIT
;
208 *evt
= TNFCTL_EVENT_TARGGONE
;
209 /* return directly - process no longer around */
210 return (TNFCTL_ERR_INTERNAL
);
212 ret_prexstat
= _tnfctl_map_to_errcode(prbstat
);
217 prbstat
= prb_proc_state(proc_p
, &state
);
219 ret_prexstat
= _tnfctl_map_to_errcode(prbstat
);
222 if (state
.ps_isbptfault
) {
223 /* dlopen or dlclose */
224 prbstat
= prb_rtld_advance(proc_p
);
226 ret_prexstat
= _tnfctl_map_to_errcode(prbstat
);
230 * actually don't know if it is a dlopen or dlclose yet.
231 * But, we return dlopen here. Up to the caller to determine
232 * which one it actually is.
234 *evt
= TNFCTL_EVENT_DLOPEN
;
236 if (state
.ps_issysentry
) {
237 switch (state
.ps_syscallnum
) {
239 *evt
= TNFCTL_EVENT_EXEC
;
240 ret_prexstat
= TNFCTL_ERR_INTERNAL
;
243 hndl
->called_exit
= B_TRUE
;
248 } else if (state
.ps_issysexit
) {
249 switch (state
.ps_syscallnum
) {
252 *evt
= TNFCTL_EVENT_FORK
;
260 * disable all our sycall tracing and bpt setup in process when it
261 * is stopped, so that even if the controlling process aborts,
262 * the target could continue running
264 prexstat
= disable_target_state(hndl
);
267 return (ret_prexstat
);
271 * enable the system call tracing and dl activity tracing
273 static tnfctl_errcode_t
274 enable_target_state(tnfctl_handle_t
*hndl
, boolean_t watch_forks
)
276 prb_status_t prbstat
;
277 prb_proc_ctl_t
*proc_p
;
279 proc_p
= hndl
->proc_p
;
282 prbstat
= prb_proc_entry(proc_p
, SYS_execve
, PRB_SYS_ADD
);
284 return (_tnfctl_map_to_errcode(prbstat
));
286 prbstat
= prb_proc_entry(proc_p
, SYS_exit
, PRB_SYS_ADD
);
288 return (_tnfctl_map_to_errcode(prbstat
));
289 /* trace fork if the caller requests */
291 prbstat
= prb_proc_exit(proc_p
, SYS_vfork
, PRB_SYS_ADD
);
293 return (_tnfctl_map_to_errcode(prbstat
));
295 prbstat
= prb_proc_exit(proc_p
, SYS_forksys
, PRB_SYS_ADD
);
297 return (_tnfctl_map_to_errcode(prbstat
));
299 prbstat
= prb_proc_setfork(proc_p
, B_TRUE
);
301 return (_tnfctl_map_to_errcode(prbstat
));
304 * tracing flags for fork and exec will get unset when
305 * process stops. see disable_target_state()
308 /* setup process to stop during dlopen() or dlclose() */
309 prbstat
= prb_rtld_stalk(proc_p
);
310 return (_tnfctl_map_to_errcode(prbstat
));
314 * disable the system call tracing and dl activity tracing
316 static tnfctl_errcode_t
317 disable_target_state(tnfctl_handle_t
*hndl
)
319 prb_status_t prbstat
;
320 prb_proc_ctl_t
*proc_p
;
322 proc_p
= hndl
->proc_p
;
324 /* remove the stalking breakpoint while the process is stopped */
325 prbstat
= prb_rtld_unstalk(proc_p
);
327 return (_tnfctl_map_to_errcode(prbstat
));
329 /* remove the exec, exit and fork tracing while stopped */
330 prbstat
= prb_proc_entry(proc_p
, SYS_execve
, PRB_SYS_DEL
);
332 return (_tnfctl_map_to_errcode(prbstat
));
333 prbstat
= prb_proc_entry(proc_p
, SYS_exit
, PRB_SYS_DEL
);
335 return (_tnfctl_map_to_errcode(prbstat
));
336 prbstat
= prb_proc_exit(proc_p
, SYS_vfork
, PRB_SYS_DEL
);
338 return (_tnfctl_map_to_errcode(prbstat
));
339 prbstat
= prb_proc_exit(proc_p
, SYS_forksys
, PRB_SYS_DEL
);
341 return (_tnfctl_map_to_errcode(prbstat
));
342 prbstat
= prb_proc_setfork(proc_p
, B_FALSE
);
344 return (_tnfctl_map_to_errcode(prbstat
));
346 return (TNFCTL_ERR_NONE
);