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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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