summaryrefslogtreecommitdiff
path: root/usr/src/cmd/tnf
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/tnf
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/tnf')
-rw-r--r--usr/src/cmd/tnf/Makefile49
-rw-r--r--usr/src/cmd/tnf/prex/Makefile67
-rw-r--r--usr/src/cmd/tnf/prex/Makefile.com111
-rw-r--r--usr/src/cmd/tnf/prex/amd64/Makefile35
-rw-r--r--usr/src/cmd/tnf/prex/cmd.c296
-rw-r--r--usr/src/cmd/tnf/prex/cmd.h102
-rw-r--r--usr/src/cmd/tnf/prex/dbg.h50
-rw-r--r--usr/src/cmd/tnf/prex/expr.c262
-rw-r--r--usr/src/cmd/tnf/prex/expr.h71
-rw-r--r--usr/src/cmd/tnf/prex/fcn.c213
-rw-r--r--usr/src/cmd/tnf/prex/fcn.h65
-rw-r--r--usr/src/cmd/tnf/prex/help.c626
-rw-r--r--usr/src/cmd/tnf/prex/i386/Makefile34
-rw-r--r--usr/src/cmd/tnf/prex/list.c571
-rw-r--r--usr/src/cmd/tnf/prex/list.h58
-rw-r--r--usr/src/cmd/tnf/prex/main.c974
-rw-r--r--usr/src/cmd/tnf/prex/new.c57
-rw-r--r--usr/src/cmd/tnf/prex/new.h58
-rw-r--r--usr/src/cmd/tnf/prex/prbk.c387
-rw-r--r--usr/src/cmd/tnf/prex/prbk.h55
-rw-r--r--usr/src/cmd/tnf/prex/prexgram.y382
-rw-r--r--usr/src/cmd/tnf/prex/prexlex.l169
-rw-r--r--usr/src/cmd/tnf/prex/queue.c154
-rw-r--r--usr/src/cmd/tnf/prex/queue.h67
-rw-r--r--usr/src/cmd/tnf/prex/set.c181
-rw-r--r--usr/src/cmd/tnf/prex/set.h70
-rw-r--r--usr/src/cmd/tnf/prex/source.c307
-rw-r--r--usr/src/cmd/tnf/prex/source.h55
-rw-r--r--usr/src/cmd/tnf/prex/sparcv9/Makefile36
-rw-r--r--usr/src/cmd/tnf/prex/spec.c394
-rw-r--r--usr/src/cmd/tnf/prex/spec.h94
-rw-r--r--usr/src/cmd/tnf/prex/util.c56
-rw-r--r--usr/src/cmd/tnf/tnfdump/Makefile66
-rw-r--r--usr/src/cmd/tnf/tnfdump/cooked.c337
-rw-r--r--usr/src/cmd/tnf/tnfdump/main.c406
-rw-r--r--usr/src/cmd/tnf/tnfdump/state.h67
-rw-r--r--usr/src/cmd/tnf/tnfdump/table.c122
-rw-r--r--usr/src/cmd/tnf/tnfxtract/Makefile60
-rw-r--r--usr/src/cmd/tnf/tnfxtract/Makefile.com58
-rw-r--r--usr/src/cmd/tnf/tnfxtract/amd64/Makefile32
-rw-r--r--usr/src/cmd/tnf/tnfxtract/i386/Makefile32
-rw-r--r--usr/src/cmd/tnf/tnfxtract/sparcv9/Makefile33
-rw-r--r--usr/src/cmd/tnf/tnfxtract/tnfxtract.c423
43 files changed, 7742 insertions, 0 deletions
diff --git a/usr/src/cmd/tnf/Makefile b/usr/src/cmd/tnf/Makefile
new file mode 100644
index 0000000000..82c77e7fed
--- /dev/null
+++ b/usr/src/cmd/tnf/Makefile
@@ -0,0 +1,49 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1995, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/tnf/Makefile
+#
+
+SUBDIRS= prex \
+ tnfdump \
+ tnfxtract
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all install clean clobber lint _msg: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/tnf/prex/Makefile b/usr/src/cmd/tnf/prex/Makefile
new file mode 100644
index 0000000000..89cc856f06
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/Makefile
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/tnf/prex/Makefile
+#
+
+PROG= prex
+
+include ../../Makefile.cmd
+
+POFILE=prex.po
+POFILES=cmd.po fcn.po list.po main.po new.po prbk.po source.po spec.po util.po
+
+$(64ONLY)SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all: $(SUBDIRS)
+
+clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS)
+ -$(RM) $(ROOTPROG)
+ -$(LN) $(ISAEXEC) $(ROOTPROG)
+
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+$(POFILE): $(POFILES)
+ rm -f $@
+ cat $(POFILES) > $@
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/tnf/prex/Makefile.com b/usr/src/cmd/tnf/prex/Makefile.com
new file mode 100644
index 0000000000..b6ea70d2dc
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/Makefile.com
@@ -0,0 +1,111 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989,2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/tnf/prex/Makefile.com
+#
+
+PROG= prex
+
+OBJS.c= source.o \
+ main.o \
+ util.o \
+ expr.o \
+ spec.o \
+ set.o \
+ queue.o \
+ cmd.o \
+ new.o \
+ list.o \
+ fcn.o \
+ prbk.o \
+ help.o
+
+OBJS.yl= prexgram.o \
+ prexlex.o
+
+OBJS= $(OBJS.yl) $(OBJS.c)
+
+SRCS= $(OBJS.c:%.o=../%.c) $(OBJS.yl:%.o=%.c)
+
+SRCS.yl = $(OBJS.yl:%.o=%.c)
+CLEANFILES = $(SRCS.yl) y.tab.h
+
+include ../../../Makefile.cmd
+
+POFILE= prex.po
+POFILES= $(OBJS.c:%.o=%.po)
+
+#YFLAGS= -d -t -v
+YFLAGS= -d
+LFLAGS= -v
+# FOR normal makefile, uncomment the next line
+LDLIBS += -lgen -ltnfctl -lelf -lc
+# Uncomment the following line for a debug build
+# COPTFLAG = -g -DDEBUG -v
+
+.KEEP_STATE:
+
+.PARALLEL: $(OBJS)
+
+all: $(PROG)
+
+#OBJS can be built in parallel after all .c (and y.tab.h) are properly built
+$(PROG): $(SRCS.yl) .WAIT $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+#This also builds y.tab.h
+prexgram.c: ../prexgram.y
+ $(YACC.y) ../prexgram.y
+ mv y.tab.c $@
+
+prexlex.c: ../prexlex.l
+ $(RM) $@
+ $(LEX.l) ../prexlex.l > $@
+
+#Use %.c in priority to ../%.c for prexgram.c and prexlec.c
+%.o: %.c
+ $(COMPILE.c) $<
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+
+
+$(ROOTBIN):
+ $(INS.dir)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ cat $(POFILES) > $@
+
+clean:
+ $(RM) $(OBJS) $(CLEANFILES)
+
+lint: $(OBJS)
+ $(LINT.c) $(SRCS)
+
+include ../../../Makefile.targ
diff --git a/usr/src/cmd/tnf/prex/amd64/Makefile b/usr/src/cmd/tnf/prex/amd64/Makefile
new file mode 100644
index 0000000000..f5c1bee5a7
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/amd64/Makefile
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.cmd.64
+CFLAGS64 += -I.. -I.
+LINTFLAGS64 += -I.. -I.
+prexgram.o prexlex.o := CCVERBOSE=
+
+install: all $(ROOTPROG64)
diff --git a/usr/src/cmd/tnf/prex/cmd.c b/usr/src/cmd/tnf/prex/cmd.c
new file mode 100644
index 0000000000..9cc6519dde
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/cmd.c
@@ -0,0 +1,296 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#ifndef DEBUG
+#define NDEBUG 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <libintl.h>
+#include "cmd.h"
+#include "set.h"
+#include "fcn.h"
+#include "new.h"
+#include "source.h"
+
+
+/*
+ * Globals
+ */
+
+static queue_node_t g_cmdlist = {
+ &g_cmdlist,
+&g_cmdlist};
+
+
+/*
+ * cmd_set() - creates a cmd using a named set and adds it to the global list
+ */
+
+cmd_t *
+cmd_set(char *setname_p, cmd_kind_t kind, char *fcnname_p)
+{
+ cmd_t *new_p;
+ set_t *set_p;
+
+ set_p = set_find(setname_p);
+ if (!set_p) {
+ semantic_err(gettext("no set named \"$%s\""), setname_p);
+ return (NULL);
+ }
+ if (kind == CMD_CONNECT && !fcn_find(fcnname_p)) {
+ semantic_err(gettext("no function named \"&%s\""), fcnname_p);
+ return (NULL);
+ }
+ new_p = new(cmd_t);
+ queue_init(&new_p->qn);
+#ifdef LATEBINDSETS
+ new_p->isnamed = B_TRUE;
+ new_p->expr.setname_p = setname_p;
+#else
+ new_p->isnamed = B_FALSE;
+ new_p->expr.expr_p = expr_dup(set_p->exprlist_p);
+#endif
+ new_p->isnew = B_TRUE;
+ new_p->kind = kind;
+ new_p->fcnname_p = fcnname_p;
+
+ (void) queue_append(&g_cmdlist, &new_p->qn);
+ return (new_p);
+
+} /* end cmd_set */
+
+
+/*
+ * cmd_expr() - creates a cmd using a set and adds it to the global list
+ */
+
+cmd_t *
+cmd_expr(expr_t * expr_p, cmd_kind_t kind, char *fcnname_p)
+{
+ cmd_t *new_p;
+
+ if (kind == CMD_CONNECT && !fcn_find(fcnname_p)) {
+ semantic_err(gettext("no function named \"&%s\""), fcnname_p);
+ return (NULL);
+ }
+ new_p = new(cmd_t);
+ queue_init(&new_p->qn);
+ new_p->isnamed = B_FALSE;
+ new_p->expr.expr_p = expr_p;
+ new_p->isnew = B_TRUE;
+ new_p->kind = kind;
+ new_p->fcnname_p = fcnname_p;
+
+ (void) queue_append(&g_cmdlist, &new_p->qn);
+ return (new_p);
+
+} /* end cmd */
+
+
+#if 0
+/*
+ * cmd_destroy()
+ */
+
+static void
+cmd_destroy(cmd_t * cmd_p)
+{
+ if (!cmd_p)
+ return;
+
+ if (!queue_isempty(&cmd_p->qn))
+ (void) queue_remove(&cmd_p->qn);
+
+ if (!cmd_p->isnamed)
+ expr_destroy(cmd_p->expr.expr_p);
+
+ free(cmd_p);
+
+} /* end cmd_destroy */
+#endif
+
+
+/*
+ * cmd_list() - pretty prints the global cmdlist
+ */
+
+void
+cmd_list(void)
+{
+ cmd_t *cmd_p;
+ int i = 0;
+ char *str_p;
+
+ cmd_p = (cmd_t *) & g_cmdlist;
+ while ((cmd_p = (cmd_t *) queue_next(&g_cmdlist, &cmd_p->qn))) {
+ switch (cmd_p->kind) {
+ case CMD_ENABLE:
+ str_p = "enable ";
+ break;
+ case CMD_DISABLE:
+ str_p = "disable";
+ break;
+ case CMD_CONNECT:
+ str_p = "connect";
+ break;
+ case CMD_CLEAR:
+ str_p = "clear ";
+ break;
+ case CMD_TRACE:
+ str_p = "trace ";
+ break;
+ case CMD_UNTRACE:
+ str_p = "untrace";
+ break;
+ default:
+ str_p = "???????";
+ break;
+ }
+ (void) printf("[%d] %s ", i++, str_p);
+
+ if (cmd_p->kind == CMD_CONNECT) {
+ (void) printf("&%s ", cmd_p->fcnname_p);
+ }
+ if (!cmd_p->isnamed) {
+ expr_print(stdout, cmd_p->expr.expr_p);
+ }
+
+ (void) printf("\n");
+ }
+
+} /* end cmd_list */
+
+
+/*
+ * cmd_traverse() - calls the suppied traversal function on each command.
+ */
+
+tnfctl_errcode_t
+cmd_traverse(cmd_traverse_func_t percmdfunc, void *calldata_p)
+{
+ cmd_t *cmd_p;
+ tnfctl_errcode_t err = TNFCTL_ERR_NONE;
+
+ cmd_p = (cmd_t *) & g_cmdlist;
+ while ((cmd_p = (cmd_t *) queue_next(&g_cmdlist, &cmd_p->qn))) {
+ expr_t *expr_p;
+ fcn_t *fcn_p;
+
+ if (!cmd_p->isnamed) {
+ expr_p = cmd_p->expr.expr_p;
+ }
+
+ if (cmd_p->kind == CMD_CONNECT) {
+ fcn_p = fcn_find(cmd_p->fcnname_p);
+ assert(fcn_p);
+ }
+ else
+ fcn_p = NULL;
+
+ err = (*percmdfunc) (expr_p,
+ cmd_p->kind,
+ fcn_p, cmd_p->isnew, calldata_p);
+ if (err)
+ return (err);
+ }
+ return (err);
+} /* end cmd_traverse */
+
+
+/*
+ * cmd_traverse() - calls the suppied traversal function on each command.
+ */
+
+tnfctl_errcode_t
+cmd_callback(cmd_t *cmd_p, cmd_traverse_func_t percmdfunc, void *calldata_p)
+{
+ tnfctl_errcode_t err = TNFCTL_ERR_NONE;
+ expr_t *expr_p;
+ fcn_t *fcn_p;
+
+ if (!cmd_p->isnamed) {
+ expr_p = cmd_p->expr.expr_p;
+ }
+
+ if (cmd_p->kind == CMD_CONNECT) {
+ fcn_p = fcn_find(cmd_p->fcnname_p);
+ assert(fcn_p);
+ }
+ else
+ fcn_p = NULL;
+
+ err = (*percmdfunc) (expr_p, cmd_p->kind, fcn_p, cmd_p->isnew,
+ calldata_p);
+
+ return (err);
+}
+
+#ifdef NOTNEEDED
+/*
+ * cmd_mark() - mark all of the commands in the global list as old
+ */
+
+void
+cmd_mark(void)
+{
+ cmd_t *cmd_p;
+
+ cmd_p = (cmd_t *) & g_cmdlist;
+ while ((cmd_p = (cmd_t *) queue_next(&g_cmdlist, &cmd_p->qn))) {
+ cmd_p->isnew = B_FALSE;
+ }
+
+} /* end cmd_mark */
+
+/*
+ * cmd_delete() -
+ */
+
+void
+cmd_delete(int cmdnum)
+{
+ cmd_t *cmd_p;
+ int i = 0;
+
+ cmd_p = (cmd_t *) & g_cmdlist;
+ while ((cmd_p = (cmd_t *) queue_next(&g_cmdlist, &cmd_p->qn))) {
+ if (cmdnum == i) {
+ cmd_destroy(cmd_p);
+ return;
+ }
+ i++;
+ }
+
+} /* end cmd_delete */
+#endif
diff --git a/usr/src/cmd/tnf/prex/cmd.h b/usr/src/cmd/tnf/prex/cmd.h
new file mode 100644
index 0000000000..8e67544b93
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/cmd.h
@@ -0,0 +1,102 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _CMD_H
+#define _CMD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <sys/types.h>
+#include "queue.h"
+#include "expr.h"
+#include "set.h"
+#include "fcn.h"
+
+#include <tnf/tnfctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Typedefs
+ */
+
+typedef enum cmd_kind {
+ CMD_ENABLE,
+ CMD_DISABLE,
+ CMD_CONNECT,
+ CMD_CLEAR,
+ CMD_TRACE,
+ CMD_UNTRACE
+} cmd_kind_t;
+
+typedef struct cmd {
+ queue_node_t qn;
+ boolean_t isnamed;
+ boolean_t isnew;
+ union {
+#ifdef LATEBINDSETS
+ char *setname_p;
+#endif
+ expr_t *expr_p;
+ } expr;
+ char *fcnname_p;
+ cmd_kind_t kind;
+} cmd_t;
+
+typedef
+tnfctl_errcode_t (*cmd_traverse_func_t) (
+ expr_t * expr_p,
+ cmd_kind_t kind,
+ fcn_t * fcn_p,
+ boolean_t isnew,
+ void *calldata_p);
+
+
+/*
+ * Declarations
+ */
+
+cmd_t *cmd_set(char *setname_p, cmd_kind_t kind, char *fcnname_p);
+cmd_t *cmd_expr(expr_t * expr_p, cmd_kind_t kind, char *fcnname_p);
+void cmd_list(void);
+#if 0
+void cmd_mark(void);
+void cmd_delete(int cmdnum);
+#endif
+tnfctl_errcode_t cmd_traverse(cmd_traverse_func_t percmdfunc, void *calldata_p);
+tnfctl_errcode_t cmd_callback(cmd_t *cmd, cmd_traverse_func_t percmdfunc,
+ void *calldata_p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CMD_H */
diff --git a/usr/src/cmd/tnf/prex/dbg.h b/usr/src/cmd/tnf/prex/dbg.h
new file mode 100644
index 0000000000..ae9f6831db
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/dbg.h
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _DBG_H
+#define _DBG_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef DEBUG
+#define DBG(x) (x)
+#else
+#define DBG(x)
+#endif
+
+#if defined(DEBUG) || defined(lint)
+#include <stdio.h>
+extern int __prb_verbose;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DBG_H */
diff --git a/usr/src/cmd/tnf/prex/expr.c b/usr/src/cmd/tnf/prex/expr.c
new file mode 100644
index 0000000000..46c14f621f
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/expr.c
@@ -0,0 +1,262 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+/* we need to define this to get strtok_r from string.h */
+/* SEEMS LIKE A BUG TO ME */
+#define _REENTRANT
+
+#ifndef DEBUG
+#define NDEBUG 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <assert.h>
+#include "spec.h"
+#include "expr.h"
+#include "new.h"
+
+
+/*
+ * Typedefs
+ */
+
+typedef enum {
+ MATCH_NONE = 0,
+ MATCH_FALSE,
+ MATCH_TRUE
+
+
+} match_t;
+
+
+/*
+ * Declarations
+ */
+
+static boolean_t matchattrs(expr_t * expr_p, const char *attrs);
+static void matchvals(spec_t * spec_p, char *attrstr,
+ char *valstr, void *calldatap);
+static void matched(spec_t * spec_p, char *valstr, void *calldatap);
+
+
+/* ---------------------------------------------------------------- */
+/* ----------------------- Public Functions ----------------------- */
+/* ---------------------------------------------------------------- */
+
+/*
+ * expr() - builds an expr
+ */
+
+expr_t *
+expr(spec_t * left_p,
+ spec_t * right_p)
+{
+ expr_t *new_p;
+
+ new_p = new(expr_t);
+ queue_init(&new_p->qn);
+ new_p->left_p = left_p;
+ new_p->right_p = right_p;
+
+ return (new_p);
+
+} /* end expr */
+
+
+/*
+ * expr_dup() - duplicates an expression list
+ */
+
+expr_t *
+expr_dup(expr_t * list_p)
+{
+ expr_t *expr_p;
+ expr_t *head_p;
+
+ if (!list_p)
+ return (NULL);
+
+ /* copy the first node */
+ head_p = expr(spec_dup(list_p->left_p),
+ spec_dup(list_p->right_p));
+
+ /* append each additional node */
+ expr_p = list_p;
+ while (expr_p = (expr_t *) queue_next(&list_p->qn, &expr_p->qn)) {
+ expr_t *new_p;
+
+ new_p = expr(spec_dup(expr_p->left_p),
+ spec_dup(expr_p->right_p));
+ (void) queue_append(&head_p->qn, &new_p->qn);
+ }
+
+ return (head_p);
+
+} /* end expr_dup */
+
+
+/*
+ * expr_destroy() - destroys an expression list
+ */
+
+void
+expr_destroy(expr_t * list_p)
+{
+ expr_t *expr_p;
+
+ while (expr_p = (expr_t *) queue_next(&list_p->qn, &list_p->qn)) {
+ (void) queue_remove(&expr_p->qn);
+
+ if (expr_p->left_p)
+ spec_destroy(expr_p->left_p);
+ if (expr_p->right_p)
+ spec_destroy(expr_p->right_p);
+ free(expr_p);
+ }
+
+ if (list_p->left_p)
+ spec_destroy(list_p->left_p);
+ if (list_p->right_p)
+ spec_destroy(list_p->right_p);
+ free(list_p);
+
+} /* end expr_destroy */
+
+
+/*
+ * expr_list() - append a expr_t to a list
+ */
+
+expr_t *
+expr_list(expr_t * h,
+ expr_t * f)
+{
+ /* queue append handles the NULL cases OK */
+ return ((expr_t *) queue_append(&h->qn, &f->qn));
+
+} /* end expr_list */
+
+
+/*
+ * expr_print() - pretty prints an expr list
+ */
+
+void
+expr_print(FILE * stream,
+ expr_t * list_p)
+{
+ expr_t *expr_p = NULL;
+
+ while ((expr_p = (expr_t *) queue_next(&list_p->qn, &expr_p->qn))) {
+ spec_print(stream, expr_p->left_p);
+ (void) fprintf(stream, "=");
+ spec_print(stream, expr_p->right_p);
+ (void) fprintf(stream, " ");
+ }
+
+} /* end expr_print */
+
+
+/*
+ * expr_match() - figures out whether a probe matches in an expression list
+ */
+
+boolean_t
+expr_match(expr_t * list_p,
+ const char *attrs)
+{
+ expr_t *expr_p = NULL;
+
+ while ((expr_p = (expr_t *) queue_next(&list_p->qn, &expr_p->qn))) {
+ if (matchattrs(expr_p, attrs))
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+
+} /* end expr_match */
+
+
+/* ---------------------------------------------------------------- */
+/* ----------------------- Private Functions ---------------------- */
+/* ---------------------------------------------------------------- */
+
+typedef struct matchargs {
+ spec_t *spec_p;
+ boolean_t match;
+
+} matchargs_t;
+
+static boolean_t
+matchattrs(expr_t * expr_p,
+ const char *attrs)
+{
+ matchargs_t args;
+
+ args.spec_p = expr_p->right_p;
+ args.match = B_FALSE;
+
+ spec_attrtrav(expr_p->left_p,
+ (char *) attrs, matchvals, (void *) &args);
+
+ return (args.match);
+
+} /* end matchattrs */
+
+
+/*ARGSUSED*/
+static void
+matchvals(spec_t * spec_p,
+ char *attrstr,
+ char *valstr,
+ void *calldatap)
+{
+ matchargs_t *args_p = (matchargs_t *) calldatap;
+
+ spec_valtrav(args_p->spec_p, valstr, matched, calldatap);
+
+} /* matchvals */
+
+
+/*ARGSUSED*/
+static void
+matched(spec_t * spec_p,
+ char *valstr,
+ void *calldatap)
+{
+ matchargs_t *args_p = (matchargs_t *) calldatap;
+
+ args_p->match = B_TRUE;
+
+} /* end matched */
diff --git a/usr/src/cmd/tnf/prex/expr.h b/usr/src/cmd/tnf/prex/expr.h
new file mode 100644
index 0000000000..96f84af525
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/expr.h
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _EXPR_H
+#define _EXPR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <stdio.h>
+
+#include "queue.h"
+#include "spec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Typedefs
+ */
+
+typedef struct expr {
+ queue_node_t qn;
+ spec_t *left_p;
+ spec_t *right_p;
+
+} expr_t;
+
+
+/*
+ * Declarations
+ */
+
+expr_t * expr(spec_t * left_p, spec_t * right_p);
+void expr_destroy(expr_t * list_p);
+expr_t * expr_list(expr_t * list_p, expr_t * item_p);
+void expr_print(FILE * stream, expr_t * list_p);
+boolean_t expr_match(expr_t * expr_p, const char *attrs);
+expr_t * expr_dup(expr_t * list_p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EXPR_H */
diff --git a/usr/src/cmd/tnf/prex/fcn.c b/usr/src/cmd/tnf/prex/fcn.c
new file mode 100644
index 0000000000..527bc5fc20
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/fcn.c
@@ -0,0 +1,213 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include "queue.h"
+#include "set.h"
+#include "fcn.h"
+#include "new.h"
+#include "source.h"
+
+
+/*
+ * Globals
+ */
+
+static queue_node_t g_fcnlist = {
+ &g_fcnlist,
+&g_fcnlist};
+
+/*
+ * Forward Declarations
+ */
+
+static void fcn_destroy(fcn_t * fcn_p);
+static void fcn_print(FILE * stream, fcn_t * fcn_p);
+
+
+/*
+ * fcn() - builds a function block and inserts it on the global list.
+ */
+
+#define NSYMS 1
+
+void
+fcn(char *name_p, char *entry_name_p)
+{
+ fcn_t *new_p;
+ fcn_t *old_p;
+
+ /* does this setname exist already? */
+ old_p = fcn_find(name_p);
+ if (old_p)
+ fcn_destroy(old_p);
+
+ /* create a new set */
+ new_p = new(fcn_t);
+ queue_init(&new_p->qn);
+ new_p->name_p = name_p;
+ new_p->entry_name_p = entry_name_p;
+
+#ifdef OLD
+ /*
+ * allocate a target function block, and stuff the init and fini
+ * addrs
+ */
+ prbstat = prb_targmem_alloc(g_procfd, sizeof (probe_funcs_t),
+ &new_p->funcs_p);
+ if (prbstat) {
+ semantic_err(gettext("problem allocating target memory"));
+ goto Error;
+ }
+ prbstat = prb_proc_write(g_procfd, new_p->funcs_p,
+ &new_p->funcs, sizeof (probe_funcs_t));
+ if (prbstat) {
+ semantic_err(gettext(
+ "setup problem, initial/final "
+ "funcs in target memory"));
+ goto Error;
+ }
+#endif
+
+ /* append the new set to the global list */
+ (void) queue_append(&g_fcnlist, &new_p->qn);
+
+ return;
+
+Error:
+ if (new_p)
+ free(new_p);
+ return;
+
+} /* end fcn */
+
+
+/*
+ * fcn_destroy() - destroys a fcn and related resources
+ */
+
+static void
+fcn_destroy(fcn_t * fcn_p)
+{
+ if (!fcn_p)
+ return;
+
+ /* remove ourselves from any list */
+ if (!queue_isempty(&fcn_p->qn))
+ (void) queue_remove(&fcn_p->qn);
+
+ if (fcn_p->name_p)
+ free(fcn_p->name_p);
+ if (fcn_p->entry_name_p)
+ free(fcn_p->entry_name_p);
+
+ free(fcn_p);
+
+} /* end fcn_destroy */
+
+
+/*
+ * fcn_list() - pretty prints the global fcnlist
+ */
+
+void
+fcn_list(void)
+{
+ fcn_t *fcn_p;
+
+ fcn_p = (fcn_t *) & g_fcnlist;
+ while ((fcn_p = (fcn_t *) queue_next(&g_fcnlist, &fcn_p->qn))) {
+ fcn_print(stdout, fcn_p);
+ }
+
+} /* end fcn_list */
+
+
+/*
+ * fcn_print() - pretty prints a fcn
+ */
+
+static void
+fcn_print(FILE * stream, fcn_t * fcn_p)
+{
+ if (!fcn_p)
+ return;
+
+ (void) fprintf(stream, "&%-8s %-24s\n",
+ fcn_p->name_p, fcn_p->entry_name_p);
+
+} /* end fcn_print */
+
+
+/*
+ * fcn_findname() - find the created name, given an entry name
+ */
+
+char *
+fcn_findname(const char * const entry_p)
+{
+ fcn_t *fcn_p;
+
+ if (!entry_p)
+ return (NULL);
+
+ fcn_p = (fcn_t *) & g_fcnlist;
+ while ((fcn_p = (fcn_t *) queue_next(&g_fcnlist, &fcn_p->qn)))
+ if (strcmp(entry_p, fcn_p->entry_name_p) == 0)
+ return (fcn_p->name_p);
+
+ return (NULL);
+
+} /* end fcn_findname */
+
+
+/*
+ * fcn_find() - finds a fcn by name
+ */
+
+fcn_t *
+fcn_find(char *fcnname_p)
+{
+ fcn_t *fcn_p;
+
+ if (!fcnname_p)
+ return (NULL);
+
+ fcn_p = (fcn_t *) & g_fcnlist;
+ while ((fcn_p = (fcn_t *) queue_next(&g_fcnlist, &fcn_p->qn)))
+ if (strcmp(fcnname_p, fcn_p->name_p) == 0)
+ return (fcn_p);
+
+ return (NULL);
+
+} /* end set_find */
diff --git a/usr/src/cmd/tnf/prex/fcn.h b/usr/src/cmd/tnf/prex/fcn.h
new file mode 100644
index 0000000000..dcf4136ec3
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/fcn.h
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _FCN_H
+#define _FCN_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include "queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Typedefs
+ */
+
+typedef struct fcn {
+ queue_node_t qn;
+ char *name_p;
+ char *entry_name_p;
+} fcn_t;
+
+
+/*
+ * Declarations
+ */
+
+void fcn(char *name_p, char *func_entry_p);
+void fcn_list(void);
+fcn_t *fcn_find(char *name_p);
+char *fcn_findname(const char * const entry_p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCN_H */
diff --git a/usr/src/cmd/tnf/prex/help.c b/usr/src/cmd/tnf/prex/help.c
new file mode 100644
index 0000000000..4af6ee3317
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/help.c
@@ -0,0 +1,626 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <strings.h>
+#include "expr.h"
+#include "y.tab.h"
+
+#define NUMHELPTOPICS 6
+static char *helptopics[NUMHELPTOPICS] = {
+ "intro", "functions", "kernel_mode", "probe_spec", "processes",
+ "set_spec" };
+static char *helptopicstrings[NUMHELPTOPICS] = {
+/* help intro */
+"Introduction to prex\n"
+"\n"
+"prex is used to control probes in a target process, or in the kernel.\n"
+"If you are reading this help text, you have sucessfully invoked prex,\n"
+"by either connecting to an existing process (prex -p), a new\n"
+"process (prex myprogram), or to the kernel (prex -k).\n"
+"\n"
+"Most often, the user will want to enable some probes in the target,\n"
+"continue the target - either to completion, or until the target is\n"
+"interrupted - and then exit from prex to perform analysis on the resulting\n"
+"tracefile. An ascii dump of the tracefile can be obtained using the\n"
+"tnfdump(1) command.\n"
+"\n"
+"The tracefile can be found in /tmp/trace-<pid> by default, or in a location\n"
+"of your choice, if you specify the -o option when you invoke prex.\n"
+"You can query the name of the current trace file by using the command.\n"
+"list tracefile.\n"
+"\n"
+"Upon invocation, prex reads commands from the files ~/.prexrc and\n"
+"./.prexrc (in that order). The \"source\" command may be used to take\n"
+"commands from an arbitrary file or set of files.\n"
+"\n"
+"Help is available for a variety of topics, and for each prex command.\n"
+"Type help with no arguments for a list of available help topics.\n"
+"\n"
+"end of help for topic intro\n",
+/* help functions */
+"Probe Functions\n"
+"\n"
+"Note - probe functions are not available from kernel mode\n"
+"\n"
+"It is possible to use prex to connect functions to probe points, such that\n"
+"the function is invoked each time a given probe point is hit. Currently,\n"
+"the only function available from prex is the &debug function, which prints\n"
+"out the arguments sent in to the probe, as well as the value (if any)\n"
+"associated with the sunw%debug attribute in the detail field.\n"
+"\n"
+"Relevant commands:\n"
+" list fcns # list the defined probe functions\n"
+" connect &debug name=myprobe # attach probe &debug to probe myprobe\n"
+" connect &debug $myset # attach probe &debug to probes in $myset\n"
+" clear name=myprobe # disconnect probe functions from myprobe\n"
+" clear $myset # disconnect probe functions from $myset\n"
+"\n"
+"end of help for topic functions\n",
+/* help kernel_mode */
+"Controlling Kernel Probes\n"
+"\n"
+"The Solaris kernel is instrumented with a small number of strategically\n"
+"placed probes, documented in tnf_kernel_probes(4). The superuser can\n"
+"control these probes by running prex with the \"-k\" option.\n"
+"\n"
+"In kernel mode, trace output is written to an in-core buffer, rather\n"
+"than to a file on disk. This buffer can be extracted with the tnfxtract(1)\n"
+"commmand. This buffer must be set up before tracing can begin, through the\n"
+"use of the \"buffer alloc\" command. After kernel tracing is complete (and\n"
+"after the buffer has been extracted), the buffer can be deallocated from\n"
+"prex using the \"buffer dealloc\" command.\n"
+"\n"
+"As in user mode, kernel probe control is accomplished using the commands\n"
+"\"trace\", \"untrace\", \"enable\", and \"disable\". Additionally, in\n"
+"kernel mode, a \"master switch\" is provided to turn all tracing activity\n"
+"on or off. This switch is toggled using the commands \"ktrace on\" and\n"
+"\"ktrace off\". Unlike user mode, where the target is stopped while\n"
+"tracing paramaters are manipulated from prex, the kernel does not stop\n"
+"running during a tracing session. Using the \"ktrace\" command, one can\n"
+"set up all tracing parameters in advance of a session, without actually\n"
+"writing trace records until a \"ktrace on\" command is given.\n"
+"\n"
+"Kernel mode also provides the ability to limit tracing to those kernel\n"
+"probes hit on behalf of a specific user process. The pfilter command\n"
+"is provided to toggle process filtering on or off, and to specify the\n"
+"set of processes that comprise the filter. If pid 0 is a member of the\n"
+"filter list, then any threads not associated with a process are included.\n"
+"\n"
+"Note that after a kernel tracing session, all tracing parameters are left\n"
+"as-is. One should re-enter prex to disable and untrace probes, turn off\n"
+"process filtering, and deallocate the in-core trace buffer.\n"
+"\n"
+"Relevant Commands:\n"
+" buffer alloc 2m # allocate a 2M in-core buffer\n"
+" enable $all # enable all kernel probes\n"
+" trace $all # trace all kernel probes\n"
+" ktrace on # turn on kernel tracing\n"
+" pfilter add 1234 # add pid 1234 to the filter list\n"
+" pfilter on # turn on process filtering\n"
+" ktrace off # turn off kernel tracing\n"
+"Also see tnfxtract(1), which is used to extract the in-core trace buffer\n"
+"to an on-disk tracefile.\n"
+"\n"
+"end of help for topic kernel_mode\n",
+/* help probe_spec */
+"Probe Specification\n"
+"\n"
+"Many prex commands operate on probes or sets of probes. Probes are\n"
+"specified by a list of space-separated selectors of the form:\n"
+" <attribute>=<value>\n"
+"If the \""
+"<attribute>=\" is omitted, the attribute defaults to \"keys=\".\n"
+"The \""
+"<value>\" can be either a string or an ed(1) regular expression\n"
+"enclosed in slashes. Regular expressions in prex are unanchored, meaning\n"
+"that any value that contains the given regex as a substring is a valid\n"
+"match, regardless of position. To anchor a regular expression, use \"^\"\n"
+"to match the beginning of a line, or \"$\" to match the end of a line.\n"
+
+"If a list of selectors is specified, an OR operation is applied - the\n"
+"resulting probe_spec includes probes that match any of the selectors.\n"
+"See the prex(1) man page for a complete specification of the accepted\n"
+"grammar.\n"
+"\n"
+"The \"list\" command is used to view available probes in the target,\n"
+"and to display their attributes. The \"trace\" and \"untrace\" commands\n"
+"determine whether a probe will write a trace record when hit. The\n"
+"\"enable\" and \"disable\" commands indicate whether a probe will perform\n"
+"any action (such as a calling a connected function or creating a trace\n"
+"record) when hit. Normally, a probe is enabled and traced for tracing,\n"
+"and disabled and untraced otherwise. It is possible to enable a probe\n"
+"with tracing off to get debug output without writing trace records.\n"
+"\n"
+"Relevant Commands:\n"
+" list probes $all # list probes in set $all (all probes)\n"
+" list probes file=test.c # list probes with a specific attribute\n"
+" list 'file' probes $all # list the file attribute in all probes\n"
+" list probes name=/^thr/ # list probes whose name attribute matches\n"
+" # the given regular expression\n"
+" list probes name=/^thr/ keys=vm # list probes matching either selector\n"
+" enable name=/^thr/ # enable probes whose name matches this regex\n"
+" trace $all # trace all probes\n"
+" untrace $myset # untrace probes in set $myset\n"
+"\n"
+"end of help for topic probe_spec\n",
+/* help processes */
+"Controlling Processes with prex\n"
+"\n"
+"Prex is used to control probes in a given process, or in the kernel.\n"
+"The process which prex is to control is identified as an argument when\n"
+"prex is invoked. If the \"-p"
+" <pid>\" switch is used, prex connects to the\n"
+"specified process. Otherwise prex exec's the command supplied at the\n"
+"end of its argument list. In either case, prex stops the target process\n"
+"immediately so that the user may set up probe control.\n"
+"\n"
+"Once probe control is set up (typically using the \"enable\" and \"trace\"\n"
+"commands), the process is continued using the \"continue\" command. Prex\n"
+"remains attached to the target, and the user can force the target to\n"
+"stop again by typing control-C, at which time additional probe control\n"
+"directives may be given.\n"
+"\n"
+"Upon quitting from prex, the target process is normally resumed if prex\n"
+"attached to it, or killed if prex invoked it. An optional argument may\n"
+"be given with the \"quit\" command to explicitly specify whether to kill\n"
+"the target, continue it, or leave it suspended.\n"
+"\n"
+"If the target forks, any probe that the child encounters will be logged to\n"
+"the same trace file as the parent. If the child calls exec, it will no\n"
+"longer be traced.\n"
+"\n"
+"In kernel mode (prex -k), process filtering may be enabled, to limit\n"
+"tracing to those kernel probes hit on behalf of a specific process or\n"
+"set of processes. Kernel-mode process filtering is controlled using\n"
+"the \"pfilter\" command.\n"
+"\n"
+"\n"
+"Relevant Commands:\n"
+" continue # continue target (user mode only)\n"
+" Control-C # stop target (user mode only)\n"
+" quit resume # quit prex, continue target\n"
+" quit suspend # quit prex, suspend target\n"
+" quit kill # quit prex, kill target\n"
+" quit # quit prex, default action\n"
+"# Note: pfilter commands apply only to kernel mode\n"
+" pfilter # show pfilter status\n"
+" pfilter on # turn on process filter mode\n"
+" pfilter off # turn off process filter mode\n"
+" pfilter add 1234 # add to process filter pid list\n"
+" pfilter delete 1234 # delete from process filter pid list\n"
+"\n"
+"end of help for topic processes\n",
+/* help set_spec */
+"Specifying Probe Sets\n"
+"\n"
+"Prex provides the ability to define named sets of probes to simplify\n"
+"commands operating on multiple probes. The set \"$all\" is predefined,\n"
+"as the set of all probes in the target. A set is defined using the\n"
+"\"create\" command, and can be used as an argument to the \"list\",\n"
+"\"enable\", \"disable\", \"trace\", \"untrace\", \"connect\" and\n"
+"\"clear\" commands.\n"
+"\n"
+"Relevant Commands:\n"
+" create $myset name=/^thr/ # create a set\n"
+" list probes $myset # list probes in a set\n"
+" list sets # list defined sets\n"
+" enable $myset # enable a set of probes\n"
+" trace $myset # trace a set of probes\n"
+"\n"
+"end of help for topic set_spec\n"
+};
+
+static char *helpstr_continue =
+"\n"
+"Usage: continue\n"
+"\n"
+"\"continue\" is used to resume execution of the target process. This\n"
+"command is not available in kernel mode, since the kernel is never stopped.\n"
+"\n"
+"end of help for cmd continue\n";
+static char *helpstr_disable =
+"\n"
+"Usage: disable <probe_spec>|<set_spec>\n"
+"\n"
+"\"disable\" is used to to turn off all tracing activity associated with a\n"
+"probe or a set of probes.\n"
+"\n"
+"End of help for cmd disable\n";
+static char *helpstr_enable=
+"\n"
+"Usage: enable <probe_spec>|<set_spec>\n"
+"\n"
+"\"enable\" is used to specify that any activity associated with the probe\n"
+"or probes will be performed when the probe is hit. This includes connected\n"
+"probe functions as well as the generation of trace records. Note that in\n"
+"order for a probe to generate a trace record, it must be \"traced\" as well\n"
+"as enabled.\n"
+"\n"
+"End of help for cmd enable\n";
+static char *helpstr_help =
+"\n"
+"Usage: help [<cmd>|<topic>]\n"
+"\n"
+"\"help\" lists all available help topics when run without any arguments.\n"
+"If a valid topic or command-name is supplied as an argument, help text for\n"
+"the topic or command is displayed.\n"
+"\n"
+"End of help for cmd help\n";
+static char *helpstr_list =
+"\n"
+"Usage: list probes <probe_spec>|<set_spec> \n"
+" list <attrs> probes <probe_spec>|<set_spec>\n"
+" list sets\n"
+" list fcns\n"
+" list history\n"
+" list tracefile\n"
+"\n"
+"\"list\" displays information about currently defined probes, sets, and\n"
+"probe functions. When listing probes, one can limit the output to a\n"
+"desired set of attributes by specifying an attribute list as a set of\n"
+"strings. If an attribute is also a reserved word (such as \"trace\", it\n"
+"must be enclosed in single quotes. For example:\n"
+"\n"
+" list file 'trace' probes $all\n"
+"\n"
+"\"list\" history lists the probe control commands history, and\n"
+"\"list\" tracefile displays the current trace file name.\n"
+"\n"
+"End of help for cmd list\n";
+static char *helpstr_quit =
+"\n"
+"Usage: quit\n"
+" quit kill\n"
+" quit resume\n"
+" quit suspend\n"
+"\n"
+"The \"quit\" command exits prex, leaving the target in a state specified\n"
+"by the user, or taking a default action if no instructions are specified.\n"
+"An optional argument may be used to indicated that the target should be\n"
+"killed, resumed, or left suspended. If no argument is supplied, then\n"
+"prex's default behavior is to resume a process to which it had attached,\n"
+"and to kill a process which it had invoked.\n"
+"\n"
+"End of help for cmd quit\n";
+static char *helpstr_source =
+"\n"
+"Usage: source <filename>\n"
+"\n"
+"The \"source\" command is used to invoke a set of prex commands stored in\n"
+"a file. A sourced file may in turn source other files. The files\n"
+"~/.prexrc and ./.prexrc are sourced automatically (in that order) when prex\n"
+"is invoked, and may be used to store commonly used probe and set\n"
+"specifications, or probe control directives. Commands in sourced files\n"
+"may override the effects of commands in previously sourced files.\n"
+"\n"
+"End of help for cmd source\n";
+static char *helpstr_trace =
+"\n"
+"Usage: trace <probe_spec>|<set_spec>\n"
+"\n"
+"\"trace\" is used to turn on tracing for the specified probe or probes.\n"
+"A \"traced\" probe that is also \"enabled\" will generate a trace record\n"
+"when it is hit.\n"
+"\n"
+"End of help for cmd trace\n";
+static char *helpstr_untrace =
+"\n"
+"Usage: untrace <probe_spec>|<set_spec>\n"
+"\n"
+"\"untrace\" turns tracing off for the specified probe or probes. A probe\n"
+"will not generate a trace record when it is not traced, although connected\n"
+"probe functions will still be invoked as long as a probe is \"enabled\".\n"
+"\n"
+"End of help for cmd untrace\n";
+static char *helpstr_buffer =
+"\n"
+"Usage: buffer alloc <size>\n"
+" buffer dealloc\n"
+"\n"
+"Note: Kernel Mode Only\n"
+"\n"
+"\"buffer\" allocates or deallocates the in-core buffer used to hold\n"
+"kernel trace records. Size can be specified in kilobytes or megabytes,\n"
+"by appending the character 'k' or 'm' to a numeric value (e.g. \"2m\").\n"
+"A buffer must be allocated prior to a kernel tracing session. Once\n"
+"allocated, the buffer remains usable until deallocated, even through\n"
+"multiple invocations of prex.\n"
+"\n"
+"Before the buffer is deallocated, data may be extracted to an on-disk\n"
+"tracefile using tnfxtract(1).\n"
+"\n"
+"End of help for cmd buffer\n";
+static char *helpstr_ktrace =
+"\n"
+"Usage: ktrace on\n"
+" ktrace off\n"
+"\n"
+"Note: Kernel Mode Only\n"
+"\n"
+"\"ktrace\" toggles the master switch that indicates whether kernel\n"
+"tracing is active or inactive. Since the kernel cannot be stopped while\n"
+"a tracing experiment is set up, \"ktrace\" is provided so that tracing\n"
+"can be set up as desired before any trace records are generated\n"
+"\n"
+"End of help for cmd ktrace\n";
+static char *helpstr_pfilter =
+"\n"
+"Usage: pfilter\n"
+" pfilter on\n"
+" pfilter off\n"
+" pfilter add <pidlist>\n"
+" pfilter delete <pidlist>\n"
+"\n"
+"Note: Kernel Mode Only\n"
+"\n"
+"\"pfilter\" controls process filtering by toggling process-filter mode,\n"
+"and maintaining a list of process id's on which to filter. When process\n"
+"filtering mode is on, tracing is limited to the kernel events hit on behalf\n"
+"of the processes in the pid list. Process id 0 is used to represent all\n"
+"threads not associated with a process.\n"
+
+"When run without arguments, \"pfilter\" displays the current process-filter\n"
+"mode and pid list. A process filter pid list can be maintained whether\n"
+"or not process filter mode is currently active.\n"
+"\n"
+"A process must exist in order to be added to the pid list, and the pid list\n"
+"is automatically updated to delete any processes that no longer exist. If\n"
+"the pid list becomes empty while process filtering is on, prex issues a\n"
+"warning. Process filtering mode is persistent between invocations of prex\n"
+"so it should be turned off manually when a tracing experiment is complete.\n"
+"\n"
+"End of help for cmd pfilter\n";
+static char *helpstr_clear =
+"\n"
+"Usage: clear <probe_spec>|<set_spec>\n"
+"\n"
+"Note: Not available in Kernel Mode\n"
+"\n"
+"\"clear\" disconnects any probe functions that have previously been\n"
+"connected to a probe or group of probes using the \"connect\" command.\n"
+"The \"clear\" command cannot be used in kernel mode, since probe functions\n"
+"are not available for kernel probes.\n"
+"\n"
+"End of help for cmd clear\n";
+static char *helpstr_connect =
+"\n"
+"Usage: connect <function> <probe_spec>|<set_spec>\n"
+"\n"
+"Note: Not available in Kernel Mode\n"
+"\n"
+"\"connect\" connects a probe function to a probe or group of probes.\n"
+"Currently, the only probe function available from prex is \"&debug\", which\n"
+"prints out the arguments sent in to the probe, as well as the value (if\n"
+"any) associated with the sunw%debug attribute in the detail field.\n"
+"In order for a probe function to be invoked, the probe to which the\n"
+"function is attached must be \"enabled\", but need not be \"traced\".\n"
+"\n"
+"The \"clear\" command is available to disconnect a probe function from\n"
+"a probe or group of probes.\n"
+"\n"
+"End of help for cmd connect\n";
+
+static char *helpstr =
+"\n"
+"Usage: help [topic|command]\n"
+"\n"
+"Topics\n"
+"\tintro functions kernel_mode\n"
+"\tprobe_spec processes set_spec\n"
+"\n"
+"User and Kernel Mode Commands\n"
+"\tdisable enable help list\n"
+"\tquit source trace untrace\n"
+"\n"
+"Additional user-mode-only commands\n"
+"\tclear connect continue\n"
+"\n"
+"Additional kernel-mode-only (prex -k) commands\n"
+"\tbuffer ktrace pfilter\n"
+;
+
+
+static char *oldhelpstr =
+"grammar for non-terminals:\n"
+"__________________________\n"
+"\n"
+"filename ::= QUOTED_STR\n"
+"\n"
+"selector_list ::= /* empty */ |\n"
+" <selector_list> <selector>\n"
+"\n"
+"spec_list ::= /*empty */ |\n"
+" <spec_list> <spec>\n"
+"\n"
+"selector ::= <spec>=<spec> | /* whitespace around '=' optional */\n"
+" <spec> /* keys attribute is default */\n"
+"\n"
+"spec ::= IDENT |\n"
+" QUOTED_STR |\n"
+" REGEXP\n"
+"\n"
+"pidlist ::= <pid> |\n"
+" <pid> ',' <pidlist>\n"
+"pid ::= INT\n"
+"\n"
+"Reg-exps to match terminals:\n"
+"____________________________\n"
+"\n"
+"IDENT = [a-zA-Z_\\.%]{[a-zA-Z0-9_\\.%]}+ \n"
+"QUOTED_STR = '[^\\n']*' /* any string in single quotes */\n"
+"REGEXP = /[^\\n/]/ /* reg-exp's have to be in / / */\n"
+"INT = [0-9]+\n"
+"\n"
+"Commands:\n"
+"_________\n"
+"\n"
+"# set creation and set listing\n"
+"create $<set_name> <selector_list>\n"
+"list sets # list the defined sets\n"
+"\n"
+"# function listing\n"
+"list fcns # list the defined functions.\n"
+"\n"
+"# commands to connect and disconnect probe functions\n"
+"# (not available in kernel mode)\n"
+"connect &<fcn_handle> $<set_name> # eg. connect &debug $all\n"
+"connect &<fcn_handle> <selector_list>\n"
+"\n"
+"# command to disconnect all connected probe functions\n"
+"# (not available in kernel mode)\n"
+"clear $<set_name>\n"
+"clear <selector_list>\n"
+"\n"
+"# commands to toggle the tracing mode\n"
+"trace $<set_name>\n"
+"trace <selector_list>\n"
+"untrace $<set_name>\n"
+"untrace <selector_list>\n"
+"\n"
+"# commands to enable and disable probes\n"
+"enable $<set_name>\n"
+"enable <selector_list>\n"
+"disable $<set_name>\n"
+"disable <selector_list>\n"
+"list history # lists probe control commands issued\n"
+"list tracefile # lists the current trace file name\n"
+"\n"
+"# commands to list probes or to list values\n"
+"list <spec_list> probes $<set_name> #eg. list probes $all\n"
+"list <spec_list> probes <selector_list> #eg. list name probes file=test.c\n"
+"list values <spec_list> # eg. list values keys\n"
+"\n"
+"# help command\n"
+"help\n"
+"\n"
+"# source a file of prex commands\n"
+"source <filename>\n"
+"\n"
+"# process control - ^C stops target and returns to 'prex>' prompt\n"
+"# (In kernel mode, `continue' is a no-op, and 'quit' detaches prex\n"
+"# from the kernel.)\n"
+"continue # continues target\n"
+"quit kill # quit prex, kill target\n"
+"quit resume # quit prex, continue target\n"
+"quit suspend # quit prex, leave target suspended\n"
+"quit # quit prex (continue or kill target)\n"
+"\n"
+
+"\n"
+"# Kernel mode commands\n"
+"# \"master switch\" enabling/disabling all tracing\n"
+"ktrace on # Enabled probes will generate trace output\n"
+"ktrace off # All trace output suppressed\n"
+"# Create, destroy, or show the size of the kernel trace buffer\n"
+"buffer [ alloc [ size ] | dealloc ]\n"
+"# Control per-process kernel trace filtering\n"
+"pfilter off # Filtering off: trace all processes\n"
+"pfilter on # Filtering on: trace only processes in filter set\n"
+"pfilter add <pidlist> # Add specified process ids to the filter set\n"
+"pfilter delete <pidlist> # Drop specified pids from the filter set\n"
+"\n"
+;
+
+void
+help(void)
+{
+ (void) fputs(helpstr, stdout);
+
+} /* end help */
+
+void
+help_on_topic(char *topic)
+{
+ int i;
+
+ if (topic && strlen(topic)) {
+ for (i = 0; i < NUMHELPTOPICS; i++)
+ if (strcmp(topic, helptopics[i]) == 0)
+ break;
+ if (i < NUMHELPTOPICS)
+ fputs(helptopicstrings[i], stdout);
+ else {
+ printf("No help for %s\n", topic);
+ help();
+ }
+ }
+}
+
+
+void
+help_on_command(int cmd)
+{
+ switch (cmd) {
+ case CONTINUE:
+ fputs(helpstr_continue, stdout);
+ break;
+ case DISABLE:
+ fputs(helpstr_disable, stdout);
+ break;
+ case ENABLE:
+ fputs(helpstr_enable, stdout);
+ break;
+ case HELP:
+ fputs(helpstr_help, stdout);
+ break;
+ case LIST:
+ fputs(helpstr_list, stdout);
+ break;
+ case QUIT:
+ fputs(helpstr_quit, stdout);
+ break;
+ case SOURCE:
+ fputs(helpstr_source, stdout);
+ break;
+ case TRACE:
+ fputs(helpstr_trace, stdout);
+ break;
+ case UNTRACE:
+ fputs(helpstr_untrace, stdout);
+ break;
+ case BUFFER:
+ fputs(helpstr_buffer, stdout);
+ break;
+ case KTRACE:
+ fputs(helpstr_ktrace, stdout);
+ break;
+ case PFILTER:
+ fputs(helpstr_pfilter, stdout);
+ break;
+ case CLEAR:
+ fputs(helpstr_clear, stdout);
+ break;
+ case CONNECT:
+ fputs(helpstr_connect, stdout);
+ break;
+ default:
+ fputs("No help for this command\n", stdout);
+ break;
+ }
+
+} /* end help */
diff --git a/usr/src/cmd/tnf/prex/i386/Makefile b/usr/src/cmd/tnf/prex/i386/Makefile
new file mode 100644
index 0000000000..b57ca8205f
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/i386/Makefile
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/tnf/prex/sparc/Makefile
+
+include ../Makefile.com
+CFLAGS += -I.. -I.
+LINTFLAGS += -I.. -I.
+
+install: all $(ROOTPROG32)
diff --git a/usr/src/cmd/tnf/prex/list.c b/usr/src/cmd/tnf/prex/list.c
new file mode 100644
index 0000000000..cfecaeef9b
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/list.c
@@ -0,0 +1,571 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#ifndef DEBUG
+#define NDEBUG 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <search.h>
+
+#include "source.h"
+#include "queue.h"
+#include "list.h"
+#include "spec.h"
+#include "new.h"
+#include "fcn.h"
+
+extern caddr_t g_commitfunc;
+
+
+/*
+ * Typedefs
+ */
+
+typedef struct list_probe_args {
+ spec_t *speclist_p;
+ expr_t *exprlist_p;
+} list_probe_args_t;
+
+typedef struct list_attrs_args {
+ spec_t *speclist_p;
+ void *attrroot_p;
+} list_attrs_args_t;
+
+typedef struct attr_node {
+ char *name;
+ void *valsroot_p;
+} attr_node_t;
+
+typedef struct vals_node {
+ char *name;
+} vals_node_t;
+
+
+/*
+ * Globals
+ */
+
+
+/*
+ * Declarations
+ */
+
+static tnfctl_errcode_t listprobe(tnfctl_handle_t *hndl,
+ tnfctl_probe_t *ref_p, void *calldata_p);
+static tnfctl_errcode_t probescan(tnfctl_handle_t *hndl,
+ tnfctl_probe_t *ref_p, void *calldata_p);
+static void printattrval(spec_t * spec_p, char *attr, char *value,
+ void *pdata);
+static void attrscan(spec_t * spec_p, char *attr, char *values, void *pdata);
+static int attrcompare(const void *node1, const void *node2);
+static int valscompare(const void *node1, const void *node2);
+static void printattrs(const void *node, VISIT order, int level);
+static void printvals(const void *node, VISIT order, int level);
+
+#if 0
+static void attrnodedel(attr_node_t * an_p);
+#endif
+
+static void valadd(spec_t * spec_p, char *val, void *calldata_p);
+
+
+/* ---------------------------------------------------------------- */
+/* ----------------------- Public Functions ----------------------- */
+/* ---------------------------------------------------------------- */
+
+extern tnfctl_handle_t *g_hndl;
+
+/*
+ * list_set() - lists all of the current probes in a target process
+ */
+
+void
+list_set(spec_t * speclist_p, char *setname_p)
+{
+ set_t *set_p;
+ list_probe_args_t args;
+ tnfctl_errcode_t err;
+
+ set_p = set_find(setname_p);
+ if (!set_p) {
+ semantic_err(gettext("missing or invalid set"));
+ return;
+ }
+ args.speclist_p = speclist_p;
+ args.exprlist_p = set_p->exprlist_p;
+ err = tnfctl_probe_apply(g_hndl, listprobe, &args);
+ if (err) {
+ semantic_err(gettext("listing error : %s"),
+ tnfctl_strerror(err));
+ }
+}
+
+
+/*
+ * list_expr() - lists all of the current probes in an expression list
+ */
+
+void
+list_expr(spec_t * speclist_p, expr_t * expr_p)
+{
+ list_probe_args_t args;
+ tnfctl_errcode_t err;
+
+ args.speclist_p = speclist_p;
+ args.exprlist_p = expr_p;
+ err = tnfctl_probe_apply(g_hndl, listprobe, &args);
+ if (err) {
+ semantic_err(gettext("listing error : %s"),
+ tnfctl_strerror(err));
+ }
+}
+
+
+/*
+ * list_values() - list all the values for a supplied spec
+ */
+
+void
+list_values(spec_t * speclist_p)
+{
+ list_attrs_args_t args;
+ tnfctl_errcode_t err;
+
+ /* setup argument block */
+ args.speclist_p = speclist_p;
+ args.attrroot_p = NULL;
+
+ /* traverse the probes, recording attributes that match */
+ err = tnfctl_probe_apply(g_hndl, probescan, &args);
+ if (err) {
+ semantic_err(gettext("probe traversal error : %s"),
+ tnfctl_strerror(err));
+ }
+
+ /* pretty print the results */
+ twalk(args.attrroot_p, printattrs);
+
+ /* destroy the attribute tree */
+ while (args.attrroot_p) {
+ attr_node_t **aptr;
+ char *anameptr;
+
+ aptr = (attr_node_t **) args.attrroot_p;
+
+ /* destroy the value tree */
+ while ((*aptr)->valsroot_p) {
+ vals_node_t **vptr;
+ char *vnameptr;
+
+ vptr = (vals_node_t **) (*aptr)->valsroot_p;
+ vnameptr = (*vptr)->name;
+#ifdef LEAKCHK
+ (void) fprintf(stderr, "freeing value \"%s\"\n",
+ vnameptr);
+#endif
+ (void) tdelete((void *) *vptr, &(*aptr)->valsroot_p,
+ valscompare);
+ if (vnameptr) free(vnameptr);
+ }
+
+ anameptr = (*aptr)->name;
+#ifdef LEAKCHK
+ (void) fprintf(stderr, "freeing attr \"%s\"\n", anameptr);
+#endif
+ (void) tdelete((void *) *aptr, &args.attrroot_p, attrcompare);
+ if (anameptr) free(anameptr);
+ }
+
+} /* end list_values */
+
+
+/*
+ * list_getattrs() - build an attribute string for this probe.
+ */
+
+
+#define BUF_LIMIT 2048
+
+char *
+list_getattrs(tnfctl_probe_t *probe_p)
+{
+ tnfctl_errcode_t err;
+ tnfctl_probe_state_t p_state;
+ char *attrs;
+ char buffer[BUF_LIMIT];
+ char *buf_p;
+ char *buf_end;
+ int str_len;
+ size_t len;
+
+ err = tnfctl_probe_state_get(g_hndl, probe_p, &p_state);
+ if (err) {
+ attrs = malloc(2);
+ if (attrs)
+ attrs[0] = '\0';
+ return (attrs);
+ }
+
+ buf_p = buffer;
+ buf_end = buf_p + BUF_LIMIT;
+ str_len = sprintf(buf_p, "enable %s; trace %s; ",
+ (p_state.enabled) ? "on" : "off",
+ (p_state.traced) ? "on" : "off");
+ buf_p += str_len;
+ if (p_state.obj_name) {
+ str_len = strlen(p_state.obj_name);
+ if (buf_p + str_len < buf_end) {
+ str_len = sprintf(buf_p, "object %s; ",
+ p_state.obj_name);
+ buf_p += str_len;
+ }
+ }
+ str_len = sprintf(buf_p, "funcs");
+ buf_p += str_len;
+
+ /* REMIND: add limit for string size */
+ if (p_state.func_names) {
+ int i = 0;
+ char *fcnname;
+
+ while (p_state.func_names[i]) {
+ (void) strcat(buffer, " ");
+
+ fcnname = fcn_findname(p_state.func_names[i]);
+ if (fcnname) {
+ (void) strcat(buffer, "&");
+ (void) strcat(buffer, fcnname);
+ } else
+ (void) strcat(buffer, p_state.func_names[i]);
+ i++;
+ }
+ }
+
+ (void) strcat(buffer, ";");
+
+ len = strlen(buffer) + strlen(p_state.attr_string) + 1;
+ attrs = (char *) malloc(len);
+
+ if (attrs) {
+ (void) strcpy(attrs, buffer);
+ (void) strcat(attrs, p_state.attr_string);
+ }
+
+ return (attrs);
+}
+
+
+/* ---------------------------------------------------------------- */
+/* ----------------------- Private Functions ---------------------- */
+/* ---------------------------------------------------------------- */
+
+/*
+ * probescan() - function used as a callback, gathers probe attributes and
+ * values
+ */
+/*ARGSUSED*/
+static tnfctl_errcode_t
+probescan(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p)
+{
+ list_attrs_args_t *args_p = (list_attrs_args_t *) calldata_p;
+ spec_t *speclist_p;
+ spec_t *spec_p;
+ char *attrs;
+
+ speclist_p = args_p->speclist_p;
+ spec_p = NULL;
+
+ attrs = list_getattrs(ref_p);
+
+ while (spec_p = (spec_t *) queue_next(&speclist_p->qn, &spec_p->qn)) {
+ spec_attrtrav(spec_p, attrs, attrscan, calldata_p);
+ }
+
+ if (attrs)
+ free(attrs);
+
+ return (TNFCTL_ERR_NONE);
+}
+
+
+/*
+ * attrscan() - called on each matching attr/values component
+ */
+
+/*ARGSUSED*/
+static void
+attrscan(spec_t * spec_p,
+ char *attr,
+ char *values,
+ void *pdata)
+{
+ list_attrs_args_t *args_p = (list_attrs_args_t *) pdata;
+ attr_node_t *an_p;
+ attr_node_t **ret_pp;
+ static spec_t *allspec = NULL;
+
+ if (!allspec)
+ allspec = spec(".*", SPEC_REGEXP);
+
+ an_p = new(attr_node_t);
+
+#ifdef LEAKCHK
+ (void) fprintf(stderr, "creating attr \"%s\"\n", attr);
+#endif
+ an_p->name = strdup(attr);
+ an_p->valsroot_p = NULL;
+
+ ret_pp = tfind((void *) an_p, &args_p->attrroot_p, attrcompare);
+
+ if (ret_pp) {
+ /*
+ * we already had a node for this attribute; delete ours *
+ * and point at the original instead.
+ */
+#ifdef LEAKCHK
+ (void) fprintf(stderr, "attr already there \"%s\"\n", attr);
+#endif
+ if (an_p->name)
+ free(an_p->name);
+ free(an_p);
+
+ an_p = *ret_pp;
+ } else {
+ (void) tsearch((void *) an_p, &args_p->attrroot_p, attrcompare);
+ }
+
+ spec_valtrav(allspec, values, valadd, (void *) an_p);
+
+} /* end attrscan */
+
+
+/*
+ * valadd() - add vals to an attributes tree
+ */
+
+/*ARGSUSED*/
+static void
+valadd(spec_t * spec_p,
+ char *val,
+ void *calldata_p)
+{
+ attr_node_t *an_p = (attr_node_t *) calldata_p;
+
+ vals_node_t *vn_p;
+ vals_node_t **ret_pp;
+
+ vn_p = new(vals_node_t);
+#ifdef LEAKCHK
+ (void) fprintf(stderr, "creating value \"%s\"\n", val);
+#endif
+ vn_p->name = strdup(val);
+
+ ret_pp = tfind((void *) vn_p, &an_p->valsroot_p, valscompare);
+
+ if (ret_pp) {
+ /* we already had a node for this value */
+#ifdef LEAKCHK
+ (void) fprintf(stderr, "value already there \"%s\"\n", val);
+#endif
+ if (vn_p->name)
+ free(vn_p->name);
+ free(vn_p);
+ } else {
+ (void) tsearch((void *) vn_p, &an_p->valsroot_p, valscompare);
+ }
+
+
+} /* end valadd */
+
+
+/*
+ * attrcompare() - compares attribute nodes, alphabetically
+ */
+
+static int
+attrcompare(const void *node1,
+ const void *node2)
+{
+ return strcmp(((attr_node_t *) node1)->name,
+ ((attr_node_t *) node2)->name);
+
+} /* end attrcompare */
+
+
+/*
+ * valscompare() - compares attribute nodes, alphabetically
+ */
+
+static int
+valscompare(const void *node1,
+ const void *node2)
+{
+ return strcmp(((vals_node_t *) node1)->name,
+ ((vals_node_t *) node2)->name);
+
+} /* end valscompare */
+
+
+/*
+ * printattrs() - prints attributes from the attr tree
+ */
+
+/*ARGSUSED*/
+static void
+printattrs(const void *node,
+ VISIT order,
+ int level)
+{
+ attr_node_t *an_p = (*(attr_node_t **) node);
+
+ if (order == postorder || order == leaf) {
+ (void) printf("%s =\n", an_p->name);
+ twalk(an_p->valsroot_p, printvals);
+ }
+} /* end printattrs */
+
+
+/*
+ * printvals() - prints values from a value tree
+ */
+
+/*ARGSUSED*/
+static void
+printvals(const void *node,
+ VISIT order,
+ int level)
+{
+ vals_node_t *vn_p = (*(vals_node_t **) node);
+
+ if (order == postorder || order == leaf)
+ (void) printf(" %s\n", vn_p->name);
+
+} /* end printvals */
+
+
+#if 0
+/*
+ * attrnodedel() - deletes an attr_node_t after the action
+ */
+
+static void
+attrnodedel(attr_node_t * an_p)
+{
+ if (an_p->name)
+ free(an_p->name);
+
+ /* destroy the value tree */
+ while (an_p->valsroot_p) {
+ vals_node_t **ptr;
+
+ ptr = (vals_node_t **) an_p->valsroot_p;
+ (void) tdelete((void *) *ptr, &an_p->valsroot_p, valscompare);
+ }
+
+ /* We don't need to free this object, since tdelete() appears to */
+ /* free(an_p); */
+
+} /* end attrnodedel */
+#endif
+
+
+/*
+ * listprobe() - function used as a callback, pretty prints a probe
+ */
+/*ARGSUSED*/
+static tnfctl_errcode_t
+listprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p)
+{
+ static spec_t *default_speclist = NULL;
+ list_probe_args_t *args_p = (list_probe_args_t *) calldata_p;
+ spec_t *speclist_p;
+ spec_t *spec_p;
+ boolean_t sawattr;
+ char *attrs;
+
+ /* build a default speclist if there is not one built already */
+ if (!default_speclist) {
+ default_speclist = spec_list(
+ spec_list(
+ spec_list(
+ spec_list(
+ spec_list(
+ spec("name",
+ SPEC_EXACT),
+ spec("enable",
+ SPEC_EXACT)),
+ spec("trace", SPEC_EXACT)),
+ spec("file", SPEC_EXACT)),
+ spec("line", SPEC_EXACT)),
+ spec("funcs", SPEC_EXACT));
+ }
+ attrs = list_getattrs(ref_p);
+
+ if (expr_match(args_p->exprlist_p, attrs)) {
+ speclist_p = args_p->speclist_p;
+ speclist_p = (speclist_p) ? speclist_p : default_speclist;
+
+ spec_p = NULL;
+ while (spec_p = (spec_t *)
+ queue_next(&speclist_p->qn, &spec_p->qn)) {
+ sawattr = B_FALSE;
+ spec_attrtrav(spec_p, attrs, printattrval, &sawattr);
+ if (!sawattr)
+ (void) printf("<no attr> ");
+ }
+ (void) printf("\n");
+ }
+ if (attrs)
+ free(attrs);
+
+ return (TNFCTL_ERR_NONE);
+}
+
+
+/*ARGSUSED*/
+static void
+printattrval(spec_t * spec_p,
+ char *attr,
+ char *value,
+ void *pdata)
+{
+ boolean_t *bptr = (boolean_t *) pdata;
+
+ *bptr = B_TRUE;
+
+ (void) printf("%s=%s ", attr, (value && *value) ? value : "<no value>");
+
+} /* end printattrval */
diff --git a/usr/src/cmd/tnf/prex/list.h b/usr/src/cmd/tnf/prex/list.h
new file mode 100644
index 0000000000..ba131db951
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/list.h
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * Includes
+ */
+
+#include "expr.h"
+#include "set.h"
+
+#include <tnf/tnfctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Declarations
+ */
+void list_expr(spec_t *speclist_p, expr_t *expr_p);
+void list_set(spec_t *speclist_p, char *setname_p);
+void list_values(spec_t *speclist_p);
+
+char *list_getattrs(tnfctl_probe_t *ref_p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIST_H */
diff --git a/usr/src/cmd/tnf/prex/main.c b/usr/src/cmd/tnf/prex/main.c
new file mode 100644
index 0000000000..fa7be93ab2
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/main.c
@@ -0,0 +1,974 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <locale.h>
+#include <libintl.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/procfs.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <sys/systeminfo.h>
+
+#include <tnf/tnfctl.h>
+
+#include "set.h"
+#include "cmd.h"
+#include "spec.h"
+#include "expr.h"
+#include "source.h"
+#include "list.h"
+#include "prbk.h"
+
+/*
+ * Defines - Project private interfaces
+ */
+
+#define DEBUG_ENTRY "tnf_probe_debug"
+#ifdef TESTING
+#define EMPTY_ENTRY "tnf_probe_empty"
+#endif
+
+#define USER_OUTSIZE (4*1024*1024)
+#define KERNEL_OUTSIZE (384*1024)
+
+#if defined(__sparc)
+#define PREX32DIR "/sparcv7/"
+#elif defined(__i386) || defined(__amd64)
+#define PREX32DIR "/i86/"
+#endif
+#define PREX32EXEC "/usr/bin" PREX32DIR "prex"
+
+/*
+ * Globals
+ */
+
+char **g_argv; /* copy of argv pointer */
+tnfctl_handle_t *g_hndl; /* handle on target or kernel */
+
+static int g_verbose; /* debugging to stderr */
+static char *g_cmdname; /* target command name */
+static char **g_cmdargs; /* target command args */
+static pid_t g_targetpid; /* target process id */
+static volatile boolean_t g_getcmds; /* accept input flag */
+static boolean_t g_testflag; /* asserted in test mode */
+static char *g_preload; /* objects to preload */
+static char *g_outname; /* tracefile name */
+static char *tracefile; /* tracefile name used by list cmd */
+int g_outsize; /* tracefile size */
+boolean_t g_kernelmode; /* -k flag: kernel mode */
+static int prex_dmodel; /* prex data model */
+/*
+ * Local Declarations
+ */
+
+static void usage(char **argv, const char *msg);
+static void scanargs(int argc, char **argv);
+static int set_signal(void);
+static int get_data_model(pid_t pid);
+static int get_elf_class(char *filename);
+static int get_executable(char *);
+static void prex_isaexec(char **argv, char **envp);
+static void check_pid_model(char **argv, char **envp);
+static void check_exec_model(char **argv, char **envp);
+
+/* #### - FIXME - need to put this in a private header file */
+extern void err_fatal(char *s, ...);
+
+extern int yyparse(void);
+
+static tnfctl_errcode_t check_trace_error(tnfctl_handle_t *hndl);
+static void set_default_cmd(void);
+static void get_commands(void);
+static tnfctl_errcode_t set_tracefile(tnfctl_handle_t *hndl);
+static tnfctl_errcode_t set_probe_discovery_callback(tnfctl_handle_t *hndl);
+static void * perprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p);
+static tnfctl_errcode_t perprobe2(tnfctl_handle_t *hndl,
+ tnfctl_probe_t *probe_p, void *ignored);
+static tnfctl_errcode_t percmd(expr_t *expr_p, cmd_kind_t kind, fcn_t *fcn_p,
+ boolean_t isnew, void *calldata_p);
+void quit(boolean_t killtarget, boolean_t runtarget);
+void cmd_listtracefile();
+
+
+/*
+ * usage() - gives a description of the arguments, and exits
+ */
+
+static void
+usage(char *argv[], const char *msg)
+{
+ if (msg)
+ (void) fprintf(stderr,
+ gettext("%s: %s\n"), argv[0], msg);
+
+ (void) fprintf(stderr, gettext(
+ "usage: %s [options] <cmd> [cmd-args...]\n"), argv[0]);
+ (void) fprintf(stderr, gettext(
+ "usage: %s [options] -p <pid>\n"), argv[0]);
+ (void) fprintf(stderr, gettext(
+ "usage: %s -s <kbytes-size> -k\n"), argv[0]);
+ (void) fprintf(stderr, gettext(
+ "options:\n"));
+ (void) fprintf(stderr, gettext(
+ " -o <outfilename> set trace output file name\n"));
+ (void) fprintf(stderr, gettext(
+ " -s <kbytes-size> set trace file size\n"));
+ (void) fprintf(stderr, gettext(
+ " -l <sharedobjs> shared objects to "
+ "be preloaded (cmd only)\n"));
+
+ exit(1);
+}
+
+
+/*
+ * main() -
+ */
+
+int
+main(int argc, char **argv, char **envp)
+{
+ tnfctl_errcode_t err = TNFCTL_ERR_NONE;
+ int sys_err;
+ tnfctl_trace_attrs_t trace_attrs;
+ tnfctl_event_t event = TNFCTL_EVENT_EINTR;
+ pid_t prex_pid;
+
+ /* internationalization stuff */
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ g_argv = argv;
+
+ prex_pid = getpid();
+#if defined(DEBUG)
+ fprintf(stderr, "### prex_pid = %d ###\n", prex_pid);
+#endif
+ prex_dmodel = get_data_model(prex_pid);
+#if defined(DEBUG)
+ fprintf(stderr, "### prex_dmodel = %d ###\n", prex_dmodel);
+#endif
+ scanargs(argc, argv);
+
+ if (g_kernelmode) {
+ /* prexing the kernel */
+ err = tnfctl_kernel_open(&g_hndl);
+ if (err) {
+ err_fatal(gettext(
+ "%s: trouble attaching to the kernel: %s\n"),
+ argv[0], tnfctl_strerror(err));
+ }
+ } else {
+ /* prexing a user process */
+ if (g_targetpid != 0) {
+ /* check data model */
+ check_pid_model(argv, envp);
+ /* attach case */
+ err = tnfctl_pid_open(g_targetpid, &g_hndl);
+ if (err == TNFCTL_ERR_NOLIBTNFPROBE) {
+ err_fatal(gettext(
+ "%s: missing symbols, is "
+ "libtnfprobe.so loaded in target?\n"),
+ argv[0], tnfctl_strerror(err));
+ } else if (err) {
+ err_fatal(gettext(
+ "%s: trouble attaching to target "
+ "process: %s\n"),
+ argv[0], tnfctl_strerror(err));
+ }
+ } else {
+ /* check elf class model */
+ check_exec_model(argv, envp);
+ /* exec case */
+ err = tnfctl_exec_open(g_cmdname, g_cmdargs, NULL,
+ g_preload, NULL, &g_hndl);
+ if (err == TNFCTL_ERR_NONE)
+ err = tnfctl_trace_attrs_get(g_hndl,
+ &trace_attrs);
+ if (err) {
+ err_fatal(gettext(
+ "%s: trouble creating target process: "
+ "%s\n"),
+ argv[0], tnfctl_strerror(err));
+ }
+ g_targetpid = trace_attrs.targ_pid;
+ }
+
+ sys_err = set_signal();
+ if (sys_err)
+ err_fatal(gettext(
+ "%s: trouble setting up signal handler: %s\n"),
+ argv[0], strerror(err));
+ }
+
+ /* initialize the source stack for the parser */
+ source_init();
+
+ if (!g_kernelmode) {
+ /* set the tracefile name and size */
+ err = set_tracefile(g_hndl);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: trouble initializing tracefile: %s\n"),
+ argv[0], tnfctl_strerror(err));
+ goto Cleanup;
+ }
+ err = check_trace_error(g_hndl);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: cannot read tracing status : %s\n"),
+ argv[0], tnfctl_strerror(err));
+ goto Cleanup;
+ }
+ }
+
+ /* accept commands from stdin the first time through */
+ g_getcmds = B_TRUE;
+
+ /* set up default aliases */
+ set_default_cmd();
+
+ /* set up creator/destructor function to call for new probes */
+ err = set_probe_discovery_callback(g_hndl);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: error in probe discovery : %s\n"),
+ argv[0], tnfctl_strerror(err));
+ goto Cleanup;
+ }
+
+ if (g_kernelmode) {
+ prbk_warn_pfilter_empty();
+ }
+
+ while (err == TNFCTL_ERR_NONE) {
+
+ if (g_kernelmode || g_getcmds) {
+ g_getcmds = B_FALSE;
+ get_commands();
+ }
+
+ if (!g_kernelmode && (g_getcmds == B_FALSE)) {
+ err = tnfctl_continue(g_hndl, &event, NULL);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: cannot continue target : %s\n"),
+ argv[0], tnfctl_strerror(err));
+ goto Cleanup;
+ }
+ }
+ err = check_trace_error(g_hndl);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: cannot read tracing status : %s\n"),
+ argv[0], tnfctl_strerror(err));
+ goto Cleanup;
+ }
+ if (!g_kernelmode) {
+ if (event == TNFCTL_EVENT_EXEC) {
+ (void) printf(gettext(
+ "Target process exec'd\n"));
+ quit(B_FALSE, B_TRUE); /* quit resume */
+ } else if (event == TNFCTL_EVENT_EXIT) {
+ /* target exited */
+ (void) fprintf(stderr, gettext(
+ "%s: target process exited\n"),
+ g_argv[0]);
+ goto Cleanup;
+ } else if (event == TNFCTL_EVENT_TARGGONE) {
+ /* target terminated */
+ (void) fprintf(stderr,
+ gettext("%s: target process disappeared (without calling exit)\n"),
+ g_argv[0]);
+ goto Cleanup;
+ }
+ }
+ }
+
+Cleanup:
+ err = tnfctl_close(g_hndl, TNFCTL_TARG_DEFAULT);
+ if (err)
+ (void) fprintf(stderr, gettext(
+ "%s: error on closing : %s\n"),
+ argv[0], tnfctl_strerror(err));
+
+ exit(0);
+
+ return (0);
+
+}
+
+/*
+ * check_trace_error() - checks whether there was an error in tracing
+ */
+static tnfctl_errcode_t
+check_trace_error(tnfctl_handle_t *hndl)
+{
+ tnfctl_trace_attrs_t trace_attrs;
+ tnfctl_errcode_t err;
+
+ err = tnfctl_trace_attrs_get(hndl, &trace_attrs);
+ if (err)
+ return (err);
+
+ if (trace_attrs.trace_buf_state == TNFCTL_BUF_BROKEN) {
+ (void) printf(gettext("Tracing shut down in target program "
+ "due to an internal error - Please restart prex "
+ "and target\n"));
+ }
+
+ return (TNFCTL_ERR_NONE);
+}
+
+/*
+ * set_default_cmd() - set the default debug entry and $all
+ */
+static void
+set_default_cmd(void)
+{
+ if (!g_kernelmode)
+ fcn(strdup("debug"), DEBUG_ENTRY);
+#ifdef TESTING
+ fcn(strdup("empty"), EMPTY_ENTRY);
+#endif
+ (void) set(strdup("all"), expr(spec(strdup("keys"), SPEC_EXACT),
+ spec(strdup(".*"), SPEC_REGEXP)));
+
+}
+
+/*
+ * process() - enable and disable selected probes
+ */
+
+typedef struct {
+ tnfctl_probe_t *probe_p;
+ tnfctl_handle_t *hndl;
+} process_args_t;
+
+static tnfctl_errcode_t
+percmd(expr_t *expr_p, cmd_kind_t kind, fcn_t *fcn_p, boolean_t isnew,
+ void *calldata_p)
+{
+ process_args_t *args_p = (process_args_t *)calldata_p;
+ tnfctl_handle_t *hndl = args_p->hndl;
+ tnfctl_probe_t *probe_p = args_p->probe_p;
+ tnfctl_errcode_t err = TNFCTL_ERR_NONE;
+ char *attrs;
+
+ attrs = list_getattrs(probe_p);
+
+ if (expr_match(expr_p, attrs)) {
+#if defined(DEBUG) || defined(lint)
+ if (g_verbose) {
+ char *cmdstr[] = {
+ "enable", "disable",
+ "connect", "clear",
+ "trace", "untrace"};
+
+ (void) fprintf(stderr, ": %s command: %s ",
+ (isnew) ? "new" : "old", cmdstr[kind]);
+ expr_print(stderr, expr_p);
+ }
+#endif
+
+ switch (kind) {
+ case CMD_ENABLE:
+ err = tnfctl_probe_enable(hndl, probe_p, NULL);
+ break;
+ case CMD_DISABLE:
+ err = tnfctl_probe_disable(hndl, probe_p, NULL);
+ break;
+ case CMD_TRACE:
+ err = tnfctl_probe_trace(hndl, probe_p, NULL);
+ break;
+ case CMD_UNTRACE:
+ err = tnfctl_probe_untrace(hndl, probe_p, NULL);
+ break;
+ case CMD_CONNECT:
+ err = tnfctl_probe_connect(hndl, probe_p, NULL,
+ fcn_p->entry_name_p);
+ break;
+ case CMD_CLEAR:
+ err = tnfctl_probe_disconnect_all(hndl, probe_p, NULL);
+ break;
+ }
+
+#if defined(DEBUG) || defined(lint)
+ if (g_verbose)
+ (void) fprintf(stderr, "\n");
+#endif
+
+ }
+ if (attrs)
+ free(attrs);
+
+ return (err);
+
+}
+
+/*ARGSUSED*/
+static void *
+perprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p)
+{
+ process_args_t args;
+ tnfctl_errcode_t err;
+
+ args.probe_p = probe_p;
+ args.hndl = hndl;
+ err = cmd_traverse(percmd, &args);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: error on new (dlopened) probe : %s\n"),
+ g_argv[0], tnfctl_strerror(err));
+ }
+ return (NULL);
+}
+
+static tnfctl_errcode_t
+set_probe_discovery_callback(tnfctl_handle_t *hndl)
+{
+ tnfctl_errcode_t err;
+
+ err = tnfctl_register_funcs(hndl, perprobe, NULL);
+ if (err)
+ return (err);
+
+ return (TNFCTL_ERR_NONE);
+}
+
+static tnfctl_errcode_t
+perprobe2(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p, void *cd)
+{
+ cmd_t *cmd = cd;
+ process_args_t args;
+ tnfctl_errcode_t err;
+
+ args.probe_p = probe_p;
+ args.hndl = hndl;
+ err = cmd_callback(cmd, percmd, &args);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: error on probe operation: %s\n"),
+ g_argv[0], tnfctl_strerror(err));
+ }
+ return (err);
+}
+
+void
+process_cmd(tnfctl_handle_t *hndl, cmd_t *cmd)
+{
+#if defined(DEBUG) || defined(lint)
+ if (g_verbose)
+ (void) fprintf(stderr, "processing commands\n");
+#endif
+ (void) tnfctl_probe_apply(hndl, perprobe2, cmd);
+}
+
+/*
+ * get_commands() - process commands from stdin
+ */
+static void
+get_commands(void)
+{
+ /* Read commands from STDIN */
+ if (g_kernelmode) {
+ (void) printf(gettext("Type \"help\" for help ...\n"));
+ } else {
+ if (g_testflag)
+ (void) printf("prex(%ld), target(%ld): ",
+ getpid(), g_targetpid);
+ (void) printf(gettext("Target process stopped\n"));
+ (void) printf(gettext(
+ "Type \"continue\" to resume the target, "
+ "\"help\" for help ...\n"));
+ }
+
+ while (yyparse());
+}
+
+
+/*
+ * quit() - called to quit the controlling process. The boolean argument
+ * specifies whether to terminate the target as well.
+ */
+
+void
+quit(boolean_t killtarget, boolean_t runtarget)
+{
+ tnfctl_errcode_t err;
+
+ if (killtarget && runtarget)
+ err = tnfctl_close(g_hndl, TNFCTL_TARG_DEFAULT);
+ else if (killtarget && !runtarget)
+ err = tnfctl_close(g_hndl, TNFCTL_TARG_KILL);
+ else if (!killtarget && runtarget)
+ err = tnfctl_close(g_hndl, TNFCTL_TARG_RESUME);
+ else if (!killtarget && !runtarget)
+ err = tnfctl_close(g_hndl, TNFCTL_TARG_SUSPEND);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "%s: trouble quitting : %s\n"),
+ g_argv[0], tnfctl_strerror(err));
+ exit(1);
+ }
+ exit(0);
+}
+
+
+/*
+ * scanargs() - processes the command line arguments
+ */
+
+#define strneq(s1, s2, n) (strncmp(s1, s2, n) == 0)
+
+static void
+scanargs(int argc,
+ char **argv)
+{
+ int c;
+#if defined(DEBUG) || defined(lint)
+ char *optstr = "l:o:p:s:tkv:"; /* debugging options */
+#else
+ char *optstr = "l:o:p:s:tk"; /* production options */
+#endif
+
+ /* set up some defaults */
+ g_targetpid = 0;
+ g_cmdname = NULL;
+ g_cmdargs = NULL;
+ g_preload = NULL;
+ g_outname = NULL;
+ g_outsize = -1;
+
+ while ((c = getopt(argc, argv, optstr)) != EOF) {
+ switch (c) {
+ case 'l': /* preload objects */
+ g_preload = optarg;
+ break;
+ case 'o': /* tracefile name */
+ g_outname = optarg;
+ break;
+ case 'p': /* target pid (attach case) */
+ g_targetpid = atoi(optarg);
+ break;
+ case 's': /* tracefile size */
+ g_outsize = atoi(optarg) * 1024;
+ break;
+ case 't': /* test flag */
+ g_testflag = B_TRUE;
+ (void) setvbuf(stdout, NULL, _IOLBF, 0);
+ break;
+ case 'k': /* kernel mode */
+ g_kernelmode = B_TRUE;
+ break;
+#if defined(DEBUG) || defined(lint)
+ case 'v': /* verbose flag */
+ g_verbose = atoi(optarg);
+ break;
+#endif
+ case '?': /* error case */
+ usage(argv, gettext("unrecognized argument"));
+ }
+ }
+
+ if (optind < argc) {
+ g_cmdname = strdup(argv[optind]);
+ g_cmdargs = &argv[optind];
+ }
+ /* sanity clause */
+ if (!g_kernelmode && (g_cmdname == NULL && g_targetpid == 0))
+ usage(argv, gettext("need to specify cmd or pid"));
+ if (g_cmdname != NULL && g_targetpid != 0)
+ usage(argv, gettext("can't specify both cmd and pid"));
+ if (g_targetpid && g_preload)
+ usage(argv, gettext("can't use preload option with attach"));
+ if (g_kernelmode) {
+ if (g_outname)
+ usage(argv, "can't specify a filename in kernel mode");
+ if (g_cmdname)
+ usage(argv, "can't specify a command in kernel mode");
+ if (g_targetpid)
+ usage(argv, "can't specify pid in kernel mode");
+ if (g_preload)
+ usage(argv, "can't use preload option in kernel mode");
+ }
+ /* default output size */
+ if (g_outsize == -1)
+ g_outsize = g_kernelmode ? KERNEL_OUTSIZE : USER_OUTSIZE;
+
+#ifdef OLD
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strneq(argv[i], "-v", 2)) {
+ int vlevel;
+
+ vlevel = (strlen(argv[i]) > 2)? atoi(&argv[i][2]) : 1;
+ g_verbose = B_TRUE;
+ prb_verbose_set(vlevel);
+ } else if (strneq(argv[i], "-pid", 2)) {
+ if (++i >= argc)
+ usage(argv, gettext("missing pid argument"));
+ g_targetpid = atoi(argv[i]);
+ } else if (strneq(argv[i], "-t", 2)) {
+ g_testflag = B_TRUE;
+ (void) setvbuf(stdout, NULL, _IOLBF, 0);
+ } else if (argv[i][0] != '-') {
+ g_cmdname = strdup(argv[i]);
+ if (!g_cmdname) {
+ err_fatal(gettext(
+ "%s: out of memory"), argv[0]);
+ }
+ if (g_verbose >= 2) {
+ (void) fprintf(stderr,
+ "cmdname=%s\n", g_cmdname);
+ }
+ /*
+ * rest of arguments are the args to the executable -
+ * by convention argv[0] should be name of
+ * executable, so we don't increment i
+ */
+ g_cmdargs = &argv[i];
+ break;
+ } else {
+ usage(argv, gettext("unrecognized argument"));
+ }
+ }
+#endif
+
+} /* end scanargs */
+
+
+/*
+ * sig_handler() - cleans up if a signal is received
+ */
+
+/*ARGSUSED*/
+static void
+sig_handler(int signo)
+{
+ g_getcmds = B_TRUE;
+} /* end sig_handler */
+
+
+/*
+ * set_signal() - sets up function to call for clean up
+ */
+
+static int
+set_signal(void)
+{
+ struct sigaction newact;
+
+ newact.sa_handler = sig_handler;
+ (void) sigemptyset(&newact.sa_mask);
+ newact.sa_flags = 0;
+ if (sigaction(SIGINT, &newact, NULL) < 0) {
+ return (errno);
+ }
+ return (0);
+}
+
+
+/*
+ * set_tracefile() - initializes tracefile, sets the tracefile name and size
+ */
+static tnfctl_errcode_t
+set_tracefile(tnfctl_handle_t *hndl)
+{
+ tnfctl_errcode_t err;
+ tnfctl_trace_attrs_t attrs;
+ size_t minoutsize;
+ char path[MAXPATHLEN];
+ char *outfile_name;
+ char *tmpdir;
+
+ /* Init tracefile name used by list cmd */
+ tracefile = NULL;
+ err = tnfctl_trace_attrs_get(hndl, &attrs);
+ if (err)
+ return (err);
+
+ if (attrs.trace_buf_state == TNFCTL_BUF_BROKEN)
+ return (TNFCTL_ERR_BUFBROKEN);
+ if (attrs.trace_buf_state == TNFCTL_BUF_OK) {
+ /* trace file set already - can't change it */
+ return (TNFCTL_ERR_NONE);
+ }
+
+ minoutsize = attrs.trace_min_size;
+ if (g_outsize < minoutsize) {
+ (void) fprintf(stderr,
+ gettext("specified tracefile size smaller then "
+ "minimum; setting to %d kbytes\n"),
+ minoutsize / 1024);
+ g_outsize = minoutsize;
+ }
+
+ /* where is $TMPDIR? */
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir || *tmpdir == '\0') {
+ tmpdir = "/tmp";
+ }
+
+ /* do we have an absolute, relative or no pathname specified? */
+ if (g_outname == NULL) {
+ /* default, no tracefile specified */
+ if ((strlen(tmpdir) + 1 + 20) > (size_t)MAXPATHLEN) {
+ (void) fprintf(stderr, gettext(
+ "%s: $TMPDIR too long\n"), g_argv[0]);
+ exit(1);
+ }
+ (void) sprintf(path, "%s/trace-%ld", tmpdir, g_targetpid);
+ outfile_name = path;
+ } else {
+ /* filename specified */
+ outfile_name = g_outname;
+ }
+ tracefile = strdup(outfile_name);
+ if (tracefile == NULL) {
+ if ((errno == ENOMEM) || (errno == EAGAIN)) {
+ return (TNFCTL_ERR_ALLOCFAIL);
+ } else {
+ return (TNFCTL_ERR_INTERNAL);
+ }
+ }
+
+#if defined(DEBUG) || defined(lint)
+ if (g_verbose)
+ (void) fprintf(stderr,
+ "setting tracefile name=\"%s\", size=%d\n",
+ path, g_outsize);
+#endif
+ err = tnfctl_buffer_alloc(hndl, outfile_name, g_outsize);
+ return (err);
+}
+/*
+ * get_data_model() - get the process data model from psinfo
+ * structure.
+ */
+#define PROCFORMAT "/proc/%d"
+static int
+get_data_model(pid_t pid)
+{
+ char path[MAXPATHLEN];
+ int fd, dmodel = -1;
+ prpsinfo_t psinfo;
+
+ (void) sprintf(path, PROCFORMAT, (int)pid);
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return (dmodel);
+ if ((dmodel = ioctl(fd, PIOCPSINFO, &psinfo)) == -1)
+ return (dmodel);
+ return ((int)psinfo.pr_dmodel);
+}
+/*
+ * get_executable - return file descriptor for PATH-resolved
+ * target file.
+ *
+ */
+static int
+get_executable(char *name) {
+ int fd = -1;
+
+ if (name != NULL) {
+ char path[PATH_MAX + 1];
+ char line[MAX_INPUT + 1];
+ char *p = line;
+ char *fname = name;
+ int N = sizeof (line);
+ struct stat file_att;
+
+ while (*fname == ' ') fname++;
+ if (fname[0] == '-' || strchr(fname, '/')) {
+ fd = open(fname, O_RDONLY);
+ } else {
+ int len = strlen(fname);
+ char *dirlist = getenv("PATH");
+ char *dir = NULL;
+
+ if (dirlist != NULL) {
+ dirlist = strdup(dirlist);
+ dir = strtok(dirlist, ":");
+ }
+ while (fd < 0 && dir != NULL) {
+ if ((strlen(dir) + len + 1) < sizeof (path)) {
+ strcat(strcat(strcpy(path, dir), "/"), fname);
+ fd = open(path, O_RDONLY);
+ }
+ dir = strtok(NULL, ":");
+ }
+ if (dirlist != NULL) free(dirlist);
+ }
+ if (fstat(fd, &file_att) || !S_ISREG(file_att.st_mode)) {
+ if (fd >= 0)
+ close(fd);
+ return (-1);
+ }
+ if (read(fd, p, 2) && p[0] == '#' && p[1] == '!') {
+ while (N-- > 1 && read(fd, p, 1) && *p != '\n')
+ p++;
+ *p = '\0';
+ close(fd);
+ return (get_executable(line));
+ }
+ if (fd >= 0) lseek(fd, 0, SEEK_SET);
+ } /* %$#@! cstyle complaint */
+ return (fd);
+}
+
+/*
+ * get_elf_class - get the target executable elf class
+ * i.e. ELFCLASS64 or ELFCLASS32.
+ */
+static int
+get_elf_class(char *filename)
+{
+ int elfclass = -1;
+ int elffd = get_executable(filename);
+ Elf *elf;
+ size_t size;
+ char *ident;
+ GElf_Ehdr ehdr;
+
+ if (elffd < 0)
+ return (elfclass);
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ (void) close(elffd);
+ return (elfclass);
+ }
+ elf = elf_begin(elffd, ELF_C_READ, (Elf *) 0);
+ /*
+ * verify information in file header
+ */
+ if (gelf_getehdr(elf, &ehdr) == (GElf_Ehdr *) 0) {
+ close(elffd);
+ return (elfclass);
+ }
+ ident = elf_getident(elf, &size);
+ if (ident[EI_CLASS] == ELFCLASS32)
+ elfclass = ELFCLASS32;
+ if (ident[EI_CLASS] == ELFCLASS64)
+ elfclass = ELFCLASS64;
+ close(elffd);
+ return (elfclass);
+}
+/*
+ * check_exec_model() - check the consistency between prex data model
+ * and target elf class and act accordingly
+ */
+static void
+check_exec_model(char **argv, char **envp)
+{
+ int elfclass;
+
+ elfclass = get_elf_class(g_cmdname);
+ if (((elfclass == ELFCLASS32) && (prex_dmodel == PR_MODEL_ILP32)) ||
+ ((elfclass == ELFCLASS64) && (prex_dmodel == PR_MODEL_LP64)))
+ return;
+ if ((prex_dmodel == PR_MODEL_ILP32) &&
+ (elfclass == ELFCLASS64)) {
+ (void) fprintf(stderr, gettext(
+ "Error: 32 bit prex can not exec 64 bit target\n"));
+ exit(1);
+ }
+ if ((prex_dmodel == PR_MODEL_LP64) &&
+ (elfclass == ELFCLASS32))
+ prex_isaexec(argv, envp);
+}
+
+/*
+ * check_pid_model() - check the consistency between prex data model
+ * and target data model and act accordingly
+ */
+static void
+check_pid_model(char **argv, char **envp)
+{
+ int dmodel;
+
+ dmodel = get_data_model(g_targetpid);
+ if (prex_dmodel == dmodel)
+ return;
+ if ((prex_dmodel == PR_MODEL_ILP32) &&
+ (dmodel == PR_MODEL_LP64)) {
+ (void) fprintf(stderr, gettext(
+ "Error: 32 bit prex can not exec 64 bit target\n"));
+ exit(1);
+ }
+ if ((prex_dmodel == PR_MODEL_LP64) &&
+ (dmodel == PR_MODEL_ILP32))
+ prex_isaexec(argv, envp);
+}
+/*
+ * prex_isaexec() - there is only one case this function get called
+ * 64 bit prex, 32 bit target, need to exec 32 bit
+ * prex here.
+ */
+static void
+prex_isaexec(char **argv, char **envp)
+{
+ char path[PATH_MAX + sizeof (PREX32DIR)];
+ strcat(strcat(strcpy(path, dirname(dirname(argv[0]))), PREX32DIR),
+ basename(argv[0]));
+ if (get_elf_class(path) != ELFCLASS32)
+ strcpy(path, PREX32EXEC);
+ argv[0] = path;
+ (void) execve(path, argv, envp);
+ (void) fprintf(stderr,
+ gettext("%s: execve(\"%s\") failed\n"),
+ argv[0], path);
+}
+void
+cmd_listtracefile()
+{
+
+ if (g_kernelmode) {
+ (void) fprintf(stderr,
+ gettext("There is no trace file in kernel mode!\n"));
+ } else {
+ (void) printf(gettext("Current trace file is: %s\n"), tracefile);
+ }
+}
diff --git a/usr/src/cmd/tnf/prex/new.c b/usr/src/cmd/tnf/prex/new.c
new file mode 100644
index 0000000000..e54276c7a3
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/new.c
@@ -0,0 +1,57 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include "new.h"
+
+
+/*
+ * new_alloc() - allocate and bail if neccessary
+ */
+
+void *
+new_alloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+
+ if (!ptr) {
+ (void) fprintf(stderr,
+ gettext("new; out of memory, aborting\n"));
+ abort();
+
+ }
+ return (ptr);
+
+} /* new_alloc */
diff --git a/usr/src/cmd/tnf/prex/new.h b/usr/src/cmd/tnf/prex/new.h
new file mode 100644
index 0000000000..73bd6fcb66
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/new.h
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _NEW_H
+#define _NEW_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Defines
+ */
+
+#define new(t) ((t *) (new_alloc(sizeof (t))))
+
+
+/*
+ * Declarations
+ */
+
+void *new_alloc(size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NEW_H */
diff --git a/usr/src/cmd/tnf/prex/prbk.c b/usr/src/cmd/tnf/prex/prbk.c
new file mode 100644
index 0000000000..5faf8a39bb
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/prbk.c
@@ -0,0 +1,387 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h> /* for strerror() */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/tnf.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <locale.h>
+
+#include "prbk.h"
+
+#include <tnf/tnfctl.h>
+
+extern tnfctl_handle_t *g_hndl;
+
+typedef struct _pidlist {
+ pid_t pid;
+ struct _pidlist *next;
+} pidlist_t;
+
+static boolean_t check_kernelmode(tnfctl_trace_attrs_t *attrs_p);
+
+static boolean_t
+check_kernelmode(tnfctl_trace_attrs_t *attrs_p)
+{
+ extern int g_kernelmode;
+ tnfctl_errcode_t err;
+
+ if (!g_kernelmode) {
+ (void) fprintf(stderr, gettext(
+ "This command is only available "
+ "in kernel mode (prex invoked with the -k flag)\n"));
+ return (B_TRUE);
+ }
+ if (attrs_p) {
+ err = tnfctl_trace_attrs_get(g_hndl, attrs_p);
+ if (err) {
+ (void) fprintf(stderr, gettext(
+ "error on checking trace attributes : %s\n"),
+ tnfctl_strerror(err));
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Print trace buffer status (is one allocated, and if so, how big is it.
+ */
+void
+prbk_buffer_list()
+{
+ tnfctl_trace_attrs_t attrs;
+
+ if (check_kernelmode(&attrs))
+ return;
+ if (attrs.trace_buf_state == TNFCTL_BUF_NONE) {
+ (void) printf(gettext("No trace buffer allocated\n"));
+ } else {
+ (void) printf(gettext("Trace buffer size is %d bytes\n"),
+ attrs.trace_buf_size);
+ if (attrs.trace_buf_state == TNFCTL_BUF_BROKEN) {
+ (void) printf(gettext("Tracing system has failed -- "
+ "tracing suspended\n"));
+ }
+ }
+}
+
+
+/*
+ * Allocate a trace buffer. Check for reasonable size; reject if there's
+ * already a buffer.
+ */
+void
+prbk_buffer_alloc(int size)
+{
+ tnfctl_errcode_t err;
+ tnfctl_trace_attrs_t attrs;
+
+ if (check_kernelmode(&attrs))
+ return;
+
+ if (attrs.trace_buf_state != TNFCTL_BUF_NONE) {
+ (void) fprintf(stderr,
+ gettext("There is already a buffer allocated\n"));
+ return;
+ }
+ if (size < attrs.trace_min_size) {
+ (void) fprintf(stderr, gettext(
+ "Size %d is less than the minimum buffer size of %d -- "
+ "buffer size set to %d bytes\n"),
+ size, attrs.trace_min_size, attrs.trace_min_size);
+ size = attrs.trace_min_size;
+ }
+
+ err = tnfctl_buffer_alloc(g_hndl, NULL, size);
+ if (err) {
+ (void) fprintf(stderr,
+ gettext("error in allocating buffer: %s\n"),
+ tnfctl_strerror(err));
+ return;
+ }
+
+ /* get the trace attributes again */
+ if (check_kernelmode(&attrs))
+ return;
+ (void) printf(gettext("Buffer of size %d bytes allocated\n"),
+ attrs.trace_buf_size);
+}
+
+
+/*
+ * Deallocate the kernel's trace buffer.
+ */
+void
+prbk_buffer_dealloc()
+{
+ tnfctl_errcode_t err;
+
+ if (check_kernelmode(NULL))
+ return;
+
+ err = tnfctl_buffer_dealloc(g_hndl);
+ switch (err) {
+ case (TNFCTL_ERR_NONE):
+ (void) printf(gettext("buffer deallocated\n"));
+ break;
+ case (TNFCTL_ERR_NOBUF):
+ (void) fprintf(stderr,
+ gettext("There is no buffer to deallocate\n"));
+ break;
+ case (TNFCTL_ERR_BADDEALLOC):
+ (void) fprintf(stderr,
+ gettext("Can't deallocate the buffer when "
+ "tracing is active\n"));
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("error in deleting buffer: %s\n"),
+ tnfctl_strerror(err));
+ break;
+ }
+}
+
+
+/*
+ * Process filter routines.
+ *
+ * Process id sets are encoded as "pidlists": a linked list of pids.
+ * In a feeble attempt at encapsulation, the pidlist_t type is private
+ * to this file; prexgram.y manipulates pidlists only as opaque handles.
+ */
+
+/*
+ * Add the given pid (new) to the pidlist (pl).
+ */
+void *
+prbk_pidlist_add(void *pl, int new)
+
+{
+ pidlist_t *npl = (pidlist_t *) malloc(sizeof (*npl));
+
+ if (npl == NULL) {
+ (void) fprintf(stderr,
+ gettext("Out of memory -- can't process pid %d\n"),
+ new);
+ return (pl);
+ }
+ npl->next = pl;
+ npl->pid = new;
+ return (npl);
+}
+
+/*
+ * Add the pids in the given pidlist to the process filter list.
+ * For each pid, check whether it's already in the filter list,
+ * and whether the process exists.
+ */
+void
+prbk_pfilter_add(void *pl)
+{
+ pidlist_t *ppl = (pidlist_t *) pl;
+ pidlist_t *tmp;
+ tnfctl_errcode_t err;
+
+ if (check_kernelmode(NULL))
+ return;
+ while (ppl != NULL) {
+ err = tnfctl_filter_list_add(g_hndl, ppl->pid);
+ if (err) {
+ (void) fprintf(stderr, gettext("Process %ld: %s\n"),
+ ppl->pid, tnfctl_strerror(err));
+ }
+ tmp = ppl;
+ ppl = ppl->next;
+ free(tmp);
+ }
+}
+
+/*
+ * Drop the pids in the given pidlist from the process filter list.
+ * For each pid, complain if it's not in the process filter list;
+ * and if the process no longer exists (and hence has already implicitly
+ * been dropped from the process filter list), say so.
+ */
+void
+prbk_pfilter_drop(void *pl)
+{
+ pidlist_t *ppl = (pidlist_t *) pl;
+ pidlist_t *tmp;
+ tnfctl_errcode_t err;
+
+ if (check_kernelmode(NULL))
+ return;
+
+ while (ppl != NULL) {
+ tmp = ppl;
+ err = tnfctl_filter_list_delete(g_hndl, tmp->pid);
+ switch (err) {
+ case (TNFCTL_ERR_NONE):
+ break;
+ case (TNFCTL_ERR_BADARG):
+ (void) fprintf(stderr,
+ gettext("Process %ld is not being traced\n"),
+ tmp->pid);
+ break;
+ case (TNFCTL_ERR_NOPROCESS):
+ (void) printf(gettext("Process %ld has exited\n"),
+ tmp->pid);
+ break;
+ default:
+ (void) fprintf(stderr, gettext("Process %ld: %s\n"),
+ tmp->pid, tnfctl_strerror(err));
+ break;
+ }
+ ppl = ppl->next;
+ free(tmp);
+ }
+}
+
+/*
+ * Turn process filter mode on or off. The process filter is maintained
+ * even when process filtering is off, but has no effect: all processes
+ * are traced.
+ */
+void
+prbk_set_pfilter_mode(boolean_t onoff)
+{
+ tnfctl_errcode_t err;
+
+ if (check_kernelmode(NULL))
+ return;
+ err = tnfctl_filter_state_set(g_hndl, onoff);
+ if (err) {
+ (void) fprintf(stderr, gettext("pfilter: %s\n"),
+ tnfctl_strerror(err));
+ }
+}
+
+
+/*
+ * Report whether process filter mode is currently on or off, and
+ * dump the current process filter set.
+ */
+void
+prbk_show_pfilter_mode()
+{
+ tnfctl_errcode_t err;
+ tnfctl_trace_attrs_t attrs;
+ pid_t *pids_p;
+ int i, pid_count;
+ pid_t *cur_pid;
+
+ if (check_kernelmode(&attrs))
+ return;
+ (void) printf(gettext("Process filtering is %s\n"),
+ attrs.filter_state ? "on" : "off");
+ err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count);
+ if (err) {
+ (void) fprintf(stderr,
+ gettext("error in getting process filter list: %s\n"),
+ tnfctl_strerror(err));
+ return;
+ }
+ (void) printf(gettext("Process filter set is "));
+ if (pid_count == 0)
+ (void) printf("empty.\n");
+ else {
+ (void) printf("{");
+ cur_pid = pids_p;
+ for (i = 0; i < pid_count; i++, cur_pid++) {
+ (void) printf("%ld%s", *cur_pid,
+ (i != (pid_count - 1)) ? ", " : "}\n");
+ }
+ }
+}
+
+/*
+ * Check for process filtering on with empty pid filter.
+ */
+void
+prbk_warn_pfilter_empty(void)
+{
+ tnfctl_errcode_t err;
+ pid_t *pids_p;
+ int pid_count;
+ tnfctl_trace_attrs_t attrs;
+
+ if (check_kernelmode(&attrs))
+ return;
+ if (attrs.filter_state) {
+ err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count);
+ if (err) {
+ (void) fprintf(stderr,
+ gettext("error in getting process filter list: %s\n"),
+ tnfctl_strerror(err));
+ return;
+ }
+ if (!pid_count)
+ (void) fprintf(stderr,
+ gettext("Warning: Process filtering on, \
+but pid filter list is empty\n"));
+ }
+}
+
+
+/*
+ * Turn kernel tracing on or off.
+ */
+void
+prbk_set_tracing(boolean_t onoff)
+{
+ tnfctl_errcode_t err;
+
+ if (check_kernelmode(NULL))
+ return;
+
+ err = tnfctl_trace_state_set(g_hndl, onoff);
+ if (err) {
+ (void) fprintf(stderr,
+ gettext("error in setting tracing state: %s\n"),
+ tnfctl_strerror(err));
+ }
+}
+
+/*
+ * Show whether kernel tracing is currently on or off.
+ */
+void
+prbk_show_tracing()
+{
+ tnfctl_trace_attrs_t attrs;
+
+ if (check_kernelmode(&attrs))
+ return;
+ (void) printf(gettext("Tracing is %s\n"),
+ attrs.trace_state ? "on" : "off");
+}
diff --git a/usr/src/cmd/tnf/prex/prbk.h b/usr/src/cmd/tnf/prex/prbk.h
new file mode 100644
index 0000000000..7b3e0fdb66
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/prbk.h
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _PRBK_H
+#define _PRBK_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Declarations
+ */
+
+void prbk_buffer_list(void);
+void prbk_buffer_alloc(int size);
+void prbk_buffer_dealloc(void);
+void *prbk_pidlist_add(void *, int);
+void prbk_pfilter_add(void *);
+void prbk_pfilter_drop(void *);
+void prbk_set_pfilter_mode(boolean_t);
+void prbk_show_pfilter_mode(void);
+void prbk_set_tracing(boolean_t);
+void prbk_show_tracing(void);
+void prbk_warn_pfilter_empty(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PRBK_H */
diff --git a/usr/src/cmd/tnf/prex/prexgram.y b/usr/src/cmd/tnf/prex/prexgram.y
new file mode 100644
index 0000000000..3dbe9495fb
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/prexgram.y
@@ -0,0 +1,382 @@
+%{
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+%}
+
+%token ADD
+%token ALLOC
+%token BUFFER
+%token CLEAR
+%token COMMA
+%token CONNECT
+%token DEALLOC
+%token DELETE
+%token FILTER
+%token CONTINUE
+%token CREATE
+%token DISABLE
+%token ENABLE
+%token EQ
+%token FCNNAME
+%token FCNS
+%token ON
+%token OFF
+%token HELP
+%token KTRACE
+%token HISTORY
+%token IDENT
+%token INVAL
+%token KILL
+%token LIST
+%token NL
+%token PFILTER
+%token PROBES
+%token QUIT
+%token REGEXP
+%token RESUME
+%token SCALED_INT
+%token SETNAME
+%token SETS
+%token SOURCE
+%token SUSPEND
+%token TRACE
+%token TRACEFILE
+%token UNTRACE
+%token VALSTR
+%token VALUES
+
+%{
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "set.h"
+#include "cmd.h"
+#include "fcn.h"
+#include "list.h"
+#include "expr.h"
+#include "spec.h"
+#include "source.h"
+#include "prbk.h"
+
+extern int yylex();
+
+extern void help_on_topic(char *topic);
+extern void help_on_command(int cmd);
+extern boolean_t g_kernelmode;
+extern tnfctl_handle_t *g_hndl;
+
+void quit(boolean_t killtarget, boolean_t runtarget);
+extern void help(void);
+extern void process_cmd(tnfctl_handle_t *hndl, cmd_t *cmd);
+extern void cmd_listtracefile();
+%}
+
+%union
+{
+ char * strval;
+ expr_t * exprval;
+ spec_t * specval;
+ void * pidlistval;
+ int intval;
+}
+
+%type <strval> SETNAME FCNNAME IDENT VALSTR REGEXP
+%type <intval> CONTINUE DISABLE ENABLE HELP LIST QUIT SOURCE TRACE UNTRACE BUFFER KTRACE PFILTER CLEAR CONNECT command
+%type <exprval> expr exprlist
+%type <specval> spec speclist
+%type <pidlistval> pidlist
+%type <intval> SCALED_INT singlepid
+
+%%
+
+file : statement_list
+ ;
+
+statement_list : /* empty */ { prompt(); }
+ | statement_list statement
+ {
+ if (g_kernelmode)
+ prbk_warn_pfilter_empty();
+ prompt();
+ }
+ ;
+
+statement : empty_statement
+ | help_statement
+ | continue_statement
+ | quit_statement
+ | enable_statement
+ | disable_statement
+ | trace_statement
+ | untrace_statement
+ | connect_statement
+ | clear_statement
+ | pfilter_statement
+ | ktrace_statement
+ | buffer_statement
+ | create_statement
+ | source_statement
+ | listsets_statement
+ | listhistory_statement
+ | listtracefile_statement
+ | listfcns_statement
+ | listprobes_statement
+ | listvalues_statement
+ | error NL { yyerrok; }
+ ;
+
+empty_statement : NL
+ ;
+
+command : CONTINUE { $$ = $1; } /* user&kernel */
+ | DISABLE { $$ = $1; }
+ | ENABLE { $$ = $1; }
+ | HELP { $$ = $1; }
+ | LIST { $$ = $1; }
+ | QUIT { $$ = $1; }
+ | SOURCE { $$ = $1; }
+ | TRACE { $$ = $1; }
+ | UNTRACE { $$ = $1; }
+ | BUFFER { $$ = $1; } /* kernel only */
+ | KTRACE { $$ = $1; }
+ | PFILTER { $$ = $1; }
+ | CLEAR { $$ = $1; } /* user only */
+ | CONNECT { $$ = $1; }
+ ;
+
+help_statement : HELP NL { help(); }
+ | HELP command NL { help_on_command($2); }
+ | HELP IDENT NL { help_on_topic($2); }
+ ;
+
+continue_statement : CONTINUE NL
+ {
+ if (!g_kernelmode) YYACCEPT;
+ }
+ ;
+
+quit_statement : QUIT NL { quit(B_TRUE, B_TRUE); }
+ | QUIT KILL NL { quit(B_TRUE, B_FALSE); }
+ | QUIT RESUME NL { quit(B_FALSE, B_TRUE); }
+ | QUIT SUSPEND NL { quit(B_FALSE, B_FALSE); }
+ ;
+
+enable_statement : ENABLE SETNAME NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_set($2, CMD_ENABLE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ | ENABLE exprlist NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_expr($2, CMD_ENABLE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ ;
+
+disable_statement : DISABLE SETNAME NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_set($2, CMD_DISABLE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ | DISABLE exprlist NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_expr($2, CMD_DISABLE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ ;
+
+trace_statement : TRACE SETNAME NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_set($2, CMD_TRACE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ | TRACE exprlist NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_expr($2, CMD_TRACE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ ;
+
+untrace_statement : UNTRACE SETNAME NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_set($2, CMD_UNTRACE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ | UNTRACE exprlist NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_expr($2, CMD_UNTRACE, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ ;
+
+connect_statement : CONNECT FCNNAME SETNAME NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_set($3, CMD_CONNECT, $2);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ | CONNECT FCNNAME exprlist NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_expr($3, CMD_CONNECT, $2);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ ;
+
+clear_statement : CLEAR SETNAME NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_set($2, CMD_CLEAR, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ | CLEAR exprlist NL
+ {
+ cmd_t *cmd_p;
+ cmd_p = cmd_expr($2, CMD_CLEAR, NULL);
+ if (cmd_p)
+ process_cmd(g_hndl, cmd_p);
+ }
+ ;
+
+create_statement : CREATE SETNAME exprlist NL { (void) set($2, $3); }
+ | CREATE FCNNAME IDENT NL { fcn($2, $3); }
+ ;
+
+source_statement : SOURCE VALSTR NL { source_file($2); }
+ | SOURCE IDENT NL { source_file($2); }
+ ;
+
+listsets_statement : LIST SETS NL { set_list(); }
+ ;
+
+listhistory_statement : LIST HISTORY NL { cmd_list(); }
+ ;
+
+listtracefile_statement : LIST TRACEFILE NL { cmd_listtracefile(); }
+ ;
+
+listfcns_statement : LIST FCNS NL { fcn_list(); }
+ ;
+
+ ;
+
+pfilter_statement : PFILTER ON NL
+ { prbk_set_pfilter_mode(B_TRUE); }
+ | PFILTER OFF NL
+ { prbk_set_pfilter_mode(B_FALSE); }
+ | PFILTER ADD pidlist NL
+ { prbk_pfilter_add($3); }
+ | PFILTER DELETE pidlist NL
+ { prbk_pfilter_drop($3); }
+ | PFILTER NL
+ { prbk_show_pfilter_mode(); }
+ ;
+
+ktrace_statement : KTRACE ON NL
+ { prbk_set_tracing(B_TRUE); }
+ | KTRACE OFF NL
+ { prbk_set_tracing(B_FALSE); }
+ | KTRACE NL
+ { prbk_show_tracing(); }
+ ;
+
+listprobes_statement : LIST speclist PROBES SETNAME NL
+ { list_set($2, $4); }
+ | LIST speclist PROBES exprlist NL
+ { list_expr($2, $4); }
+ ;
+
+listvalues_statement : LIST VALUES speclist NL { list_values($3); }
+ ;
+
+exprlist : /* empty */ { $$ = NULL; }
+ | exprlist expr { $$ = expr_list($1, $2); }
+ ;
+
+speclist : /* empty */ { $$ = NULL; }
+ | speclist spec { $$ = spec_list($1, $2); }
+ ;
+
+expr : spec EQ spec { $$ = expr($1, $3); }
+ | spec { $$ = expr(spec(strdup("keys"),
+ SPEC_EXACT), $1); }
+ ;
+
+spec : IDENT { $$ = spec($1, SPEC_EXACT); }
+ | VALSTR { $$ = spec($1, SPEC_EXACT); }
+ | REGEXP { $$ = spec($1, SPEC_REGEXP); }
+ ;
+
+pidlist : pidlist COMMA singlepid
+ { $$ = prbk_pidlist_add($1, $3); }
+ | singlepid
+ { $$ = prbk_pidlist_add(NULL, $1); }
+ ;
+
+singlepid : SCALED_INT
+ ;
+
+buffer_statement : BUFFER NL
+ {
+ prbk_buffer_list();
+ }
+ | BUFFER ALLOC NL
+ {
+ extern int g_outsize;
+ prbk_buffer_alloc(g_outsize);
+ }
+ | BUFFER ALLOC SCALED_INT NL
+ {
+ prbk_buffer_alloc($3);
+ }
+ | BUFFER DEALLOC NL
+ {
+ prbk_buffer_dealloc();
+ }
+ ;
+
+
+%%
diff --git a/usr/src/cmd/tnf/prex/prexlex.l b/usr/src/cmd/tnf/prex/prexlex.l
new file mode 100644
index 0000000000..c307c429a9
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/prexlex.l
@@ -0,0 +1,169 @@
+%{
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+%}
+
+%a 10000
+%o 10000
+
+%{
+#include "spec.h"
+#include "expr.h"
+#include "y.tab.h"
+#include <stdlib.h>
+#include <string.h>
+
+char * qtstr (char * instr);
+char * rgstr (char * instr);
+
+/*
+** we substitute i/o routines defined in main.c for the
+** standard fare. This allows us to support the "source"
+** function by redirecting the input stream from different
+** places
+*/
+#include "source.h"
+#undef input
+#undef unput
+#undef output
+#define input() source_input()
+#define unput(c) source_unput(c)
+#define output(c) source_output(c)
+%}
+
+IDFIRST [a-zA-Z_\.%]
+IDCHAR ({IDFIRST}|[0-9])
+ID {IDFIRST}{IDCHAR}*
+
+%%
+
+#.* ; /* eat comments */
+[ \t]+ ; /* eats whitespace */
+
+\n { source_nl(); return NL; }
+\\\n { source_nl(); } /* escaped newline */
+= return (EQ);
+\, return (COMMA);
+
+add { yylval.intval = ADD; return (ADD); }
+alloc { yylval.intval = ALLOC; return (ALLOC); }
+buffer { yylval.intval = BUFFER; return (BUFFER); }
+clear { yylval.intval = CLEAR; return (CLEAR); }
+connect { yylval.intval = CONNECT; return (CONNECT); }
+continue { yylval.intval = CONTINUE; return (CONTINUE); }
+create { yylval.intval = CREATE; return (CREATE); }
+dealloc { yylval.intval = DEALLOC; return (DEALLOC); }
+delete { yylval.intval = DELETE; return (DELETE); }
+disable { yylval.intval = DISABLE; return (DISABLE); }
+enable { yylval.intval = ENABLE; return (ENABLE); }
+fcns { yylval.intval = FCNS; return (FCNS); }
+filter { yylval.intval = FILTER; return (FILTER); }
+help { yylval.intval = HELP; return (HELP); }
+history { yylval.intval = HISTORY; return (HISTORY); }
+tracefile { yylval.intval = TRACEFILE; return (TRACEFILE); }
+kill { yylval.intval = KILL; return (KILL); }
+ktrace { yylval.intval = KTRACE; return (KTRACE); }
+list { yylval.intval = LIST; return (LIST); }
+off { yylval.intval = OFF; return (OFF); }
+on { yylval.intval = ON; return (ON); }
+pfilter { yylval.intval = PFILTER; return (PFILTER); }
+probes { yylval.intval = PROBES; return (PROBES); }
+quit { yylval.intval = QUIT; return (QUIT); }
+resume { yylval.intval = RESUME; return (RESUME); }
+sets { yylval.intval = SETS; return (SETS); }
+source { yylval.intval = SOURCE; return (SOURCE); }
+suspend { yylval.intval = SUSPEND; return (SUSPEND); }
+trace { yylval.intval = TRACE; return (TRACE); }
+untrace { yylval.intval = UNTRACE; return (UNTRACE); }
+values { yylval.intval = VALUES; return (VALUES); }
+
+${ID} { yylval.strval = strdup(&yytext[1]); return SETNAME; }
+&{ID} { yylval.strval = strdup(&yytext[1]); return FCNNAME; }
+{ID} { yylval.strval = strdup(yytext); return IDENT; }
+\'[^'\n]*\' { yylval.strval = qtstr(yytext); return VALSTR; }
+
+\/([^/\\\n]|\\.)*\/ { yylval.strval = rgstr(yytext); return REGEXP; }
+
+[0-9]+[KkMm]? {
+ char scale = yytext[yyleng - 1];
+ yylval.intval = atoi(yytext);
+ if (scale == 'k' || scale == 'K')
+ yylval.intval *= 1024;
+ else if (scale == 'm' || scale == 'M')
+ yylval.intval *= 1024 * 1024;
+ return (SCALED_INT);
+ }
+
+. return (INVAL); /* barf on anything else */
+
+%%
+
+/****************************************************************
+qtstr() - shucks a quoted str, and copies it into new memory
+****************************************************************/
+
+char *
+qtstr (char * instr)
+{
+ char *ptr;
+ int indx;
+
+ /* skip the leading quote in the copy */
+ ptr = strdup(&instr[1]);
+
+ /* null out the trailing quote */
+ indx = strlen(ptr) - 1;
+ indx = (indx < 0) ? 0 : indx;
+ ptr[indx] = '\0';
+
+ return ptr;
+} /* end qtstr */
+
+
+/****************************************************************
+rgstr() - shucks a decorated regular expression, and copies it
+into new memory
+****************************************************************/
+
+char *
+rgstr (char * instr)
+{
+ char *ptr;
+ int indx;
+
+ /* skip the leading slash in the copy */
+ ptr = strdup(&instr[1]);
+
+ /* null out the trailing slash */
+ indx = strlen(ptr) - 1;
+ indx = (indx < 0) ? 0 : indx;
+ ptr[indx] = '\0';
+
+ return (ptr);
+
+} /* end rgstr */
+
+
diff --git a/usr/src/cmd/tnf/prex/queue.c b/usr/src/cmd/tnf/prex/queue.c
new file mode 100644
index 0000000000..c2e6867bce
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/queue.c
@@ -0,0 +1,154 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include "queue.h"
+#include "new.h"
+
+
+/*
+ * queue_init() - initializes a queue_node to be unlinked.
+ */
+
+void
+queue_init(queue_node_t * q)
+{
+ q->next_p = q->prev_p = q;
+
+} /* end queue_init */
+
+
+/*
+ * queue_prepend() - prepends a queue_node to another in a list
+ */
+
+queue_node_t *
+queue_prepend(queue_node_t * h, queue_node_t * q)
+{
+ if (!h)
+ return ((q) ? q : NULL);
+
+ if (q) {
+ queue_node_t *qtail_p = q->prev_p;
+ queue_node_t *hnode_p = h->next_p;
+
+ hnode_p->prev_p = qtail_p;
+ h->next_p = q;
+
+ q->prev_p = h;
+ qtail_p->next_p = hnode_p;
+ }
+ return (h);
+
+} /* end queue_prepend */
+
+
+/*
+ * queue_append() - appends a queue_node to another in a list
+ */
+
+queue_node_t *
+queue_append(queue_node_t * h, queue_node_t * q)
+{
+ if (!h)
+ return ((q) ? q : NULL);
+
+ if (q) {
+ queue_node_t *htail_p = h->prev_p;
+ queue_node_t *qtail_p = q->prev_p;
+
+ h->prev_p = qtail_p;
+ htail_p->next_p = q;
+
+ q->prev_p = htail_p;
+ qtail_p->next_p = h;
+ }
+ return (h);
+
+} /* end queue_append */
+
+
+/*
+ * queue_remove() - removes a node from a list, returns a pointer to the next
+ * node in the list.
+ */
+
+queue_node_t *
+queue_remove(queue_node_t * q)
+{
+ queue_node_t *n;
+
+ n = q->next_p;
+
+ if (queue_isempty(q))
+ return (NULL);
+
+ q->next_p->prev_p = q->prev_p;
+ q->prev_p->next_p = q->next_p;
+
+ q->next_p = q->prev_p = q;
+
+ return (n);
+
+} /* end queue_remove */
+
+
+/*
+ * queue_isempty()
+ */
+
+boolean_t
+queue_isempty(queue_node_t * q)
+{
+ return ((q->next_p == q));
+
+} /* queue_isempty */
+
+
+/*
+ * queue_next() - returns the next element in a queue, or NULL if the
+ * supplied previous item was the last.
+ */
+
+queue_node_t *
+queue_next(queue_node_t * h, queue_node_t * q)
+{
+ if (!h)
+ return (NULL);
+
+ if (!q)
+ return (h);
+
+ if (q->next_p == h)
+ return (NULL);
+
+ return (q->next_p);
+
+} /* end queue_next */
diff --git a/usr/src/cmd/tnf/prex/queue.h b/usr/src/cmd/tnf/prex/queue.h
new file mode 100644
index 0000000000..ee9529c0fa
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/queue.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _QUEUE_H
+#define _QUEUE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Typedefs
+ */
+
+typedef struct queue_node queue_node_t;
+struct queue_node {
+ queue_node_t *next_p;
+ queue_node_t *prev_p;
+};
+
+
+/*
+ * Declarations
+ */
+
+boolean_t queue_isempty(queue_node_t * q);
+queue_node_t *queue_prepend(queue_node_t * h, queue_node_t * q);
+queue_node_t *queue_append(queue_node_t * h, queue_node_t * q);
+void queue_init(queue_node_t * q);
+queue_node_t *queue_next(queue_node_t * h, queue_node_t * q);
+queue_node_t *queue_remove(queue_node_t * q);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _QUEUE_H */
diff --git a/usr/src/cmd/tnf/prex/set.c b/usr/src/cmd/tnf/prex/set.c
new file mode 100644
index 0000000000..db7f4fb29a
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/set.c
@@ -0,0 +1,181 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "queue.h"
+#include "set.h"
+#include "new.h"
+
+
+/*
+ * Globals
+ */
+
+static queue_node_t g_setlist = {
+ &g_setlist,
+&g_setlist};
+
+
+/*
+ * Forward Declarations
+ */
+
+static void set_destroy(set_t * set_p);
+static void set_print(FILE * stream, set_t * set_p);
+
+
+/*
+ * set() - creates a set
+ */
+
+set_t *
+set(char *setname_p, expr_t * exprlist_p)
+{
+ set_t *new_p;
+ set_t *old_p;
+
+ /* does this setname exist already? */
+ old_p = set_find(setname_p);
+ if (old_p)
+ set_destroy(old_p);
+
+ /* create a new set */
+ new_p = new(set_t);
+ queue_init(&new_p->qn);
+ new_p->setname_p = setname_p;
+ new_p->exprlist_p = exprlist_p;
+
+ /* append the new set to the global list */
+ (void) queue_append(&g_setlist, &new_p->qn);
+
+ return (new_p);
+
+} /* end set */
+
+
+/*
+ * set_destroy() - destroys a set and related resources
+ */
+
+static void
+set_destroy(set_t * set_p)
+{
+ if (!set_p)
+ return;
+
+ /* remove ourselves from any list */
+ if (!queue_isempty(&set_p->qn))
+ (void) queue_remove(&set_p->qn);
+
+ if (set_p->setname_p)
+ free(set_p->setname_p);
+
+ /* destroy the exprlist */
+ expr_destroy(set_p->exprlist_p);
+
+ free(set_p);
+
+} /* end set_destroy */
+
+
+/*
+ * set_list() - pretty prints the global setlist
+ */
+
+void
+set_list(void)
+{
+ set_t *set_p;
+
+ set_p = (set_t *) & g_setlist;
+ while ((set_p = (set_t *) queue_next(&g_setlist, &set_p->qn))) {
+ (void) printf("$%-8s ", set_p->setname_p);
+ set_print(stdout, set_p);
+ (void) printf("\n");
+ }
+
+} /* end set_list */
+
+
+/*
+ * set_print() - pretty prints a set
+ */
+
+static void
+set_print(FILE * stream, set_t * set_p)
+{
+ if (!set_p)
+ return;
+
+ expr_print(stream, set_p->exprlist_p);
+
+} /* end set_print */
+
+
+#ifdef OLD
+/*
+ * set_match() - discerns whether a probe is in a set
+ */
+
+boolean_t
+set_match(set_t * set_p, const char *name, const char *keys)
+{
+ if (!set_p)
+ return (B_FALSE);
+
+ return (expr_match(set_p->exprlist_p, name, keys));
+
+} /* end set_match */
+#endif
+
+
+/*
+ * set_find() - finds a set by name
+ */
+
+set_t *
+set_find(char *setname_p)
+{
+ set_t *set_p;
+
+ if (!setname_p)
+ return (NULL);
+
+ set_p = (set_t *) & g_setlist;
+ while ((set_p = (set_t *) queue_next(&g_setlist, &set_p->qn)))
+ if (strcmp(setname_p, set_p->setname_p) == 0)
+ return (set_p);
+
+ return (NULL);
+
+} /* end set_find */
diff --git a/usr/src/cmd/tnf/prex/set.h b/usr/src/cmd/tnf/prex/set.h
new file mode 100644
index 0000000000..a3bf53be9d
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/set.h
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _SET_H
+#define _SET_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "queue.h"
+#include "expr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Typedefs
+ */
+
+typedef struct set {
+ queue_node_t qn;
+ char *setname_p;
+ expr_t *exprlist_p;
+
+} set_t;
+
+
+/*
+ * Declarations
+ */
+
+set_t *set(char *name, expr_t * exprlist_p);
+void set_list(void);
+set_t *set_find(char *setname_p);
+boolean_t set_match(set_t * set_p, const char *name, const char *keys);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SET_H */
diff --git a/usr/src/cmd/tnf/prex/source.c b/usr/src/cmd/tnf/prex/source.c
new file mode 100644
index 0000000000..140c2bcecd
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/source.c
@@ -0,0 +1,307 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libintl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include "new.h"
+#include "queue.h"
+#include "source.h"
+
+
+/*
+ * Typedefs
+ */
+
+typedef struct source {
+ queue_node_t qn;
+ char *path;
+ FILE *instream;
+ int linenum;
+ boolean_t isatty;
+
+} source_t;
+
+
+/*
+ * Defines
+ */
+
+#define HOME "HOME"
+#define PREXRC ".prexrc"
+
+
+/*
+ * Globals
+ */
+
+static queue_node_t stack;
+static source_t *top;
+
+
+/*
+ * source_init() - initializes the source stack
+ */
+
+void
+source_init(void)
+{
+ source_t *new_p;
+ struct stat statbuf;
+ char *home;
+ int retval;
+
+
+ /* initialize the stack queue head */
+ queue_init(&stack);
+
+ /* stick the standard input on the bottom of the stack */
+ new_p = new(source_t);
+ queue_init(&new_p->qn);
+ new_p->path = strdup("<STDIN>");
+ new_p->instream = stdin;
+ new_p->linenum = 1;
+ new_p->isatty = isatty(fileno(new_p->instream));
+
+ (void) queue_prepend(&stack, &new_p->qn);
+ top = new_p;
+
+ /*
+ * since we are pushing onto a stack, we invert the search order *
+ * and push the prexrc in the current directory on next.
+ */
+ retval = stat(PREXRC, &statbuf);
+ if (retval != -1) {
+ source_file(PREXRC);
+ }
+ home = getenv(HOME);
+ if (home) {
+ char path[MAXPATHLEN];
+
+ if ((strlen(home) + strlen(PREXRC) + 2) < (size_t) MAXPATHLEN) {
+ (void) sprintf(path, "%s/%s", home, PREXRC);
+ retval = stat(path, &statbuf);
+ if (retval != -1) {
+ source_file(path);
+ }
+ }
+ }
+} /* end source_init */
+
+
+/*
+ * source_file() - pushes a new source onto the stack
+ */
+
+void
+source_file(char *path)
+{
+ FILE *newfile;
+ source_t *new_p;
+
+ newfile = fopen(path, "r");
+ if (!newfile) {
+ semantic_err(gettext("cannot open \"%s\""), path);
+ return;
+ }
+ new_p = new(source_t);
+ queue_init(&new_p->qn);
+ new_p->path = strdup(path);
+ new_p->instream = newfile;
+ new_p->linenum = 1;
+ new_p->isatty = isatty(fileno(new_p->instream));
+
+ (void) queue_prepend(&stack, &new_p->qn);
+ top = new_p;
+
+} /* end source_file */
+
+
+/*
+ * source_input() - lexical analyzer input routine
+ */
+
+extern void quit(boolean_t, boolean_t);
+
+int
+source_input(void)
+{
+ int c;
+
+ if (!top)
+ return (0);
+
+ c = getc(top->instream);
+
+ if (c == EOF) {
+ /*
+ * If we get an EOF at the top level, we quit if we are *
+ * non-interactive, pretend we saw a new-line if we are *
+ * interactive.
+ */
+ if (top->instream == stdin) {
+ if (top->isatty) {
+ source_output('\n');
+ return ('\n');
+ } else
+ quit(B_TRUE, B_TRUE);
+ }
+ /* we've exhausted the current stream, pop it, delete it ... */
+ if (top->path)
+ free(top->path);
+ (void) fclose(top->instream);
+ (void) queue_remove(&top->qn);
+ free(top);
+
+ /* point to the new top level i/o stream */
+ top = (source_t *) queue_next(&stack, &stack);
+
+ if (!top)
+ return (0);
+
+ /* trigger a prompt if neccessary */
+ prompt();
+ return (source_input());
+ }
+ return (c);
+
+} /* end source_input */
+
+
+/*
+ * source_unput() - lexical analyzer unput routine
+ */
+
+void
+source_unput(int c)
+{
+ if (top)
+ (void) ungetc(c, top->instream);
+
+} /* end source_unput */
+
+
+/*
+ * source_output() - lexical analyzer output routine
+ */
+
+void
+source_output(int c)
+{
+ (void) putc(c, stdout);
+
+} /* end source_output */
+
+
+/*
+ * source_nl() - increment the line counter
+ */
+
+void
+source_nl(void)
+{
+ if (top)
+ top->linenum++;
+
+} /* end source_nl */
+
+
+/*
+ * yyerror() -
+ */
+
+extern char yytext[];
+extern int g_linenum;
+
+void
+yyerror(char *s)
+{
+ (void) fprintf(stderr,
+ gettext("\"%s\", line %d: %s on or before \"%s\"\n"),
+ top->path, top->linenum, s, yytext);
+
+}
+
+
+/*
+ * yywrap() -
+ */
+
+int
+yywrap()
+{
+ return (1);
+
+} /* end yywrap */
+
+
+/*
+ * prompt() -
+ */
+
+extern char **g_argv;
+
+void
+prompt(void)
+{
+ if (top && top->isatty)
+ (void) printf("%s> ", g_argv[0]);
+
+} /* end g_prompt */
+
+
+/*
+ * semantic_err() - reports a semantic error
+ */
+
+void
+semantic_err(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ if (!top)
+ return;
+
+ (void) fprintf(stderr, gettext("\"%s\", line %d: semantic error: "),
+ top->path, top->linenum);
+ (void) vfprintf(stderr, format, ap);
+ (void) fprintf(stderr, gettext("\n"));
+
+} /* end semantic_err */
diff --git a/usr/src/cmd/tnf/prex/source.h b/usr/src/cmd/tnf/prex/source.h
new file mode 100644
index 0000000000..6979bf9f6c
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/source.h
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _SOURCE_H
+#define _SOURCE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Declarations
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void source_init(void);
+void source_file(char *path);
+int source_input(void);
+void source_unput(int c);
+void source_output(int c);
+void source_nl(void);
+
+void yyerror(char *s);
+void prompt(void);
+void
+semantic_err(char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SOURCE_H */
diff --git a/usr/src/cmd/tnf/prex/sparcv9/Makefile b/usr/src/cmd/tnf/prex/sparcv9/Makefile
new file mode 100644
index 0000000000..1b8392fdbe
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/sparcv9/Makefile
@@ -0,0 +1,36 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/tnf/prex/sparcv9/Makefile
+
+include ../Makefile.com
+include ../../../Makefile.cmd.64
+CFLAGS64 += -I.. -I.
+LINTFLAGS64 += -I.. -I.
+prexgram.o prexlex.o := CCVERBOSE=
+
+install: all $(ROOTPROG64)
diff --git a/usr/src/cmd/tnf/prex/spec.c b/usr/src/cmd/tnf/prex/spec.c
new file mode 100644
index 0000000000..159212d8e6
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/spec.c
@@ -0,0 +1,394 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+/* we need to define this to get strtok_r from string.h */
+/* SEEMS LIKE A BUG TO ME */
+#define _REENTRANT
+
+#ifndef DEBUG
+#define NDEBUG 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <regexpr.h>
+#include <assert.h>
+#include <sys/types.h>
+#include "spec.h"
+#include "new.h"
+#include "source.h"
+
+
+static boolean_t spec_match(spec_t * spec_p, char *str);
+
+/*
+ * Globals
+ */
+
+
+
+/*
+ * spec() - builds a spec
+ */
+
+spec_t *
+spec(char *str_p,
+ spec_type_t type)
+{
+ spec_t *new_p;
+
+ new_p = new(spec_t);
+ queue_init(&new_p->qn);
+ new_p->str = str_p;
+ new_p->type = type;
+ new_p->regexp_p = NULL;
+
+ if (type == SPEC_REGEXP) {
+ new_p->regexp_p = compile(str_p, NULL, NULL);
+ if (!new_p->regexp_p) {
+ semantic_err(gettext("invalid regular expression"));
+ free(new_p);
+ return (NULL);
+ }
+ }
+ return (new_p);
+
+} /* end spec */
+
+
+/*
+ * spec_dup() - duplicates a spec, NOT A SPEC LIST!
+ */
+
+spec_t *
+spec_dup(spec_t * spec_p)
+{
+ spec_t *new_p;
+
+ new_p = spec(strdup(spec_p->str), spec_p->type);
+
+ return (new_p);
+
+} /* end spec_dup */
+
+
+/*
+ * spec_destroy() - destroys a spec list
+ */
+
+void
+spec_destroy(spec_t * list_p)
+{
+ spec_t *spec_p;
+
+ while ((spec_p = (spec_t *) queue_next(&list_p->qn, &list_p->qn))) {
+ (void) queue_remove(&spec_p->qn);
+
+ if (spec_p->str)
+ free(spec_p->str);
+ if (spec_p->regexp_p)
+ free(spec_p->regexp_p);
+ free(spec_p);
+ }
+
+ if (list_p->str)
+ free(list_p->str);
+ if (list_p->regexp_p)
+ free(list_p->regexp_p);
+ free(list_p);
+
+} /* end spec_destroy */
+
+
+/*
+ * spec_list() - append a spec_t to a list
+ */
+
+spec_t *
+spec_list(spec_t * h,
+ spec_t * f)
+{
+ /* queue append handles the NULL cases OK */
+ return ((spec_t *) queue_append(&h->qn, &f->qn));
+
+} /* end spec_list */
+
+
+/*
+ * spec_print() - pretty prints a speclist
+ */
+
+void
+spec_print(FILE * stream,
+ spec_t * list_p)
+{
+ spec_t *spec_p = NULL;
+
+ while ((spec_p = (spec_t *) queue_next(&list_p->qn, &spec_p->qn))) {
+ switch (spec_p->type) {
+ case SPEC_EXACT:
+ (void) fprintf(stream, "'%s'", spec_p->str);
+ break;
+ case SPEC_REGEXP:
+ (void) fprintf(stream, "/%s/", spec_p->str);
+ break;
+ }
+ }
+
+} /* end spec_print */
+
+
+/*
+ * spec_match() - called with a spec and a string, returns whether they
+ * match.
+ */
+
+static boolean_t
+spec_match(spec_t * spec_p,
+ char *str)
+{
+ if (!spec_p)
+ return (B_FALSE);
+
+ switch (spec_p->type) {
+ case SPEC_EXACT:
+ return ((strcmp(spec_p->str, str) == 0));
+
+ case SPEC_REGEXP:
+ return ((step(str, spec_p->regexp_p) != NULL));
+ }
+
+ return (B_FALSE);
+
+} /* end spec_match */
+
+
+/*
+ * spec_attrtrav() - traverse an attribute list, calling the supplied
+ * function on each matching attribute.
+ */
+
+void
+spec_attrtrav(spec_t * spec_p,
+ char *attrs,
+ spec_attr_fun_t fun,
+ void *calldatap)
+{
+ char *lasts;
+ char *refptr = NULL;
+ char *escptr = NULL;
+ char *pair;
+ char *s;
+ boolean_t inquote = B_FALSE;
+
+ /*
+ * * STRATEGY - we make two copies of the attr string. In one *
+ * string we escape (translate) all relevant quoted characters to * a
+ * non-significant character. We use this string to feed to * strtok
+ * to do the parsing. * Once strtok has parsed the string, we use the
+ * same fragement * positions from the unescaped string to pass to
+ * the next level.
+ */
+
+ /* make two copies of the string */
+ refptr = strdup(attrs);
+ escptr = strdup(attrs);
+
+ /* escape any quoted ';'s in the escptr string */
+ for (s = escptr; *s; s++) {
+ switch (*s) {
+ case ';':
+ if (inquote)
+ *s = '#';
+ break;
+
+ case '\'':
+ inquote = (inquote) ? B_FALSE : B_TRUE;
+ break;
+
+ default:
+ /* nothing on purpose */
+ break;
+ }
+ }
+
+ /* loop over each attribute section separated by ';' */
+ for (pair = strtok_r(escptr, ";", &lasts); pair;
+ pair = strtok_r(NULL, ";", &lasts)) {
+ char *escattr;
+ char *escvals;
+ char *refattr;
+ char *refvals;
+ char emptystr[1];
+
+ escattr = strtok_r(pair, " \t", &escvals);
+
+ /*
+ * setup the ref pointers to the same locations as the esc
+ * ptrs
+ */
+ /*
+ * null the reference string in the same spots as the esc
+ * string
+ */
+ refattr = (refptr + (escattr - escptr));
+ refattr[strlen(escattr)] = '\0';
+
+ if (escvals && *escvals) {
+ refvals = (refptr + (escvals - escptr));
+ refvals[strlen(escvals)] = '\0';
+ } else {
+ refvals = NULL;
+ emptystr[0] = '\0';
+ }
+
+ if (spec_match(spec_p, refattr)) {
+ if (refvals)
+ (*fun) (spec_p, refattr, refvals, calldatap);
+ else
+ (*fun) (spec_p, refattr, emptystr, calldatap);
+ }
+ }
+
+alldone:
+ if (refptr)
+ free(refptr);
+ if (escptr)
+ free(escptr);
+
+} /* end spec_attrtrav */
+
+
+/*
+ * spec_valtrav() - traverse an value list, calling the supplied function on
+ * each matching value.
+ */
+
+void
+spec_valtrav(spec_t * spec_p,
+ char *valstr,
+ spec_val_fun_t fun,
+ void *calldatap)
+{
+ char *s0;
+ char *s;
+ boolean_t intoken = B_FALSE;
+ boolean_t inquote = B_FALSE;
+
+ /* return immeadiatly on null pointers */
+ if (!valstr)
+ return;
+
+ /* special case, match once on empty string */
+ if (!*valstr) {
+ if (spec_match(spec_p, valstr))
+ (*fun) (spec_p, valstr, calldatap);
+ return;
+ }
+ for (s = s0 = valstr; ; s++) {
+ switch (*s) {
+ case NULL:
+ if (intoken) {
+ if (spec_match(spec_p, s0))
+ (*fun) (spec_p, s0, calldatap);
+ }
+ return; /* ALL DONE */
+
+ case '\'':
+ if (inquote) {
+ /* end a quoted string */
+ inquote = B_FALSE;
+ intoken = B_FALSE;
+ *s = '\0';
+ if (spec_match(spec_p, s0))
+ (*fun) (spec_p, s0, calldatap);
+ /* next string starts past the quote */
+ s0 = s + 1;
+ } else {
+ /* start a quoted string */
+ inquote = B_TRUE;
+ intoken = B_TRUE;
+ s0 = s + 1; /* point past the quote */
+ }
+ break;
+
+ case ' ':
+ case '\t':
+ /* ignore whitespace in quoted strings */
+ if (inquote)
+ break;
+
+ if (intoken) {
+ /* whitespace ended this token */
+ intoken = B_FALSE;
+ *s = '\0';
+ if (spec_match(spec_p, s0))
+ (*fun) (spec_p, s0, calldatap);
+ /* next string starts past the whitespace */
+ s0 = s + 1;
+ }
+ break;
+
+ default:
+ /* characters all OK inside quoted string */
+ if (inquote)
+ break;
+
+ if (!intoken) {
+ /* start of unquoted token */
+ intoken = B_TRUE;
+ s0 = s; /* token starts here */
+ }
+ break;
+ }
+ }
+
+
+#ifdef TOOSIMPLE
+ char *v;
+ char *ls;
+
+ /*
+ * #### MISSING - need to handle quoted value strings * containing
+ * whitespace.
+ */
+
+ for (v = strtok_r(valstr, " \t", &ls); v;
+ v = strtok_r(NULL, " \t", &ls)) {
+ if (spec_match(spec_p, v)) {
+ (*fun) (spec_p, v, calldatap);
+ }
+ }
+#endif
+
+} /* end spec_valtrav */
diff --git a/usr/src/cmd/tnf/prex/spec.h b/usr/src/cmd/tnf/prex/spec.h
new file mode 100644
index 0000000000..5972b351e1
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/spec.h
@@ -0,0 +1,94 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _SPEC_H
+#define _SPEC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Includes
+ */
+
+#include <stdio.h>
+#include <libgen.h>
+#include <sys/types.h>
+
+#include "queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Typedefs
+ */
+
+typedef enum spec_type {
+ SPEC_EXACT,
+ SPEC_REGEXP
+
+
+} spec_type_t;
+
+
+typedef struct spec {
+ queue_node_t qn;
+ char *str;
+ spec_type_t type;
+ char *regexp_p;
+
+} spec_t;
+
+typedef void
+(*spec_attr_fun_t) (spec_t * spec, char *attr, char *value, void *calldatap);
+typedef void
+(*spec_val_fun_t) (spec_t * spec, char *value, void *calldatap);
+
+
+/*
+ * Globals
+ */
+
+
+/*
+ * Declarations
+ */
+
+spec_t * spec(char *str_p, spec_type_t type);
+void spec_destroy(spec_t * list_p);
+void spec_print(FILE * stream, spec_t * list_p);
+spec_t * spec_list(spec_t * list_p, spec_t * item_p);
+void spec_attrtrav(spec_t * spec_p, char *attrs,
+ spec_attr_fun_t fun, void *calldata_p);
+void spec_valtrav(spec_t * spec_p, char *valstr,
+ spec_val_fun_t fun, void *calldata_p);
+spec_t *spec_dup(spec_t * spec_p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SPEC_H */
diff --git a/usr/src/cmd/tnf/prex/util.c b/usr/src/cmd/tnf/prex/util.c
new file mode 100644
index 0000000000..bcb0fa8021
--- /dev/null
+++ b/usr/src/cmd/tnf/prex/util.c
@@ -0,0 +1,56 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <libintl.h>
+
+void
+err_fatal(char *s, ...)
+{
+ va_list ap;
+
+ va_start(ap, s);
+ (void) vfprintf(stderr, s, ap);
+ (void) fprintf(stderr, gettext("\n"));
+ va_end(ap);
+ exit(1);
+}
+
+#if 0
+void
+err_warning(char *s, ...)
+{
+ va_list ap;
+
+ va_start(ap, s);
+ (void) vfprintf(stderr, s, ap);
+ (void) fprintf(stderr, gettext("\n"));
+ va_end(ap);
+}
+#endif
diff --git a/usr/src/cmd/tnf/tnfdump/Makefile b/usr/src/cmd/tnf/tnfdump/Makefile
new file mode 100644
index 0000000000..a4fb64a00c
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfdump/Makefile
@@ -0,0 +1,66 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1989 by Sun Microsystems, Inc.
+#
+# cmd/tnf/tnfdump/Makefile
+#
+
+PROG= tnfdump
+
+OBJS.c= main.o cooked.o table.o
+OBJS= $(OBJS.c)
+
+SRCS= $(OBJS.c:%.o=%.c)
+
+include ../../Makefile.cmd
+
+POFILES= $(OBJS.c:%.o=%.po)
+
+CPPFLAGS += -I../../../lib/libtnfprobe
+LDLIBS += -ltnf
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTBIN) $(ROOTPROG)
+
+$(ROOTBIN):
+ $(INS.dir)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ cat $(POFILES) > $@
+
+clean:
+ $(RM) $(OBJS)
+
+lint: $(SRCS) lint_SRCS
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/tnf/tnfdump/cooked.c b/usr/src/cmd/tnf/tnfdump/cooked.c
new file mode 100644
index 0000000000..ff63d27ba4
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfdump/cooked.c
@@ -0,0 +1,337 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <tnf/tnf.h>
+#include <errno.h>
+#include <libintl.h>
+
+#include "state.h"
+
+#define STREQ(s1, s2, n) (strncmp(s1, s2, n) == 0)
+
+#define IS_64BIT(kind) ((1 << kind) & \
+ ((1 << TNF_K_UINT64) | (1 << TNF_K_INT64)))
+
+#define PROBE_TYPE "tnf_probe_type"
+
+static void print_event (entry_t *ent);
+static void insert_event (tnf_datum_t, tnf_datum_t);
+static void describe_c_brief (tnf_datum_t);
+static void describe_target (tnf_datum_t);
+static void describe_c_struct (tnf_datum_t);
+static void describe_probe_type (tnf_datum_t);
+static void describe_event (tnf_datum_t, tnf_datum_t, hrtime_t);
+
+static hrtime_t base_time = 0;
+
+void
+print_c_header(void)
+{
+ (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n",
+ "----------------", "----------------", "-----", "-----",
+ "----------", "---", "-------------------------",
+ "------------------------");
+ (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n",
+ "Elapsed (ms)", "Delta (ms)", "PID", "LWPID",
+ " TID ", "CPU", "Probe Name", "Data / Description . . .");
+ (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n",
+ "----------------", "----------------", "-----", "-----",
+ "----------", "---", "-------------------------",
+ "------------------------");
+}
+
+static void
+print_event(entry_t *ent)
+{
+ tnf_datum_t evt, sched;
+ hrtime_t normalized_time;
+
+ evt = ent->record;
+ sched = tnf_get_tag_arg(evt);
+ if (sched == TNF_DATUM_NULL) {
+ /*
+ * should never happen because it had a schedule
+ * record earlier
+ */
+ fail(0, gettext("event without a schedule record"));
+ }
+ normalized_time = ent->time - base_time;
+ describe_event(evt, sched, normalized_time);
+}
+
+void
+print_sorted_events(void)
+{
+ entry_t *ent;
+
+ table_sort();
+ ent = table_get_entry_indexed(0);
+ if (ent) {
+ base_time = ent->time;
+ }
+ table_print(&print_event);
+}
+
+void
+describe_c_record(tnf_datum_t datum)
+{
+ char *name_str;
+ tnf_datum_t schedule_rec;
+
+ switch (tnf_get_kind(datum)) {
+
+ case TNF_K_STRUCT:
+ /* print only event records */
+ schedule_rec = tnf_get_tag_arg(datum);
+ if (schedule_rec != TNF_DATUM_NULL) {
+ /* event record */
+ insert_event(datum, schedule_rec);
+ }
+ break;
+ case TNF_K_STRING:
+ case TNF_K_ARRAY:
+ /* Skip arrays at top level */
+ break;
+ case TNF_K_TYPE:
+ name_str = tnf_get_type_name(datum);
+ /* REMIND: filter based on property */
+ if (STREQ(name_str, PROBE_TYPE, strlen(name_str)))
+ describe_probe_type(datum);
+ break;
+ default:
+ fail(0, gettext("illegal record at %x (%d)"),
+ tnf_get_raw(datum), tnf_get_kind(datum));
+ break;
+ }
+
+}
+
+static void
+describe_probe_type(tnf_datum_t datum)
+{
+ unsigned n, i;
+ char *slotname;
+ size_t slot_len;
+
+ n = tnf_get_slot_count(datum);
+#if 0
+ /* print the OUTPUT PAD */
+ (void) printf("%16s %14s %5s %5s %8s %3s %-25s",
+ "-", "-", "-", "-", "-", "-", "-");
+#endif
+ (void) printf("probe\t");
+ for (i = 0; i < n; i++) {
+ slotname = tnf_get_slot_name(datum, i);
+ slot_len = strlen(slotname);
+
+ /* print all fields except ... */
+ if ((!STREQ(slotname, TNF_N_TAG, slot_len)) &&
+ (!STREQ(slotname, TNF_N_PROPERTIES, slot_len)) &&
+ (!STREQ(slotname, TNF_N_SLOT_TYPES, slot_len)) &&
+ (!STREQ(slotname, TNF_N_TYPE_SIZE, slot_len)) &&
+ (!STREQ(slotname, TNF_N_SLOT_NAMES, slot_len))) {
+ (void) printf(" ");
+ (void) printf("%s: ", slotname);
+ describe_c_brief(tnf_get_slot_indexed(datum,
+ i));
+ }
+ }
+ (void) printf("\n");
+}
+
+static void
+insert_event(tnf_datum_t datum, tnf_datum_t schedule_rec)
+{
+ tnf_datum_t temp;
+ hrtime_t evt_time;
+ unsigned time_delta = 0;
+ entry_t element;
+
+ temp = tnf_get_slot_named(schedule_rec, TNF_N_TIME_BASE);
+ evt_time = tnf_get_int64(temp);
+ temp = tnf_get_slot_named(datum, TNF_N_TIME_DELTA);
+ time_delta = (unsigned) tnf_get_int32(temp);
+ evt_time = evt_time + time_delta;
+
+ element.time = evt_time;
+ element.record = datum;
+ table_insert(&element);
+}
+
+#define K_TID "tnf_kthread_id"
+#define CPUID "cpuid"
+
+static void
+describe_event(tnf_datum_t datum, tnf_datum_t schedule_rec, hrtime_t evt_time)
+{
+ unsigned n, i;
+ char *slotname, *eventname, *tidtype;
+ tnf_datum_t temp;
+ int lwpid = 0, pid = 0;
+ int start_slots = 0;
+ static hrtime_t last_time = 0;
+ unsigned long long tid = 0;
+
+ temp = tnf_get_slot_named(schedule_rec, TNF_N_TID);
+ if (IS_64BIT(tnf_get_kind(temp))) {
+ tid = tnf_get_int64(temp);
+ } else {
+ tid = (unsigned int)tnf_get_int32(temp);
+ }
+ tidtype = tnf_get_type_name(temp);
+
+ temp = tnf_get_slot_named(schedule_rec, TNF_N_LWPID);
+ lwpid = tnf_get_int32(temp);
+ temp = tnf_get_slot_named(schedule_rec, TNF_N_PID);
+ pid = tnf_get_int32(temp);
+
+ /* XXX should use TNF_N_KERNEL_SCHEDULE, TNF_N_USER_SCHEDULE */
+ if (strcmp(tidtype, K_TID) == 0) {
+ int cpuid;
+ /* XXX Assumes cpuid always exists in kernel schedule */
+ cpuid = tnf_get_int32(tnf_get_slot_named(schedule_rec, CPUID));
+ /* print the OUTPUT schedule record for Kernel case */
+ (void) printf("%16.6f %16.6f %5u %5u 0x%-8llx %3d",
+ evt_time / 1000000.0,
+ (evt_time - last_time)/1000000.0,
+ pid, lwpid, tid, cpuid);
+ } else {
+ /* print the OUTPUT schedule record */
+ (void) printf("%16.6f %16.6f %5u %5u %10llu %3s",
+ evt_time / 1000000.0,
+ (evt_time - last_time)/1000000.0,
+ pid, lwpid, tid, "-");
+ }
+ /* print the tag */
+ eventname = tnf_type_get_name(tnf_get_slot_named(datum, TNF_N_TAG));
+ (void) printf(" %-25s", eventname);
+
+ /* heuristic - start of data is after TIME_DELTA field */
+ start_slots = tnf_get_slot_index(datum, TNF_N_TIME_DELTA);
+ start_slots++;
+
+ n = tnf_get_slot_count(datum);
+
+ /* print the rest of the fields */
+ for (i = start_slots; i < n; i++) {
+ (void) printf(" ");
+ slotname = tnf_get_slot_name(datum, i);
+ (void) printf("%s: ", slotname);
+ describe_target(tnf_get_slot_indexed(datum, i));
+ }
+ (void) printf("\n");
+ last_time = evt_time;
+}
+
+static void
+describe_c_struct(tnf_datum_t datum)
+{
+ unsigned n, i, tag_index;
+ char *slotname;
+
+ n = tnf_get_slot_count(datum);
+
+ /* print the tag */
+ (void) printf(" ");
+ (void) printf("%s: ", "type");
+ describe_c_brief(tnf_get_slot_named(datum, TNF_N_TAG));
+ tag_index = tnf_get_slot_index(datum, TNF_N_TAG);
+
+ for (i = 0; i < n; i++) {
+ /* print the rest of the members */
+ if (i != tag_index) {
+ (void) printf(" ");
+ slotname = tnf_get_slot_name(datum, i);
+ (void) printf("%s: ", slotname);
+ describe_target(tnf_get_slot_indexed(datum, i));
+ }
+ }
+}
+
+static void
+describe_c_brief(tnf_datum_t datum)
+{
+ if (datum == TNF_DATUM_NULL) /* allowed */
+ (void) printf("0x%-8x <NULL>", 0);
+
+ else if (tnf_is_scalar(datum))
+ describe_scalar(datum);
+
+ else if (tnf_is_record(datum)) {
+
+ switch (tnf_get_kind(datum)) {
+ case TNF_K_TYPE:
+ (void) printf("%s", tnf_type_get_name(datum));
+ break;
+ case TNF_K_STRING:
+ (void) printf("\"%s\"", tnf_get_chars(datum));
+ break;
+ default:
+ (void) printf("<%s>", tnf_get_type_name(datum));
+ }
+ } else
+ fail(0, gettext("inline aggregate slots/elements unhandled"));
+}
+
+static void
+describe_target(tnf_datum_t datum)
+{
+ if (datum == TNF_DATUM_NULL) /* allowed */
+ (void) printf("0x%-8x <NULL>", 0);
+
+ else if (tnf_is_scalar(datum))
+ describe_scalar(datum);
+
+ else if (tnf_is_record(datum)) {
+
+ switch (tnf_get_kind(datum)) {
+ case TNF_K_STRUCT:
+ (void) printf("{");
+ describe_c_struct(datum);
+ (void) printf(" }");
+ break;
+ case TNF_K_TYPE:
+ (void) printf("%s", tnf_type_get_name(datum));
+ break;
+ case TNF_K_STRING:
+ (void) printf("\"%s\"", tnf_get_chars(datum));
+ break;
+ default:
+ (void) printf("<%s>", tnf_get_type_name(datum));
+ }
+ } else
+ fail(0, gettext("inline aggregate slots/elements unhandled"));
+}
diff --git a/usr/src/cmd/tnf/tnfdump/main.c b/usr/src/cmd/tnf/tnfdump/main.c
new file mode 100644
index 0000000000..4c3d76ad7c
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfdump/main.c
@@ -0,0 +1,406 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <tnf/tnf.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include "state.h"
+
+static caddr_t g_file_base; /* base address of file */
+static char *g_cmdname; /* name of this command */
+static int g_raw = B_FALSE; /* output format */
+static int g_status = EXIT_SUCCESS; /* exit status (from stdlib.h) */
+static const char *print_unsigned = "%u";
+static const char *print_unsigned64 = "%llu";
+
+#define OFF(p) (p - g_file_base)
+
+static void describe_array (tnf_datum_t);
+static void describe_brief (tnf_datum_t);
+static void describe_record (tnf_datum_t);
+static void describe_struct (tnf_datum_t);
+static void describe_type (tnf_datum_t);
+static void read_tnf_file (int, char *);
+static void usage (void);
+static void scanargs (int, char **, int *, char ***);
+
+int
+main(int ac, char *av[])
+{
+ int numfiles; /* number of files to be printed */
+ char **filenames; /* start of file names list */
+ int i;
+
+ /* internationalization stuff */
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ g_cmdname = av[0];
+ scanargs(ac, av, &numfiles, &filenames);
+ for (i = 0; i < numfiles; i++) {
+ read_tnf_file(g_raw, filenames[i]);
+ }
+
+ if (!g_raw) {
+ if (table_get_num_elements() > 0) {
+ print_c_header();
+ print_sorted_events();
+ }
+ }
+
+ exit(g_status);
+
+ return (0);
+}
+
+static void
+scanargs(int argc, char **argv, int *nfiles, char ***files)
+{
+ int c;
+ int errflg = B_FALSE;
+ char *optstr = "rx";
+
+ while ((c = getopt(argc, argv, optstr)) != EOF) {
+ switch (c) {
+ case 'r':
+ g_raw = B_TRUE;
+ break;
+ case 'x':
+ print_unsigned = "0x%x";
+ print_unsigned64 = "0x%llx";
+ break;
+ case '?':
+ errflg = B_TRUE;
+ break;
+ }
+ }
+ *files = &argv[optind];
+ *nfiles = argc - optind;
+ if (*nfiles <= 0) {
+ errflg = B_TRUE;
+ }
+ if (errflg) {
+ usage();
+ }
+}
+
+
+static void
+read_tnf_file(int raw, char *path)
+{
+ int fd;
+ struct stat st;
+ caddr_t p, curr_p, end_p;
+ TNF *tnf;
+ tnf_errcode_t err;
+ tnf_datum_t record;
+ void (*desc_func)(tnf_datum_t) = describe_c_record;
+
+ if ((fd = open(path, O_RDONLY, 0777)) == -1) {
+ (void) fprintf(stderr, gettext("%s: cannot open %s\n"),
+ g_cmdname, path);
+ g_status = EXIT_FAILURE;
+ return;
+ }
+ if (fstat(fd, &st) != 0) {
+ (void) fprintf(stderr, gettext("%s: fstat error on %s\n"),
+ g_cmdname, path);
+ (void) close(fd);
+ g_status = EXIT_FAILURE;
+ return;
+ }
+ if (st.st_size == 0) {
+ (void) fprintf(stderr, gettext("%s: %s is empty\n"),
+ g_cmdname, path);
+ (void) close(fd);
+ g_status = EXIT_FAILURE;
+ return;
+ }
+ if ((p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))
+ == (caddr_t)-1) {
+ (void) fprintf(stderr, gettext("%s: mmap error on %s\n"),
+ g_cmdname, path);
+ (void) close(fd);
+ g_status = EXIT_FAILURE;
+ return;
+ }
+
+ if (raw)
+ g_file_base = p; /* for OFF() */
+
+ if (*p == 0) {
+ /*
+ * magic word is 0 - catch the error if entire file is zero.
+ * tnf_reader_begin() will catch the "not a TNF file" error.
+ */
+ curr_p = p;
+ end_p = p + st.st_size;
+ while ((curr_p < end_p) && (*curr_p == 0))
+ curr_p++;
+ if (curr_p == end_p) {
+ (void) fprintf(stderr,
+ gettext("%s: %s is an empty TNF file\n"),
+ g_cmdname, path);
+ (void) munmap(p, st.st_size);
+ (void) close(fd);
+ return;
+ }
+ }
+
+ if ((err = tnf_reader_begin(p, st.st_size, &tnf)) != TNF_ERR_NONE) {
+ (void) fprintf(stderr, gettext("%s: error in %s: %s\n"),
+ g_cmdname, path, tnf_error_message(err));
+ (void) munmap(p, st.st_size);
+ (void) close(fd);
+ g_status = EXIT_FAILURE;
+ return;
+ }
+
+ /* Describe file header */
+ record = tnf_get_file_header(tnf);
+ if (raw) {
+ describe_record(record);
+ desc_func = describe_record;
+ }
+
+ /* Describe all other records */
+ while ((record = tnf_get_next_record(record)) != TNF_DATUM_NULL)
+ desc_func(record);
+
+ /* Don't munmap for cooked output because we access records later */
+ if (raw)
+ (void) munmap(p, st.st_size);
+ (void) close(fd);
+}
+
+static void
+describe_record(tnf_datum_t datum)
+{
+ (void) printf("0x%-8x: {\n", OFF(tnf_get_raw(datum)));
+
+ switch (tnf_get_kind(datum)) {
+
+ case TNF_K_STRUCT:
+ describe_struct(datum);
+ break;
+ case TNF_K_STRING:
+ case TNF_K_ARRAY:
+ describe_array(datum);
+ break;
+ case TNF_K_TYPE:
+ describe_type(datum);
+ break;
+ default:
+ fail(0, gettext("illegal record at %x (%d)"),
+ tnf_get_raw(datum), tnf_get_kind(datum));
+ break;
+ }
+
+ (void) printf("\t}\n");
+}
+
+void
+describe_scalar(tnf_datum_t datum)
+{
+ switch (tnf_get_kind(datum)) {
+
+ case TNF_K_CHAR:
+ (void) printf("%c", tnf_get_char(datum));
+ break;
+ case TNF_K_INT8:
+ (void) printf("%d", tnf_get_int8(datum));
+ break;
+ case TNF_K_UINT8:
+ (void) printf(print_unsigned, (tnf_uint8_t)tnf_get_int8(datum));
+ break;
+ case TNF_K_INT16:
+ (void) printf("%d", tnf_get_int16(datum));
+ break;
+ case TNF_K_UINT16:
+ (void) printf(print_unsigned,
+ (tnf_uint16_t)tnf_get_int16(datum));
+ break;
+ case TNF_K_INT32:
+ (void) printf("%d", (int)tnf_get_int32(datum));
+ break;
+ case TNF_K_UINT32:
+ if ((tnf_type_get_property(tnf_get_type(datum), TNF_N_OPAQUE))
+ != TNF_DATUM_NULL) {
+ /* XXX */
+ (void) printf("0x%x",
+ (tnf_uint32_t)tnf_get_int32(datum));
+ } else {
+ (void) printf(print_unsigned,
+ (tnf_uint32_t)tnf_get_int32(datum));
+ }
+ break;
+ case TNF_K_INT64:
+ /* lint not updated, it complains: malformed format string */
+ (void) printf("%lld", tnf_get_int64(datum));
+ break;
+ case TNF_K_UINT64:
+ if ((tnf_type_get_property(tnf_get_type(datum), TNF_N_OPAQUE))
+ != TNF_DATUM_NULL) {
+ (void) printf("0x%llx",
+ (tnf_uint64_t)tnf_get_int64(datum));
+ } else {
+ /* lint not updated, it complains: malformed format string */
+ (void) printf(print_unsigned64,
+ (tnf_uint64_t)tnf_get_int64(datum));
+ }
+ break;
+ case TNF_K_FLOAT32:
+ (void) printf("%f", tnf_get_float32(datum));
+ break;
+ case TNF_K_FLOAT64:
+ (void) printf("%f", tnf_get_float64(datum));
+ break;
+ case TNF_K_SCALAR:
+ (void) printf("unhandled scalar");
+ break;
+ default:
+ fail(0, gettext("not a scalar"));
+ break;
+ }
+}
+
+static void
+describe_struct(tnf_datum_t datum)
+{
+ unsigned n, i;
+ char *slotname;
+
+ n = tnf_get_slot_count(datum);
+ for (i = 0; i < n; i++) {
+ slotname = tnf_get_slot_name(datum, i);
+ (void) printf("%24s ", slotname);
+ describe_brief(tnf_get_slot_indexed(datum, i));
+ (void) printf("\n");
+ /* tag_arg heuristic */
+ if ((i == 0) && tnf_is_record(datum)) {
+ tnf_datum_t tag_arg;
+
+ if ((tag_arg = tnf_get_tag_arg(datum))
+ != TNF_DATUM_NULL) {
+ (void) printf("%24s ", TNF_N_TAG_ARG);
+ describe_brief(tag_arg);
+ (void) printf("\n");
+ }
+ }
+ }
+}
+
+static void
+describe_array(tnf_datum_t datum)
+{
+ unsigned n, i;
+
+ describe_struct(datum); /* XXX */
+
+ if (tnf_is_string(datum))
+ (void) printf("%24s \"%s\"\n", "chars", tnf_get_chars(datum));
+ else {
+ n = tnf_get_element_count(datum);
+ for (i = 0; i < n; i++) {
+ (void) printf("%24d ", i);
+ describe_brief(tnf_get_element(datum, i));
+ (void) printf("\n");
+ }
+ }
+}
+
+static void
+describe_type(tnf_datum_t datum)
+{
+ describe_struct(datum);
+}
+
+static void
+describe_brief(tnf_datum_t datum)
+{
+ if (datum == TNF_DATUM_NULL) /* allowed */
+ (void) printf("0x%-8x <NULL>", 0);
+
+ else if (tnf_is_scalar(datum))
+ describe_scalar(datum);
+
+ else if (tnf_is_record(datum)) {
+
+ (void) printf("0x%-8x ",
+ OFF(tnf_get_raw(datum))); /* common */
+
+ switch (tnf_get_kind(datum)) {
+ case TNF_K_TYPE:
+ (void) printf("%s", tnf_type_get_name(datum));
+ break;
+ case TNF_K_STRING:
+ (void) printf("\"%s\"", tnf_get_chars(datum));
+ break;
+ default:
+ (void) printf("<%s>", tnf_get_type_name(datum));
+ }
+ } else
+ fail(0, gettext("inline aggregate slots/elements unhandled"));
+}
+
+void
+fail(int do_perror, char *message, ...)
+{
+ va_list args;
+
+ va_start(args, message);
+ (void) fprintf(stderr, gettext("%s: "), g_cmdname);
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+ if (do_perror)
+ (void) fprintf(stderr, gettext(": %s"), strerror(errno));
+ (void) fprintf(stderr, gettext("\n"));
+ exit(EXIT_FAILURE);
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ gettext("Usage: %s [-r] <tnf_file> [<tnf_file> ...]\n"),
+ g_cmdname);
+ exit(EXIT_FAILURE);
+}
diff --git a/usr/src/cmd/tnf/tnfdump/state.h b/usr/src/cmd/tnf/tnfdump/state.h
new file mode 100644
index 0000000000..3b6a51af8d
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfdump/state.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#ifndef _STATE_H
+#define _STATE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/time.h>
+#include <tnf/tnf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * data structures for table of record pointers:
+ * time: timestamp of record
+ * record: handle on record
+ */
+typedef struct entry {
+ hrtime_t time;
+ tnf_datum_t record;
+} entry_t;
+
+void print_c_header (void);
+void describe_c_record (tnf_datum_t);
+void print_sorted_events(void);
+
+void describe_scalar (tnf_datum_t);
+
+void fail (int, char *, ...);
+
+/* routines for manipulating table of records */
+void table_insert (entry_t *);
+void table_sort (void);
+void table_print (void (*print_elem)(entry_t *));
+int table_get_num_elements(void);
+entry_t *table_get_entry_indexed(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STATE_H */
diff --git a/usr/src/cmd/tnf/tnfdump/table.c b/usr/src/cmd/tnf/tnfdump/table.c
new file mode 100644
index 0000000000..581b2b7dd3
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfdump/table.c
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsytems, Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <locale.h>
+
+#include "state.h"
+
+/*
+ * This file defines routines on a table data structure. There is one
+ * static table that has the following operations: insert, sort, print,
+ * and get an element by index.
+ */
+
+static entry_t *table_start = NULL; /* start of table */
+static int table_cur = 0; /* current size of table */
+static int table_size = 0; /* max number of elements */
+
+#define GUESS_NUM_ELEM (16 * 1024)
+
+static void table_grow (int);
+static int timecompare (const void *, const void *);
+
+static void
+table_grow(int num_entries)
+{
+ entry_t *temp;
+
+ if (table_start == NULL) {
+ table_size = num_entries;
+ table_start = malloc(table_size * sizeof (struct entry));
+ if (table_start == NULL)
+ fail(1, gettext("malloc:"));
+ return;
+ }
+ table_size += num_entries;
+ temp = realloc(table_start, table_size * sizeof (struct entry));
+ if (temp == NULL)
+ fail(1, gettext("realloc:"));
+ table_start = temp;
+}
+
+static int
+timecompare(const void *i, const void *j)
+{
+ hrtime_t result;
+
+ result = ((entry_t *)i)->time - ((entry_t *)j)->time;
+ if (result < (longlong_t) 0)
+ return (-1);
+ else if (result == (longlong_t) 0)
+ return (0);
+ else
+ return (1);
+}
+
+/*
+ * insert an entry into the table. Automatically grows it if needed
+ */
+void
+table_insert(entry_t *element)
+{
+ if (table_cur >= table_size) {
+ table_grow(GUESS_NUM_ELEM);
+ }
+ /* copy the structure to the array, increment cur index */
+ table_start[table_cur++] = *element;
+}
+
+int
+table_get_num_elements(void)
+{
+ return (table_size);
+}
+
+void
+table_sort(void)
+{
+ qsort(table_start, table_cur, sizeof (struct entry), &timecompare);
+}
+
+void
+table_print(void (*print_elem)(entry_t *))
+{
+ int i;
+
+ for (i = 0; i < table_cur; i++) {
+ print_elem(&(table_start[i]));
+ }
+}
+
+entry_t *
+table_get_entry_indexed(int n)
+{
+ if (n < table_cur)
+ return (&(table_start[n]));
+ return (NULL);
+}
diff --git a/usr/src/cmd/tnf/tnfxtract/Makefile b/usr/src/cmd/tnf/tnfxtract/Makefile
new file mode 100644
index 0000000000..543ec63c9b
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfxtract/Makefile
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/tnf/tnfxtract/Makefile
+#
+
+PROG= tnfxtract
+
+include ../../Makefile.cmd
+
+$(64ONLY)SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all: $(SUBDIRS)
+
+clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS)
+ -$(RM) $(ROOTPROG)
+ -$(LN) $(ISAEXEC) $(ROOTPROG)
+
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/tnf/tnfxtract/Makefile.com b/usr/src/cmd/tnf/tnfxtract/Makefile.com
new file mode 100644
index 0000000000..747f5030f1
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfxtract/Makefile.com
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1994, 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG= tnfxtract
+
+OBJS.c= tnfxtract.o
+
+OBJS= $(OBJS.c)
+
+SRCS= $(OBJS.c:%.o=../%.c)
+
+include ../../../Makefile.cmd
+
+LFLAGS= -v
+LDLIBS += -lkvm
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+
+include ../../../Makefile.targ
diff --git a/usr/src/cmd/tnf/tnfxtract/amd64/Makefile b/usr/src/cmd/tnf/tnfxtract/amd64/Makefile
new file mode 100644
index 0000000000..074aa0891e
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfxtract/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.cmd.64
+
+install: all $(ROOTPROG64)
diff --git a/usr/src/cmd/tnf/tnfxtract/i386/Makefile b/usr/src/cmd/tnf/tnfxtract/i386/Makefile
new file mode 100644
index 0000000000..84309e70a3
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfxtract/i386/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/tnf/tnfxtract/sparc/Makefile
+
+include ../Makefile.com
+
+install: all $(ROOTPROG32)
diff --git a/usr/src/cmd/tnf/tnfxtract/sparcv9/Makefile b/usr/src/cmd/tnf/tnfxtract/sparcv9/Makefile
new file mode 100644
index 0000000000..f77e6f4858
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfxtract/sparcv9/Makefile
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/tnf/tnfxtract/sparcv9/Makefile
+
+include ../Makefile.com
+include ../../../Makefile.cmd.64
+
+install: all $(ROOTPROG64)
diff --git a/usr/src/cmd/tnf/tnfxtract/tnfxtract.c b/usr/src/cmd/tnf/tnfxtract/tnfxtract.c
new file mode 100644
index 0000000000..5e48d6094d
--- /dev/null
+++ b/usr/src/cmd/tnf/tnfxtract/tnfxtract.c
@@ -0,0 +1,423 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <libintl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <kvm.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/tnf.h>
+#include <sys/tnf_com.h>
+#include <nlist.h>
+#include <errno.h>
+
+#define TNFDEV "/dev/tnfmap"
+
+#define MAXFWTRY 5
+
+typedef struct {
+ boolean_t ever_read;
+ tnf_uint32_t generation;
+ tnf_uint16_t bytes_valid;
+} BLOCK_STATUS;
+
+static char *dumpfile; /* Dump file if extracting from crashdump */
+static char *namelist; /* Symbol tbl. if extracting from crashdump */
+static kvm_t *kvm_p; /* Handle for kvm_open, kvm_read, ... */
+
+static struct nlist kvm_syms[] = {
+ { "tnf_buf" },
+ { "tnf_trace_file_size" },
+ { NULL }
+};
+
+static uintptr_t dump_bufaddr;
+static size_t tnf_bufsize;
+static char *program_name;
+static int input_fd;
+static int output_fd;
+static tnf_file_header_t *tnf_header;
+
+/*
+ * usage() - gives a description of the arguments, and exits
+ */
+
+static void
+usage(char *argv[], const char *msg)
+{
+ if (msg)
+ (void) fprintf(stderr,
+ gettext("%s: %s\n"), argv[0], msg);
+
+ (void) fprintf(stderr, gettext(
+ "usage: %s [-d <dumpfile> -n <symbolfile> ] "
+ "<output-filename>\n"), argv[0]);
+ exit(1);
+} /* end usage */
+
+
+/*
+ * Write 'size' bytes at offset 'offset' from 'addr'
+ * to the output file. Bail out unceremoniously if anything goes wrong.
+ */
+static void
+writeout(char *addr, int offset, int size)
+
+{
+ if (lseek(output_fd, offset, SEEK_SET) < 0) {
+ perror("lseek");
+ exit(1);
+ }
+ if (write(output_fd, addr, size) != size) {
+ perror("write");
+ exit(1);
+ }
+}
+
+
+static void
+dumpfile_init()
+
+{
+ kvm_p = kvm_open(namelist, dumpfile, NULL, O_RDONLY, program_name);
+ if (kvm_p == NULL) {
+ /* kvm_open prints an error message */
+ exit(1);
+ }
+ if (kvm_nlist(kvm_p, kvm_syms) != 0) {
+ (void) fprintf(stderr, gettext(
+ "Symbol lookup error in %s\n"), namelist);
+ exit(1);
+ }
+ if (kvm_read(kvm_p, kvm_syms[0].n_value, (char *) &dump_bufaddr,
+ sizeof (dump_bufaddr)) != sizeof (dump_bufaddr) ||
+ kvm_read(kvm_p, kvm_syms[1].n_value, (char *) &tnf_bufsize,
+ sizeof (tnf_bufsize)) != sizeof (tnf_bufsize)) {
+ (void) fprintf(stderr, gettext(
+ "kvm_read error in %s\n"), dumpfile);
+ exit(1);
+ }
+ if (dump_bufaddr == NULL || tnf_bufsize == 0) {
+ (void) fprintf(stderr, gettext(
+ "No trace data available in the kernel.\n"));
+ exit(1);
+ }
+}
+
+static void
+live_kernel_init()
+
+{
+ tifiocstate_t tstate;
+
+ if ((input_fd = open(TNFDEV, O_RDWR)) < 0) {
+ perror(TNFDEV);
+ exit(1);
+ }
+ if (ioctl(input_fd, TIFIOCGSTATE, &tstate) < 0) {
+ perror(gettext("Error getting trace system state"));
+ exit(1);
+ }
+ if (tstate.buffer_state != TIFIOCBUF_OK) {
+ (void) fprintf(stderr, gettext(
+ "No trace data available in the kernel.\n"));
+ exit(1);
+ }
+ tnf_bufsize = tstate.buffer_size;
+}
+
+static void
+read_tnf_header(char *addr)
+
+{
+ if (dumpfile != NULL) {
+ if (kvm_read(kvm_p, dump_bufaddr, addr, 512) != 512) {
+ (void) fprintf(stderr, gettext(
+ "Error reading tnf header from dump file.\n"));
+ exit(1);
+ }
+ } else {
+ if (ioctl(input_fd, TIFIOCGHEADER, addr) != 0) {
+ perror(gettext("Error reading tnf header from kernel"));
+ exit(1);
+ }
+ }
+}
+
+static int
+read_tnf_block(tnf_block_header_t *addr, int block_num)
+
+{
+ int offset;
+ tifiocgblock_t ioctl_arg;
+
+ if (dumpfile != NULL) {
+ offset = tnf_header->directory_size +
+ block_num * tnf_header->block_size;
+ if (kvm_read(kvm_p, dump_bufaddr + offset, (char *) addr,
+ tnf_header->block_size) != tnf_header->block_size) {
+ (void) fprintf(stderr, gettext(
+ "Error reading tnf block.\n"));
+ exit(1);
+ }
+ } else {
+ ioctl_arg.dst_addr = (char *) addr;
+ ioctl_arg.block_num = block_num;
+ if (ioctl(input_fd, TIFIOCGBLOCK, &ioctl_arg) < 0) {
+ if (errno == EBUSY)
+ return (EBUSY);
+ perror(gettext("Error reading tnf block"));
+ exit(1);
+ }
+ }
+ return (0);
+}
+
+static void
+read_tnf_fwzone(tnf_ref32_t *dest, int start, int slots)
+
+{
+ int offset;
+ int len;
+ tifiocgfw_t ioctl_arg;
+
+ if (dumpfile != NULL) {
+ /* LINTED assignment of 64-bit integer to 32-bit integer */
+ offset = tnf_header->block_size + start * sizeof (tnf_ref32_t);
+ /* LINTED assignment of 64-bit integer to 32-bit integer */
+ len = slots * sizeof (tnf_ref32_t);
+ if (kvm_read(kvm_p, dump_bufaddr + offset, (char *) dest,
+ len) != len) {
+ (void) fprintf(stderr, gettext(
+ "Error reading tnf forwarding zone.\n"));
+ exit(1);
+ }
+ } else {
+ /* LINTED pointer cast may result in improper alignment */
+ ioctl_arg.dst_addr = (long *) dest;
+ ioctl_arg.start = start;
+ ioctl_arg.slots = slots;
+ if (ioctl(input_fd, TIFIOCGFWZONE, &ioctl_arg) < 0) {
+ perror(gettext("Error reading tnf block"));
+ exit(1);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *optstr = "d:n:";
+ const char *outfile;
+ char *local_buf;
+ int c;
+ tnf_uint32_t *magicp;
+ tnf_block_header_t *block_base, *blockp;
+ BLOCK_STATUS *block_stat, *bsp;
+ int block_num;
+ boolean_t any_unread, any_different, retry;
+ tnf_ref32_t *fwzone;
+ int fwzonesize;
+ int i;
+ int fwtries;
+ int block_count;
+
+ program_name = argv[0];
+ while ((c = getopt(argc, argv, optstr)) != EOF) {
+ switch (c) {
+ case 'd':
+ dumpfile = optarg;
+ break;
+ case 'n':
+ namelist = optarg;
+ break;
+ case '?':
+ usage(argv, gettext("unrecognized argument"));
+ }
+ }
+ if (optind != argc - 1) {
+ usage(argv, gettext("too many or too few arguments"));
+ } else {
+ outfile = argv[optind];
+ }
+ if ((dumpfile != NULL) ^ (namelist != NULL)) {
+ usage(argv, gettext("must specify both or neither of the "
+ "-d and -n options"));
+ }
+
+ output_fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (output_fd < 0) {
+ perror(outfile);
+ exit(1);
+ }
+ if (dumpfile != NULL)
+ dumpfile_init();
+ else
+ live_kernel_init();
+
+ if ((local_buf = malloc(tnf_bufsize)) == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnfxtract memory allocation failure\n"));
+ exit(1);
+ }
+
+ /* Read header, get block size, check for version mismatch */
+ read_tnf_header(local_buf);
+ /*LINTED pointer cast may result in improper alignment*/
+ magicp = (tnf_uint32_t *) local_buf;
+ /*LINTED pointer cast may result in improper alignment*/
+ tnf_header = (tnf_file_header_t *)(local_buf + sizeof (*magicp));
+ if (*magicp != TNF_MAGIC) {
+ (void) fprintf(stderr, gettext(
+ "Buffer is not in TNF format.\n"));
+ exit(1);
+ }
+ if (tnf_header->file_version != TNF_FILE_VERSION) {
+ (void) fprintf(stderr,
+ gettext("Version mismatch (tnfxtract: %d; buffer: %d)\n"),
+ TNF_FILE_VERSION, tnf_header->file_version);
+ exit(1);
+ }
+ writeout(local_buf, 0, tnf_header->block_size);
+ /* LINTED pointer cast may result in improper alignment */
+ block_base = (tnf_block_header_t *)
+ (local_buf + tnf_header->directory_size);
+ block_count = tnf_header->block_count -
+ tnf_header->directory_size / tnf_header->block_size;
+ fwzonesize = tnf_header->directory_size - tnf_header->block_size;
+
+ block_stat = (BLOCK_STATUS *)
+ calloc(block_count, sizeof (BLOCK_STATUS));
+ if (block_stat == NULL) {
+ (void) fprintf(stderr,
+ gettext("tnfxtract memory allocation failure\n"));
+ exit(1);
+ }
+
+ for (bsp = block_stat; bsp != block_stat + block_count; ++bsp)
+ bsp->ever_read = B_FALSE;
+ /*
+ * Make repeated passes until we've read every non-tag block.
+ */
+ do {
+ any_unread = B_FALSE;
+ bsp = block_stat;
+ block_num = 0;
+ blockp = block_base;
+ while (block_num != block_count) {
+ if (!bsp->ever_read) {
+ if (read_tnf_block(blockp, block_num) != 0)
+ any_unread = B_TRUE;
+ else {
+ bsp->ever_read = B_TRUE;
+ bsp->generation = blockp->generation;
+ bsp->bytes_valid = blockp->bytes_valid;
+ writeout((char *) blockp,
+ /* LINTED cast 64 to 32 bit */
+ (int)((char *) blockp - local_buf),
+ tnf_header->block_size);
+ }
+ }
+ ++bsp;
+ ++block_num;
+ /* LINTED pointer cast may result in improper alignment */
+ blockp = (tnf_block_header_t *)
+ ((char *) blockp + tnf_header->block_size);
+ }
+ } while (any_unread);
+
+ /*
+ * Then read tag blocks only, until we have two consecutive,
+ * consistent reads.
+ */
+ do {
+ any_different = B_FALSE;
+ bsp = block_stat;
+ block_num = 0;
+ blockp = block_base;
+ while (block_num != block_count) {
+ if (read_tnf_block(blockp, block_num) == 0 &&
+ blockp->generation == TNF_TAG_GENERATION_NUM &&
+ (bsp->generation != TNF_TAG_GENERATION_NUM ||
+ bsp->bytes_valid != blockp->bytes_valid)) {
+ bsp->generation = TNF_TAG_GENERATION_NUM;
+ bsp->bytes_valid = blockp->bytes_valid;
+ writeout((char *) blockp,
+ /* LINTED cast 64bit to 32 bit */
+ (int)((char *) blockp - local_buf),
+ tnf_header->block_size);
+ any_different = B_TRUE;
+ }
+ ++bsp;
+ ++block_num;
+ /* LINTED pointer cast may result in improper alignment */
+ blockp = (tnf_block_header_t *)
+ ((char *) blockp + tnf_header->block_size);
+ }
+ } while (any_different);
+
+ /*
+ * Then read the forwarding pointers. If any are -1:
+ * sleep briefly, then make another pass.
+ */
+ /*LINTED pointer cast may result in improper alignment*/
+ fwzone = (tnf_ref32_t *)(local_buf + tnf_header->block_size);
+
+ read_tnf_fwzone(fwzone, 0,
+ /* LINTED cast from 64-bit integer to 32-bit integer */
+ (int)(fwzonesize / sizeof (fwzone[0])));
+ fwtries = 0;
+ while (fwtries != MAXFWTRY) {
+ retry = B_FALSE;
+ for (i = 0; i != fwzonesize / sizeof (fwzone[0]); ++i) {
+ if (fwzone[i] == -1) {
+ read_tnf_fwzone(&fwzone[i], i, 1);
+ if (!retry) {
+ retry = B_TRUE;
+ ++fwtries;
+ }
+ }
+ }
+ if (!retry)
+ break;
+ sleep(2);
+ }
+ if (fwtries == MAXFWTRY) {
+ (void) fprintf(stderr, gettext(
+ "Warning: forwarding pointers may "
+ "be invalid.\n"));
+ }
+ writeout((char *) fwzone, tnf_header->block_size, fwzonesize);
+ return (0);
+}