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 * Utility functions to initialize tnfctl handle, find functions that 30*7c478bd9Sstevel@tonic-gate * can be plugged into probes, find trace file information, and create 31*7c478bd9Sstevel@tonic-gate * a trace file for process tracing. 32*7c478bd9Sstevel@tonic-gate */ 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #ifndef DEBUG 35*7c478bd9Sstevel@tonic-gate #define NDEBUG 1 36*7c478bd9Sstevel@tonic-gate #endif 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include "tnfctl_int.h" 39*7c478bd9Sstevel@tonic-gate #include "dbg.h" 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #include <assert.h> 42*7c478bd9Sstevel@tonic-gate #include <errno.h> 43*7c478bd9Sstevel@tonic-gate #include <stdio.h> 44*7c478bd9Sstevel@tonic-gate #include <string.h> 45*7c478bd9Sstevel@tonic-gate #include <unistd.h> 46*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 47*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #include "tnf_buf.h" 51*7c478bd9Sstevel@tonic-gate /* 52*7c478bd9Sstevel@tonic-gate * Defines - Project private interfaces in libtnfprobe.so 53*7c478bd9Sstevel@tonic-gate */ 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #define TRACEFILE_NAME "tnf_trace_file_name" 56*7c478bd9Sstevel@tonic-gate #define TRACEFILE_SIZE "tnf_trace_file_size" 57*7c478bd9Sstevel@tonic-gate #define TRACEFILE_MIN "tnf_trace_file_min" 58*7c478bd9Sstevel@tonic-gate #define TRACE_ERROR "_tnfw_b_control" 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #define TRACE_ALLOC "tnf_trace_alloc" 61*7c478bd9Sstevel@tonic-gate #define TRACE_COMMIT "tnf_trace_commit" 62*7c478bd9Sstevel@tonic-gate #define TRACE_ROLLBACK "tnf_trace_rollback" 63*7c478bd9Sstevel@tonic-gate #define DEBUG_ENTRY "tnf_probe_debug" 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate #define PROBE_LIST_HEAD "__tnf_probe_list_head" 66*7c478bd9Sstevel@tonic-gate #define PROBE_LIST_VALID "__tnf_probe_list_valid" 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #define NONTHREAD_TEST "tnf_non_threaded_test_addr" 69*7c478bd9Sstevel@tonic-gate #define THREAD_TEST "tnf_threaded_test_addr" 70*7c478bd9Sstevel@tonic-gate #define PROBE_THR_SYNC "__tnf_probe_thr_sync" 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #define MEMSEG_PTR "__tnf_probe_memseg_p" 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* Project private interfaces in libthread.so */ 75*7c478bd9Sstevel@tonic-gate #define LIBTHREAD_PRESENT "thr_probe_getfunc_addr" 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * Local declarations 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t find_test_func(tnfctl_handle_t *hndl); 82*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t find_target_syms(tnfctl_handle_t *hndl); 83*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t find_trace_file_info(tnfctl_handle_t *hndl); 84*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t check_trace_error(tnfctl_handle_t *hndl); 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * _tnfctl_refresh_process() - search for new shared objects. If any 88*7c478bd9Sstevel@tonic-gate * found, discover probes in new shared objects. 89*7c478bd9Sstevel@tonic-gate * NOT to be called in kernel mode. 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 93*7c478bd9Sstevel@tonic-gate _tnfctl_refresh_process(tnfctl_handle_t *hndl, boolean_t *lmap_ok, 94*7c478bd9Sstevel@tonic-gate enum event_op_t *dl_evt) 95*7c478bd9Sstevel@tonic-gate { 96*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 97*7c478bd9Sstevel@tonic-gate boolean_t release_lock; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate assert(hndl->mode != KERNEL_MODE); 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/ 102*7c478bd9Sstevel@tonic-gate LOCK(hndl, prexstat, release_lock); 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate prexstat = check_trace_error(hndl); 105*7c478bd9Sstevel@tonic-gate if (prexstat) 106*7c478bd9Sstevel@tonic-gate goto finish_func; 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* 109*7c478bd9Sstevel@tonic-gate * update the link map. caller decides what to do on 110*7c478bd9Sstevel@tonic-gate * inconsistent link map 111*7c478bd9Sstevel@tonic-gate */ 112*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_lmap_update(hndl, lmap_ok, dl_evt); 113*7c478bd9Sstevel@tonic-gate if (prexstat) 114*7c478bd9Sstevel@tonic-gate goto finish_func; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate /* link map is ok now */ 117*7c478bd9Sstevel@tonic-gate prexstat = find_test_func(hndl); 118*7c478bd9Sstevel@tonic-gate if (prexstat) 119*7c478bd9Sstevel@tonic-gate goto finish_func; 120*7c478bd9Sstevel@tonic-gate if (*dl_evt != EVT_NONE) { 121*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_find_all_probes(hndl); 122*7c478bd9Sstevel@tonic-gate if (prexstat) 123*7c478bd9Sstevel@tonic-gate goto finish_func; 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate finish_func: 127*7c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/ 128*7c478bd9Sstevel@tonic-gate UNLOCK(hndl, release_lock); 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate return (prexstat); 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate /* 134*7c478bd9Sstevel@tonic-gate * initialize tnfctl handle for a new target 135*7c478bd9Sstevel@tonic-gate */ 136*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 137*7c478bd9Sstevel@tonic-gate _tnfctl_set_state(tnfctl_handle_t *hndl) 138*7c478bd9Sstevel@tonic-gate { 139*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat = TNFCTL_ERR_NONE; 140*7c478bd9Sstevel@tonic-gate boolean_t lmap_ok; 141*7c478bd9Sstevel@tonic-gate enum event_op_t dl_evt; 142*7c478bd9Sstevel@tonic-gate boolean_t release_lock; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate hndl->targ_pid = hndl->p_getpid(hndl->proc_p); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/ 147*7c478bd9Sstevel@tonic-gate LOCK(hndl, prexstat, release_lock); 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* 150*7c478bd9Sstevel@tonic-gate * initialize the link map table. If link map is not ok, it is an 151*7c478bd9Sstevel@tonic-gate * error. 152*7c478bd9Sstevel@tonic-gate */ 153*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_lmap_update(hndl, &lmap_ok, &dl_evt); 154*7c478bd9Sstevel@tonic-gate if (prexstat) 155*7c478bd9Sstevel@tonic-gate goto end_func; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate /* find the needed target symbols */ 158*7c478bd9Sstevel@tonic-gate prexstat = find_target_syms(hndl); 159*7c478bd9Sstevel@tonic-gate if (prexstat) { 160*7c478bd9Sstevel@tonic-gate /* is libtnfprobe.so loaded in target ? */ 161*7c478bd9Sstevel@tonic-gate goto end_func; 162*7c478bd9Sstevel@tonic-gate } 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate prexstat = find_trace_file_info(hndl); 165*7c478bd9Sstevel@tonic-gate if (prexstat) 166*7c478bd9Sstevel@tonic-gate goto end_func; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate prexstat = find_test_func(hndl); 169*7c478bd9Sstevel@tonic-gate if (prexstat) 170*7c478bd9Sstevel@tonic-gate goto end_func; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_find_all_probes(hndl); 173*7c478bd9Sstevel@tonic-gate if (prexstat) 174*7c478bd9Sstevel@tonic-gate goto end_func; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate prexstat = check_trace_error(hndl); 177*7c478bd9Sstevel@tonic-gate /* fall into end_func */ 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate end_func: 180*7c478bd9Sstevel@tonic-gate /*LINTED statement has no consequent: else*/ 181*7c478bd9Sstevel@tonic-gate UNLOCK(hndl, release_lock); 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate return (prexstat); 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate * find the test function for a probe. The test function could change 188*7c478bd9Sstevel@tonic-gate * with time, so we have to repeatedly check for the test function to use 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 191*7c478bd9Sstevel@tonic-gate find_test_func(tnfctl_handle_t *hndl) 192*7c478bd9Sstevel@tonic-gate { 193*7c478bd9Sstevel@tonic-gate long thr_sync; 194*7c478bd9Sstevel@tonic-gate int miscstat; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate if (hndl->mt_target == B_FALSE) { 197*7c478bd9Sstevel@tonic-gate /* no libthread linked in */ 198*7c478bd9Sstevel@tonic-gate hndl->testfunc = hndl->nonthread_test; 199*7c478bd9Sstevel@tonic-gate } else { 200*7c478bd9Sstevel@tonic-gate /* 201*7c478bd9Sstevel@tonic-gate * check whether libthread/libtnfw have synced up. 202*7c478bd9Sstevel@tonic-gate * If not yet synced up, use non-threaded test function 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate /* assume we are going to use threaded test */ 206*7c478bd9Sstevel@tonic-gate hndl->testfunc = hndl->thread_test; 207*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, hndl->thread_sync, 208*7c478bd9Sstevel@tonic-gate &thr_sync, sizeof (thr_sync)); 209*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 210*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 211*7c478bd9Sstevel@tonic-gate /* if not yet synced up, change test func to non-threaded one */ 212*7c478bd9Sstevel@tonic-gate if (thr_sync == 0) { 213*7c478bd9Sstevel@tonic-gate hndl->testfunc = hndl->nonthread_test; 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * Note: the testfunc in the target can change underneath us because 219*7c478bd9Sstevel@tonic-gate * in an MT program the init section of libthread changes all the 220*7c478bd9Sstevel@tonic-gate * test functions from the non-threaded one to the threaded one. 221*7c478bd9Sstevel@tonic-gate * So, every time we write out a probe, we have to make sure that 222*7c478bd9Sstevel@tonic-gate * we are using the correct test function by not trusting the test 223*7c478bd9Sstevel@tonic-gate * function in our copy of the probe. A more fool-proof solution 224*7c478bd9Sstevel@tonic-gate * which will allow other fields in the probe to change internally 225*7c478bd9Sstevel@tonic-gate * is to refresh every probe on a _tnfctl_refresh_process() 226*7c478bd9Sstevel@tonic-gate */ 227*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * check_trace_error() - checks whether there was an error in tracing 232*7c478bd9Sstevel@tonic-gate * side effects trace_buf_state and trace_state in hndl 233*7c478bd9Sstevel@tonic-gate * note: call this function only after trace_file_name is set up 234*7c478bd9Sstevel@tonic-gate * in hndl 235*7c478bd9Sstevel@tonic-gate */ 236*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 237*7c478bd9Sstevel@tonic-gate check_trace_error(tnfctl_handle_t *hndl) 238*7c478bd9Sstevel@tonic-gate { 239*7c478bd9Sstevel@tonic-gate int miscstat; 240*7c478bd9Sstevel@tonic-gate uintptr_t trace_error_ptr; 241*7c478bd9Sstevel@tonic-gate TNFW_B_CONTROL trace_error_rec; 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate /* read in the value of the control structure pointer */ 244*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, hndl->trace_error, 245*7c478bd9Sstevel@tonic-gate &trace_error_ptr, sizeof (trace_error_ptr)); 246*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 247*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* read in the value of the control structure */ 250*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, trace_error_ptr, &trace_error_rec, 251*7c478bd9Sstevel@tonic-gate sizeof (trace_error_rec)); 252*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 253*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate if (trace_error_rec.tnf_state == TNFW_B_NOBUFFER) { 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * massage into correct state for caller - the target might 258*7c478bd9Sstevel@tonic-gate * not have hit the first probe and hence we got "no buffer". 259*7c478bd9Sstevel@tonic-gate * So, if the user had given a file name, return BUF_OK. 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate if (hndl->trace_file_name == NULL) 262*7c478bd9Sstevel@tonic-gate hndl->trace_buf_state = TNFCTL_BUF_NONE; 263*7c478bd9Sstevel@tonic-gate else 264*7c478bd9Sstevel@tonic-gate hndl->trace_buf_state = TNFCTL_BUF_OK; 265*7c478bd9Sstevel@tonic-gate } else if (trace_error_rec.tnf_state == TNFW_B_BROKEN) { 266*7c478bd9Sstevel@tonic-gate hndl->trace_buf_state = TNFCTL_BUF_BROKEN; 267*7c478bd9Sstevel@tonic-gate } else { 268*7c478bd9Sstevel@tonic-gate hndl->trace_buf_state = TNFCTL_BUF_OK; 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if (TNFW_B_IS_STOPPED(trace_error_rec.tnf_state)) 272*7c478bd9Sstevel@tonic-gate hndl->trace_state = B_FALSE; 273*7c478bd9Sstevel@tonic-gate else 274*7c478bd9Sstevel@tonic-gate hndl->trace_state = B_TRUE; 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate } /* end find_alloc_func */ 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate /* 281*7c478bd9Sstevel@tonic-gate * find_target_syms() - finds needed target functions 282*7c478bd9Sstevel@tonic-gate * sideffects allocfunc, commitfunc, endfunc, rollbackfunc in hndl 283*7c478bd9Sstevel@tonic-gate */ 284*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 285*7c478bd9Sstevel@tonic-gate find_target_syms(tnfctl_handle_t *hndl) 286*7c478bd9Sstevel@tonic-gate { 287*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 288*7c478bd9Sstevel@tonic-gate uintptr_t temp_addr; 289*7c478bd9Sstevel@tonic-gate int miscstat; 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACE_ALLOC, &hndl->allocfunc); 292*7c478bd9Sstevel@tonic-gate if (prexstat) 293*7c478bd9Sstevel@tonic-gate goto end_of_func; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACE_COMMIT, &hndl->commitfunc); 296*7c478bd9Sstevel@tonic-gate if (prexstat) 297*7c478bd9Sstevel@tonic-gate goto end_of_func; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACE_END_FUNC, &hndl->endfunc); 300*7c478bd9Sstevel@tonic-gate if (prexstat) 301*7c478bd9Sstevel@tonic-gate goto end_of_func; 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACE_ROLLBACK, &hndl->rollbackfunc); 304*7c478bd9Sstevel@tonic-gate if (prexstat) 305*7c478bd9Sstevel@tonic-gate goto end_of_func; 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, PROBE_LIST_HEAD, 308*7c478bd9Sstevel@tonic-gate &hndl->probelist_head); 309*7c478bd9Sstevel@tonic-gate if (prexstat) 310*7c478bd9Sstevel@tonic-gate goto end_of_func; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACE_ERROR, &hndl->trace_error); 313*7c478bd9Sstevel@tonic-gate if (prexstat) 314*7c478bd9Sstevel@tonic-gate goto end_of_func; 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, MEMSEG_PTR, &temp_addr); 317*7c478bd9Sstevel@tonic-gate if (prexstat) 318*7c478bd9Sstevel@tonic-gate goto end_of_func; 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate /* dereference to get the actual address of structure */ 321*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, temp_addr, &hndl->memseg_p, 322*7c478bd9Sstevel@tonic-gate sizeof (hndl->memseg_p)); 323*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 324*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, PROBE_LIST_VALID, 327*7c478bd9Sstevel@tonic-gate &hndl->probelist_valid); 328*7c478bd9Sstevel@tonic-gate if (prexstat) 329*7c478bd9Sstevel@tonic-gate goto end_of_func; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, NONTHREAD_TEST, &temp_addr); 332*7c478bd9Sstevel@tonic-gate if (prexstat) 333*7c478bd9Sstevel@tonic-gate goto end_of_func; 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate /* dereference to get the actual function address */ 336*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, temp_addr, &hndl->nonthread_test, 337*7c478bd9Sstevel@tonic-gate sizeof (hndl->nonthread_test)); 338*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 339*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, THREAD_TEST, &temp_addr); 342*7c478bd9Sstevel@tonic-gate if (prexstat) 343*7c478bd9Sstevel@tonic-gate goto end_of_func; 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate /* dereference to get the actual function address */ 346*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, temp_addr, &hndl->thread_test, 347*7c478bd9Sstevel@tonic-gate sizeof (hndl->thread_test)); 348*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 349*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, PROBE_THR_SYNC, &hndl->thread_sync); 352*7c478bd9Sstevel@tonic-gate if (prexstat) 353*7c478bd9Sstevel@tonic-gate goto end_of_func; 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, LIBTHREAD_PRESENT, &temp_addr); 356*7c478bd9Sstevel@tonic-gate if (prexstat) { 357*7c478bd9Sstevel@tonic-gate if (prexstat == TNFCTL_ERR_BADARG) { 358*7c478bd9Sstevel@tonic-gate /* no libthread linked in */ 359*7c478bd9Sstevel@tonic-gate hndl->mt_target = B_FALSE; 360*7c478bd9Sstevel@tonic-gate /* this is not an error condition */ 361*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_NONE; 362*7c478bd9Sstevel@tonic-gate } else { 363*7c478bd9Sstevel@tonic-gate return (prexstat); 364*7c478bd9Sstevel@tonic-gate } 365*7c478bd9Sstevel@tonic-gate } else { 366*7c478bd9Sstevel@tonic-gate hndl->mt_target = B_TRUE; 367*7c478bd9Sstevel@tonic-gate } 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate end_of_func: 370*7c478bd9Sstevel@tonic-gate if (prexstat == TNFCTL_ERR_BADARG) 371*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_NOLIBTNFPROBE; 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate return (prexstat); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate /* 377*7c478bd9Sstevel@tonic-gate * _tnfctl_create_tracefile() - initializes tracefile, sets the tracefile name 378*7c478bd9Sstevel@tonic-gate * and size 379*7c478bd9Sstevel@tonic-gate * side effects trace_file_name and trace_buf_size in hndl 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate #define ZBUFSZ (64 * 1024) 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 385*7c478bd9Sstevel@tonic-gate _tnfctl_create_tracefile(tnfctl_handle_t *hndl, const char *trace_file_name, 386*7c478bd9Sstevel@tonic-gate uint_t trace_file_size) 387*7c478bd9Sstevel@tonic-gate { 388*7c478bd9Sstevel@tonic-gate char *preexisting; 389*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 390*7c478bd9Sstevel@tonic-gate int miscstat; 391*7c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 392*7c478bd9Sstevel@tonic-gate uintptr_t name_addr, size_addr; 393*7c478bd9Sstevel@tonic-gate uint_t outsize; 394*7c478bd9Sstevel@tonic-gate char zerobuf[ZBUFSZ]; 395*7c478bd9Sstevel@tonic-gate int fd, sz, i; 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate /* find the neccessary symbols in the target */ 398*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACEFILE_NAME, &name_addr); 399*7c478bd9Sstevel@tonic-gate if (prexstat) { 400*7c478bd9Sstevel@tonic-gate if (prexstat == TNFCTL_ERR_BADARG) 401*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_INTERNAL; 402*7c478bd9Sstevel@tonic-gate return (prexstat); 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACEFILE_SIZE, &size_addr); 405*7c478bd9Sstevel@tonic-gate if (prexstat) { 406*7c478bd9Sstevel@tonic-gate if (prexstat == TNFCTL_ERR_BADARG) 407*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_INTERNAL; 408*7c478bd9Sstevel@tonic-gate return (prexstat); 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* Double check that a file name doesn't already exist */ 412*7c478bd9Sstevel@tonic-gate preexisting = NULL; 413*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_readstr_targ(hndl, name_addr, &preexisting); 414*7c478bd9Sstevel@tonic-gate if (prexstat) { 415*7c478bd9Sstevel@tonic-gate if (preexisting) 416*7c478bd9Sstevel@tonic-gate free(preexisting); 417*7c478bd9Sstevel@tonic-gate return (prexstat); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* There better not be a file name there yet */ 421*7c478bd9Sstevel@tonic-gate assert(preexisting[0] == '\0'); 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate /* paranoia - for optimized compilation */ 424*7c478bd9Sstevel@tonic-gate if (preexisting[0] != '\0') 425*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BUFEXISTS); 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* free memory in preexisting string */ 428*7c478bd9Sstevel@tonic-gate if (preexisting) 429*7c478bd9Sstevel@tonic-gate free(preexisting); 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate if (trace_file_size < hndl->trace_min_size) { 432*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_SIZETOOSMALL); 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate /* do we have an absolute, relative or no pathname specified? */ 436*7c478bd9Sstevel@tonic-gate if (trace_file_name == NULL) { 437*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BADARG); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate if (trace_file_name[0] == '/') { 440*7c478bd9Sstevel@tonic-gate /* absolute path to tracefile specified */ 441*7c478bd9Sstevel@tonic-gate if ((strlen(trace_file_name) + 1) > (size_t) MAXPATHLEN) { 442*7c478bd9Sstevel@tonic-gate /* directory specification too long */ 443*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BADARG); 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate (void) strcpy(path, trace_file_name); 446*7c478bd9Sstevel@tonic-gate } else { 447*7c478bd9Sstevel@tonic-gate char *cwd; 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate /* relative path to tracefile specified */ 450*7c478bd9Sstevel@tonic-gate cwd = getcwd(NULL, MAXPATHLEN); 451*7c478bd9Sstevel@tonic-gate if (!cwd) { 452*7c478bd9Sstevel@tonic-gate return (tnfctl_status_map(errno)); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate if ((strlen(cwd) + 1 + strlen(trace_file_name) + 1) > 455*7c478bd9Sstevel@tonic-gate (size_t) MAXPATHLEN) { 456*7c478bd9Sstevel@tonic-gate /* path name too long */ 457*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BADARG); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate (void) sprintf(path, "%s/%s", cwd, trace_file_name); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate free(cwd); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate outsize = trace_file_size; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate DBG_TNF_PROBE_2(_tnfctl_create_tracefile_1, "libtnfctl", 467*7c478bd9Sstevel@tonic-gate "sunw%verbosity 1; sunw%debug 'setting trace file name'", 468*7c478bd9Sstevel@tonic-gate tnf_string, tracefile_name, path, 469*7c478bd9Sstevel@tonic-gate tnf_long, tracefile_size, outsize); 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate /* unlink a previous tracefile (if one exists) */ 472*7c478bd9Sstevel@tonic-gate (void) unlink(path); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* create the new tracefile */ 475*7c478bd9Sstevel@tonic-gate fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644); 476*7c478bd9Sstevel@tonic-gate if (fd < 0) { 477*7c478bd9Sstevel@tonic-gate return (tnfctl_status_map(errno)); 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* zero fill the file */ 481*7c478bd9Sstevel@tonic-gate (void) memset(zerobuf, 0, ZBUFSZ); 482*7c478bd9Sstevel@tonic-gate sz = ZBUFSZ; 483*7c478bd9Sstevel@tonic-gate for (i = 0; i < outsize; i += sz) { 484*7c478bd9Sstevel@tonic-gate ulong_t retval; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate sz = ((outsize - i) > ZBUFSZ) ? ZBUFSZ : (outsize - i); 487*7c478bd9Sstevel@tonic-gate retval = write(fd, zerobuf, sz); 488*7c478bd9Sstevel@tonic-gate if (retval != sz) { 489*7c478bd9Sstevel@tonic-gate /* trouble zeroing tracefile */ 490*7c478bd9Sstevel@tonic-gate return (tnfctl_status_map(errno)); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate /* close the file */ 495*7c478bd9Sstevel@tonic-gate (void) close(fd); 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate /* write the tracefile name and size into the target process */ 498*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_write(hndl->proc_p, name_addr, path, 499*7c478bd9Sstevel@tonic-gate strlen(path) + 1); 500*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 501*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 502*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_write(hndl->proc_p, size_addr, &outsize, 503*7c478bd9Sstevel@tonic-gate sizeof (outsize)); 504*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 505*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate hndl->trace_file_name = strdup(path); 508*7c478bd9Sstevel@tonic-gate if (hndl->trace_file_name == NULL) 509*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 510*7c478bd9Sstevel@tonic-gate hndl->trace_buf_size = outsize; 511*7c478bd9Sstevel@tonic-gate hndl->trace_buf_state = TNFCTL_BUF_OK; 512*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 513*7c478bd9Sstevel@tonic-gate } /* end _tnfctl_create_tracefile */ 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate /* 516*7c478bd9Sstevel@tonic-gate * find_trace_file_info() 517*7c478bd9Sstevel@tonic-gate * finds out information about the trace file. 518*7c478bd9Sstevel@tonic-gate * side effects trace_buf_size, trace_min_size, trace_file_name in hndl 519*7c478bd9Sstevel@tonic-gate */ 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate static tnfctl_errcode_t 522*7c478bd9Sstevel@tonic-gate find_trace_file_info(tnfctl_handle_t *hndl) 523*7c478bd9Sstevel@tonic-gate { 524*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t prexstat; 525*7c478bd9Sstevel@tonic-gate int miscstat; 526*7c478bd9Sstevel@tonic-gate char *preexisting; 527*7c478bd9Sstevel@tonic-gate uintptr_t name_addr, size_addr, min_addr; 528*7c478bd9Sstevel@tonic-gate uint_t outsize, minoutsize; 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate /* find the neccessary symbols in the target */ 531*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACEFILE_NAME, &name_addr); 532*7c478bd9Sstevel@tonic-gate if (prexstat) { 533*7c478bd9Sstevel@tonic-gate if (prexstat == TNFCTL_ERR_BADARG) 534*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_INTERNAL; 535*7c478bd9Sstevel@tonic-gate return (prexstat); 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACEFILE_SIZE, &size_addr); 538*7c478bd9Sstevel@tonic-gate if (prexstat) { 539*7c478bd9Sstevel@tonic-gate if (prexstat == TNFCTL_ERR_BADARG) 540*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_INTERNAL; 541*7c478bd9Sstevel@tonic-gate return (prexstat); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_sym_find(hndl, TRACEFILE_MIN, &min_addr); 544*7c478bd9Sstevel@tonic-gate if (prexstat) { 545*7c478bd9Sstevel@tonic-gate if (prexstat == TNFCTL_ERR_BADARG) 546*7c478bd9Sstevel@tonic-gate prexstat = TNFCTL_ERR_INTERNAL; 547*7c478bd9Sstevel@tonic-gate return (prexstat); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* read file name */ 551*7c478bd9Sstevel@tonic-gate preexisting = NULL; 552*7c478bd9Sstevel@tonic-gate prexstat = _tnfctl_readstr_targ(hndl, name_addr, &preexisting); 553*7c478bd9Sstevel@tonic-gate if (prexstat) { 554*7c478bd9Sstevel@tonic-gate if (preexisting) 555*7c478bd9Sstevel@tonic-gate free(preexisting); 556*7c478bd9Sstevel@tonic-gate return (prexstat); 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate /* read the minimum file size from the target */ 560*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, min_addr, &minoutsize, 561*7c478bd9Sstevel@tonic-gate sizeof (minoutsize)); 562*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 563*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 564*7c478bd9Sstevel@tonic-gate hndl->trace_min_size = minoutsize; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate /* if there is no filename, we are done */ 567*7c478bd9Sstevel@tonic-gate if (preexisting[0] == '\0') { 568*7c478bd9Sstevel@tonic-gate hndl->trace_file_name = NULL; 569*7c478bd9Sstevel@tonic-gate hndl->trace_buf_size = 0; 570*7c478bd9Sstevel@tonic-gate } else { 571*7c478bd9Sstevel@tonic-gate hndl->trace_file_name = preexisting; 572*7c478bd9Sstevel@tonic-gate /* read size of file */ 573*7c478bd9Sstevel@tonic-gate miscstat = hndl->p_read(hndl->proc_p, size_addr, 574*7c478bd9Sstevel@tonic-gate &outsize, sizeof (outsize)); 575*7c478bd9Sstevel@tonic-gate if (miscstat != 0) 576*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 577*7c478bd9Sstevel@tonic-gate hndl->trace_buf_size = outsize; 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 581*7c478bd9Sstevel@tonic-gate } /* end find_trace_file_info */ 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate /* 584*7c478bd9Sstevel@tonic-gate * wrapper functions over native /proc functions implemented by proc 585*7c478bd9Sstevel@tonic-gate * layer 586*7c478bd9Sstevel@tonic-gate */ 587*7c478bd9Sstevel@tonic-gate int 588*7c478bd9Sstevel@tonic-gate _tnfctl_read_targ(void *proc_p, uintptr_t addr, void *buf, size_t size) 589*7c478bd9Sstevel@tonic-gate { 590*7c478bd9Sstevel@tonic-gate return (prb_proc_read(proc_p, addr, buf, size)); 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate int 594*7c478bd9Sstevel@tonic-gate _tnfctl_write_targ(void *proc_p, uintptr_t addr, void *buf, size_t size) 595*7c478bd9Sstevel@tonic-gate { 596*7c478bd9Sstevel@tonic-gate return (prb_proc_write(proc_p, addr, buf, size)); 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate int 600*7c478bd9Sstevel@tonic-gate _tnfctl_loadobj_iter(void *proc_p, tnfctl_ind_obj_f *func, void *client_data) 601*7c478bd9Sstevel@tonic-gate { 602*7c478bd9Sstevel@tonic-gate prb_loadobj_f *same_func = (prb_loadobj_f *) func; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate return (prb_loadobj_iter(proc_p, same_func, client_data)); 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate pid_t 608*7c478bd9Sstevel@tonic-gate _tnfctl_pid_get(void *proc_p) 609*7c478bd9Sstevel@tonic-gate { 610*7c478bd9Sstevel@tonic-gate return (prb_proc_pid_get(proc_p)); 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate /* 614*7c478bd9Sstevel@tonic-gate * _tnfctl_readstr_targ() - dereferences a string in the target 615*7c478bd9Sstevel@tonic-gate * NOTE: There is a similar routine called prb_proc_readstr() 616*7c478bd9Sstevel@tonic-gate * used by proc layer. It would be better if there was only 617*7c478bd9Sstevel@tonic-gate * one of these functions defined. 618*7c478bd9Sstevel@tonic-gate */ 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate #define BUFSZ 256 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate tnfctl_errcode_t 623*7c478bd9Sstevel@tonic-gate _tnfctl_readstr_targ(tnfctl_handle_t *hndl, uintptr_t addr, char **outstr_pp) 624*7c478bd9Sstevel@tonic-gate { 625*7c478bd9Sstevel@tonic-gate int retstat; 626*7c478bd9Sstevel@tonic-gate int bufsz = BUFSZ; 627*7c478bd9Sstevel@tonic-gate char buffer[BUFSZ + 1]; 628*7c478bd9Sstevel@tonic-gate offset_t offset; 629*7c478bd9Sstevel@tonic-gate char *ptr, *orig_ptr; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate *outstr_pp = NULL; 632*7c478bd9Sstevel@tonic-gate offset = 0; 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate /* allocate an inital return buffer */ 635*7c478bd9Sstevel@tonic-gate ptr = (char *) malloc(BUFSZ); 636*7c478bd9Sstevel@tonic-gate if (!ptr) { 637*7c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, 638*7c478bd9Sstevel@tonic-gate "_tnfctl_readstr_targ: malloc failed\n")); 639*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate /*LINTED constant in conditional context*/ 642*7c478bd9Sstevel@tonic-gate while (1) { 643*7c478bd9Sstevel@tonic-gate int i; 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate /* read a chunk into our buffer */ 646*7c478bd9Sstevel@tonic-gate retstat = hndl->p_read(hndl->proc_p, addr + offset, buffer, 647*7c478bd9Sstevel@tonic-gate bufsz); 648*7c478bd9Sstevel@tonic-gate if (retstat != 0) { 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate /* 651*7c478bd9Sstevel@tonic-gate * if we get into trouble with a large read, try again 652*7c478bd9Sstevel@tonic-gate * with a single byte. Subsequent failiure is real ... 653*7c478bd9Sstevel@tonic-gate */ 654*7c478bd9Sstevel@tonic-gate if (bufsz > 1) { 655*7c478bd9Sstevel@tonic-gate bufsz = 1; 656*7c478bd9Sstevel@tonic-gate continue; 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, 660*7c478bd9Sstevel@tonic-gate "_tnfctl_readstr_targ: target read failed: \n")); 661*7c478bd9Sstevel@tonic-gate free(ptr); 662*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate /* copy the chracters into the return buffer */ 665*7c478bd9Sstevel@tonic-gate for (i = 0; i < bufsz; i++) { 666*7c478bd9Sstevel@tonic-gate char c = buffer[i]; 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate ptr[offset + i] = c; 669*7c478bd9Sstevel@tonic-gate if (c == '\0') { 670*7c478bd9Sstevel@tonic-gate /* hooray! we saw the end of the string */ 671*7c478bd9Sstevel@tonic-gate *outstr_pp = ptr; 672*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate /* bummer, need to grab another bufsz characters */ 677*7c478bd9Sstevel@tonic-gate offset += bufsz; 678*7c478bd9Sstevel@tonic-gate orig_ptr = ptr; 679*7c478bd9Sstevel@tonic-gate ptr = (char *) realloc(ptr, offset + bufsz); 680*7c478bd9Sstevel@tonic-gate if (!ptr) { 681*7c478bd9Sstevel@tonic-gate free(orig_ptr); 682*7c478bd9Sstevel@tonic-gate DBG((void) fprintf(stderr, 683*7c478bd9Sstevel@tonic-gate "_tnfctl_readstr_targ: realloc failed\n")); 684*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate #if defined(lint) 689*7c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE); 690*7c478bd9Sstevel@tonic-gate #endif 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate } 693