summaryrefslogtreecommitdiff
path: root/usr/src/lib/libtnfctl/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libtnfctl/open.c')
-rw-r--r--usr/src/lib/libtnfctl/open.c541
1 files changed, 0 insertions, 541 deletions
diff --git a/usr/src/lib/libtnfctl/open.c b/usr/src/lib/libtnfctl/open.c
deleted file mode 100644
index f3087aa40a..0000000000
--- a/usr/src/lib/libtnfctl/open.c
+++ /dev/null
@@ -1,541 +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.
- */
-
-/*
- * Interfaces that return a tnfctl handle back to client (except for
- * tnfctl_internal_open()) and helper functions for these interfaces.
- * Also has buffer alloc, buffer dealloc, and trace attributes retrieval
- * interfaces.
- */
-
-#include "tnfctl_int.h"
-#include "kernel_int.h"
-#include "dbg.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-
-static tnfctl_errcode_t attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp);
-static tnfctl_errcode_t step_to_end_of_exec(tnfctl_handle_t *hndl);
-
-/*
- * invokes the target program and executes it till the run time linker (rtld)
- * has loaded in the shared objects (but before any .init sections are
- * executed). Returns a pointer to a tnfctl handle.
- */
-tnfctl_errcode_t
-tnfctl_exec_open(const char *pgm_name, char * const *args, char * const *envp,
- const char *ld_preload,
- const char *libtnfprobe_path,
- tnfctl_handle_t **ret_val)
-{
- tnfctl_handle_t *hdl;
- prb_proc_ctl_t *proc_p = NULL;
- prb_status_t prbstat;
- uintptr_t dbgaddr;
- tnfctl_errcode_t prexstat;
-
- prbstat = prb_child_create(pgm_name, args, ld_preload, libtnfprobe_path,
- envp, &proc_p);
- if (prbstat) {
- return (_tnfctl_map_to_errcode(prbstat));
- }
-
- /* allocate hdl and zero fill */
- hdl = calloc(1, sizeof (*hdl));
- if (hdl == NULL) {
- (void) prb_proc_close(proc_p);
- return (TNFCTL_ERR_ALLOCFAIL);
- }
-
- hdl->proc_p = proc_p;
- hdl->mode = DIRECT_MODE;
- hdl->called_exit = B_FALSE;
-
- /* use native /proc on this target */
- hdl->p_read = _tnfctl_read_targ;
- hdl->p_write = _tnfctl_write_targ;
- hdl->p_obj_iter = _tnfctl_loadobj_iter;
- hdl->p_getpid = _tnfctl_pid_get;
-
- /*
- * get the address of DT_DEBUG and send it in to prb_ layer.
- * This is needed before before prb_rtld_sync() can be called.
- */
- prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
- if (prexstat)
- goto failure_ret;
-
- prb_dbgaddr(proc_p, dbgaddr);
-
- /* sync up to rtld sync point */
- prbstat = prb_rtld_sync_if_needed(proc_p);
- if (prbstat) {
- prexstat = _tnfctl_map_to_errcode(prbstat);
- goto failure_ret;
- }
-
- /* initialize state in handle */
- prexstat = _tnfctl_set_state(hdl);
- if (prexstat)
- goto failure_ret;
-
- prexstat = _tnfctl_external_getlock(hdl);
- if (prexstat)
- goto failure_ret;
-
- *ret_val = hdl;
- /* Successful return */
- return (TNFCTL_ERR_NONE);
-
-failure_ret:
- (void) prb_proc_close(proc_p);
- free(hdl);
- return (prexstat);
-}
-
-
-/*
- * attaches to a running process. If the process is in the beginning
- * of an exec(2) system call (which is how tnfctl_continue() returns on exec),
- * it steps the process till the end of the the exec. If the process hasn't
- * reached the rtld sync point, the process is continued until it does
- * reach it. Returns a pointer to a tnfctl handle.
- */
-tnfctl_errcode_t
-tnfctl_pid_open(pid_t pid, tnfctl_handle_t **ret_val)
-{
- tnfctl_handle_t *hdl;
- prb_proc_ctl_t *proc_p = NULL;
- uintptr_t dbgaddr;
- prb_status_t prbstat;
- tnfctl_errcode_t prexstat;
-
- prexstat = attach_pid(pid, &proc_p);
- if (prexstat) {
- return (prexstat);
- }
-
- /* allocate hdl and zero fill */
- hdl = calloc(1, sizeof (*hdl));
- if (hdl == NULL) {
- (void) prb_proc_close(proc_p);
- return (TNFCTL_ERR_ALLOCFAIL);
- }
-
- hdl->proc_p = proc_p;
- hdl->mode = DIRECT_MODE;
- hdl->called_exit = B_FALSE;
-
- /* use native /proc on this target */
- hdl->p_read = _tnfctl_read_targ;
- hdl->p_write = _tnfctl_write_targ;
- hdl->p_obj_iter = _tnfctl_loadobj_iter;
- hdl->p_getpid = _tnfctl_pid_get;
-
- /*
- * Since tnfctl_continue() returns when a process does an exec
- * and leaves the process stopped at the beginning of exec, we
- * have to be sure to catch this case.
- */
- prexstat = step_to_end_of_exec(hdl);
- /* proc_p could be side effected by step_to_end_of_exec() */
- proc_p = hdl->proc_p;
- if (prexstat)
- goto failure_ret;
-
- /*
- * get the address of DT_DEBUG and send it in to prb_ layer.
- */
- prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
- if (prexstat)
- goto failure_ret;
-
- prb_dbgaddr(proc_p, dbgaddr);
-
- /* sync up to rtld sync point if target is not there yet */
- prbstat = prb_rtld_sync_if_needed(proc_p);
- if (prbstat) {
- prexstat = _tnfctl_map_to_errcode(prbstat);
- goto failure_ret;
- }
-
- /* initialize state in handle */
- prexstat = _tnfctl_set_state(hdl);
- if (prexstat)
- goto failure_ret;
-
- /* set state in target indicating we're tracing externally */
- prexstat = _tnfctl_external_getlock(hdl);
- if (prexstat)
- goto failure_ret;
-
- *ret_val = hdl;
-
- /* Sucessful return */
- return (TNFCTL_ERR_NONE);
-
-failure_ret:
- (void) prb_proc_close(proc_p);
- free(hdl);
- return (prexstat);
-}
-
-/*
- * open a process for tracing without using native /proc on it. The client
- * provides a set of callback functions which encapsulate the /proc
- * functionality we need. Returns a pointer to a tnfctl handle.
- */
-tnfctl_errcode_t
-tnfctl_indirect_open(void *prochandle, tnfctl_ind_config_t *config,
- tnfctl_handle_t **ret_val)
-{
- tnfctl_handle_t *hdl;
- tnfctl_errcode_t prexstat;
-
- /* allocate hdl and zero fill */
- hdl = calloc(1, sizeof (*hdl));
- if (hdl == NULL) {
- return (TNFCTL_ERR_ALLOCFAIL);
- }
-
- hdl->proc_p = prochandle;
- hdl->mode = INDIRECT_MODE;
- hdl->called_exit = B_FALSE;
-
- /* initialize callback functions */
- hdl->p_read = config->p_read;
- hdl->p_write = config->p_write;
- hdl->p_obj_iter = config->p_obj_iter;
- hdl->p_getpid = config->p_getpid;
-
- /* initialize state in handle */
- prexstat = _tnfctl_set_state(hdl);
- if (prexstat) {
- free(hdl);
- return (prexstat);
- }
- /* set state in target indicating we're tracing externally */
- prexstat = _tnfctl_external_getlock(hdl);
- if (prexstat) {
- free(hdl);
- return (prexstat);
- }
- *ret_val = hdl;
- return (TNFCTL_ERR_NONE);
-}
-
-/*
- * Returns a pointer to a tnfctl handle that can do kernel trace control
- * and kernel probe control.
- */
-tnfctl_errcode_t
-tnfctl_kernel_open(tnfctl_handle_t **ret_val)
-{
- tnfctl_handle_t *hdl;
- tnfctl_errcode_t prexstat;
-
- /* allocate hdl and zero fill */
- hdl = calloc(1, sizeof (*hdl));
- if (hdl == NULL) {
- return (TNFCTL_ERR_ALLOCFAIL);
- }
-
- /* initialize kernel tracing */
- prexstat = _tnfctl_prbk_init(hdl);
- if (prexstat)
- return (prexstat);
-
- hdl->mode = KERNEL_MODE;
- hdl->targ_pid = 0;
-
- /* initialize function pointers that can be stuffed into a probe */
- _tnfctl_prbk_get_other_funcs(&hdl->allocfunc, &hdl->commitfunc,
- &hdl->rollbackfunc, &hdl->endfunc);
- _tnfctl_prbk_test_func(&hdl->testfunc);
-
- /* find the probes in the kernel */
- prexstat = _tnfctl_refresh_kernel(hdl);
- if (prexstat)
- return (prexstat);
-
- *ret_val = hdl;
- return (TNFCTL_ERR_NONE);
-}
-
-/*
- * Returns the trace attributes to the client. Since there can be
- * only one controlling agent on a target at a time, our cached information
- * is correct and we don't have to actually retrieve any information
- * from the target.
- */
-tnfctl_errcode_t
-tnfctl_trace_attrs_get(tnfctl_handle_t *hdl, tnfctl_trace_attrs_t *attrs)
-{
- boolean_t release_lock;
- tnfctl_errcode_t prexstat;
-
- /*LINTED statement has no consequent: else*/
- LOCK_SYNC(hdl, prexstat, release_lock);
-
- attrs->targ_pid = hdl->targ_pid;
- attrs->trace_file_name = hdl->trace_file_name;
- attrs->trace_buf_size = hdl->trace_buf_size;
- attrs->trace_min_size = hdl->trace_min_size;
- attrs->trace_buf_state = hdl->trace_buf_state;
- attrs->trace_state = hdl->trace_state;
- attrs->filter_state = hdl->kpidfilter_state;
-
- /*LINTED statement has no consequent: else*/
- UNLOCK(hdl, release_lock);
-
- return (TNFCTL_ERR_NONE);
-}
-
-
-/*
- * Allocate a trace buffer of the specified name and size.
- */
-tnfctl_errcode_t
-tnfctl_buffer_alloc(tnfctl_handle_t *hdl, const char *trace_file_name,
- uint_t trace_file_size)
-{
- tnfctl_errcode_t prexstat;
-
- if (hdl->mode == KERNEL_MODE) {
- /* trace_file_name is ignored in kernel mode */
- prexstat = _tnfctl_prbk_buffer_alloc(hdl, trace_file_size);
- if (prexstat)
- return (prexstat);
- return (TNFCTL_ERR_NONE);
- }
-
- /* Not KERNEL_MODE */
- if (hdl->trace_file_name != NULL) {
- /* buffer already allocated */
- return (TNFCTL_ERR_BUFEXISTS);
- }
-
- prexstat = _tnfctl_create_tracefile(hdl, trace_file_name,
- trace_file_size);
- if (prexstat) {
- return (prexstat);
- }
-
- return (TNFCTL_ERR_NONE);
-}
-
-/*
- * Deallocate the trace buffer - only works for kernel mode
- */
-tnfctl_errcode_t
-tnfctl_buffer_dealloc(tnfctl_handle_t *hdl)
-{
- tnfctl_errcode_t prexstat;
-
- if (hdl->mode != KERNEL_MODE)
- return (TNFCTL_ERR_BADARG);
-
- /* KERNEL_MODE */
- prexstat = _tnfctl_prbk_buffer_dealloc(hdl);
- if (prexstat)
- return (prexstat);
- return (TNFCTL_ERR_NONE);
-}
-
-
-/*
- * Helper function for attaching to a target process
- */
-static tnfctl_errcode_t
-attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp)
-{
- prb_status_t prbstat;
- prb_proc_ctl_t *proc_p;
-
- if (getpid() == pid)
- return (TNFCTL_ERR_BADARG);
-
- /* check if pid is valid */
- if ((kill(pid, 0) == -1) && errno == ESRCH) {
- return (TNFCTL_ERR_NOPROCESS);
- }
- /* open up /proc fd */
- prbstat = prb_proc_open(pid, proc_pp);
- if (prbstat)
- return (_tnfctl_map_to_errcode(prbstat));
-
- proc_p = *proc_pp;
- /*
- * default is to run-on-last-close. In case we cannot sync with
- * target, we don't want to kill the target.
- */
- prbstat = prb_proc_setrlc(proc_p, B_TRUE);
- if (prbstat)
- goto failure_ret;
- prbstat = prb_proc_setklc(proc_p, B_FALSE);
- if (prbstat)
- goto failure_ret;
-
- /* stop process */
- prbstat = prb_proc_stop(proc_p);
- if (prbstat)
- goto failure_ret;
-
- /* Sucessful return */
- return (TNFCTL_ERR_NONE);
-
-failure_ret:
- (void) prb_proc_close(proc_p);
- return (_tnfctl_map_to_errcode(prbstat));
-}
-
-/*
- * Checks if target is at the beginning of an exec system call. If so,
- * it runs it till the end of the exec system call. It takes care of
- * the case where you're about to exec a setuid program.
- * CAUTION: could side effect hndl->proc_p
- */
-static tnfctl_errcode_t
-step_to_end_of_exec(tnfctl_handle_t *hndl)
-{
- prb_proc_ctl_t *proc_p, *oldproc_p;
- prb_status_t prbstat, tempstat;
- int pid;
- prb_proc_state_t pstate;
-
- proc_p = hndl->proc_p;
- pid = hndl->p_getpid(proc_p);
-
- prbstat = prb_proc_state(proc_p, &pstate);
- if (prbstat)
- return (_tnfctl_map_to_errcode(prbstat));
- if (!(pstate.ps_issysentry && pstate.ps_syscallnum == SYS_execve)) {
- /* not stopped at beginning of exec system call */
- return (TNFCTL_ERR_NONE);
- }
-
- /* we are stopped at beginning of exec system call */
-
- prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD);
- if (prbstat)
- return (_tnfctl_map_to_errcode(prbstat));
-
- prbstat = prb_proc_cont(proc_p);
- if (prbstat)
- return (_tnfctl_map_to_errcode(prbstat));
-
- prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
- switch (prbstat) {
- case PRB_STATUS_OK:
- break;
- case PRB_STATUS_EAGAIN:
- /*
- * If we had exec'ed a setuid/setgid program PIOCWSTOP
- * will return EAGAIN. Reopen the 'fd' and try again.
- * Read the last section of /proc man page - we reopen first
- * and then close the old fd.
- */
- oldproc_p = proc_p;
- tempstat = prb_proc_reopen(pid, &proc_p);
- if (tempstat) {
- /* here EACCES means exec'ed a setuid/setgid program */
- return (_tnfctl_map_to_errcode(tempstat));
- }
-
- prb_proc_close(oldproc_p);
- hndl->proc_p = proc_p;
- break;
- default:
- return (_tnfctl_map_to_errcode(prbstat));
- }
-
- prbstat = prb_proc_state(proc_p, &pstate);
- if (prbstat)
- return (_tnfctl_map_to_errcode(prbstat));
-
- if (!(pstate.ps_issysexit && pstate.ps_syscallnum == SYS_execve)) {
- /* unexpected condition */
- return (tnfctl_status_map(ENOENT));
- }
-
- /* clear old interest mask */
- prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_DEL);
- if (prbstat)
- return (_tnfctl_map_to_errcode(prbstat));
- return (TNFCTL_ERR_NONE);
-}
-
-
-tnfctl_errcode_t
-_tnfctl_external_getlock(tnfctl_handle_t *hdl)
-{
-
- tnfctl_errcode_t prexstat;
- prb_status_t prbstat;
- uintptr_t targ_symbol_ptr;
- int internal_tracing_on;
-
- prexstat = _tnfctl_sym_find(hdl, TNFCTL_INTERNAL_TRACEFLAG,
- &targ_symbol_ptr);
- if (prexstat) {
- /* no libtnfctl in target: success */
- return (TNFCTL_ERR_NONE);
- }
- prbstat = hdl->p_read(hdl->proc_p, targ_symbol_ptr,
- &internal_tracing_on, sizeof (internal_tracing_on));
-
- if (prbstat) {
- prexstat = _tnfctl_map_to_errcode(prbstat);
- goto failure_ret;
- }
- if (internal_tracing_on) {
- /* target process being traced internally */
- prexstat = TNFCTL_ERR_BUSY;
- goto failure_ret;
- }
- prexstat = _tnfctl_sym_find(hdl, TNFCTL_EXTERNAL_TRACEDPID,
- &targ_symbol_ptr);
- if (prexstat) {
- /* this shouldn't happen. we know we have libtnfctl */
- goto failure_ret;
- }
- prbstat = hdl->p_write(hdl->proc_p, targ_symbol_ptr,
- &(hdl->targ_pid), sizeof (hdl->targ_pid));
- if (prbstat) {
- prexstat = _tnfctl_map_to_errcode(prbstat);
- goto failure_ret;
- }
- /* success */
- DBG((void) fprintf(stderr, "_tnfctl_external_getlock: ok to trace %d\n",
- hdl->targ_pid));
- return (TNFCTL_ERR_NONE);
-
-failure_ret:
- return (prexstat);
-}