4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/procfs.h>
48 #include <sys/systeminfo.h>
50 #include <tnf/tnfctl.h>
61 * Defines - Project private interfaces
64 #define DEBUG_ENTRY "tnf_probe_debug"
66 #define EMPTY_ENTRY "tnf_probe_empty"
69 #define USER_OUTSIZE (4*1024*1024)
70 #define KERNEL_OUTSIZE (384*1024)
73 #define PREX32DIR "/sparcv7/"
74 #elif defined(__i386) || defined(__amd64)
75 #define PREX32DIR "/i86/"
77 #define PREX32EXEC "/usr/bin" PREX32DIR "prex"
83 char **g_argv
; /* copy of argv pointer */
84 tnfctl_handle_t
*g_hndl
; /* handle on target or kernel */
86 static int g_verbose
; /* debugging to stderr */
87 static char *g_cmdname
; /* target command name */
88 static char **g_cmdargs
; /* target command args */
89 static pid_t g_targetpid
; /* target process id */
90 static volatile boolean_t g_getcmds
; /* accept input flag */
91 static boolean_t g_testflag
; /* asserted in test mode */
92 static char *g_preload
; /* objects to preload */
93 static char *g_outname
; /* tracefile name */
94 static char *tracefile
; /* tracefile name used by list cmd */
95 int g_outsize
; /* tracefile size */
96 boolean_t g_kernelmode
; /* -k flag: kernel mode */
97 static int prex_dmodel
; /* prex data model */
102 static void usage(char **argv
, const char *msg
);
103 static void scanargs(int argc
, char **argv
);
104 static int set_signal(void);
105 static int get_data_model(pid_t pid
);
106 static int get_elf_class(char *filename
);
107 static int get_executable(char *);
108 static void prex_isaexec(char **argv
, char **envp
);
109 static void check_pid_model(char **argv
, char **envp
);
110 static void check_exec_model(char **argv
, char **envp
);
112 /* #### - FIXME - need to put this in a private header file */
113 extern void err_fatal(char *s
, ...);
115 extern int yyparse(void);
117 static tnfctl_errcode_t
check_trace_error(tnfctl_handle_t
*hndl
);
118 static void set_default_cmd(void);
119 static void get_commands(void);
120 static tnfctl_errcode_t
set_tracefile(tnfctl_handle_t
*hndl
);
121 static tnfctl_errcode_t
set_probe_discovery_callback(tnfctl_handle_t
*hndl
);
122 static void * perprobe(tnfctl_handle_t
*hndl
, tnfctl_probe_t
*probe_p
);
123 static tnfctl_errcode_t
perprobe2(tnfctl_handle_t
*hndl
,
124 tnfctl_probe_t
*probe_p
, void *ignored
);
125 static tnfctl_errcode_t
percmd(expr_t
*expr_p
, cmd_kind_t kind
, fcn_t
*fcn_p
,
126 boolean_t isnew
, void *calldata_p
);
127 void quit(boolean_t killtarget
, boolean_t runtarget
);
128 void cmd_listtracefile();
132 * usage() - gives a description of the arguments, and exits
136 usage(char *argv
[], const char *msg
)
139 (void) fprintf(stderr
,
140 gettext("%s: %s\n"), argv
[0], msg
);
142 (void) fprintf(stderr
, gettext(
143 "usage: %s [options] <cmd> [cmd-args...]\n"), argv
[0]);
144 (void) fprintf(stderr
, gettext(
145 "usage: %s [options] -p <pid>\n"), argv
[0]);
146 (void) fprintf(stderr
, gettext(
147 "usage: %s -s <kbytes-size> -k\n"), argv
[0]);
148 (void) fprintf(stderr
, gettext(
150 (void) fprintf(stderr
, gettext(
151 " -o <outfilename> set trace output file name\n"));
152 (void) fprintf(stderr
, gettext(
153 " -s <kbytes-size> set trace file size\n"));
154 (void) fprintf(stderr
, gettext(
155 " -l <sharedobjs> shared objects to "
156 "be preloaded (cmd only)\n"));
167 main(int argc
, char **argv
, char **envp
)
169 tnfctl_errcode_t err
= TNFCTL_ERR_NONE
;
171 tnfctl_trace_attrs_t trace_attrs
;
172 tnfctl_event_t event
= TNFCTL_EVENT_EINTR
;
175 /* internationalization stuff */
176 (void) setlocale(LC_ALL
, "");
177 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
178 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
180 (void) textdomain(TEXT_DOMAIN
);
186 fprintf(stderr
, "### prex_pid = %d ###\n", prex_pid
);
188 prex_dmodel
= get_data_model(prex_pid
);
190 fprintf(stderr
, "### prex_dmodel = %d ###\n", prex_dmodel
);
192 scanargs(argc
, argv
);
195 /* prexing the kernel */
196 err
= tnfctl_kernel_open(&g_hndl
);
199 "%s: trouble attaching to the kernel: %s\n"),
200 argv
[0], tnfctl_strerror(err
));
203 /* prexing a user process */
204 if (g_targetpid
!= 0) {
205 /* check data model */
206 check_pid_model(argv
, envp
);
208 err
= tnfctl_pid_open(g_targetpid
, &g_hndl
);
209 if (err
== TNFCTL_ERR_NOLIBTNFPROBE
) {
211 "%s: missing symbols, is "
212 "libtnfprobe.so loaded in target?\n"),
213 argv
[0], tnfctl_strerror(err
));
216 "%s: trouble attaching to target "
218 argv
[0], tnfctl_strerror(err
));
221 /* check elf class model */
222 check_exec_model(argv
, envp
);
224 err
= tnfctl_exec_open(g_cmdname
, g_cmdargs
, NULL
,
225 g_preload
, NULL
, &g_hndl
);
226 if (err
== TNFCTL_ERR_NONE
)
227 err
= tnfctl_trace_attrs_get(g_hndl
,
231 "%s: trouble creating target process: "
233 argv
[0], tnfctl_strerror(err
));
235 g_targetpid
= trace_attrs
.targ_pid
;
238 sys_err
= set_signal();
241 "%s: trouble setting up signal handler: %s\n"),
242 argv
[0], strerror(err
));
245 /* initialize the source stack for the parser */
249 /* set the tracefile name and size */
250 err
= set_tracefile(g_hndl
);
252 (void) fprintf(stderr
, gettext(
253 "%s: trouble initializing tracefile: %s\n"),
254 argv
[0], tnfctl_strerror(err
));
257 err
= check_trace_error(g_hndl
);
259 (void) fprintf(stderr
, gettext(
260 "%s: cannot read tracing status : %s\n"),
261 argv
[0], tnfctl_strerror(err
));
266 /* accept commands from stdin the first time through */
269 /* set up default aliases */
272 /* set up creator/destructor function to call for new probes */
273 err
= set_probe_discovery_callback(g_hndl
);
275 (void) fprintf(stderr
, gettext(
276 "%s: error in probe discovery : %s\n"),
277 argv
[0], tnfctl_strerror(err
));
282 prbk_warn_pfilter_empty();
285 while (err
== TNFCTL_ERR_NONE
) {
287 if (g_kernelmode
|| g_getcmds
) {
292 if (!g_kernelmode
&& (g_getcmds
== B_FALSE
)) {
293 err
= tnfctl_continue(g_hndl
, &event
, NULL
);
295 (void) fprintf(stderr
, gettext(
296 "%s: cannot continue target : %s\n"),
297 argv
[0], tnfctl_strerror(err
));
301 err
= check_trace_error(g_hndl
);
303 (void) fprintf(stderr
, gettext(
304 "%s: cannot read tracing status : %s\n"),
305 argv
[0], tnfctl_strerror(err
));
309 if (event
== TNFCTL_EVENT_EXEC
) {
310 (void) printf(gettext(
311 "Target process exec'd\n"));
312 quit(B_FALSE
, B_TRUE
); /* quit resume */
313 } else if (event
== TNFCTL_EVENT_EXIT
) {
315 (void) fprintf(stderr
, gettext(
316 "%s: target process exited\n"),
319 } else if (event
== TNFCTL_EVENT_TARGGONE
) {
320 /* target terminated */
321 (void) fprintf(stderr
,
322 gettext("%s: target process disappeared (without calling exit)\n"),
330 err
= tnfctl_close(g_hndl
, TNFCTL_TARG_DEFAULT
);
332 (void) fprintf(stderr
, gettext(
333 "%s: error on closing : %s\n"),
334 argv
[0], tnfctl_strerror(err
));
343 * check_trace_error() - checks whether there was an error in tracing
345 static tnfctl_errcode_t
346 check_trace_error(tnfctl_handle_t
*hndl
)
348 tnfctl_trace_attrs_t trace_attrs
;
349 tnfctl_errcode_t err
;
351 err
= tnfctl_trace_attrs_get(hndl
, &trace_attrs
);
355 if (trace_attrs
.trace_buf_state
== TNFCTL_BUF_BROKEN
) {
356 (void) printf(gettext("Tracing shut down in target program "
357 "due to an internal error - Please restart prex "
361 return (TNFCTL_ERR_NONE
);
365 * set_default_cmd() - set the default debug entry and $all
368 set_default_cmd(void)
371 fcn(strdup("debug"), DEBUG_ENTRY
);
373 fcn(strdup("empty"), EMPTY_ENTRY
);
375 (void) set(strdup("all"), expr(spec(strdup("keys"), SPEC_EXACT
),
376 spec(strdup(".*"), SPEC_REGEXP
)));
381 * process() - enable and disable selected probes
385 tnfctl_probe_t
*probe_p
;
386 tnfctl_handle_t
*hndl
;
389 static tnfctl_errcode_t
390 percmd(expr_t
*expr_p
, cmd_kind_t kind
, fcn_t
*fcn_p
, boolean_t isnew
,
393 process_args_t
*args_p
= (process_args_t
*)calldata_p
;
394 tnfctl_handle_t
*hndl
= args_p
->hndl
;
395 tnfctl_probe_t
*probe_p
= args_p
->probe_p
;
396 tnfctl_errcode_t err
= TNFCTL_ERR_NONE
;
399 attrs
= list_getattrs(probe_p
);
401 if (expr_match(expr_p
, attrs
)) {
402 #if defined(DEBUG) || defined(lint)
409 (void) fprintf(stderr
, ": %s command: %s ",
410 (isnew
) ? "new" : "old", cmdstr
[kind
]);
411 expr_print(stderr
, expr_p
);
417 err
= tnfctl_probe_enable(hndl
, probe_p
, NULL
);
420 err
= tnfctl_probe_disable(hndl
, probe_p
, NULL
);
423 err
= tnfctl_probe_trace(hndl
, probe_p
, NULL
);
426 err
= tnfctl_probe_untrace(hndl
, probe_p
, NULL
);
429 err
= tnfctl_probe_connect(hndl
, probe_p
, NULL
,
430 fcn_p
->entry_name_p
);
433 err
= tnfctl_probe_disconnect_all(hndl
, probe_p
, NULL
);
437 #if defined(DEBUG) || defined(lint)
439 (void) fprintf(stderr
, "\n");
452 perprobe(tnfctl_handle_t
*hndl
, tnfctl_probe_t
*probe_p
)
455 tnfctl_errcode_t err
;
457 args
.probe_p
= probe_p
;
459 err
= cmd_traverse(percmd
, &args
);
461 (void) fprintf(stderr
, gettext(
462 "%s: error on new (dlopened) probe : %s\n"),
463 g_argv
[0], tnfctl_strerror(err
));
468 static tnfctl_errcode_t
469 set_probe_discovery_callback(tnfctl_handle_t
*hndl
)
471 tnfctl_errcode_t err
;
473 err
= tnfctl_register_funcs(hndl
, perprobe
, NULL
);
477 return (TNFCTL_ERR_NONE
);
480 static tnfctl_errcode_t
481 perprobe2(tnfctl_handle_t
*hndl
, tnfctl_probe_t
*probe_p
, void *cd
)
485 tnfctl_errcode_t err
;
487 args
.probe_p
= probe_p
;
489 err
= cmd_callback(cmd
, percmd
, &args
);
491 (void) fprintf(stderr
, gettext(
492 "%s: error on probe operation: %s\n"),
493 g_argv
[0], tnfctl_strerror(err
));
499 process_cmd(tnfctl_handle_t
*hndl
, cmd_t
*cmd
)
501 #if defined(DEBUG) || defined(lint)
503 (void) fprintf(stderr
, "processing commands\n");
505 (void) tnfctl_probe_apply(hndl
, perprobe2
, cmd
);
509 * get_commands() - process commands from stdin
514 /* Read commands from STDIN */
516 (void) printf(gettext("Type \"help\" for help ...\n"));
519 (void) printf("prex(%ld), target(%ld): ",
520 getpid(), g_targetpid
);
521 (void) printf(gettext("Target process stopped\n"));
522 (void) printf(gettext(
523 "Type \"continue\" to resume the target, "
524 "\"help\" for help ...\n"));
532 * quit() - called to quit the controlling process. The boolean argument
533 * specifies whether to terminate the target as well.
537 quit(boolean_t killtarget
, boolean_t runtarget
)
539 tnfctl_errcode_t err
;
541 if (killtarget
&& runtarget
)
542 err
= tnfctl_close(g_hndl
, TNFCTL_TARG_DEFAULT
);
543 else if (killtarget
&& !runtarget
)
544 err
= tnfctl_close(g_hndl
, TNFCTL_TARG_KILL
);
545 else if (!killtarget
&& runtarget
)
546 err
= tnfctl_close(g_hndl
, TNFCTL_TARG_RESUME
);
547 else if (!killtarget
&& !runtarget
)
548 err
= tnfctl_close(g_hndl
, TNFCTL_TARG_SUSPEND
);
550 (void) fprintf(stderr
, gettext(
551 "%s: trouble quitting : %s\n"),
552 g_argv
[0], tnfctl_strerror(err
));
560 * scanargs() - processes the command line arguments
563 #define strneq(s1, s2, n) (strncmp(s1, s2, n) == 0)
570 #if defined(DEBUG) || defined(lint)
571 char *optstr
= "l:o:p:s:tkv:"; /* debugging options */
573 char *optstr
= "l:o:p:s:tk"; /* production options */
576 /* set up some defaults */
584 while ((c
= getopt(argc
, argv
, optstr
)) != EOF
) {
586 case 'l': /* preload objects */
589 case 'o': /* tracefile name */
592 case 'p': /* target pid (attach case) */
593 g_targetpid
= atoi(optarg
);
595 case 's': /* tracefile size */
596 g_outsize
= atoi(optarg
) * 1024;
598 case 't': /* test flag */
600 (void) setvbuf(stdout
, NULL
, _IOLBF
, 0);
602 case 'k': /* kernel mode */
603 g_kernelmode
= B_TRUE
;
605 #if defined(DEBUG) || defined(lint)
606 case 'v': /* verbose flag */
607 g_verbose
= atoi(optarg
);
610 case '?': /* error case */
611 usage(argv
, gettext("unrecognized argument"));
616 g_cmdname
= strdup(argv
[optind
]);
617 g_cmdargs
= &argv
[optind
];
620 if (!g_kernelmode
&& (g_cmdname
== NULL
&& g_targetpid
== 0))
621 usage(argv
, gettext("need to specify cmd or pid"));
622 if (g_cmdname
!= NULL
&& g_targetpid
!= 0)
623 usage(argv
, gettext("can't specify both cmd and pid"));
624 if (g_targetpid
&& g_preload
)
625 usage(argv
, gettext("can't use preload option with attach"));
628 usage(argv
, "can't specify a filename in kernel mode");
630 usage(argv
, "can't specify a command in kernel mode");
632 usage(argv
, "can't specify pid in kernel mode");
634 usage(argv
, "can't use preload option in kernel mode");
636 /* default output size */
638 g_outsize
= g_kernelmode
? KERNEL_OUTSIZE
: USER_OUTSIZE
;
643 for (i
= 1; i
< argc
; i
++) {
644 if (strneq(argv
[i
], "-v", 2)) {
647 vlevel
= (strlen(argv
[i
]) > 2)? atoi(&argv
[i
][2]) : 1;
649 prb_verbose_set(vlevel
);
650 } else if (strneq(argv
[i
], "-pid", 2)) {
652 usage(argv
, gettext("missing pid argument"));
653 g_targetpid
= atoi(argv
[i
]);
654 } else if (strneq(argv
[i
], "-t", 2)) {
656 (void) setvbuf(stdout
, NULL
, _IOLBF
, 0);
657 } else if (argv
[i
][0] != '-') {
658 g_cmdname
= strdup(argv
[i
]);
661 "%s: out of memory"), argv
[0]);
663 if (g_verbose
>= 2) {
664 (void) fprintf(stderr
,
665 "cmdname=%s\n", g_cmdname
);
668 * rest of arguments are the args to the executable -
669 * by convention argv[0] should be name of
670 * executable, so we don't increment i
672 g_cmdargs
= &argv
[i
];
675 usage(argv
, gettext("unrecognized argument"));
684 * sig_handler() - cleans up if a signal is received
689 sig_handler(int signo
)
692 } /* end sig_handler */
696 * set_signal() - sets up function to call for clean up
702 struct sigaction newact
;
704 newact
.sa_handler
= sig_handler
;
705 (void) sigemptyset(&newact
.sa_mask
);
707 if (sigaction(SIGINT
, &newact
, NULL
) < 0) {
715 * set_tracefile() - initializes tracefile, sets the tracefile name and size
717 static tnfctl_errcode_t
718 set_tracefile(tnfctl_handle_t
*hndl
)
720 tnfctl_errcode_t err
;
721 tnfctl_trace_attrs_t attrs
;
723 char path
[MAXPATHLEN
];
727 /* Init tracefile name used by list cmd */
729 err
= tnfctl_trace_attrs_get(hndl
, &attrs
);
733 if (attrs
.trace_buf_state
== TNFCTL_BUF_BROKEN
)
734 return (TNFCTL_ERR_BUFBROKEN
);
735 if (attrs
.trace_buf_state
== TNFCTL_BUF_OK
) {
736 /* trace file set already - can't change it */
737 return (TNFCTL_ERR_NONE
);
740 minoutsize
= attrs
.trace_min_size
;
741 if (g_outsize
< minoutsize
) {
742 (void) fprintf(stderr
,
743 gettext("specified tracefile size smaller then "
744 "minimum; setting to %d kbytes\n"),
746 g_outsize
= minoutsize
;
749 /* where is $TMPDIR? */
750 tmpdir
= getenv("TMPDIR");
751 if (!tmpdir
|| *tmpdir
== '\0') {
755 /* do we have an absolute, relative or no pathname specified? */
756 if (g_outname
== NULL
) {
757 /* default, no tracefile specified */
758 if ((strlen(tmpdir
) + 1 + 20) > (size_t)MAXPATHLEN
) {
759 (void) fprintf(stderr
, gettext(
760 "%s: $TMPDIR too long\n"), g_argv
[0]);
763 (void) sprintf(path
, "%s/trace-%ld", tmpdir
, g_targetpid
);
766 /* filename specified */
767 outfile_name
= g_outname
;
769 tracefile
= strdup(outfile_name
);
770 if (tracefile
== NULL
) {
771 if ((errno
== ENOMEM
) || (errno
== EAGAIN
)) {
772 return (TNFCTL_ERR_ALLOCFAIL
);
774 return (TNFCTL_ERR_INTERNAL
);
778 #if defined(DEBUG) || defined(lint)
780 (void) fprintf(stderr
,
781 "setting tracefile name=\"%s\", size=%d\n",
784 err
= tnfctl_buffer_alloc(hndl
, outfile_name
, g_outsize
);
788 * get_data_model() - get the process data model from psinfo
791 #define PROCFORMAT "/proc/%d"
793 get_data_model(pid_t pid
)
795 char path
[MAXPATHLEN
];
799 (void) sprintf(path
, PROCFORMAT
, (int)pid
);
800 fd
= open(path
, O_RDONLY
);
803 if ((dmodel
= ioctl(fd
, PIOCPSINFO
, &psinfo
)) == -1)
805 return ((int)psinfo
.pr_dmodel
);
808 * get_executable - return file descriptor for PATH-resolved
813 get_executable(char *name
) {
817 char path
[PATH_MAX
+ 1];
818 char line
[MAX_INPUT
+ 1];
821 int N
= sizeof (line
);
822 struct stat file_att
;
824 while (*fname
== ' ') fname
++;
825 if (fname
[0] == '-' || strchr(fname
, '/')) {
826 fd
= open(fname
, O_RDONLY
);
828 int len
= strlen(fname
);
829 char *dirlist
= getenv("PATH");
832 if (dirlist
!= NULL
) {
833 dirlist
= strdup(dirlist
);
834 dir
= strtok(dirlist
, ":");
836 while (fd
< 0 && dir
!= NULL
) {
837 if ((strlen(dir
) + len
+ 1) < sizeof (path
)) {
838 strcat(strcat(strcpy(path
, dir
), "/"), fname
);
839 fd
= open(path
, O_RDONLY
);
841 dir
= strtok(NULL
, ":");
843 if (dirlist
!= NULL
) free(dirlist
);
845 if (fstat(fd
, &file_att
) || !S_ISREG(file_att
.st_mode
)) {
850 if (read(fd
, p
, 2) && p
[0] == '#' && p
[1] == '!') {
851 while (N
-- > 1 && read(fd
, p
, 1) && *p
!= '\n')
855 return (get_executable(line
));
857 if (fd
>= 0) lseek(fd
, 0, SEEK_SET
);
858 } /* %$#@! cstyle complaint */
863 * get_elf_class - get the target executable elf class
864 * i.e. ELFCLASS64 or ELFCLASS32.
867 get_elf_class(char *filename
)
870 int elffd
= get_executable(filename
);
878 if (elf_version(EV_CURRENT
) == EV_NONE
) {
882 elf
= elf_begin(elffd
, ELF_C_READ
, (Elf
*) 0);
884 * verify information in file header
886 if (gelf_getehdr(elf
, &ehdr
) == (GElf_Ehdr
*) 0) {
890 ident
= elf_getident(elf
, &size
);
891 if (ident
[EI_CLASS
] == ELFCLASS32
)
892 elfclass
= ELFCLASS32
;
893 if (ident
[EI_CLASS
] == ELFCLASS64
)
894 elfclass
= ELFCLASS64
;
899 * check_exec_model() - check the consistency between prex data model
900 * and target elf class and act accordingly
903 check_exec_model(char **argv
, char **envp
)
907 elfclass
= get_elf_class(g_cmdname
);
908 if (((elfclass
== ELFCLASS32
) && (prex_dmodel
== PR_MODEL_ILP32
)) ||
909 ((elfclass
== ELFCLASS64
) && (prex_dmodel
== PR_MODEL_LP64
)))
911 if ((prex_dmodel
== PR_MODEL_ILP32
) &&
912 (elfclass
== ELFCLASS64
)) {
913 (void) fprintf(stderr
, gettext(
914 "Error: 32 bit prex can not exec 64 bit target\n"));
917 if ((prex_dmodel
== PR_MODEL_LP64
) &&
918 (elfclass
== ELFCLASS32
))
919 prex_isaexec(argv
, envp
);
923 * check_pid_model() - check the consistency between prex data model
924 * and target data model and act accordingly
927 check_pid_model(char **argv
, char **envp
)
931 dmodel
= get_data_model(g_targetpid
);
932 if (prex_dmodel
== dmodel
)
934 if ((prex_dmodel
== PR_MODEL_ILP32
) &&
935 (dmodel
== PR_MODEL_LP64
)) {
936 (void) fprintf(stderr
, gettext(
937 "Error: 32 bit prex can not exec 64 bit target\n"));
940 if ((prex_dmodel
== PR_MODEL_LP64
) &&
941 (dmodel
== PR_MODEL_ILP32
))
942 prex_isaexec(argv
, envp
);
945 * prex_isaexec() - there is only one case this function get called
946 * 64 bit prex, 32 bit target, need to exec 32 bit
950 prex_isaexec(char **argv
, char **envp
)
952 char path
[PATH_MAX
+ sizeof (PREX32DIR
)];
953 strcat(strcat(strcpy(path
, dirname(dirname(argv
[0]))), PREX32DIR
),
955 if (get_elf_class(path
) != ELFCLASS32
)
956 strcpy(path
, PREX32EXEC
);
958 (void) execve(path
, argv
, envp
);
959 (void) fprintf(stderr
,
960 gettext("%s: execve(\"%s\") failed\n"),
969 (void) fprintf(stderr
,
970 gettext("There is no trace file in kernel mode!\n"));
972 (void) printf(gettext("Current trace file is: %s\n"), tracefile
);