1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1994, by Sun Microsytems, Inc. 24*7c478bd9Sstevel@tonic-gate */ 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * Interfaces that return a tnfctl handle back to client (except for 30*7c478bd9Sstevel@tonic-gate * tnfctl_internal_open()) and helper functions for these interfaces. 31*7c478bd9Sstevel@tonic-gate * Also has buffer alloc, buffer dealloc, and trace attributes retrieval 32*7c478bd9Sstevel@tonic-gate * interfaces. 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h" 36*7c478bd9Sstevel@tonic-gate #include "kernel_int.h" 37*7c478bd9Sstevel@tonic-gate #include "dbg.h" 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 40*7c478bd9Sstevel@tonic-gate #include <unistd.h> 41*7c478bd9Sstevel@tonic-gate #include <signal.h> 42*7c478bd9Sstevel@tonic-gate #include <errno.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp); 45*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t step_to_end_of_exec(tnfctl_handle_t *hndl); 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* 48*7c478bd9Sstevel@tonic-gate * invokes the target program and executes it till the run time linker (rtld) 49*7c478bd9Sstevel@tonic-gate * has loaded in the shared objects (but before any .init sections are 50*7c478bd9Sstevel@tonic-gate * executed). Returns a pointer to a tnfctl handle. 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 53*7c478bd9Sstevel@tonic-gate tnfctl_exec_open(const char *pgm_name, char * const *args, char * const *envp, 54*7c478bd9Sstevel@tonic-gate const char *ld_preload, 55*7c478bd9Sstevel@tonic-gate const char *libtnfprobe_path, 56*7c478bd9Sstevel@tonic-gate tnfctl_handle_t **ret_val) 57*7c478bd9Sstevel@tonic-gate { 58*7c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl; 59*7c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p = NULL; 60*7c478bd9Sstevel@tonic-gate prb_status_t prbstat; 61*7c478bd9Sstevel@tonic-gate uintptr_t dbgaddr; 62*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate prbstat = prb_child_create(pgm_name, args, ld_preload, libtnfprobe_path, 65*7c478bd9Sstevel@tonic-gate envp, &proc_p); 66*7c478bd9Sstevel@tonic-gate if (prbstat) { 67*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 68*7c478bd9Sstevel@tonic-gate } 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */ 71*7c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl)); 72*7c478bd9Sstevel@tonic-gate if (hdl == NULL) { 73*7c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p); 74*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate hdl->proc_p = proc_p; 78*7c478bd9Sstevel@tonic-gate hdl->mode = DIRECT_MODE; 79*7c478bd9Sstevel@tonic-gate hdl->called_exit = B_FALSE; 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* use native /proc on this target */ 82*7c478bd9Sstevel@tonic-gate hdl->p_read = _tnfctl_read_targ; 83*7c478bd9Sstevel@tonic-gate hdl->p_write = _tnfctl_write_targ; 84*7c478bd9Sstevel@tonic-gate hdl->p_obj_iter = _tnfctl_loadobj_iter; 85*7c478bd9Sstevel@tonic-gate hdl->p_getpid = _tnfctl_pid_get; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* 88*7c478bd9Sstevel@tonic-gate * get the address of DT_DEBUG and send it in to prb_ layer. 89*7c478bd9Sstevel@tonic-gate * This is needed before before prb_rtld_sync() can be called. 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr); 92*7c478bd9Sstevel@tonic-gate if (prexstat) 93*7c478bd9Sstevel@tonic-gate goto failure_ret; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate prb_dbgaddr(proc_p, dbgaddr); 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate /* sync up to rtld sync point */ 98*7c478bd9Sstevel@tonic-gate prbstat = prb_rtld_sync_if_needed(proc_p); 99*7c478bd9Sstevel@tonic-gate if (prbstat) { 100*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat); 101*7c478bd9Sstevel@tonic-gate goto failure_ret; 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* initialize state in handle */ 105*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_set_state(hdl); 106*7c478bd9Sstevel@tonic-gate if (prexstat) 107*7c478bd9Sstevel@tonic-gate goto failure_ret; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_external_getlock(hdl); 110*7c478bd9Sstevel@tonic-gate if (prexstat) 111*7c478bd9Sstevel@tonic-gate goto failure_ret; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate *ret_val = hdl; 114*7c478bd9Sstevel@tonic-gate /* Successful return */ 115*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate failure_ret: 118*7c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p); 119*7c478bd9Sstevel@tonic-gate free(hdl); 120*7c478bd9Sstevel@tonic-gate return (prexstat); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate /* 125*7c478bd9Sstevel@tonic-gate * attaches to a running process. If the process is in the beginning 126*7c478bd9Sstevel@tonic-gate * of an exec(2) system call (which is how tnfctl_continue() returns on exec), 127*7c478bd9Sstevel@tonic-gate * it steps the process till the end of the the exec. If the process hasn't 128*7c478bd9Sstevel@tonic-gate * reached the rtld sync point, the process is continued until it does 129*7c478bd9Sstevel@tonic-gate * reach it. Returns a pointer to a tnfctl handle. 130*7c478bd9Sstevel@tonic-gate */ 131*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 132*7c478bd9Sstevel@tonic-gate tnfctl_pid_open(pid_t pid, tnfctl_handle_t **ret_val) 133*7c478bd9Sstevel@tonic-gate { 134*7c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl; 135*7c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p = NULL; 136*7c478bd9Sstevel@tonic-gate uintptr_t dbgaddr; 137*7c478bd9Sstevel@tonic-gate prb_status_t prbstat; 138*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate prexstat = attach_pid(pid, &proc_p); 141*7c478bd9Sstevel@tonic-gate if (prexstat) { 142*7c478bd9Sstevel@tonic-gate return (prexstat); 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */ 146*7c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl)); 147*7c478bd9Sstevel@tonic-gate if (hdl == NULL) { 148*7c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p); 149*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate hdl->proc_p = proc_p; 153*7c478bd9Sstevel@tonic-gate hdl->mode = DIRECT_MODE; 154*7c478bd9Sstevel@tonic-gate hdl->called_exit = B_FALSE; 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /* use native /proc on this target */ 157*7c478bd9Sstevel@tonic-gate hdl->p_read = _tnfctl_read_targ; 158*7c478bd9Sstevel@tonic-gate hdl->p_write = _tnfctl_write_targ; 159*7c478bd9Sstevel@tonic-gate hdl->p_obj_iter = _tnfctl_loadobj_iter; 160*7c478bd9Sstevel@tonic-gate hdl->p_getpid = _tnfctl_pid_get; 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Since tnfctl_continue() returns when a process does an exec 164*7c478bd9Sstevel@tonic-gate * and leaves the process stopped at the beginning of exec, we 165*7c478bd9Sstevel@tonic-gate * have to be sure to catch this case. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate prexstat = step_to_end_of_exec(hdl); 168*7c478bd9Sstevel@tonic-gate /* proc_p could be side effected by step_to_end_of_exec() */ 169*7c478bd9Sstevel@tonic-gate proc_p = hdl->proc_p; 170*7c478bd9Sstevel@tonic-gate if (prexstat) 171*7c478bd9Sstevel@tonic-gate goto failure_ret; 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate /* 174*7c478bd9Sstevel@tonic-gate * get the address of DT_DEBUG and send it in to prb_ layer. 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_elf_dbgent(hdl, &dbgaddr); 177*7c478bd9Sstevel@tonic-gate if (prexstat) 178*7c478bd9Sstevel@tonic-gate goto failure_ret; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate prb_dbgaddr(proc_p, dbgaddr); 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate /* sync up to rtld sync point if target is not there yet */ 183*7c478bd9Sstevel@tonic-gate prbstat = prb_rtld_sync_if_needed(proc_p); 184*7c478bd9Sstevel@tonic-gate if (prbstat) { 185*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat); 186*7c478bd9Sstevel@tonic-gate goto failure_ret; 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate /* initialize state in handle */ 190*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_set_state(hdl); 191*7c478bd9Sstevel@tonic-gate if (prexstat) 192*7c478bd9Sstevel@tonic-gate goto failure_ret; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate /* set state in target indicating we're tracing externally */ 195*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_external_getlock(hdl); 196*7c478bd9Sstevel@tonic-gate if (prexstat) 197*7c478bd9Sstevel@tonic-gate goto failure_ret; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate *ret_val = hdl; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* Sucessful return */ 202*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate failure_ret: 205*7c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p); 206*7c478bd9Sstevel@tonic-gate free(hdl); 207*7c478bd9Sstevel@tonic-gate return (prexstat); 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate /* 211*7c478bd9Sstevel@tonic-gate * open a process for tracing without using native /proc on it. The client 212*7c478bd9Sstevel@tonic-gate * provides a set of callback functions which encapsulate the /proc 213*7c478bd9Sstevel@tonic-gate * functionality we need. Returns a pointer to a tnfctl handle. 214*7c478bd9Sstevel@tonic-gate */ 215*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 216*7c478bd9Sstevel@tonic-gate tnfctl_indirect_open(void *prochandle, tnfctl_ind_config_t *config, 217*7c478bd9Sstevel@tonic-gate tnfctl_handle_t **ret_val) 218*7c478bd9Sstevel@tonic-gate { 219*7c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl; 220*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */ 223*7c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl)); 224*7c478bd9Sstevel@tonic-gate if (hdl == NULL) { 225*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate hdl->proc_p = prochandle; 229*7c478bd9Sstevel@tonic-gate hdl->mode = INDIRECT_MODE; 230*7c478bd9Sstevel@tonic-gate hdl->called_exit = B_FALSE; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /* initialize callback functions */ 233*7c478bd9Sstevel@tonic-gate hdl->p_read = config->p_read; 234*7c478bd9Sstevel@tonic-gate hdl->p_write = config->p_write; 235*7c478bd9Sstevel@tonic-gate hdl->p_obj_iter = config->p_obj_iter; 236*7c478bd9Sstevel@tonic-gate hdl->p_getpid = config->p_getpid; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate /* initialize state in handle */ 239*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_set_state(hdl); 240*7c478bd9Sstevel@tonic-gate if (prexstat) { 241*7c478bd9Sstevel@tonic-gate free(hdl); 242*7c478bd9Sstevel@tonic-gate return (prexstat); 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate /* set state in target indicating we're tracing externally */ 245*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_external_getlock(hdl); 246*7c478bd9Sstevel@tonic-gate if (prexstat) { 247*7c478bd9Sstevel@tonic-gate free(hdl); 248*7c478bd9Sstevel@tonic-gate return (prexstat); 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate *ret_val = hdl; 251*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* 255*7c478bd9Sstevel@tonic-gate * Returns a pointer to a tnfctl handle that can do kernel trace control 256*7c478bd9Sstevel@tonic-gate * and kernel probe control. 257*7c478bd9Sstevel@tonic-gate */ 258*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 259*7c478bd9Sstevel@tonic-gate tnfctl_kernel_open(tnfctl_handle_t **ret_val) 260*7c478bd9Sstevel@tonic-gate { 261*7c478bd9Sstevel@tonic-gate tnfctl_handle_t *hdl; 262*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate /* allocate hdl and zero fill */ 265*7c478bd9Sstevel@tonic-gate hdl = calloc(1, sizeof (*hdl)); 266*7c478bd9Sstevel@tonic-gate if (hdl == NULL) { 267*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate /* initialize kernel tracing */ 271*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_prbk_init(hdl); 272*7c478bd9Sstevel@tonic-gate if (prexstat) 273*7c478bd9Sstevel@tonic-gate return (prexstat); 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate hdl->mode = KERNEL_MODE; 276*7c478bd9Sstevel@tonic-gate hdl->targ_pid = 0; 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate /* initialize function pointers that can be stuffed into a probe */ 279*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_get_other_funcs(&hdl->allocfunc, &hdl->commitfunc, 280*7c478bd9Sstevel@tonic-gate &hdl->rollbackfunc, &hdl->endfunc); 281*7c478bd9Sstevel@tonic-gate _tnfctl_prbk_test_func(&hdl->testfunc); 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate /* find the probes in the kernel */ 284*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_refresh_kernel(hdl); 285*7c478bd9Sstevel@tonic-gate if (prexstat) 286*7c478bd9Sstevel@tonic-gate return (prexstat); 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate *ret_val = hdl; 289*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate /* 293*7c478bd9Sstevel@tonic-gate * Returns the trace attributes to the client. Since there can be 294*7c478bd9Sstevel@tonic-gate * only one controlling agent on a target at a time, our cached information 295*7c478bd9Sstevel@tonic-gate * is correct and we don't have to actually retrieve any information 296*7c478bd9Sstevel@tonic-gate * from the target. 297*7c478bd9Sstevel@tonic-gate */ 298*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 299*7c478bd9Sstevel@tonic-gate tnfctl_trace_attrs_get(tnfctl_handle_t *hdl, tnfctl_trace_attrs_t *attrs) 300*7c478bd9Sstevel@tonic-gate { 301*7c478bd9Sstevel@tonic-gate boolean_t release_lock; 302*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/ 305*7c478bd9Sstevel@tonic-gate LOCK_SYNC(hdl, prexstat, release_lock); 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate attrs->targ_pid = hdl->targ_pid; 308*7c478bd9Sstevel@tonic-gate attrs->trace_file_name = hdl->trace_file_name; 309*7c478bd9Sstevel@tonic-gate attrs->trace_buf_size = hdl->trace_buf_size; 310*7c478bd9Sstevel@tonic-gate attrs->trace_min_size = hdl->trace_min_size; 311*7c478bd9Sstevel@tonic-gate attrs->trace_buf_state = hdl->trace_buf_state; 312*7c478bd9Sstevel@tonic-gate attrs->trace_state = hdl->trace_state; 313*7c478bd9Sstevel@tonic-gate attrs->filter_state = hdl->kpidfilter_state; 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/ 316*7c478bd9Sstevel@tonic-gate UNLOCK(hdl, release_lock); 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * Allocate a trace buffer of the specified name and size. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 326*7c478bd9Sstevel@tonic-gate tnfctl_buffer_alloc(tnfctl_handle_t *hdl, const char *trace_file_name, 327*7c478bd9Sstevel@tonic-gate uint_t trace_file_size) 328*7c478bd9Sstevel@tonic-gate { 329*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate if (hdl->mode == KERNEL_MODE) { 332*7c478bd9Sstevel@tonic-gate /* trace_file_name is ignored in kernel mode */ 333*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_prbk_buffer_alloc(hdl, trace_file_size); 334*7c478bd9Sstevel@tonic-gate if (prexstat) 335*7c478bd9Sstevel@tonic-gate return (prexstat); 336*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* Not KERNEL_MODE */ 340*7c478bd9Sstevel@tonic-gate if (hdl->trace_file_name != NULL) { 341*7c478bd9Sstevel@tonic-gate /* buffer already allocated */ 342*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BUFEXISTS); 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_create_tracefile(hdl, trace_file_name, 346*7c478bd9Sstevel@tonic-gate trace_file_size); 347*7c478bd9Sstevel@tonic-gate if (prexstat) { 348*7c478bd9Sstevel@tonic-gate return (prexstat); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 352*7c478bd9Sstevel@tonic-gate } 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate /* 355*7c478bd9Sstevel@tonic-gate * Deallocate the trace buffer - only works for kernel mode 356*7c478bd9Sstevel@tonic-gate */ 357*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 358*7c478bd9Sstevel@tonic-gate tnfctl_buffer_dealloc(tnfctl_handle_t *hdl) 359*7c478bd9Sstevel@tonic-gate { 360*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate if (hdl->mode != KERNEL_MODE) 363*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BADARG); 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* KERNEL_MODE */ 366*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_prbk_buffer_dealloc(hdl); 367*7c478bd9Sstevel@tonic-gate if (prexstat) 368*7c478bd9Sstevel@tonic-gate return (prexstat); 369*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* 374*7c478bd9Sstevel@tonic-gate * Helper function for attaching to a target process 375*7c478bd9Sstevel@tonic-gate */ 376*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 377*7c478bd9Sstevel@tonic-gate attach_pid(pid_t pid, prb_proc_ctl_t **proc_pp) 378*7c478bd9Sstevel@tonic-gate { 379*7c478bd9Sstevel@tonic-gate prb_status_t prbstat; 380*7c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p; 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate if (getpid() == pid) 383*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BADARG); 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate /* check if pid is valid */ 386*7c478bd9Sstevel@tonic-gate if ((kill(pid, 0) == -1) && errno == ESRCH) { 387*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NOPROCESS); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate /* open up /proc fd */ 390*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_open(pid, proc_pp); 391*7c478bd9Sstevel@tonic-gate if (prbstat) 392*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate proc_p = *proc_pp; 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * default is to run-on-last-close. In case we cannot sync with 397*7c478bd9Sstevel@tonic-gate * target, we don't want to kill the target. 398*7c478bd9Sstevel@tonic-gate */ 399*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_setrlc(proc_p, B_TRUE); 400*7c478bd9Sstevel@tonic-gate if (prbstat) 401*7c478bd9Sstevel@tonic-gate goto failure_ret; 402*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_setklc(proc_p, B_FALSE); 403*7c478bd9Sstevel@tonic-gate if (prbstat) 404*7c478bd9Sstevel@tonic-gate goto failure_ret; 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* stop process */ 407*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_stop(proc_p); 408*7c478bd9Sstevel@tonic-gate if (prbstat) 409*7c478bd9Sstevel@tonic-gate goto failure_ret; 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* Sucessful return */ 412*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate failure_ret: 415*7c478bd9Sstevel@tonic-gate (void) prb_proc_close(proc_p); 416*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate /* 420*7c478bd9Sstevel@tonic-gate * Checks if target is at the beginning of an exec system call. If so, 421*7c478bd9Sstevel@tonic-gate * it runs it till the end of the exec system call. It takes care of 422*7c478bd9Sstevel@tonic-gate * the case where you're about to exec a setuid program. 423*7c478bd9Sstevel@tonic-gate * CAUTION: could side effect hndl->proc_p 424*7c478bd9Sstevel@tonic-gate */ 425*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 426*7c478bd9Sstevel@tonic-gate step_to_end_of_exec(tnfctl_handle_t *hndl) 427*7c478bd9Sstevel@tonic-gate { 428*7c478bd9Sstevel@tonic-gate prb_proc_ctl_t *proc_p, *oldproc_p; 429*7c478bd9Sstevel@tonic-gate prb_status_t prbstat, tempstat; 430*7c478bd9Sstevel@tonic-gate int pid; 431*7c478bd9Sstevel@tonic-gate prb_proc_state_t pstate; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate proc_p = hndl->proc_p; 434*7c478bd9Sstevel@tonic-gate pid = hndl->p_getpid(proc_p); 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_state(proc_p, &pstate); 437*7c478bd9Sstevel@tonic-gate if (prbstat) 438*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 439*7c478bd9Sstevel@tonic-gate if (!(pstate.ps_issysentry && (pstate.ps_syscallnum == SYS_exec || 440*7c478bd9Sstevel@tonic-gate pstate.ps_syscallnum == SYS_execve))) { 441*7c478bd9Sstevel@tonic-gate /* not stopped at beginning of exec system call */ 442*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate /* we are stopped at beginning of exec system call */ 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* REMIND: do we have to wait on SYS_exec also ? */ 448*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD); 449*7c478bd9Sstevel@tonic-gate if (prbstat) 450*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_cont(proc_p); 453*7c478bd9Sstevel@tonic-gate if (prbstat) 454*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_wait(proc_p, B_FALSE, NULL); 457*7c478bd9Sstevel@tonic-gate switch (prbstat) { 458*7c478bd9Sstevel@tonic-gate case PRB_STATUS_OK: 459*7c478bd9Sstevel@tonic-gate break; 460*7c478bd9Sstevel@tonic-gate case EAGAIN: 461*7c478bd9Sstevel@tonic-gate /* 462*7c478bd9Sstevel@tonic-gate * If we had exec'ed a setuid/setgid program PIOCWSTOP 463*7c478bd9Sstevel@tonic-gate * will return EAGAIN. Reopen the 'fd' and try again. 464*7c478bd9Sstevel@tonic-gate * Read the last section of /proc man page - we reopen first 465*7c478bd9Sstevel@tonic-gate * and then close the old fd. 466*7c478bd9Sstevel@tonic-gate */ 467*7c478bd9Sstevel@tonic-gate oldproc_p = proc_p; 468*7c478bd9Sstevel@tonic-gate tempstat = prb_proc_reopen(pid, &proc_p); 469*7c478bd9Sstevel@tonic-gate if (tempstat) { 470*7c478bd9Sstevel@tonic-gate /* here EACCES means exec'ed a setuid/setgid program */ 471*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(tempstat)); 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate prb_proc_close(oldproc_p); 475*7c478bd9Sstevel@tonic-gate hndl->proc_p = proc_p; 476*7c478bd9Sstevel@tonic-gate break; 477*7c478bd9Sstevel@tonic-gate default: 478*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_state(proc_p, &pstate); 482*7c478bd9Sstevel@tonic-gate if (prbstat) 483*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate if (!(pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_execve))) { 486*7c478bd9Sstevel@tonic-gate /* unexpected condition */ 487*7c478bd9Sstevel@tonic-gate return (tnfctl_status_map(ENOENT)); 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate /* clear old interest mask */ 491*7c478bd9Sstevel@tonic-gate prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_DEL); 492*7c478bd9Sstevel@tonic-gate if (prbstat) 493*7c478bd9Sstevel@tonic-gate return (_tnfctl_map_to_errcode(prbstat)); 494*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 499*7c478bd9Sstevel@tonic-gate _tnfctl_external_getlock(tnfctl_handle_t *hdl) 500*7c478bd9Sstevel@tonic-gate { 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 503*7c478bd9Sstevel@tonic-gate prb_status_t prbstat; 504*7c478bd9Sstevel@tonic-gate uintptr_t targ_symbol_ptr; 505*7c478bd9Sstevel@tonic-gate int internal_tracing_on; 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hdl, TNFCTL_INTERNAL_TRACEFLAG, 508*7c478bd9Sstevel@tonic-gate &targ_symbol_ptr); 509*7c478bd9Sstevel@tonic-gate if (prexstat) { 510*7c478bd9Sstevel@tonic-gate /* no libtnfctl in target: success */ 511*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate prbstat = hdl->p_read(hdl->proc_p, targ_symbol_ptr, 514*7c478bd9Sstevel@tonic-gate &internal_tracing_on, sizeof (internal_tracing_on)); 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate if (prbstat) { 517*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat); 518*7c478bd9Sstevel@tonic-gate goto failure_ret; 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate if (internal_tracing_on) { 521*7c478bd9Sstevel@tonic-gate /* target process being traced internally */ 522*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_BUSY; 523*7c478bd9Sstevel@tonic-gate goto failure_ret; 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hdl, TNFCTL_EXTERNAL_TRACEDPID, 526*7c478bd9Sstevel@tonic-gate &targ_symbol_ptr); 527*7c478bd9Sstevel@tonic-gate if (prexstat) { 528*7c478bd9Sstevel@tonic-gate /* this shouldn't happen. we know we have libtnfctl */ 529*7c478bd9Sstevel@tonic-gate goto failure_ret; 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate prbstat = hdl->p_write(hdl->proc_p, targ_symbol_ptr, 532*7c478bd9Sstevel@tonic-gate &(hdl->targ_pid), sizeof (hdl->targ_pid)); 533*7c478bd9Sstevel@tonic-gate if (prbstat) { 534*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_map_to_errcode(prbstat); 535*7c478bd9Sstevel@tonic-gate goto failure_ret; 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate /* success */ 538*7c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, "_tnfctl_external_getlock: ok to trace %d\n", 539*7c478bd9Sstevel@tonic-gate hdl->targ_pid)); 540*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate failure_ret: 543*7c478bd9Sstevel@tonic-gate return (prexstat); 544*7c478bd9Sstevel@tonic-gate } 545