17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*8fd04b83SRoger A. Faulkner * Common Development and Distribution License (the "License").
6*8fd04b83SRoger A. Faulkner * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate
22*8fd04b83SRoger A. Faulkner /*
23*8fd04b83SRoger A. Faulkner * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24*8fd04b83SRoger A. Faulkner * Use is subject to license terms.
25*8fd04b83SRoger A. Faulkner */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * Interfaces that return a tnfctl handle back to client (except for
297c478bd9Sstevel@tonic-gate * tnfctl_internal_open()) and helper functions for these interfaces.
307c478bd9Sstevel@tonic-gate * Also has buffer alloc, buffer dealloc, and trace attributes retrieval
317c478bd9Sstevel@tonic-gate * interfaces.
327c478bd9Sstevel@tonic-gate */
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate #include "tnfctl_int.h"
357c478bd9Sstevel@tonic-gate #include "kernel_int.h"
367c478bd9Sstevel@tonic-gate #include "dbg.h"
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
397c478bd9Sstevel@tonic-gate #include <unistd.h>
407c478bd9Sstevel@tonic-gate #include <signal.h>
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate static tnfctl_errcode_t attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp);
447c478bd9Sstevel@tonic-gate static tnfctl_errcode_t step_to_end_of_exec(tnfctl_handle_t *hndl);
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate * invokes the target program and executes it till the run time linker (rtld)
487c478bd9Sstevel@tonic-gate * has loaded in the shared objects (but before any .init sections are
497c478bd9Sstevel@tonic-gate * executed). Returns a pointer to a tnfctl handle.
507c478bd9Sstevel@tonic-gate */
517c478bd9Sstevel@tonic-gate 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)527c478bd9Sstevel@tonic-gate tnfctl_exec_open(const char *pgm_name, char * const *args, char * const *envp,
537c478bd9Sstevel@tonic-gate const char *ld_preload,
547c478bd9Sstevel@tonic-gate const char *libtnfprobe_path,
557c478bd9Sstevel@tonic-gate tnfctl_handle_t **ret_val)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl;
587c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p = NULL;
597c478bd9Sstevel@tonic-gate prb_status_t prbstat;
607c478bd9Sstevel@tonic-gate uintptr_t dbgaddr;
617c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate prbstat = prb_child_create(pgm_name, args, ld_preload, libtnfprobe_path,
647c478bd9Sstevel@tonic-gate envp, &proc_p);
657c478bd9Sstevel@tonic-gate if (prbstat) {
667c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */
707c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl));
717c478bd9Sstevel@tonic-gate if (hdl == NULL) {
727c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p);
737c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate hdl->proc_p = proc_p;
777c478bd9Sstevel@tonic-gate hdl->mode = DIRECT_MODE;
787c478bd9Sstevel@tonic-gate hdl->called_exit = B_FALSE;
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate /* use native /proc on this target */
817c478bd9Sstevel@tonic-gate hdl->p_read = _tnfctl_read_targ;
827c478bd9Sstevel@tonic-gate hdl->p_write = _tnfctl_write_targ;
837c478bd9Sstevel@tonic-gate hdl->p_obj_iter = _tnfctl_loadobj_iter;
847c478bd9Sstevel@tonic-gate hdl->p_getpid = _tnfctl_pid_get;
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate * get the address of DT_DEBUG and send it in to prb_ layer.
887c478bd9Sstevel@tonic-gate * This is needed before before prb_rtld_sync() can be called.
897c478bd9Sstevel@tonic-gate */
907c478bd9Sstevel@tonic-gate prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
917c478bd9Sstevel@tonic-gate if (prexstat)
927c478bd9Sstevel@tonic-gate goto failure_ret;
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate prb_dbgaddr(proc_p, dbgaddr);
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate /* sync up to rtld sync point */
977c478bd9Sstevel@tonic-gate prbstat = prb_rtld_sync_if_needed(proc_p);
987c478bd9Sstevel@tonic-gate if (prbstat) {
997c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat);
1007c478bd9Sstevel@tonic-gate goto failure_ret;
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate /* initialize state in handle */
1047c478bd9Sstevel@tonic-gate prexstat = _tnfctl_set_state(hdl);
1057c478bd9Sstevel@tonic-gate if (prexstat)
1067c478bd9Sstevel@tonic-gate goto failure_ret;
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate prexstat = _tnfctl_external_getlock(hdl);
1097c478bd9Sstevel@tonic-gate if (prexstat)
1107c478bd9Sstevel@tonic-gate goto failure_ret;
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate *ret_val = hdl;
1137c478bd9Sstevel@tonic-gate /* Successful return */
1147c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate failure_ret:
1177c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p);
1187c478bd9Sstevel@tonic-gate free(hdl);
1197c478bd9Sstevel@tonic-gate return (prexstat);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * attaches to a running process. If the process is in the beginning
1257c478bd9Sstevel@tonic-gate * of an exec(2) system call (which is how tnfctl_continue() returns on exec),
1267c478bd9Sstevel@tonic-gate * it steps the process till the end of the the exec. If the process hasn't
1277c478bd9Sstevel@tonic-gate * reached the rtld sync point, the process is continued until it does
1287c478bd9Sstevel@tonic-gate * reach it. Returns a pointer to a tnfctl handle.
1297c478bd9Sstevel@tonic-gate */
1307c478bd9Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_pid_open(pid_t pid,tnfctl_handle_t ** ret_val)1317c478bd9Sstevel@tonic-gate tnfctl_pid_open(pid_t pid, tnfctl_handle_t **ret_val)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl;
1347c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p = NULL;
1357c478bd9Sstevel@tonic-gate uintptr_t dbgaddr;
1367c478bd9Sstevel@tonic-gate prb_status_t prbstat;
1377c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate prexstat = attach_pid(pid, &proc_p);
1407c478bd9Sstevel@tonic-gate if (prexstat) {
1417c478bd9Sstevel@tonic-gate return (prexstat);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */
1457c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl));
1467c478bd9Sstevel@tonic-gate if (hdl == NULL) {
1477c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p);
1487c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate hdl->proc_p = proc_p;
1527c478bd9Sstevel@tonic-gate hdl->mode = DIRECT_MODE;
1537c478bd9Sstevel@tonic-gate hdl->called_exit = B_FALSE;
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate /* use native /proc on this target */
1567c478bd9Sstevel@tonic-gate hdl->p_read = _tnfctl_read_targ;
1577c478bd9Sstevel@tonic-gate hdl->p_write = _tnfctl_write_targ;
1587c478bd9Sstevel@tonic-gate hdl->p_obj_iter = _tnfctl_loadobj_iter;
1597c478bd9Sstevel@tonic-gate hdl->p_getpid = _tnfctl_pid_get;
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate * Since tnfctl_continue() returns when a process does an exec
1637c478bd9Sstevel@tonic-gate * and leaves the process stopped at the beginning of exec, we
1647c478bd9Sstevel@tonic-gate * have to be sure to catch this case.
1657c478bd9Sstevel@tonic-gate */
1667c478bd9Sstevel@tonic-gate prexstat = step_to_end_of_exec(hdl);
1677c478bd9Sstevel@tonic-gate /* proc_p could be side effected by step_to_end_of_exec() */
1687c478bd9Sstevel@tonic-gate proc_p = hdl->proc_p;
1697c478bd9Sstevel@tonic-gate if (prexstat)
1707c478bd9Sstevel@tonic-gate goto failure_ret;
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate * get the address of DT_DEBUG and send it in to prb_ layer.
1747c478bd9Sstevel@tonic-gate */
1757c478bd9Sstevel@tonic-gate prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr);
1767c478bd9Sstevel@tonic-gate if (prexstat)
1777c478bd9Sstevel@tonic-gate goto failure_ret;
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate prb_dbgaddr(proc_p, dbgaddr);
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /* sync up to rtld sync point if target is not there yet */
1827c478bd9Sstevel@tonic-gate prbstat = prb_rtld_sync_if_needed(proc_p);
1837c478bd9Sstevel@tonic-gate if (prbstat) {
1847c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat);
1857c478bd9Sstevel@tonic-gate goto failure_ret;
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /* initialize state in handle */
1897c478bd9Sstevel@tonic-gate prexstat = _tnfctl_set_state(hdl);
1907c478bd9Sstevel@tonic-gate if (prexstat)
1917c478bd9Sstevel@tonic-gate goto failure_ret;
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate /* set state in target indicating we're tracing externally */
1947c478bd9Sstevel@tonic-gate prexstat = _tnfctl_external_getlock(hdl);
1957c478bd9Sstevel@tonic-gate if (prexstat)
1967c478bd9Sstevel@tonic-gate goto failure_ret;
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate *ret_val = hdl;
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate /* Sucessful return */
2017c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate failure_ret:
2047c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p);
2057c478bd9Sstevel@tonic-gate free(hdl);
2067c478bd9Sstevel@tonic-gate return (prexstat);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate * open a process for tracing without using native /proc on it. The client
2117c478bd9Sstevel@tonic-gate * provides a set of callback functions which encapsulate the /proc
2127c478bd9Sstevel@tonic-gate * functionality we need. Returns a pointer to a tnfctl handle.
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_indirect_open(void * prochandle,tnfctl_ind_config_t * config,tnfctl_handle_t ** ret_val)2157c478bd9Sstevel@tonic-gate tnfctl_indirect_open(void *prochandle, tnfctl_ind_config_t *config,
2167c478bd9Sstevel@tonic-gate tnfctl_handle_t **ret_val)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl;
2197c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */
2227c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl));
2237c478bd9Sstevel@tonic-gate if (hdl == NULL) {
2247c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate hdl->proc_p = prochandle;
2287c478bd9Sstevel@tonic-gate hdl->mode = INDIRECT_MODE;
2297c478bd9Sstevel@tonic-gate hdl->called_exit = B_FALSE;
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate /* initialize callback functions */
2327c478bd9Sstevel@tonic-gate hdl->p_read = config->p_read;
2337c478bd9Sstevel@tonic-gate hdl->p_write = config->p_write;
2347c478bd9Sstevel@tonic-gate hdl->p_obj_iter = config->p_obj_iter;
2357c478bd9Sstevel@tonic-gate hdl->p_getpid = config->p_getpid;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate /* initialize state in handle */
2387c478bd9Sstevel@tonic-gate prexstat = _tnfctl_set_state(hdl);
2397c478bd9Sstevel@tonic-gate if (prexstat) {
2407c478bd9Sstevel@tonic-gate free(hdl);
2417c478bd9Sstevel@tonic-gate return (prexstat);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate /* set state in target indicating we're tracing externally */
2447c478bd9Sstevel@tonic-gate prexstat = _tnfctl_external_getlock(hdl);
2457c478bd9Sstevel@tonic-gate if (prexstat) {
2467c478bd9Sstevel@tonic-gate free(hdl);
2477c478bd9Sstevel@tonic-gate return (prexstat);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate *ret_val = hdl;
2507c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate * Returns a pointer to a tnfctl handle that can do kernel trace control
2557c478bd9Sstevel@tonic-gate * and kernel probe control.
2567c478bd9Sstevel@tonic-gate */
2577c478bd9Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_kernel_open(tnfctl_handle_t ** ret_val)2587c478bd9Sstevel@tonic-gate tnfctl_kernel_open(tnfctl_handle_t **ret_val)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl;
2617c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */
2647c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl));
2657c478bd9Sstevel@tonic-gate if (hdl == NULL) {
2667c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate /* initialize kernel tracing */
2707c478bd9Sstevel@tonic-gate prexstat = _tnfctl_prbk_init(hdl);
2717c478bd9Sstevel@tonic-gate if (prexstat)
2727c478bd9Sstevel@tonic-gate return (prexstat);
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate hdl->mode = KERNEL_MODE;
2757c478bd9Sstevel@tonic-gate hdl->targ_pid = 0;
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate /* initialize function pointers that can be stuffed into a probe */
2787c478bd9Sstevel@tonic-gate _tnfctl_prbk_get_other_funcs(&hdl->allocfunc, &hdl->commitfunc,
2797c478bd9Sstevel@tonic-gate &hdl->rollbackfunc, &hdl->endfunc);
2807c478bd9Sstevel@tonic-gate _tnfctl_prbk_test_func(&hdl->testfunc);
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate /* find the probes in the kernel */
2837c478bd9Sstevel@tonic-gate prexstat = _tnfctl_refresh_kernel(hdl);
2847c478bd9Sstevel@tonic-gate if (prexstat)
2857c478bd9Sstevel@tonic-gate return (prexstat);
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate *ret_val = hdl;
2887c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate * Returns the trace attributes to the client. Since there can be
2937c478bd9Sstevel@tonic-gate * only one controlling agent on a target at a time, our cached information
2947c478bd9Sstevel@tonic-gate * is correct and we don't have to actually retrieve any information
2957c478bd9Sstevel@tonic-gate * from the target.
2967c478bd9Sstevel@tonic-gate */
2977c478bd9Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_trace_attrs_get(tnfctl_handle_t * hdl,tnfctl_trace_attrs_t * attrs)2987c478bd9Sstevel@tonic-gate tnfctl_trace_attrs_get(tnfctl_handle_t *hdl, tnfctl_trace_attrs_t *attrs)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate boolean_t release_lock;
3017c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
3027c478bd9Sstevel@tonic-gate
3037c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/
3047c478bd9Sstevel@tonic-gate LOCK_SYNC(hdl, prexstat, release_lock);
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate attrs->targ_pid = hdl->targ_pid;
3077c478bd9Sstevel@tonic-gate attrs->trace_file_name = hdl->trace_file_name;
3087c478bd9Sstevel@tonic-gate attrs->trace_buf_size = hdl->trace_buf_size;
3097c478bd9Sstevel@tonic-gate attrs->trace_min_size = hdl->trace_min_size;
3107c478bd9Sstevel@tonic-gate attrs->trace_buf_state = hdl->trace_buf_state;
3117c478bd9Sstevel@tonic-gate attrs->trace_state = hdl->trace_state;
3127c478bd9Sstevel@tonic-gate attrs->filter_state = hdl->kpidfilter_state;
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/
3157c478bd9Sstevel@tonic-gate UNLOCK(hdl, release_lock);
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate * Allocate a trace buffer of the specified name and size.
3237c478bd9Sstevel@tonic-gate */
3247c478bd9Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_buffer_alloc(tnfctl_handle_t * hdl,const char * trace_file_name,uint_t trace_file_size)3257c478bd9Sstevel@tonic-gate tnfctl_buffer_alloc(tnfctl_handle_t *hdl, const char *trace_file_name,
3267c478bd9Sstevel@tonic-gate uint_t trace_file_size)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate if (hdl->mode == KERNEL_MODE) {
3317c478bd9Sstevel@tonic-gate /* trace_file_name is ignored in kernel mode */
3327c478bd9Sstevel@tonic-gate prexstat = _tnfctl_prbk_buffer_alloc(hdl, trace_file_size);
3337c478bd9Sstevel@tonic-gate if (prexstat)
3347c478bd9Sstevel@tonic-gate return (prexstat);
3357c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate /* Not KERNEL_MODE */
3397c478bd9Sstevel@tonic-gate if (hdl->trace_file_name != NULL) {
3407c478bd9Sstevel@tonic-gate /* buffer already allocated */
3417c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BUFEXISTS);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate prexstat = _tnfctl_create_tracefile(hdl, trace_file_name,
3457c478bd9Sstevel@tonic-gate trace_file_size);
3467c478bd9Sstevel@tonic-gate if (prexstat) {
3477c478bd9Sstevel@tonic-gate return (prexstat);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate * Deallocate the trace buffer - only works for kernel mode
3557c478bd9Sstevel@tonic-gate */
3567c478bd9Sstevel@tonic-gate tnfctl_errcode_t
tnfctl_buffer_dealloc(tnfctl_handle_t * hdl)3577c478bd9Sstevel@tonic-gate tnfctl_buffer_dealloc(tnfctl_handle_t *hdl)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate if (hdl->mode != KERNEL_MODE)
3627c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BADARG);
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate /* KERNEL_MODE */
3657c478bd9Sstevel@tonic-gate prexstat = _tnfctl_prbk_buffer_dealloc(hdl);
3667c478bd9Sstevel@tonic-gate if (prexstat)
3677c478bd9Sstevel@tonic-gate return (prexstat);
3687c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate /*
3737c478bd9Sstevel@tonic-gate * Helper function for attaching to a target process
3747c478bd9Sstevel@tonic-gate */
3757c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
attach_pid(pid_t pid,prb_proc_ctl_t ** proc_pp)3767c478bd9Sstevel@tonic-gate attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate prb_status_t prbstat;
3797c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p;
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate if (getpid() == pid)
3827c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BADARG);
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate /* check if pid is valid */
3857c478bd9Sstevel@tonic-gate if ((kill(pid, 0) == -1) && errno == ESRCH) {
3867c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NOPROCESS);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate /* open up /proc fd */
3897c478bd9Sstevel@tonic-gate prbstat = prb_proc_open(pid, proc_pp);
3907c478bd9Sstevel@tonic-gate if (prbstat)
3917c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate proc_p = *proc_pp;
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate * default is to run-on-last-close. In case we cannot sync with
3967c478bd9Sstevel@tonic-gate * target, we don't want to kill the target.
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate prbstat = prb_proc_setrlc(proc_p, B_TRUE);
3997c478bd9Sstevel@tonic-gate if (prbstat)
4007c478bd9Sstevel@tonic-gate goto failure_ret;
4017c478bd9Sstevel@tonic-gate prbstat = prb_proc_setklc(proc_p, B_FALSE);
4027c478bd9Sstevel@tonic-gate if (prbstat)
4037c478bd9Sstevel@tonic-gate goto failure_ret;
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate /* stop process */
4067c478bd9Sstevel@tonic-gate prbstat = prb_proc_stop(proc_p);
4077c478bd9Sstevel@tonic-gate if (prbstat)
4087c478bd9Sstevel@tonic-gate goto failure_ret;
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate /* Sucessful return */
4117c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate failure_ret:
4147c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p);
4157c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate * Checks if target is at the beginning of an exec system call. If so,
4207c478bd9Sstevel@tonic-gate * it runs it till the end of the exec system call. It takes care of
4217c478bd9Sstevel@tonic-gate * the case where you're about to exec a setuid program.
4227c478bd9Sstevel@tonic-gate * CAUTION: could side effect hndl->proc_p
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
step_to_end_of_exec(tnfctl_handle_t * hndl)4257c478bd9Sstevel@tonic-gate step_to_end_of_exec(tnfctl_handle_t *hndl)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p, *oldproc_p;
4287c478bd9Sstevel@tonic-gate prb_status_t prbstat, tempstat;
4297c478bd9Sstevel@tonic-gate int pid;
4307c478bd9Sstevel@tonic-gate prb_proc_state_t pstate;
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate proc_p = hndl->proc_p;
4337c478bd9Sstevel@tonic-gate pid = hndl->p_getpid(proc_p);
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate prbstat = prb_proc_state(proc_p, &pstate);
4367c478bd9Sstevel@tonic-gate if (prbstat)
4377c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
438*8fd04b83SRoger A. Faulkner if (!(pstate.ps_issysentry && pstate.ps_syscallnum == SYS_execve)) {
4397c478bd9Sstevel@tonic-gate /* not stopped at beginning of exec system call */
4407c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate /* we are stopped at beginning of exec system call */
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD);
4467c478bd9Sstevel@tonic-gate if (prbstat)
4477c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate prbstat = prb_proc_cont(proc_p);
4507c478bd9Sstevel@tonic-gate if (prbstat)
4517c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate prbstat = prb_proc_wait(proc_p, B_FALSE, NULL);
4547c478bd9Sstevel@tonic-gate switch (prbstat) {
4557c478bd9Sstevel@tonic-gate case PRB_STATUS_OK:
4567c478bd9Sstevel@tonic-gate break;
4577c478bd9Sstevel@tonic-gate case EAGAIN:
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate * If we had exec'ed a setuid/setgid program PIOCWSTOP
4607c478bd9Sstevel@tonic-gate * will return EAGAIN. Reopen the 'fd' and try again.
4617c478bd9Sstevel@tonic-gate * Read the last section of /proc man page - we reopen first
4627c478bd9Sstevel@tonic-gate * and then close the old fd.
4637c478bd9Sstevel@tonic-gate */
4647c478bd9Sstevel@tonic-gate oldproc_p = proc_p;
4657c478bd9Sstevel@tonic-gate tempstat = prb_proc_reopen(pid, &proc_p);
4667c478bd9Sstevel@tonic-gate if (tempstat) {
4677c478bd9Sstevel@tonic-gate /* here EACCES means exec'ed a setuid/setgid program */
4687c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(tempstat));
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate prb_proc_close(oldproc_p);
4727c478bd9Sstevel@tonic-gate hndl->proc_p = proc_p;
4737c478bd9Sstevel@tonic-gate break;
4747c478bd9Sstevel@tonic-gate default:
4757c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate prbstat = prb_proc_state(proc_p, &pstate);
4797c478bd9Sstevel@tonic-gate if (prbstat)
4807c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
4817c478bd9Sstevel@tonic-gate
482*8fd04b83SRoger A. Faulkner if (!(pstate.ps_issysexit && pstate.ps_syscallnum == SYS_execve)) {
4837c478bd9Sstevel@tonic-gate /* unexpected condition */
4847c478bd9Sstevel@tonic-gate return (tnfctl_status_map(ENOENT));
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate /* clear old interest mask */
4887c478bd9Sstevel@tonic-gate prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_DEL);
4897c478bd9Sstevel@tonic-gate if (prbstat)
4907c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat));
4917c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate tnfctl_errcode_t
_tnfctl_external_getlock(tnfctl_handle_t * hdl)4967c478bd9Sstevel@tonic-gate _tnfctl_external_getlock(tnfctl_handle_t *hdl)
4977c478bd9Sstevel@tonic-gate {
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat;
5007c478bd9Sstevel@tonic-gate prb_status_t prbstat;
5017c478bd9Sstevel@tonic-gate uintptr_t targ_symbol_ptr;
5027c478bd9Sstevel@tonic-gate int internal_tracing_on;
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hdl, TNFCTL_INTERNAL_TRACEFLAG,
5057c478bd9Sstevel@tonic-gate &targ_symbol_ptr);
5067c478bd9Sstevel@tonic-gate if (prexstat) {
5077c478bd9Sstevel@tonic-gate /* no libtnfctl in target: success */
5087c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate prbstat = hdl->p_read(hdl->proc_p, targ_symbol_ptr,
5117c478bd9Sstevel@tonic-gate &internal_tracing_on, sizeof (internal_tracing_on));
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate if (prbstat) {
5147c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat);
5157c478bd9Sstevel@tonic-gate goto failure_ret;
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate if (internal_tracing_on) {
5187c478bd9Sstevel@tonic-gate /* target process being traced internally */
5197c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_BUSY;
5207c478bd9Sstevel@tonic-gate goto failure_ret;
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hdl, TNFCTL_EXTERNAL_TRACEDPID,
5237c478bd9Sstevel@tonic-gate &targ_symbol_ptr);
5247c478bd9Sstevel@tonic-gate if (prexstat) {
5257c478bd9Sstevel@tonic-gate /* this shouldn't happen. we know we have libtnfctl */
5267c478bd9Sstevel@tonic-gate goto failure_ret;
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate prbstat = hdl->p_write(hdl->proc_p, targ_symbol_ptr,
5297c478bd9Sstevel@tonic-gate &(hdl->targ_pid), sizeof (hdl->targ_pid));
5307c478bd9Sstevel@tonic-gate if (prbstat) {
5317c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat);
5327c478bd9Sstevel@tonic-gate goto failure_ret;
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate /* success */
5357c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, "_tnfctl_external_getlock: ok to trace %d\n",
5367c478bd9Sstevel@tonic-gate hdl->targ_pid));
5377c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate failure_ret:
5407c478bd9Sstevel@tonic-gate return (prexstat);
5417c478bd9Sstevel@tonic-gate }
542