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