6429 SMB domain join doesn't work with libreSSL
[unleashed.git] / usr / src / lib / libtnfctl / continue.c
blobcc4ef319d34ad580ec212cf40c95bec20586091e
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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"
33 #include "prb_proc.h"
34 #include "dbg.h"
37 #include <stdlib.h>
38 #include <errno.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
49 * process.
51 tnfctl_errcode_t
52 tnfctl_continue(tnfctl_handle_t *hndl, tnfctl_event_t *evt,
53 tnfctl_handle_t **child_hndl)
55 tnfctl_errcode_t prexstat;
56 prb_status_t prbstat;
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;
64 prgreg_t reg0, reg1;
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,
97 watch_forks);
98 if (prexstat) {
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);
109 *evt = my_evt;
110 return (TNFCTL_ERR_NONE);
111 } else if (my_evt == TNFCTL_EVENT_EXEC) {
112 *evt = my_evt;
113 return (TNFCTL_ERR_NONE);
114 } else if (prexstat == TNFCTL_ERR_FILENOTFOUND) {
115 return (TNFCTL_ERR_NOPROCESS);
116 } else {
117 return (prexstat);
120 if (my_evt == TNFCTL_EVENT_FORK) {
122 * sanity check. we should only get here if child_hndl is set
124 if (child_hndl) {
125 *evt = my_evt;
126 prbstat = prb_proc_get_r0_r1(proc_p,
127 &reg0, &reg1);
128 if (prbstat) {
129 prexstat = _tnfctl_map_to_errcode(prbstat);
130 return (prexstat);
132 prexstat = tnfctl_pid_open((pid_t)reg0,
133 child_hndl);
134 disable_target_state(*child_hndl);
135 return (prexstat);
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
145 * be called here.
147 prexstat = _tnfctl_refresh_process(hndl, &lmapok, &dl_evt);
148 if (prexstat && (lmapok == B_TRUE))
149 return (prexstat);
150 prexstat = TNFCTL_ERR_NONE;
152 *evt = my_evt;
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);
181 if (prexstat)
182 return (prexstat);
184 again:
186 /* resume target */
187 prbstat = prb_proc_cont(proc_p);
188 if (prbstat) {
189 ret_prexstat = _tnfctl_map_to_errcode(prbstat);
190 goto end_of_func;
193 /* wait on target to stop (standby) */
194 prbstat = prb_proc_wait(proc_p, B_TRUE, oldmask);
195 if (prbstat) {
196 if (prbstat == EINTR) {
197 *evt = TNFCTL_EVENT_EINTR;
198 prbstat2 = prb_proc_stop(proc_p);
199 if (prbstat2) {
200 ret_prexstat = _tnfctl_map_to_errcode(prbstat2);
201 goto end_of_func;
203 } else if (prbstat == ENOENT) {
204 /* target process finished */
205 if (hndl->called_exit)
206 *evt = TNFCTL_EVENT_EXIT;
207 else
208 *evt = TNFCTL_EVENT_TARGGONE;
209 /* return directly - process no longer around */
210 return (TNFCTL_ERR_INTERNAL);
211 } else {
212 ret_prexstat = _tnfctl_map_to_errcode(prbstat);
213 goto end_of_func;
217 prbstat = prb_proc_state(proc_p, &state);
218 if (prbstat) {
219 ret_prexstat = _tnfctl_map_to_errcode(prbstat);
220 goto end_of_func;
222 if (state.ps_isbptfault) {
223 /* dlopen or dlclose */
224 prbstat = prb_rtld_advance(proc_p);
225 if (prbstat) {
226 ret_prexstat = _tnfctl_map_to_errcode(prbstat);
227 goto end_of_func;
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;
235 } else
236 if (state.ps_issysentry) {
237 switch (state.ps_syscallnum) {
238 case SYS_execve:
239 *evt = TNFCTL_EVENT_EXEC;
240 ret_prexstat = TNFCTL_ERR_INTERNAL;
241 break;
242 case SYS_exit:
243 hndl->called_exit = B_TRUE;
244 goto again;
245 default:
246 break;
248 } else if (state.ps_issysexit) {
249 switch (state.ps_syscallnum) {
250 case SYS_vfork:
251 case SYS_forksys:
252 *evt = TNFCTL_EVENT_FORK;
253 break;
254 default:
255 break;
258 end_of_func:
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);
265 if (prexstat)
266 return (prexstat);
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;
281 /* trace exec */
282 prbstat = prb_proc_entry(proc_p, SYS_execve, PRB_SYS_ADD);
283 if (prbstat)
284 return (_tnfctl_map_to_errcode(prbstat));
285 /* trace exit */
286 prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD);
287 if (prbstat)
288 return (_tnfctl_map_to_errcode(prbstat));
289 /* trace fork if the caller requests */
290 if (watch_forks) {
291 prbstat = prb_proc_exit(proc_p, SYS_vfork, PRB_SYS_ADD);
292 if (prbstat)
293 return (_tnfctl_map_to_errcode(prbstat));
295 prbstat = prb_proc_exit(proc_p, SYS_forksys, PRB_SYS_ADD);
296 if (prbstat)
297 return (_tnfctl_map_to_errcode(prbstat));
299 prbstat = prb_proc_setfork(proc_p, B_TRUE);
300 if (prbstat)
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);
326 if (prbstat)
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);
331 if (prbstat)
332 return (_tnfctl_map_to_errcode(prbstat));
333 prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL);
334 if (prbstat)
335 return (_tnfctl_map_to_errcode(prbstat));
336 prbstat = prb_proc_exit(proc_p, SYS_vfork, PRB_SYS_DEL);
337 if (prbstat)
338 return (_tnfctl_map_to_errcode(prbstat));
339 prbstat = prb_proc_exit(proc_p, SYS_forksys, PRB_SYS_DEL);
340 if (prbstat)
341 return (_tnfctl_map_to_errcode(prbstat));
342 prbstat = prb_proc_setfork(proc_p, B_FALSE);
343 if (prbstat)
344 return (_tnfctl_map_to_errcode(prbstat));
346 return (TNFCTL_ERR_NONE);