17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*c5024742Srab * Common Development and Distribution License (the "License").
6*c5024742Srab * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*c5024742Srab * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * Includes
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate #include <stdio.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <signal.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <locale.h>
397c478bd9Sstevel@tonic-gate #include <libintl.h>
407c478bd9Sstevel@tonic-gate #include <fcntl.h>
417c478bd9Sstevel@tonic-gate #include <limits.h>
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <sys/param.h>
457c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
467c478bd9Sstevel@tonic-gate #include <libelf.h>
477c478bd9Sstevel@tonic-gate #include <gelf.h>
487c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #include <tnf/tnfctl.h>
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate #include "set.h"
537c478bd9Sstevel@tonic-gate #include "cmd.h"
547c478bd9Sstevel@tonic-gate #include "spec.h"
557c478bd9Sstevel@tonic-gate #include "expr.h"
567c478bd9Sstevel@tonic-gate #include "source.h"
577c478bd9Sstevel@tonic-gate #include "list.h"
587c478bd9Sstevel@tonic-gate #include "prbk.h"
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate * Defines - Project private interfaces
627c478bd9Sstevel@tonic-gate */
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate #define DEBUG_ENTRY "tnf_probe_debug"
657c478bd9Sstevel@tonic-gate #ifdef TESTING
667c478bd9Sstevel@tonic-gate #define EMPTY_ENTRY "tnf_probe_empty"
677c478bd9Sstevel@tonic-gate #endif
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate #define USER_OUTSIZE (4*1024*1024)
707c478bd9Sstevel@tonic-gate #define KERNEL_OUTSIZE (384*1024)
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate #if defined(__sparc)
737c478bd9Sstevel@tonic-gate #define PREX32DIR "/sparcv7/"
747c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64)
757c478bd9Sstevel@tonic-gate #define PREX32DIR "/i86/"
767c478bd9Sstevel@tonic-gate #endif
777c478bd9Sstevel@tonic-gate #define PREX32EXEC "/usr/bin" PREX32DIR "prex"
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate * Globals
817c478bd9Sstevel@tonic-gate */
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate char **g_argv; /* copy of argv pointer */
847c478bd9Sstevel@tonic-gate tnfctl_handle_t *g_hndl; /* handle on target or kernel */
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate static int g_verbose; /* debugging to stderr */
877c478bd9Sstevel@tonic-gate static char *g_cmdname; /* target command name */
887c478bd9Sstevel@tonic-gate static char **g_cmdargs; /* target command args */
897c478bd9Sstevel@tonic-gate static pid_t g_targetpid; /* target process id */
907c478bd9Sstevel@tonic-gate static volatile boolean_t g_getcmds; /* accept input flag */
917c478bd9Sstevel@tonic-gate static boolean_t g_testflag; /* asserted in test mode */
927c478bd9Sstevel@tonic-gate static char *g_preload; /* objects to preload */
937c478bd9Sstevel@tonic-gate static char *g_outname; /* tracefile name */
947c478bd9Sstevel@tonic-gate static char *tracefile; /* tracefile name used by list cmd */
957c478bd9Sstevel@tonic-gate int g_outsize; /* tracefile size */
967c478bd9Sstevel@tonic-gate boolean_t g_kernelmode; /* -k flag: kernel mode */
977c478bd9Sstevel@tonic-gate static int prex_dmodel; /* prex data model */
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate * Local Declarations
1007c478bd9Sstevel@tonic-gate */
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate static void usage(char **argv, const char *msg);
1037c478bd9Sstevel@tonic-gate static void scanargs(int argc, char **argv);
1047c478bd9Sstevel@tonic-gate static int set_signal(void);
1057c478bd9Sstevel@tonic-gate static int get_data_model(pid_t pid);
1067c478bd9Sstevel@tonic-gate static int get_elf_class(char *filename);
1077c478bd9Sstevel@tonic-gate static int get_executable(char *);
1087c478bd9Sstevel@tonic-gate static void prex_isaexec(char **argv, char **envp);
1097c478bd9Sstevel@tonic-gate static void check_pid_model(char **argv, char **envp);
1107c478bd9Sstevel@tonic-gate static void check_exec_model(char **argv, char **envp);
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /* #### - FIXME - need to put this in a private header file */
1137c478bd9Sstevel@tonic-gate extern void err_fatal(char *s, ...);
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate extern int yyparse(void);
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate static tnfctl_errcode_t check_trace_error(tnfctl_handle_t *hndl);
1187c478bd9Sstevel@tonic-gate static void set_default_cmd(void);
1197c478bd9Sstevel@tonic-gate static void get_commands(void);
1207c478bd9Sstevel@tonic-gate static tnfctl_errcode_t set_tracefile(tnfctl_handle_t *hndl);
1217c478bd9Sstevel@tonic-gate static tnfctl_errcode_t set_probe_discovery_callback(tnfctl_handle_t *hndl);
1227c478bd9Sstevel@tonic-gate static void * perprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p);
1237c478bd9Sstevel@tonic-gate static tnfctl_errcode_t perprobe2(tnfctl_handle_t *hndl,
1247c478bd9Sstevel@tonic-gate tnfctl_probe_t *probe_p, void *ignored);
1257c478bd9Sstevel@tonic-gate static tnfctl_errcode_t percmd(expr_t *expr_p, cmd_kind_t kind, fcn_t *fcn_p,
1267c478bd9Sstevel@tonic-gate boolean_t isnew, void *calldata_p);
1277c478bd9Sstevel@tonic-gate void quit(boolean_t killtarget, boolean_t runtarget);
1287c478bd9Sstevel@tonic-gate void cmd_listtracefile();
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate * usage() - gives a description of the arguments, and exits
1337c478bd9Sstevel@tonic-gate */
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate static void
usage(char * argv[],const char * msg)1367c478bd9Sstevel@tonic-gate usage(char *argv[], const char *msg)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate if (msg)
1397c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
1407c478bd9Sstevel@tonic-gate gettext("%s: %s\n"), argv[0], msg);
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1437c478bd9Sstevel@tonic-gate "usage: %s [options] <cmd> [cmd-args...]\n"), argv[0]);
1447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1457c478bd9Sstevel@tonic-gate "usage: %s [options] -p <pid>\n"), argv[0]);
1467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1477c478bd9Sstevel@tonic-gate "usage: %s -s <kbytes-size> -k\n"), argv[0]);
1487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1497c478bd9Sstevel@tonic-gate "options:\n"));
1507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1517c478bd9Sstevel@tonic-gate " -o <outfilename> set trace output file name\n"));
1527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1537c478bd9Sstevel@tonic-gate " -s <kbytes-size> set trace file size\n"));
1547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1557c478bd9Sstevel@tonic-gate " -l <sharedobjs> shared objects to "
1567c478bd9Sstevel@tonic-gate "be preloaded (cmd only)\n"));
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate exit(1);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate * main() -
1647c478bd9Sstevel@tonic-gate */
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv,char ** envp)1677c478bd9Sstevel@tonic-gate main(int argc, char **argv, char **envp)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate tnfctl_errcode_t err = TNFCTL_ERR_NONE;
1707c478bd9Sstevel@tonic-gate int sys_err;
1717c478bd9Sstevel@tonic-gate tnfctl_trace_attrs_t trace_attrs;
1727c478bd9Sstevel@tonic-gate tnfctl_event_t event = TNFCTL_EVENT_EINTR;
1737c478bd9Sstevel@tonic-gate pid_t prex_pid;
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /* internationalization stuff */
1767c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1777c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
1787c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
1797c478bd9Sstevel@tonic-gate #endif
1807c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate g_argv = argv;
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate prex_pid = getpid();
1857c478bd9Sstevel@tonic-gate #if defined(DEBUG)
1867c478bd9Sstevel@tonic-gate fprintf(stderr, "### prex_pid = %d ###\n", prex_pid);
1877c478bd9Sstevel@tonic-gate #endif
1887c478bd9Sstevel@tonic-gate prex_dmodel = get_data_model(prex_pid);
1897c478bd9Sstevel@tonic-gate #if defined(DEBUG)
1907c478bd9Sstevel@tonic-gate fprintf(stderr, "### prex_dmodel = %d ###\n", prex_dmodel);
1917c478bd9Sstevel@tonic-gate #endif
1927c478bd9Sstevel@tonic-gate scanargs(argc, argv);
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate if (g_kernelmode) {
1957c478bd9Sstevel@tonic-gate /* prexing the kernel */
1967c478bd9Sstevel@tonic-gate err = tnfctl_kernel_open(&g_hndl);
1977c478bd9Sstevel@tonic-gate if (err) {
1987c478bd9Sstevel@tonic-gate err_fatal(gettext(
1997c478bd9Sstevel@tonic-gate "%s: trouble attaching to the kernel: %s\n"),
2007c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate } else {
2037c478bd9Sstevel@tonic-gate /* prexing a user process */
2047c478bd9Sstevel@tonic-gate if (g_targetpid != 0) {
2057c478bd9Sstevel@tonic-gate /* check data model */
2067c478bd9Sstevel@tonic-gate check_pid_model(argv, envp);
2077c478bd9Sstevel@tonic-gate /* attach case */
2087c478bd9Sstevel@tonic-gate err = tnfctl_pid_open(g_targetpid, &g_hndl);
2097c478bd9Sstevel@tonic-gate if (err == TNFCTL_ERR_NOLIBTNFPROBE) {
2107c478bd9Sstevel@tonic-gate err_fatal(gettext(
2117c478bd9Sstevel@tonic-gate "%s: missing symbols, is "
2127c478bd9Sstevel@tonic-gate "libtnfprobe.so loaded in target?\n"),
2137c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2147c478bd9Sstevel@tonic-gate } else if (err) {
2157c478bd9Sstevel@tonic-gate err_fatal(gettext(
2167c478bd9Sstevel@tonic-gate "%s: trouble attaching to target "
2177c478bd9Sstevel@tonic-gate "process: %s\n"),
2187c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate } else {
2217c478bd9Sstevel@tonic-gate /* check elf class model */
2227c478bd9Sstevel@tonic-gate check_exec_model(argv, envp);
2237c478bd9Sstevel@tonic-gate /* exec case */
2247c478bd9Sstevel@tonic-gate err = tnfctl_exec_open(g_cmdname, g_cmdargs, NULL,
2257c478bd9Sstevel@tonic-gate g_preload, NULL, &g_hndl);
2267c478bd9Sstevel@tonic-gate if (err == TNFCTL_ERR_NONE)
2277c478bd9Sstevel@tonic-gate err = tnfctl_trace_attrs_get(g_hndl,
2287c478bd9Sstevel@tonic-gate &trace_attrs);
2297c478bd9Sstevel@tonic-gate if (err) {
2307c478bd9Sstevel@tonic-gate err_fatal(gettext(
2317c478bd9Sstevel@tonic-gate "%s: trouble creating target process: "
2327c478bd9Sstevel@tonic-gate "%s\n"),
2337c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate g_targetpid = trace_attrs.targ_pid;
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate sys_err = set_signal();
2397c478bd9Sstevel@tonic-gate if (sys_err)
2407c478bd9Sstevel@tonic-gate err_fatal(gettext(
2417c478bd9Sstevel@tonic-gate "%s: trouble setting up signal handler: %s\n"),
2427c478bd9Sstevel@tonic-gate argv[0], strerror(err));
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate /* initialize the source stack for the parser */
2467c478bd9Sstevel@tonic-gate source_init();
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate if (!g_kernelmode) {
2497c478bd9Sstevel@tonic-gate /* set the tracefile name and size */
2507c478bd9Sstevel@tonic-gate err = set_tracefile(g_hndl);
2517c478bd9Sstevel@tonic-gate if (err) {
2527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2537c478bd9Sstevel@tonic-gate "%s: trouble initializing tracefile: %s\n"),
2547c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2557c478bd9Sstevel@tonic-gate goto Cleanup;
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate err = check_trace_error(g_hndl);
2587c478bd9Sstevel@tonic-gate if (err) {
2597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2607c478bd9Sstevel@tonic-gate "%s: cannot read tracing status : %s\n"),
2617c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2627c478bd9Sstevel@tonic-gate goto Cleanup;
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /* accept commands from stdin the first time through */
2677c478bd9Sstevel@tonic-gate g_getcmds = B_TRUE;
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate /* set up default aliases */
2707c478bd9Sstevel@tonic-gate set_default_cmd();
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate /* set up creator/destructor function to call for new probes */
2737c478bd9Sstevel@tonic-gate err = set_probe_discovery_callback(g_hndl);
2747c478bd9Sstevel@tonic-gate if (err) {
2757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2767c478bd9Sstevel@tonic-gate "%s: error in probe discovery : %s\n"),
2777c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2787c478bd9Sstevel@tonic-gate goto Cleanup;
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate if (g_kernelmode) {
2827c478bd9Sstevel@tonic-gate prbk_warn_pfilter_empty();
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate while (err == TNFCTL_ERR_NONE) {
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate if (g_kernelmode || g_getcmds) {
2887c478bd9Sstevel@tonic-gate g_getcmds = B_FALSE;
2897c478bd9Sstevel@tonic-gate get_commands();
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate if (!g_kernelmode && (g_getcmds == B_FALSE)) {
2937c478bd9Sstevel@tonic-gate err = tnfctl_continue(g_hndl, &event, NULL);
2947c478bd9Sstevel@tonic-gate if (err) {
2957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2967c478bd9Sstevel@tonic-gate "%s: cannot continue target : %s\n"),
2977c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
2987c478bd9Sstevel@tonic-gate goto Cleanup;
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate err = check_trace_error(g_hndl);
3027c478bd9Sstevel@tonic-gate if (err) {
3037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3047c478bd9Sstevel@tonic-gate "%s: cannot read tracing status : %s\n"),
3057c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
3067c478bd9Sstevel@tonic-gate goto Cleanup;
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate if (!g_kernelmode) {
3097c478bd9Sstevel@tonic-gate if (event == TNFCTL_EVENT_EXEC) {
3107c478bd9Sstevel@tonic-gate (void) printf(gettext(
3117c478bd9Sstevel@tonic-gate "Target process exec'd\n"));
3127c478bd9Sstevel@tonic-gate quit(B_FALSE, B_TRUE); /* quit resume */
3137c478bd9Sstevel@tonic-gate } else if (event == TNFCTL_EVENT_EXIT) {
3147c478bd9Sstevel@tonic-gate /* target exited */
3157c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3167c478bd9Sstevel@tonic-gate "%s: target process exited\n"),
3177c478bd9Sstevel@tonic-gate g_argv[0]);
3187c478bd9Sstevel@tonic-gate goto Cleanup;
3197c478bd9Sstevel@tonic-gate } else if (event == TNFCTL_EVENT_TARGGONE) {
3207c478bd9Sstevel@tonic-gate /* target terminated */
3217c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3227c478bd9Sstevel@tonic-gate gettext("%s: target process disappeared (without calling exit)\n"),
3237c478bd9Sstevel@tonic-gate g_argv[0]);
3247c478bd9Sstevel@tonic-gate goto Cleanup;
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate Cleanup:
3307c478bd9Sstevel@tonic-gate err = tnfctl_close(g_hndl, TNFCTL_TARG_DEFAULT);
3317c478bd9Sstevel@tonic-gate if (err)
3327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3337c478bd9Sstevel@tonic-gate "%s: error on closing : %s\n"),
3347c478bd9Sstevel@tonic-gate argv[0], tnfctl_strerror(err));
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate exit(0);
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate return (0);
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate * check_trace_error() - checks whether there was an error in tracing
3447c478bd9Sstevel@tonic-gate */
3457c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
check_trace_error(tnfctl_handle_t * hndl)3467c478bd9Sstevel@tonic-gate check_trace_error(tnfctl_handle_t *hndl)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate tnfctl_trace_attrs_t trace_attrs;
3497c478bd9Sstevel@tonic-gate tnfctl_errcode_t err;
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate err = tnfctl_trace_attrs_get(hndl, &trace_attrs);
3527c478bd9Sstevel@tonic-gate if (err)
3537c478bd9Sstevel@tonic-gate return (err);
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate if (trace_attrs.trace_buf_state == TNFCTL_BUF_BROKEN) {
3567c478bd9Sstevel@tonic-gate (void) printf(gettext("Tracing shut down in target program "
3577c478bd9Sstevel@tonic-gate "due to an internal error - Please restart prex "
3587c478bd9Sstevel@tonic-gate "and target\n"));
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate * set_default_cmd() - set the default debug entry and $all
3667c478bd9Sstevel@tonic-gate */
3677c478bd9Sstevel@tonic-gate static void
set_default_cmd(void)3687c478bd9Sstevel@tonic-gate set_default_cmd(void)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate if (!g_kernelmode)
3717c478bd9Sstevel@tonic-gate fcn(strdup("debug"), DEBUG_ENTRY);
3727c478bd9Sstevel@tonic-gate #ifdef TESTING
3737c478bd9Sstevel@tonic-gate fcn(strdup("empty"), EMPTY_ENTRY);
3747c478bd9Sstevel@tonic-gate #endif
3757c478bd9Sstevel@tonic-gate (void) set(strdup("all"), expr(spec(strdup("keys"), SPEC_EXACT),
3767c478bd9Sstevel@tonic-gate spec(strdup(".*"), SPEC_REGEXP)));
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate * process() - enable and disable selected probes
3827c478bd9Sstevel@tonic-gate */
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate typedef struct {
3857c478bd9Sstevel@tonic-gate tnfctl_probe_t *probe_p;
3867c478bd9Sstevel@tonic-gate tnfctl_handle_t *hndl;
3877c478bd9Sstevel@tonic-gate } process_args_t;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
percmd(expr_t * expr_p,cmd_kind_t kind,fcn_t * fcn_p,boolean_t isnew,void * calldata_p)3907c478bd9Sstevel@tonic-gate percmd(expr_t *expr_p, cmd_kind_t kind, fcn_t *fcn_p, boolean_t isnew,
3917c478bd9Sstevel@tonic-gate void *calldata_p)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate process_args_t *args_p = (process_args_t *)calldata_p;
3947c478bd9Sstevel@tonic-gate tnfctl_handle_t *hndl = args_p->hndl;
3957c478bd9Sstevel@tonic-gate tnfctl_probe_t *probe_p = args_p->probe_p;
3967c478bd9Sstevel@tonic-gate tnfctl_errcode_t err = TNFCTL_ERR_NONE;
3977c478bd9Sstevel@tonic-gate char *attrs;
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate attrs = list_getattrs(probe_p);
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate if (expr_match(expr_p, attrs)) {
4027c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint)
4037c478bd9Sstevel@tonic-gate if (g_verbose) {
4047c478bd9Sstevel@tonic-gate char *cmdstr[] = {
4057c478bd9Sstevel@tonic-gate "enable", "disable",
4067c478bd9Sstevel@tonic-gate "connect", "clear",
4077c478bd9Sstevel@tonic-gate "trace", "untrace"};
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate (void) fprintf(stderr, ": %s command: %s ",
4107c478bd9Sstevel@tonic-gate (isnew) ? "new" : "old", cmdstr[kind]);
4117c478bd9Sstevel@tonic-gate expr_print(stderr, expr_p);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate #endif
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate switch (kind) {
4167c478bd9Sstevel@tonic-gate case CMD_ENABLE:
4177c478bd9Sstevel@tonic-gate err = tnfctl_probe_enable(hndl, probe_p, NULL);
4187c478bd9Sstevel@tonic-gate break;
4197c478bd9Sstevel@tonic-gate case CMD_DISABLE:
4207c478bd9Sstevel@tonic-gate err = tnfctl_probe_disable(hndl, probe_p, NULL);
4217c478bd9Sstevel@tonic-gate break;
4227c478bd9Sstevel@tonic-gate case CMD_TRACE:
4237c478bd9Sstevel@tonic-gate err = tnfctl_probe_trace(hndl, probe_p, NULL);
4247c478bd9Sstevel@tonic-gate break;
4257c478bd9Sstevel@tonic-gate case CMD_UNTRACE:
4267c478bd9Sstevel@tonic-gate err = tnfctl_probe_untrace(hndl, probe_p, NULL);
4277c478bd9Sstevel@tonic-gate break;
4287c478bd9Sstevel@tonic-gate case CMD_CONNECT:
4297c478bd9Sstevel@tonic-gate err = tnfctl_probe_connect(hndl, probe_p, NULL,
4307c478bd9Sstevel@tonic-gate fcn_p->entry_name_p);
4317c478bd9Sstevel@tonic-gate break;
4327c478bd9Sstevel@tonic-gate case CMD_CLEAR:
4337c478bd9Sstevel@tonic-gate err = tnfctl_probe_disconnect_all(hndl, probe_p, NULL);
4347c478bd9Sstevel@tonic-gate break;
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint)
4387c478bd9Sstevel@tonic-gate if (g_verbose)
4397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n");
4407c478bd9Sstevel@tonic-gate #endif
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate if (attrs)
4447c478bd9Sstevel@tonic-gate free(attrs);
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate return (err);
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4517c478bd9Sstevel@tonic-gate static void *
perprobe(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_p)4527c478bd9Sstevel@tonic-gate perprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate process_args_t args;
4557c478bd9Sstevel@tonic-gate tnfctl_errcode_t err;
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate args.probe_p = probe_p;
4587c478bd9Sstevel@tonic-gate args.hndl = hndl;
4597c478bd9Sstevel@tonic-gate err = cmd_traverse(percmd, &args);
4607c478bd9Sstevel@tonic-gate if (err) {
4617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
4627c478bd9Sstevel@tonic-gate "%s: error on new (dlopened) probe : %s\n"),
4637c478bd9Sstevel@tonic-gate g_argv[0], tnfctl_strerror(err));
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate return (NULL);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
set_probe_discovery_callback(tnfctl_handle_t * hndl)4697c478bd9Sstevel@tonic-gate set_probe_discovery_callback(tnfctl_handle_t *hndl)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate tnfctl_errcode_t err;
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate err = tnfctl_register_funcs(hndl, perprobe, NULL);
4747c478bd9Sstevel@tonic-gate if (err)
4757c478bd9Sstevel@tonic-gate return (err);
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
perprobe2(tnfctl_handle_t * hndl,tnfctl_probe_t * probe_p,void * cd)4817c478bd9Sstevel@tonic-gate perprobe2(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p, void *cd)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate cmd_t *cmd = cd;
4847c478bd9Sstevel@tonic-gate process_args_t args;
4857c478bd9Sstevel@tonic-gate tnfctl_errcode_t err;
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate args.probe_p = probe_p;
4887c478bd9Sstevel@tonic-gate args.hndl = hndl;
4897c478bd9Sstevel@tonic-gate err = cmd_callback(cmd, percmd, &args);
4907c478bd9Sstevel@tonic-gate if (err) {
4917c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
4927c478bd9Sstevel@tonic-gate "%s: error on probe operation: %s\n"),
4937c478bd9Sstevel@tonic-gate g_argv[0], tnfctl_strerror(err));
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate return (err);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate void
process_cmd(tnfctl_handle_t * hndl,cmd_t * cmd)4997c478bd9Sstevel@tonic-gate process_cmd(tnfctl_handle_t *hndl, cmd_t *cmd)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint)
5027c478bd9Sstevel@tonic-gate if (g_verbose)
5037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "processing commands\n");
5047c478bd9Sstevel@tonic-gate #endif
5057c478bd9Sstevel@tonic-gate (void) tnfctl_probe_apply(hndl, perprobe2, cmd);
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate * get_commands() - process commands from stdin
5107c478bd9Sstevel@tonic-gate */
5117c478bd9Sstevel@tonic-gate static void
get_commands(void)5127c478bd9Sstevel@tonic-gate get_commands(void)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate /* Read commands from STDIN */
5157c478bd9Sstevel@tonic-gate if (g_kernelmode) {
5167c478bd9Sstevel@tonic-gate (void) printf(gettext("Type \"help\" for help ...\n"));
5177c478bd9Sstevel@tonic-gate } else {
5187c478bd9Sstevel@tonic-gate if (g_testflag)
5197c478bd9Sstevel@tonic-gate (void) printf("prex(%ld), target(%ld): ",
5207c478bd9Sstevel@tonic-gate getpid(), g_targetpid);
5217c478bd9Sstevel@tonic-gate (void) printf(gettext("Target process stopped\n"));
5227c478bd9Sstevel@tonic-gate (void) printf(gettext(
5237c478bd9Sstevel@tonic-gate "Type \"continue\" to resume the target, "
5247c478bd9Sstevel@tonic-gate "\"help\" for help ...\n"));
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate while (yyparse());
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate * quit() - called to quit the controlling process. The boolean argument
5337c478bd9Sstevel@tonic-gate * specifies whether to terminate the target as well.
5347c478bd9Sstevel@tonic-gate */
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate void
quit(boolean_t killtarget,boolean_t runtarget)5377c478bd9Sstevel@tonic-gate quit(boolean_t killtarget, boolean_t runtarget)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate tnfctl_errcode_t err;
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate if (killtarget && runtarget)
5427c478bd9Sstevel@tonic-gate err = tnfctl_close(g_hndl, TNFCTL_TARG_DEFAULT);
5437c478bd9Sstevel@tonic-gate else if (killtarget && !runtarget)
5447c478bd9Sstevel@tonic-gate err = tnfctl_close(g_hndl, TNFCTL_TARG_KILL);
5457c478bd9Sstevel@tonic-gate else if (!killtarget && runtarget)
5467c478bd9Sstevel@tonic-gate err = tnfctl_close(g_hndl, TNFCTL_TARG_RESUME);
5477c478bd9Sstevel@tonic-gate else if (!killtarget && !runtarget)
5487c478bd9Sstevel@tonic-gate err = tnfctl_close(g_hndl, TNFCTL_TARG_SUSPEND);
5497c478bd9Sstevel@tonic-gate if (err) {
5507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
5517c478bd9Sstevel@tonic-gate "%s: trouble quitting : %s\n"),
5527c478bd9Sstevel@tonic-gate g_argv[0], tnfctl_strerror(err));
5537c478bd9Sstevel@tonic-gate exit(1);
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate exit(0);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate * scanargs() - processes the command line arguments
5617c478bd9Sstevel@tonic-gate */
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate #define strneq(s1, s2, n) (strncmp(s1, s2, n) == 0)
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate static void
scanargs(int argc,char ** argv)5667c478bd9Sstevel@tonic-gate scanargs(int argc,
5677c478bd9Sstevel@tonic-gate char **argv)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate int c;
5707c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint)
5717c478bd9Sstevel@tonic-gate char *optstr = "l:o:p:s:tkv:"; /* debugging options */
5727c478bd9Sstevel@tonic-gate #else
5737c478bd9Sstevel@tonic-gate char *optstr = "l:o:p:s:tk"; /* production options */
5747c478bd9Sstevel@tonic-gate #endif
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate /* set up some defaults */
5777c478bd9Sstevel@tonic-gate g_targetpid = 0;
5787c478bd9Sstevel@tonic-gate g_cmdname = NULL;
5797c478bd9Sstevel@tonic-gate g_cmdargs = NULL;
5807c478bd9Sstevel@tonic-gate g_preload = NULL;
5817c478bd9Sstevel@tonic-gate g_outname = NULL;
5827c478bd9Sstevel@tonic-gate g_outsize = -1;
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, optstr)) != EOF) {
5857c478bd9Sstevel@tonic-gate switch (c) {
5867c478bd9Sstevel@tonic-gate case 'l': /* preload objects */
5877c478bd9Sstevel@tonic-gate g_preload = optarg;
5887c478bd9Sstevel@tonic-gate break;
5897c478bd9Sstevel@tonic-gate case 'o': /* tracefile name */
5907c478bd9Sstevel@tonic-gate g_outname = optarg;
5917c478bd9Sstevel@tonic-gate break;
5927c478bd9Sstevel@tonic-gate case 'p': /* target pid (attach case) */
5937c478bd9Sstevel@tonic-gate g_targetpid = atoi(optarg);
5947c478bd9Sstevel@tonic-gate break;
5957c478bd9Sstevel@tonic-gate case 's': /* tracefile size */
5967c478bd9Sstevel@tonic-gate g_outsize = atoi(optarg) * 1024;
5977c478bd9Sstevel@tonic-gate break;
5987c478bd9Sstevel@tonic-gate case 't': /* test flag */
5997c478bd9Sstevel@tonic-gate g_testflag = B_TRUE;
6007c478bd9Sstevel@tonic-gate (void) setvbuf(stdout, NULL, _IOLBF, 0);
6017c478bd9Sstevel@tonic-gate break;
6027c478bd9Sstevel@tonic-gate case 'k': /* kernel mode */
6037c478bd9Sstevel@tonic-gate g_kernelmode = B_TRUE;
6047c478bd9Sstevel@tonic-gate break;
6057c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint)
6067c478bd9Sstevel@tonic-gate case 'v': /* verbose flag */
6077c478bd9Sstevel@tonic-gate g_verbose = atoi(optarg);
6087c478bd9Sstevel@tonic-gate break;
6097c478bd9Sstevel@tonic-gate #endif
6107c478bd9Sstevel@tonic-gate case '?': /* error case */
6117c478bd9Sstevel@tonic-gate usage(argv, gettext("unrecognized argument"));
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate if (optind < argc) {
6167c478bd9Sstevel@tonic-gate g_cmdname = strdup(argv[optind]);
6177c478bd9Sstevel@tonic-gate g_cmdargs = &argv[optind];
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate /* sanity clause */
6207c478bd9Sstevel@tonic-gate if (!g_kernelmode && (g_cmdname == NULL && g_targetpid == 0))
6217c478bd9Sstevel@tonic-gate usage(argv, gettext("need to specify cmd or pid"));
6227c478bd9Sstevel@tonic-gate if (g_cmdname != NULL && g_targetpid != 0)
6237c478bd9Sstevel@tonic-gate usage(argv, gettext("can't specify both cmd and pid"));
6247c478bd9Sstevel@tonic-gate if (g_targetpid && g_preload)
6257c478bd9Sstevel@tonic-gate usage(argv, gettext("can't use preload option with attach"));
6267c478bd9Sstevel@tonic-gate if (g_kernelmode) {
6277c478bd9Sstevel@tonic-gate if (g_outname)
6287c478bd9Sstevel@tonic-gate usage(argv, "can't specify a filename in kernel mode");
6297c478bd9Sstevel@tonic-gate if (g_cmdname)
6307c478bd9Sstevel@tonic-gate usage(argv, "can't specify a command in kernel mode");
6317c478bd9Sstevel@tonic-gate if (g_targetpid)
6327c478bd9Sstevel@tonic-gate usage(argv, "can't specify pid in kernel mode");
6337c478bd9Sstevel@tonic-gate if (g_preload)
6347c478bd9Sstevel@tonic-gate usage(argv, "can't use preload option in kernel mode");
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate /* default output size */
6377c478bd9Sstevel@tonic-gate if (g_outsize == -1)
6387c478bd9Sstevel@tonic-gate g_outsize = g_kernelmode ? KERNEL_OUTSIZE : USER_OUTSIZE;
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate #ifdef OLD
6417c478bd9Sstevel@tonic-gate int i;
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate for (i = 1; i < argc; i++) {
6447c478bd9Sstevel@tonic-gate if (strneq(argv[i], "-v", 2)) {
6457c478bd9Sstevel@tonic-gate int vlevel;
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate vlevel = (strlen(argv[i]) > 2)? atoi(&argv[i][2]) : 1;
6487c478bd9Sstevel@tonic-gate g_verbose = B_TRUE;
6497c478bd9Sstevel@tonic-gate prb_verbose_set(vlevel);
6507c478bd9Sstevel@tonic-gate } else if (strneq(argv[i], "-pid", 2)) {
6517c478bd9Sstevel@tonic-gate if (++i >= argc)
6527c478bd9Sstevel@tonic-gate usage(argv, gettext("missing pid argument"));
6537c478bd9Sstevel@tonic-gate g_targetpid = atoi(argv[i]);
6547c478bd9Sstevel@tonic-gate } else if (strneq(argv[i], "-t", 2)) {
6557c478bd9Sstevel@tonic-gate g_testflag = B_TRUE;
6567c478bd9Sstevel@tonic-gate (void) setvbuf(stdout, NULL, _IOLBF, 0);
6577c478bd9Sstevel@tonic-gate } else if (argv[i][0] != '-') {
6587c478bd9Sstevel@tonic-gate g_cmdname = strdup(argv[i]);
6597c478bd9Sstevel@tonic-gate if (!g_cmdname) {
6607c478bd9Sstevel@tonic-gate err_fatal(gettext(
6617c478bd9Sstevel@tonic-gate "%s: out of memory"), argv[0]);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate if (g_verbose >= 2) {
6647c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
6657c478bd9Sstevel@tonic-gate "cmdname=%s\n", g_cmdname);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate /*
6687c478bd9Sstevel@tonic-gate * rest of arguments are the args to the executable -
6697c478bd9Sstevel@tonic-gate * by convention argv[0] should be name of
6707c478bd9Sstevel@tonic-gate * executable, so we don't increment i
6717c478bd9Sstevel@tonic-gate */
6727c478bd9Sstevel@tonic-gate g_cmdargs = &argv[i];
6737c478bd9Sstevel@tonic-gate break;
6747c478bd9Sstevel@tonic-gate } else {
6757c478bd9Sstevel@tonic-gate usage(argv, gettext("unrecognized argument"));
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate #endif
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate } /* end scanargs */
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate /*
6847c478bd9Sstevel@tonic-gate * sig_handler() - cleans up if a signal is received
6857c478bd9Sstevel@tonic-gate */
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6887c478bd9Sstevel@tonic-gate static void
sig_handler(int signo)6897c478bd9Sstevel@tonic-gate sig_handler(int signo)
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate g_getcmds = B_TRUE;
6927c478bd9Sstevel@tonic-gate } /* end sig_handler */
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate /*
6967c478bd9Sstevel@tonic-gate * set_signal() - sets up function to call for clean up
6977c478bd9Sstevel@tonic-gate */
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate static int
set_signal(void)7007c478bd9Sstevel@tonic-gate set_signal(void)
7017c478bd9Sstevel@tonic-gate {
7027c478bd9Sstevel@tonic-gate struct sigaction newact;
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate newact.sa_handler = sig_handler;
7057c478bd9Sstevel@tonic-gate (void) sigemptyset(&newact.sa_mask);
7067c478bd9Sstevel@tonic-gate newact.sa_flags = 0;
7077c478bd9Sstevel@tonic-gate if (sigaction(SIGINT, &newact, NULL) < 0) {
7087c478bd9Sstevel@tonic-gate return (errno);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate return (0);
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate * set_tracefile() - initializes tracefile, sets the tracefile name and size
7167c478bd9Sstevel@tonic-gate */
7177c478bd9Sstevel@tonic-gate static tnfctl_errcode_t
set_tracefile(tnfctl_handle_t * hndl)7187c478bd9Sstevel@tonic-gate set_tracefile(tnfctl_handle_t *hndl)
7197c478bd9Sstevel@tonic-gate {
7207c478bd9Sstevel@tonic-gate tnfctl_errcode_t err;
7217c478bd9Sstevel@tonic-gate tnfctl_trace_attrs_t attrs;
7227c478bd9Sstevel@tonic-gate size_t minoutsize;
7237c478bd9Sstevel@tonic-gate char path[MAXPATHLEN];
7247c478bd9Sstevel@tonic-gate char *outfile_name;
7257c478bd9Sstevel@tonic-gate char *tmpdir;
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /* Init tracefile name used by list cmd */
7287c478bd9Sstevel@tonic-gate tracefile = NULL;
7297c478bd9Sstevel@tonic-gate err = tnfctl_trace_attrs_get(hndl, &attrs);
7307c478bd9Sstevel@tonic-gate if (err)
7317c478bd9Sstevel@tonic-gate return (err);
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate if (attrs.trace_buf_state == TNFCTL_BUF_BROKEN)
7347c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_BUFBROKEN);
7357c478bd9Sstevel@tonic-gate if (attrs.trace_buf_state == TNFCTL_BUF_OK) {
7367c478bd9Sstevel@tonic-gate /* trace file set already - can't change it */
7377c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_NONE);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate minoutsize = attrs.trace_min_size;
7417c478bd9Sstevel@tonic-gate if (g_outsize < minoutsize) {
7427c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7437c478bd9Sstevel@tonic-gate gettext("specified tracefile size smaller then "
7447c478bd9Sstevel@tonic-gate "minimum; setting to %d kbytes\n"),
7457c478bd9Sstevel@tonic-gate minoutsize / 1024);
7467c478bd9Sstevel@tonic-gate g_outsize = minoutsize;
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate /* where is $TMPDIR? */
7507c478bd9Sstevel@tonic-gate tmpdir = getenv("TMPDIR");
7517c478bd9Sstevel@tonic-gate if (!tmpdir || *tmpdir == '\0') {
7527c478bd9Sstevel@tonic-gate tmpdir = "/tmp";
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate /* do we have an absolute, relative or no pathname specified? */
7567c478bd9Sstevel@tonic-gate if (g_outname == NULL) {
7577c478bd9Sstevel@tonic-gate /* default, no tracefile specified */
7587c478bd9Sstevel@tonic-gate if ((strlen(tmpdir) + 1 + 20) > (size_t)MAXPATHLEN) {
7597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
7607c478bd9Sstevel@tonic-gate "%s: $TMPDIR too long\n"), g_argv[0]);
7617c478bd9Sstevel@tonic-gate exit(1);
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate (void) sprintf(path, "%s/trace-%ld", tmpdir, g_targetpid);
7647c478bd9Sstevel@tonic-gate outfile_name = path;
7657c478bd9Sstevel@tonic-gate } else {
7667c478bd9Sstevel@tonic-gate /* filename specified */
7677c478bd9Sstevel@tonic-gate outfile_name = g_outname;
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate tracefile = strdup(outfile_name);
7707c478bd9Sstevel@tonic-gate if (tracefile == NULL) {
7717c478bd9Sstevel@tonic-gate if ((errno == ENOMEM) || (errno == EAGAIN)) {
7727c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_ALLOCFAIL);
7737c478bd9Sstevel@tonic-gate } else {
7747c478bd9Sstevel@tonic-gate return (TNFCTL_ERR_INTERNAL);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate
7787c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint)
7797c478bd9Sstevel@tonic-gate if (g_verbose)
7807c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7817c478bd9Sstevel@tonic-gate "setting tracefile name=\"%s\", size=%d\n",
7827c478bd9Sstevel@tonic-gate path, g_outsize);
7837c478bd9Sstevel@tonic-gate #endif
7847c478bd9Sstevel@tonic-gate err = tnfctl_buffer_alloc(hndl, outfile_name, g_outsize);
7857c478bd9Sstevel@tonic-gate return (err);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate /*
7887c478bd9Sstevel@tonic-gate * get_data_model() - get the process data model from psinfo
7897c478bd9Sstevel@tonic-gate * structure.
7907c478bd9Sstevel@tonic-gate */
7917c478bd9Sstevel@tonic-gate #define PROCFORMAT "/proc/%d"
7927c478bd9Sstevel@tonic-gate static int
get_data_model(pid_t pid)7937c478bd9Sstevel@tonic-gate get_data_model(pid_t pid)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate char path[MAXPATHLEN];
7967c478bd9Sstevel@tonic-gate int fd, dmodel = -1;
7977c478bd9Sstevel@tonic-gate prpsinfo_t psinfo;
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate (void) sprintf(path, PROCFORMAT, (int)pid);
8007c478bd9Sstevel@tonic-gate fd = open(path, O_RDONLY);
8017c478bd9Sstevel@tonic-gate if (fd == -1)
8027c478bd9Sstevel@tonic-gate return (dmodel);
8037c478bd9Sstevel@tonic-gate if ((dmodel = ioctl(fd, PIOCPSINFO, &psinfo)) == -1)
8047c478bd9Sstevel@tonic-gate return (dmodel);
8057c478bd9Sstevel@tonic-gate return ((int)psinfo.pr_dmodel);
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate /*
8087c478bd9Sstevel@tonic-gate * get_executable - return file descriptor for PATH-resolved
8097c478bd9Sstevel@tonic-gate * target file.
8107c478bd9Sstevel@tonic-gate *
8117c478bd9Sstevel@tonic-gate */
8127c478bd9Sstevel@tonic-gate static int
get_executable(char * name)8137c478bd9Sstevel@tonic-gate get_executable(char *name) {
8147c478bd9Sstevel@tonic-gate int fd = -1;
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate if (name != NULL) {
8177c478bd9Sstevel@tonic-gate char path[PATH_MAX + 1];
8187c478bd9Sstevel@tonic-gate char line[MAX_INPUT + 1];
8197c478bd9Sstevel@tonic-gate char *p = line;
8207c478bd9Sstevel@tonic-gate char *fname = name;
8217c478bd9Sstevel@tonic-gate int N = sizeof (line);
8227c478bd9Sstevel@tonic-gate struct stat file_att;
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate while (*fname == ' ') fname++;
8257c478bd9Sstevel@tonic-gate if (fname[0] == '-' || strchr(fname, '/')) {
8267c478bd9Sstevel@tonic-gate fd = open(fname, O_RDONLY);
8277c478bd9Sstevel@tonic-gate } else {
8287c478bd9Sstevel@tonic-gate int len = strlen(fname);
8297c478bd9Sstevel@tonic-gate char *dirlist = getenv("PATH");
8307c478bd9Sstevel@tonic-gate char *dir = NULL;
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate if (dirlist != NULL) {
8337c478bd9Sstevel@tonic-gate dirlist = strdup(dirlist);
8347c478bd9Sstevel@tonic-gate dir = strtok(dirlist, ":");
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate while (fd < 0 && dir != NULL) {
8377c478bd9Sstevel@tonic-gate if ((strlen(dir) + len + 1) < sizeof (path)) {
8387c478bd9Sstevel@tonic-gate strcat(strcat(strcpy(path, dir), "/"), fname);
8397c478bd9Sstevel@tonic-gate fd = open(path, O_RDONLY);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate dir = strtok(NULL, ":");
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate if (dirlist != NULL) free(dirlist);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate if (fstat(fd, &file_att) || !S_ISREG(file_att.st_mode)) {
8467c478bd9Sstevel@tonic-gate if (fd >= 0)
8477c478bd9Sstevel@tonic-gate close(fd);
8487c478bd9Sstevel@tonic-gate return (-1);
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate if (read(fd, p, 2) && p[0] == '#' && p[1] == '!') {
8517c478bd9Sstevel@tonic-gate while (N-- > 1 && read(fd, p, 1) && *p != '\n')
8527c478bd9Sstevel@tonic-gate p++;
8537c478bd9Sstevel@tonic-gate *p = '\0';
8547c478bd9Sstevel@tonic-gate close(fd);
8557c478bd9Sstevel@tonic-gate return (get_executable(line));
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate if (fd >= 0) lseek(fd, 0, SEEK_SET);
8587c478bd9Sstevel@tonic-gate } /* %$#@! cstyle complaint */
8597c478bd9Sstevel@tonic-gate return (fd);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate * get_elf_class - get the target executable elf class
8647c478bd9Sstevel@tonic-gate * i.e. ELFCLASS64 or ELFCLASS32.
8657c478bd9Sstevel@tonic-gate */
8667c478bd9Sstevel@tonic-gate static int
get_elf_class(char * filename)8677c478bd9Sstevel@tonic-gate get_elf_class(char *filename)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate int elfclass = -1;
8707c478bd9Sstevel@tonic-gate int elffd = get_executable(filename);
8717c478bd9Sstevel@tonic-gate Elf *elf;
8727c478bd9Sstevel@tonic-gate size_t size;
8737c478bd9Sstevel@tonic-gate char *ident;
8747c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr;
8757c478bd9Sstevel@tonic-gate
8767c478bd9Sstevel@tonic-gate if (elffd < 0)
8777c478bd9Sstevel@tonic-gate return (elfclass);
8787c478bd9Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) {
8797c478bd9Sstevel@tonic-gate (void) close(elffd);
8807c478bd9Sstevel@tonic-gate return (elfclass);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate elf = elf_begin(elffd, ELF_C_READ, (Elf *) 0);
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate * verify information in file header
8857c478bd9Sstevel@tonic-gate */
8867c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == (GElf_Ehdr *) 0) {
8877c478bd9Sstevel@tonic-gate close(elffd);
8887c478bd9Sstevel@tonic-gate return (elfclass);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate ident = elf_getident(elf, &size);
8917c478bd9Sstevel@tonic-gate if (ident[EI_CLASS] == ELFCLASS32)
8927c478bd9Sstevel@tonic-gate elfclass = ELFCLASS32;
8937c478bd9Sstevel@tonic-gate if (ident[EI_CLASS] == ELFCLASS64)
8947c478bd9Sstevel@tonic-gate elfclass = ELFCLASS64;
8957c478bd9Sstevel@tonic-gate close(elffd);
8967c478bd9Sstevel@tonic-gate return (elfclass);
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate * check_exec_model() - check the consistency between prex data model
9007c478bd9Sstevel@tonic-gate * and target elf class and act accordingly
9017c478bd9Sstevel@tonic-gate */
9027c478bd9Sstevel@tonic-gate static void
check_exec_model(char ** argv,char ** envp)9037c478bd9Sstevel@tonic-gate check_exec_model(char **argv, char **envp)
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate int elfclass;
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate elfclass = get_elf_class(g_cmdname);
9087c478bd9Sstevel@tonic-gate if (((elfclass == ELFCLASS32) && (prex_dmodel == PR_MODEL_ILP32)) ||
9097c478bd9Sstevel@tonic-gate ((elfclass == ELFCLASS64) && (prex_dmodel == PR_MODEL_LP64)))
9107c478bd9Sstevel@tonic-gate return;
9117c478bd9Sstevel@tonic-gate if ((prex_dmodel == PR_MODEL_ILP32) &&
9127c478bd9Sstevel@tonic-gate (elfclass == ELFCLASS64)) {
9137c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9147c478bd9Sstevel@tonic-gate "Error: 32 bit prex can not exec 64 bit target\n"));
9157c478bd9Sstevel@tonic-gate exit(1);
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate if ((prex_dmodel == PR_MODEL_LP64) &&
9187c478bd9Sstevel@tonic-gate (elfclass == ELFCLASS32))
9197c478bd9Sstevel@tonic-gate prex_isaexec(argv, envp);
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate /*
9237c478bd9Sstevel@tonic-gate * check_pid_model() - check the consistency between prex data model
9247c478bd9Sstevel@tonic-gate * and target data model and act accordingly
9257c478bd9Sstevel@tonic-gate */
9267c478bd9Sstevel@tonic-gate static void
check_pid_model(char ** argv,char ** envp)9277c478bd9Sstevel@tonic-gate check_pid_model(char **argv, char **envp)
9287c478bd9Sstevel@tonic-gate {
9297c478bd9Sstevel@tonic-gate int dmodel;
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate dmodel = get_data_model(g_targetpid);
9327c478bd9Sstevel@tonic-gate if (prex_dmodel == dmodel)
9337c478bd9Sstevel@tonic-gate return;
9347c478bd9Sstevel@tonic-gate if ((prex_dmodel == PR_MODEL_ILP32) &&
9357c478bd9Sstevel@tonic-gate (dmodel == PR_MODEL_LP64)) {
9367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
9377c478bd9Sstevel@tonic-gate "Error: 32 bit prex can not exec 64 bit target\n"));
9387c478bd9Sstevel@tonic-gate exit(1);
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate if ((prex_dmodel == PR_MODEL_LP64) &&
9417c478bd9Sstevel@tonic-gate (dmodel == PR_MODEL_ILP32))
9427c478bd9Sstevel@tonic-gate prex_isaexec(argv, envp);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate * prex_isaexec() - there is only one case this function get called
9467c478bd9Sstevel@tonic-gate * 64 bit prex, 32 bit target, need to exec 32 bit
9477c478bd9Sstevel@tonic-gate * prex here.
9487c478bd9Sstevel@tonic-gate */
9497c478bd9Sstevel@tonic-gate static void
prex_isaexec(char ** argv,char ** envp)9507c478bd9Sstevel@tonic-gate prex_isaexec(char **argv, char **envp)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate char path[PATH_MAX + sizeof (PREX32DIR)];
9537c478bd9Sstevel@tonic-gate strcat(strcat(strcpy(path, dirname(dirname(argv[0]))), PREX32DIR),
9547c478bd9Sstevel@tonic-gate basename(argv[0]));
9557c478bd9Sstevel@tonic-gate if (get_elf_class(path) != ELFCLASS32)
9567c478bd9Sstevel@tonic-gate strcpy(path, PREX32EXEC);
9577c478bd9Sstevel@tonic-gate argv[0] = path;
9587c478bd9Sstevel@tonic-gate (void) execve(path, argv, envp);
9597c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
9607c478bd9Sstevel@tonic-gate gettext("%s: execve(\"%s\") failed\n"),
9617c478bd9Sstevel@tonic-gate argv[0], path);
962*c5024742Srab exit(1);
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate void
cmd_listtracefile()9657c478bd9Sstevel@tonic-gate cmd_listtracefile()
9667c478bd9Sstevel@tonic-gate {
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate if (g_kernelmode) {
9697c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
9707c478bd9Sstevel@tonic-gate gettext("There is no trace file in kernel mode!\n"));
9717c478bd9Sstevel@tonic-gate } else {
9727c478bd9Sstevel@tonic-gate (void) printf(gettext("Current trace file is: %s\n"), tracefile);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate }
975