/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Includes
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <locale.h>
#include <libintl.h>
#include <fcntl.h>
#include <limits.h>
#include <libelf.h>
#include <gelf.h>
#include <sys/systeminfo.h>
#include "set.h"
#include "cmd.h"
#include "spec.h"
#include "expr.h"
#include "source.h"
#include "list.h"
#include "prbk.h"
/*
* Defines - Project private interfaces
*/
#ifdef TESTING
#endif
#if defined(__sparc)
#endif
/*
* Globals
*/
/*
* Local Declarations
*/
static int set_signal(void);
static int get_elf_class(char *filename);
static int get_executable(char *);
/* #### - FIXME - need to put this in a private header file */
extern void err_fatal(char *s, ...);
extern int yyparse(void);
static void set_default_cmd(void);
static void get_commands(void);
void cmd_listtracefile();
/*
* usage() - gives a description of the arguments, and exits
*/
static void
{
if (msg)
"usage: %s [options] <cmd> [cmd-args...]\n"), argv[0]);
"usage: %s [options] -p <pid>\n"), argv[0]);
"usage: %s -s <kbytes-size> -k\n"), argv[0]);
"options:\n"));
" -o <outfilename> set trace output file name\n"));
" -s <kbytes-size> set trace file size\n"));
" -l <sharedobjs> shared objects to "
"be preloaded (cmd only)\n"));
exit(1);
}
/*
* main() -
*/
int
{
int sys_err;
/* internationalization stuff */
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
#if defined(DEBUG)
#endif
#if defined(DEBUG)
#endif
if (g_kernelmode) {
/* prexing the kernel */
if (err) {
"%s: trouble attaching to the kernel: %s\n"),
}
} else {
/* prexing a user process */
if (g_targetpid != 0) {
/* check data model */
/* attach case */
if (err == TNFCTL_ERR_NOLIBTNFPROBE) {
"%s: missing symbols, is "
"libtnfprobe.so loaded in target?\n"),
} else if (err) {
"%s: trouble attaching to target "
"process: %s\n"),
}
} else {
/* check elf class model */
/* exec case */
if (err == TNFCTL_ERR_NONE)
&trace_attrs);
if (err) {
"%s: trouble creating target process: "
"%s\n"),
}
}
sys_err = set_signal();
if (sys_err)
"%s: trouble setting up signal handler: %s\n"),
}
/* initialize the source stack for the parser */
source_init();
if (!g_kernelmode) {
/* set the tracefile name and size */
if (err) {
"%s: trouble initializing tracefile: %s\n"),
goto Cleanup;
}
if (err) {
"%s: cannot read tracing status : %s\n"),
goto Cleanup;
}
}
/* accept commands from stdin the first time through */
/* set up default aliases */
/* set up creator/destructor function to call for new probes */
if (err) {
"%s: error in probe discovery : %s\n"),
goto Cleanup;
}
if (g_kernelmode) {
}
while (err == TNFCTL_ERR_NONE) {
if (g_kernelmode || g_getcmds) {
get_commands();
}
if (err) {
"%s: cannot continue target : %s\n"),
goto Cleanup;
}
}
if (err) {
"%s: cannot read tracing status : %s\n"),
goto Cleanup;
}
if (!g_kernelmode) {
if (event == TNFCTL_EVENT_EXEC) {
"Target process exec'd\n"));
} else if (event == TNFCTL_EVENT_EXIT) {
/* target exited */
"%s: target process exited\n"),
g_argv[0]);
goto Cleanup;
} else if (event == TNFCTL_EVENT_TARGGONE) {
/* target terminated */
gettext("%s: target process disappeared (without calling exit)\n"),
g_argv[0]);
goto Cleanup;
}
}
}
if (err)
"%s: error on closing : %s\n"),
exit(0);
return (0);
}
/*
* check_trace_error() - checks whether there was an error in tracing
*/
static tnfctl_errcode_t
{
if (err)
return (err);
"due to an internal error - Please restart prex "
"and target\n"));
}
return (TNFCTL_ERR_NONE);
}
/*
* set_default_cmd() - set the default debug entry and $all
*/
static void
set_default_cmd(void)
{
if (!g_kernelmode)
#ifdef TESTING
#endif
}
/*
* process() - enable and disable selected probes
*/
typedef struct {
static tnfctl_errcode_t
void *calldata_p)
{
char *attrs;
if (g_verbose) {
char *cmdstr[] = {
"enable", "disable",
"connect", "clear",
"trace", "untrace"};
}
#endif
switch (kind) {
case CMD_ENABLE:
break;
case CMD_DISABLE:
break;
case CMD_TRACE:
break;
case CMD_UNTRACE:
break;
case CMD_CONNECT:
break;
case CMD_CLEAR:
break;
}
if (g_verbose)
#endif
}
if (attrs)
return (err);
}
/*ARGSUSED*/
static void *
{
if (err) {
"%s: error on new (dlopened) probe : %s\n"),
}
return (NULL);
}
static tnfctl_errcode_t
{
if (err)
return (err);
return (TNFCTL_ERR_NONE);
}
static tnfctl_errcode_t
{
if (err) {
"%s: error on probe operation: %s\n"),
}
return (err);
}
void
{
if (g_verbose)
#endif
}
/*
* get_commands() - process commands from stdin
*/
static void
get_commands(void)
{
/* Read commands from STDIN */
if (g_kernelmode) {
} else {
if (g_testflag)
(void) printf("prex(%ld), target(%ld): ",
getpid(), g_targetpid);
"Type \"continue\" to resume the target, "
"\"help\" for help ...\n"));
}
while (yyparse());
}
/*
* quit() - called to quit the controlling process. The boolean argument
* specifies whether to terminate the target as well.
*/
void
{
if (killtarget && runtarget)
else if (killtarget && !runtarget)
else if (!killtarget && runtarget)
else if (!killtarget && !runtarget)
if (err) {
"%s: trouble quitting : %s\n"),
exit(1);
}
exit(0);
}
/*
* scanargs() - processes the command line arguments
*/
static void
char **argv)
{
int c;
#else
#endif
/* set up some defaults */
g_targetpid = 0;
g_outsize = -1;
switch (c) {
case 'l': /* preload objects */
break;
case 'o': /* tracefile name */
break;
case 'p': /* target pid (attach case) */
break;
case 's': /* tracefile size */
break;
case 't': /* test flag */
g_testflag = B_TRUE;
break;
case 'k': /* kernel mode */
break;
case 'v': /* verbose flag */
break;
#endif
case '?': /* error case */
}
}
}
/* sanity clause */
if (g_targetpid && g_preload)
if (g_kernelmode) {
if (g_outname)
if (g_cmdname)
if (g_targetpid)
if (g_preload)
}
/* default output size */
if (g_outsize == -1)
#ifdef OLD
int i;
for (i = 1; i < argc; i++) {
int vlevel;
if (++i >= argc)
g_testflag = B_TRUE;
} else if (argv[i][0] != '-') {
if (!g_cmdname) {
"%s: out of memory"), argv[0]);
}
if (g_verbose >= 2) {
"cmdname=%s\n", g_cmdname);
}
/*
* rest of arguments are the args to the executable -
* by convention argv[0] should be name of
* executable, so we don't increment i
*/
break;
} else {
}
}
#endif
} /* end scanargs */
/*
* sig_handler() - cleans up if a signal is received
*/
/*ARGSUSED*/
static void
{
} /* end sig_handler */
/*
* set_signal() - sets up function to call for clean up
*/
static int
set_signal(void)
{
return (errno);
}
return (0);
}
/*
* set_tracefile() - initializes tracefile, sets the tracefile name and size
*/
static tnfctl_errcode_t
{
char *outfile_name;
char *tmpdir;
/* Init tracefile name used by list cmd */
if (err)
return (err);
return (TNFCTL_ERR_BUFBROKEN);
/* trace file set already - can't change it */
return (TNFCTL_ERR_NONE);
}
if (g_outsize < minoutsize) {
gettext("specified tracefile size smaller then "
"minimum; setting to %d kbytes\n"),
minoutsize / 1024);
}
/* where is $TMPDIR? */
tmpdir = "/tmp";
}
/* do we have an absolute, relative or no pathname specified? */
/* default, no tracefile specified */
"%s: $TMPDIR too long\n"), g_argv[0]);
exit(1);
}
outfile_name = path;
} else {
/* filename specified */
}
return (TNFCTL_ERR_ALLOCFAIL);
} else {
return (TNFCTL_ERR_INTERNAL);
}
}
if (g_verbose)
"setting tracefile name=\"%s\", size=%d\n",
#endif
return (err);
}
/*
* get_data_model() - get the process data model from psinfo
* structure.
*/
static int
{
if (fd == -1)
return (dmodel);
return (dmodel);
}
/*
* get_executable - return file descriptor for PATH-resolved
* target file.
*
*/
static int
char *p = line;
int N = sizeof (line);
} else {
}
}
}
}
if (fd >= 0)
return (-1);
}
p++;
*p = '\0';
return (get_executable(line));
}
} /* %$#@! cstyle complaint */
return (fd);
}
/*
* get_elf_class - get the target executable elf class
* i.e. ELFCLASS64 or ELFCLASS32.
*/
static int
{
char *ident;
if (elffd < 0)
return (elfclass);
return (elfclass);
}
/*
* verify information in file header
*/
return (elfclass);
}
if (ident[EI_CLASS] == ELFCLASS32)
if (ident[EI_CLASS] == ELFCLASS64)
return (elfclass);
}
/*
* check_exec_model() - check the consistency between prex data model
* and target elf class and act accordingly
*/
static void
{
int elfclass;
return;
if ((prex_dmodel == PR_MODEL_ILP32) &&
(elfclass == ELFCLASS64)) {
"Error: 32 bit prex can not exec 64 bit target\n"));
exit(1);
}
if ((prex_dmodel == PR_MODEL_LP64) &&
(elfclass == ELFCLASS32))
}
/*
* check_pid_model() - check the consistency between prex data model
* and target data model and act accordingly
*/
static void
{
int dmodel;
if (prex_dmodel == dmodel)
return;
if ((prex_dmodel == PR_MODEL_ILP32) &&
(dmodel == PR_MODEL_LP64)) {
"Error: 32 bit prex can not exec 64 bit target\n"));
exit(1);
}
if ((prex_dmodel == PR_MODEL_LP64) &&
(dmodel == PR_MODEL_ILP32))
}
/*
* prex_isaexec() - there is only one case this function get called
* 64 bit prex, 32 bit target, need to exec 32 bit
* prex here.
*/
static void
{
gettext("%s: execve(\"%s\") failed\n"),
exit(1);
}
void
{
if (g_kernelmode) {
gettext("There is no trace file in kernel mode!\n"));
} else {
}
}