util.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1994, by Sun Microsytems, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Utility functions to initialize tnfctl handle, find functions that
* can be plugged into probes, find trace file information, and create
* a trace file for process tracing.
*/
#ifndef DEBUG
#define NDEBUG 1
#endif
#include "tnfctl_int.h"
#include "dbg.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include "tnf_buf.h"
/*
* Defines - Project private interfaces in libtnfprobe.so
*/
#define TRACEFILE_NAME "tnf_trace_file_name"
#define TRACEFILE_SIZE "tnf_trace_file_size"
#define TRACEFILE_MIN "tnf_trace_file_min"
#define TRACE_ERROR "_tnfw_b_control"
#define TRACE_ALLOC "tnf_trace_alloc"
#define TRACE_COMMIT "tnf_trace_commit"
#define TRACE_ROLLBACK "tnf_trace_rollback"
#define DEBUG_ENTRY "tnf_probe_debug"
#define PROBE_LIST_HEAD "__tnf_probe_list_head"
#define PROBE_LIST_VALID "__tnf_probe_list_valid"
#define NONTHREAD_TEST "tnf_non_threaded_test_addr"
#define THREAD_TEST "tnf_threaded_test_addr"
#define PROBE_THR_SYNC "__tnf_probe_thr_sync"
#define MEMSEG_PTR "__tnf_probe_memseg_p"
/* Project private interfaces in libthread.so */
#define LIBTHREAD_PRESENT "thr_probe_getfunc_addr"
/*
* Local declarations
*/
/*
* _tnfctl_refresh_process() - search for new shared objects. If any
* found, discover probes in new shared objects.
* NOT to be called in kernel mode.
*/
enum event_op_t *dl_evt)
{
/*LINTED statement has no consequent: else*/
if (prexstat)
goto finish_func;
/*
* update the link map. caller decides what to do on
* inconsistent link map
*/
if (prexstat)
goto finish_func;
/* link map is ok now */
if (prexstat)
goto finish_func;
if (prexstat)
goto finish_func;
}
/*LINTED statement has no consequent: else*/
return (prexstat);
}
/*
* initialize tnfctl handle for a new target
*/
{
enum event_op_t dl_evt;
/*LINTED statement has no consequent: else*/
/*
* initialize the link map table. If link map is not ok, it is an
* error.
*/
if (prexstat)
goto end_func;
/* find the needed target symbols */
if (prexstat) {
/* is libtnfprobe.so loaded in target ? */
goto end_func;
}
if (prexstat)
goto end_func;
if (prexstat)
goto end_func;
if (prexstat)
goto end_func;
/* fall into end_func */
/*LINTED statement has no consequent: else*/
return (prexstat);
}
/*
* find the test function for a probe. The test function could change
* with time, so we have to repeatedly check for the test function to use
*/
static tnfctl_errcode_t
{
long thr_sync;
int miscstat;
/* no libthread linked in */
} else {
/*
* If not yet synced up, use non-threaded test function
*/
/* assume we are going to use threaded test */
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
/* if not yet synced up, change test func to non-threaded one */
if (thr_sync == 0) {
}
}
/*
* Note: the testfunc in the target can change underneath us because
* in an MT program the init section of libthread changes all the
* test functions from the non-threaded one to the threaded one.
* So, every time we write out a probe, we have to make sure that
* we are using the correct test function by not trusting the test
* function in our copy of the probe. A more fool-proof solution
* which will allow other fields in the probe to change internally
* is to refresh every probe on a _tnfctl_refresh_process()
*/
return (TNFCTL_ERR_NONE);
}
/*
* check_trace_error() - checks whether there was an error in tracing
* side effects trace_buf_state and trace_state in hndl
* note: call this function only after trace_file_name is set up
* in hndl
*/
{
int miscstat;
/* read in the value of the control structure pointer */
&trace_error_ptr, sizeof (trace_error_ptr));
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
/* read in the value of the control structure */
sizeof (trace_error_rec));
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
/*
* massage into correct state for caller - the target might
* not have hit the first probe and hence we got "no buffer".
* So, if the user had given a file name, return BUF_OK.
*/
else
} else {
}
else
return (TNFCTL_ERR_NONE);
} /* end find_alloc_func */
/*
* find_target_syms() - finds needed target functions
* sideffects allocfunc, commitfunc, endfunc, rollbackfunc in hndl
*/
static tnfctl_errcode_t
{
int miscstat;
if (prexstat)
goto end_of_func;
if (prexstat)
goto end_of_func;
if (prexstat)
goto end_of_func;
if (prexstat)
goto end_of_func;
&hndl->probelist_head);
if (prexstat)
goto end_of_func;
if (prexstat)
goto end_of_func;
if (prexstat)
goto end_of_func;
/* dereference to get the actual address of structure */
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
&hndl->probelist_valid);
if (prexstat)
goto end_of_func;
if (prexstat)
goto end_of_func;
/* dereference to get the actual function address */
sizeof (hndl->nonthread_test));
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
if (prexstat)
goto end_of_func;
/* dereference to get the actual function address */
sizeof (hndl->thread_test));
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
if (prexstat)
goto end_of_func;
if (prexstat) {
if (prexstat == TNFCTL_ERR_BADARG) {
/* no libthread linked in */
/* this is not an error condition */
} else {
return (prexstat);
}
} else {
}
if (prexstat == TNFCTL_ERR_BADARG)
return (prexstat);
}
/*
* _tnfctl_create_tracefile() - initializes tracefile, sets the tracefile name
* and size
* side effects trace_file_name and trace_buf_size in hndl
*/
{
char *preexisting;
int miscstat;
char path[MAXPATHLEN];
/* find the neccessary symbols in the target */
if (prexstat) {
if (prexstat == TNFCTL_ERR_BADARG)
return (prexstat);
}
if (prexstat) {
if (prexstat == TNFCTL_ERR_BADARG)
return (prexstat);
}
/* Double check that a file name doesn't already exist */
preexisting = NULL;
if (prexstat) {
if (preexisting)
return (prexstat);
}
/* There better not be a file name there yet */
/* paranoia - for optimized compilation */
if (preexisting[0] != '\0')
return (TNFCTL_ERR_BUFEXISTS);
/* free memory in preexisting string */
if (preexisting)
return (TNFCTL_ERR_SIZETOOSMALL);
}
/* do we have an absolute, relative or no pathname specified? */
if (trace_file_name == NULL) {
return (TNFCTL_ERR_BADARG);
}
if (trace_file_name[0] == '/') {
/* absolute path to tracefile specified */
/* directory specification too long */
return (TNFCTL_ERR_BADARG);
}
} else {
char *cwd;
/* relative path to tracefile specified */
if (!cwd) {
return (tnfctl_status_map(errno));
}
(size_t) MAXPATHLEN) {
/* path name too long */
return (TNFCTL_ERR_BADARG);
}
}
"sunw%verbosity 1; sunw%debug 'setting trace file name'",
/* unlink a previous tracefile (if one exists) */
/* create the new tracefile */
if (fd < 0) {
return (tnfctl_status_map(errno));
}
/* zero fill the file */
/* trouble zeroing tracefile */
return (tnfctl_status_map(errno));
}
}
/* close the file */
/* write the tracefile name and size into the target process */
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
sizeof (outsize));
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
return (TNFCTL_ERR_ALLOCFAIL);
return (TNFCTL_ERR_NONE);
} /* end _tnfctl_create_tracefile */
/*
* find_trace_file_info()
* finds out information about the trace file.
* side effects trace_buf_size, trace_min_size, trace_file_name in hndl
*/
static tnfctl_errcode_t
{
int miscstat;
char *preexisting;
/* find the neccessary symbols in the target */
if (prexstat) {
if (prexstat == TNFCTL_ERR_BADARG)
return (prexstat);
}
if (prexstat) {
if (prexstat == TNFCTL_ERR_BADARG)
return (prexstat);
}
if (prexstat) {
if (prexstat == TNFCTL_ERR_BADARG)
return (prexstat);
}
/* read file name */
preexisting = NULL;
if (prexstat) {
if (preexisting)
return (prexstat);
}
/* read the minimum file size from the target */
sizeof (minoutsize));
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
/* if there is no filename, we are done */
if (preexisting[0] == '\0') {
hndl->trace_buf_size = 0;
} else {
/* read size of file */
if (miscstat != 0)
return (TNFCTL_ERR_INTERNAL);
}
return (TNFCTL_ERR_NONE);
} /* end find_trace_file_info */
/*
* wrapper functions over native /proc functions implemented by proc
* layer
*/
int
{
}
int
{
}
int
{
}
_tnfctl_pid_get(void *proc_p)
{
return (prb_proc_pid_get(proc_p));
}
/*
* _tnfctl_readstr_targ() - dereferences a string in the target
* NOTE: There is a similar routine called prb_proc_readstr()
* used by proc layer. It would be better if there was only
* one of these functions defined.
*/
#define BUFSZ 256
{
int retstat;
offset = 0;
/* allocate an inital return buffer */
if (!ptr) {
"_tnfctl_readstr_targ: malloc failed\n"));
return (TNFCTL_ERR_ALLOCFAIL);
}
/*LINTED constant in conditional context*/
while (1) {
int i;
/* read a chunk into our buffer */
bufsz);
if (retstat != 0) {
/*
* if we get into trouble with a large read, try again
* with a single byte. Subsequent failiure is real ...
*/
if (bufsz > 1) {
bufsz = 1;
continue;
}
"_tnfctl_readstr_targ: target read failed: \n"));
return (TNFCTL_ERR_INTERNAL);
}
/* copy the chracters into the return buffer */
for (i = 0; i < bufsz; i++) {
char c = buffer[i];
if (c == '\0') {
/* hooray! we saw the end of the string */
return (TNFCTL_ERR_NONE);
}
}
/* bummer, need to grab another bufsz characters */
if (!ptr) {
"_tnfctl_readstr_targ: realloc failed\n"));
return (TNFCTL_ERR_ALLOCFAIL);
}
}
#if defined(lint)
return (TNFCTL_ERR_NONE);
#endif
}