summaryrefslogtreecommitdiff
path: root/usr/src/lib/libtnfctl/continue.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libtnfctl/continue.c')
-rw-r--r--usr/src/lib/libtnfctl/continue.c347
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,
- &reg0, &reg1);
- 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);
-}