diff options
Diffstat (limited to 'usr/src/lib/libtnfctl/continue.c')
-rw-r--r-- | usr/src/lib/libtnfctl/continue.c | 347 |
1 files changed, 0 insertions, 347 deletions
diff --git a/usr/src/lib/libtnfctl/continue.c b/usr/src/lib/libtnfctl/continue.c deleted file mode 100644 index cc4ef319d3..0000000000 --- a/usr/src/lib/libtnfctl/continue.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * interface to continue a target process (DIRECT_MODE) and helper - * functions needed by this routine. - */ - -#include "tnfctl_int.h" -#include "prb_proc.h" -#include "dbg.h" - - -#include <stdlib.h> -#include <errno.h> - -static tnfctl_errcode_t _tnfctl_continue(tnfctl_handle_t *hndl, - tnfctl_event_t *evt, sigset_t *oldmask, boolean_t watch_forks); -static tnfctl_errcode_t enable_target_state(tnfctl_handle_t *hndl, - boolean_t watch_forks); -static tnfctl_errcode_t disable_target_state(tnfctl_handle_t *hndl); - -/* - * continue the target process and return the evt it stopped on. - * If child_hndl is set and we see a fork, return a handle on child - * process. - */ -tnfctl_errcode_t -tnfctl_continue(tnfctl_handle_t *hndl, tnfctl_event_t *evt, - tnfctl_handle_t **child_hndl) -{ - tnfctl_errcode_t prexstat; - prb_status_t prbstat; - boolean_t lmapok = B_FALSE; - boolean_t watch_forks; - /* set my_evt to something other than TNFCTL_EVENT_TARGGONE */ - tnfctl_event_t my_evt = TNFCTL_EVENT_EINTR; - enum event_op_t dl_evt; - sigset_t newmask, oldmask; - prb_proc_ctl_t *proc_p; - prgreg_t reg0, reg1; - - /* this interface only works for DIRECT_MODE clients */ - if (hndl->mode != DIRECT_MODE) - return (TNFCTL_ERR_BADARG); - - proc_p = hndl->proc_p; - - if (sigfillset(&newmask) == -1) - return (tnfctl_status_map(errno)); - - watch_forks = (child_hndl != NULL); - - /* - * XXXX block all signals. Synchronous signals like SEGV that - * the user could catch and handle will now result in a core dump. - * But, this is very unlikely for 2 reasons - most users don't try - * to handle synchronous signals - it usually just aborts the process. - * And, secondly, the code until we return the original mask is the - * place where this synchronous signal would be generated - and, it - * is not very much code. - */ - if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) == -1) - return (tnfctl_status_map(errno)); - - /* - * Target is stopped on entry because tnfctl_continue() - * only returns with a stopped target. - */ - - /* target process shouldn't be stopped when link maps are incosistent */ - while (lmapok == B_FALSE) { - prexstat = _tnfctl_continue(hndl, &my_evt, &oldmask, - watch_forks); - if (prexstat) { - if (my_evt == TNFCTL_EVENT_TARGGONE || - my_evt == TNFCTL_EVENT_EXIT) { - /* - * target exited - free obj list and probe - * list so that we keep our internal state - * correct, else probe control interfaces will - * have wrong information. - */ - DBG(fprintf(stderr, "target is gone\n")); - _tnfctl_free_objs_and_probes(hndl); - *evt = my_evt; - return (TNFCTL_ERR_NONE); - } else if (my_evt == TNFCTL_EVENT_EXEC) { - *evt = my_evt; - return (TNFCTL_ERR_NONE); - } else if (prexstat == TNFCTL_ERR_FILENOTFOUND) { - return (TNFCTL_ERR_NOPROCESS); - } else { - return (prexstat); - } - } - if (my_evt == TNFCTL_EVENT_FORK) { - /* - * sanity check. we should only get here if child_hndl is set - */ - if (child_hndl) { - *evt = my_evt; - prbstat = prb_proc_get_r0_r1(proc_p, - ®0, ®1); - if (prbstat) { - prexstat = _tnfctl_map_to_errcode(prbstat); - return (prexstat); - } - prexstat = tnfctl_pid_open((pid_t)reg0, - child_hndl); - disable_target_state(*child_hndl); - return (prexstat); - } - return (TNFCTL_ERR_NONE); - } - - /* - * update state in handle - * REMIND: Only need to call _tnfctl_refresh_process on - * dlopen or dlclose. Need to take out other functionality - * of refresh_process into a separate function that should - * be called here. - */ - prexstat = _tnfctl_refresh_process(hndl, &lmapok, &dl_evt); - if (prexstat && (lmapok == B_TRUE)) - return (prexstat); - prexstat = TNFCTL_ERR_NONE; - } - *evt = my_evt; - /* see if we have more detail about the event */ - if (dl_evt == EVT_OPEN) - *evt = TNFCTL_EVENT_DLOPEN; - else if (dl_evt == EVT_CLOSE) - *evt = TNFCTL_EVENT_DLCLOSE; - - return (TNFCTL_ERR_NONE); -} - -/* - * Continues target and waits for it to stop. - * warning: This routine returns TNFCTL_EVENT_DLOPEN for any kind of - * dl activity. Up to the caller to determine the actual DL event. - */ -static tnfctl_errcode_t -_tnfctl_continue(tnfctl_handle_t *hndl, tnfctl_event_t *evt, sigset_t *oldmask, - boolean_t watch_forks) -{ - tnfctl_errcode_t prexstat; - tnfctl_errcode_t ret_prexstat = TNFCTL_ERR_NONE; - prb_status_t prbstat, prbstat2; - prb_proc_ctl_t *proc_p; - prb_proc_state_t state; - - proc_p = hndl->proc_p; - - /* set up state before we run process */ - prexstat = enable_target_state(hndl, watch_forks); - if (prexstat) - return (prexstat); - -again: - - /* resume target */ - prbstat = prb_proc_cont(proc_p); - if (prbstat) { - ret_prexstat = _tnfctl_map_to_errcode(prbstat); - goto end_of_func; - } - - /* wait on target to stop (standby) */ - prbstat = prb_proc_wait(proc_p, B_TRUE, oldmask); - if (prbstat) { - if (prbstat == EINTR) { - *evt = TNFCTL_EVENT_EINTR; - prbstat2 = prb_proc_stop(proc_p); - if (prbstat2) { - ret_prexstat = _tnfctl_map_to_errcode(prbstat2); - goto end_of_func; - } - } else if (prbstat == ENOENT) { - /* target process finished */ - if (hndl->called_exit) - *evt = TNFCTL_EVENT_EXIT; - else - *evt = TNFCTL_EVENT_TARGGONE; - /* return directly - process no longer around */ - return (TNFCTL_ERR_INTERNAL); - } else { - ret_prexstat = _tnfctl_map_to_errcode(prbstat); - goto end_of_func; - } - } - - prbstat = prb_proc_state(proc_p, &state); - if (prbstat) { - ret_prexstat = _tnfctl_map_to_errcode(prbstat); - goto end_of_func; - } - if (state.ps_isbptfault) { - /* dlopen or dlclose */ - prbstat = prb_rtld_advance(proc_p); - if (prbstat) { - ret_prexstat = _tnfctl_map_to_errcode(prbstat); - goto end_of_func; - } - /* - * actually don't know if it is a dlopen or dlclose yet. - * But, we return dlopen here. Up to the caller to determine - * which one it actually is. - */ - *evt = TNFCTL_EVENT_DLOPEN; - } else - if (state.ps_issysentry) { - switch (state.ps_syscallnum) { - case SYS_execve: - *evt = TNFCTL_EVENT_EXEC; - ret_prexstat = TNFCTL_ERR_INTERNAL; - break; - case SYS_exit: - hndl->called_exit = B_TRUE; - goto again; - default: - break; - } - } else if (state.ps_issysexit) { - switch (state.ps_syscallnum) { - case SYS_vfork: - case SYS_forksys: - *evt = TNFCTL_EVENT_FORK; - break; - default: - break; - } - } -end_of_func: - /* - * disable all our sycall tracing and bpt setup in process when it - * is stopped, so that even if the controlling process aborts, - * the target could continue running - */ - prexstat = disable_target_state(hndl); - if (prexstat) - return (prexstat); - return (ret_prexstat); -} - -/* - * enable the system call tracing and dl activity tracing - */ -static tnfctl_errcode_t -enable_target_state(tnfctl_handle_t *hndl, boolean_t watch_forks) -{ - prb_status_t prbstat; - prb_proc_ctl_t *proc_p; - - proc_p = hndl->proc_p; - - /* trace exec */ - prbstat = prb_proc_entry(proc_p, SYS_execve, PRB_SYS_ADD); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - /* trace exit */ - prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - /* trace fork if the caller requests */ - if (watch_forks) { - prbstat = prb_proc_exit(proc_p, SYS_vfork, PRB_SYS_ADD); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - - prbstat = prb_proc_exit(proc_p, SYS_forksys, PRB_SYS_ADD); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - - prbstat = prb_proc_setfork(proc_p, B_TRUE); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - } - /* - * tracing flags for fork and exec will get unset when - * process stops. see disable_target_state() - */ - - /* setup process to stop during dlopen() or dlclose() */ - prbstat = prb_rtld_stalk(proc_p); - return (_tnfctl_map_to_errcode(prbstat)); -} - -/* - * disable the system call tracing and dl activity tracing - */ -static tnfctl_errcode_t -disable_target_state(tnfctl_handle_t *hndl) -{ - prb_status_t prbstat; - prb_proc_ctl_t *proc_p; - - proc_p = hndl->proc_p; - - /* remove the stalking breakpoint while the process is stopped */ - prbstat = prb_rtld_unstalk(proc_p); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - - /* remove the exec, exit and fork tracing while stopped */ - prbstat = prb_proc_entry(proc_p, SYS_execve, PRB_SYS_DEL); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_DEL); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - prbstat = prb_proc_exit(proc_p, SYS_vfork, PRB_SYS_DEL); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - prbstat = prb_proc_exit(proc_p, SYS_forksys, PRB_SYS_DEL); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - prbstat = prb_proc_setfork(proc_p, B_FALSE); - if (prbstat) - return (_tnfctl_map_to_errcode(prbstat)); - - return (TNFCTL_ERR_NONE); -} |