diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/Makefile.am src/Makefile.am
--- src-orig/Makefile.am	2006-09-29 04:12:16.000000000 -0500
+++ src/Makefile.am	2006-10-06 14:45:56.000000000 -0500
@@ -12,7 +12,7 @@ AM_CFLAGS = -std=gnu99 -D_GNU_SOURCE -fe
 AM_CXXFLAGS = -Wall
 
 dist_man_MANS = stap.1 stapprobes.5 stapfuncs.5 stapex.5 lket.5 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.tcp.5 man/stapprobes.udp.5 
-bin_PROGRAMS = stap staprun
+bin_PROGRAMS = stap staprun stp_parse stp_server
 stap_SOURCES = main.cxx \
 	parse.cxx staptree.cxx elaborate.cxx translate.cxx \
 	tapsets.cxx buildrun.cxx loc2c.c
@@ -47,9 +47,13 @@ install-elfutils:
 install-exec-local: install-elfutils
 endif
 
-staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c
+staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c runtime/stpd/stp_utt.c runtime/stpd/utt.c
 staprun_LDADD = -lpthread
 
+stp_parse_SOURCES = runtime/stpd/stp_parse.c runtime/stpd/rbtree.c
+stp_server_SOURCES = runtime/stpd/stp_server.c runtime/stpd/utt.c
+stp_server_LDADD = -lpthread
+
 pkglibexec_SCRIPTS = stp_check
 CLEANFILES += $(pkglibexec_SCRIPTS)
 
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/Makefile.in src/Makefile.in
--- src-orig/Makefile.in	2006-09-29 04:12:16.000000000 -0500
+++ src/Makefile.in	2006-10-06 14:45:56.000000000 -0500
@@ -37,7 +37,8 @@ POST_INSTALL = :
 NORMAL_UNINSTALL = :
 PRE_UNINSTALL = :
 POST_UNINSTALL = :
-bin_PROGRAMS = stap$(EXEEXT) staprun$(EXEEXT)
+bin_PROGRAMS = stap$(EXEEXT) staprun$(EXEEXT) stp_parse$(EXEEXT) \
+	stp_server$(EXEEXT)
 @BUILD_ELFUTILS_TRUE@am__append_1 = -Iinclude-elfutils
 @BUILD_ELFUTILS_TRUE@am__append_2 = -Llib-elfutils -Wl,-rpath-link,lib-elfutils \
 @BUILD_ELFUTILS_TRUE@		-Wl,--enable-new-dtags,-rpath,$(pkglibdir)
@@ -94,9 +95,17 @@ am_stap_OBJECTS = stap-main.$(OBJEXT) st
 	stap-translate.$(OBJEXT) stap-tapsets.$(OBJEXT) \
 	stap-buildrun.$(OBJEXT) stap-loc2c.$(OBJEXT)
 stap_OBJECTS = $(am_stap_OBJECTS)
-am_staprun_OBJECTS = stpd.$(OBJEXT) librelay.$(OBJEXT)
+am_staprun_OBJECTS = stpd.$(OBJEXT) librelay.$(OBJEXT) \
+	stp_utt.$(OBJEXT) utt.$(OBJEXT)
 staprun_OBJECTS = $(am_staprun_OBJECTS)
 staprun_DEPENDENCIES =
+am_stp_parse_OBJECTS = stp_parse.$(OBJEXT) rbtree.$(OBJEXT)
+stp_parse_OBJECTS = $(am_stp_parse_OBJECTS)
+stp_parse_LDADD = $(LDADD)
+stp_parse_DEPENDENCIES =
+am_stp_server_OBJECTS = stp_server.$(OBJEXT) utt.$(OBJEXT)
+stp_server_OBJECTS = $(am_stp_server_OBJECTS)
+stp_server_DEPENDENCIES =
 pkglibexecSCRIPT_INSTALL = $(INSTALL_SCRIPT)
 SCRIPTS = $(pkglibexec_SCRIPTS)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
@@ -111,9 +120,10 @@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_IN
 CXXLD = $(CXX)
 CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
 	-o $@
-SOURCES = $(loc2c_test_SOURCES) $(stap_SOURCES) $(staprun_SOURCES)
+SOURCES = $(loc2c_test_SOURCES) $(stap_SOURCES) $(staprun_SOURCES) \
+	$(stp_parse_SOURCES) $(stp_server_SOURCES)
 DIST_SOURCES = $(loc2c_test_SOURCES) $(stap_SOURCES) \
-	$(staprun_SOURCES)
+	$(staprun_SOURCES) $(stp_parse_SOURCES) $(stp_server_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
 	html-recursive info-recursive install-data-recursive \
 	install-exec-recursive install-info-recursive \
@@ -247,8 +257,11 @@ stap_LDFLAGS = $(AM_LDFLAGS) $(am__appen
 CLEANFILES = $(am__append_3) $(pkglibexec_SCRIPTS)
 @BUILD_ELFUTILS_TRUE@BUILT_SOURCES = stamp-elfutils
 @BUILD_ELFUTILS_TRUE@stap_DEPENDENCIES = lib-elfutils/libdw.so
-staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c
+staprun_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c runtime/stpd/stp_utt.c runtime/stpd/utt.c
 staprun_LDADD = -lpthread
+stp_parse_SOURCES = runtime/stpd/stp_parse.c runtime/stpd/rbtree.c
+stp_server_SOURCES = runtime/stpd/stp_server.c runtime/stpd/utt.c
+stp_server_LDADD = -lpthread
 pkglibexec_SCRIPTS = stp_check
 loc2c_test_SOURCES = loc2c-test.c loc2c.c
 loc2c_test_CPPFLAGS = $(stap_CPPFLAGS)
@@ -389,6 +402,12 @@ stap$(EXEEXT): $(stap_OBJECTS) $(stap_DE
 staprun$(EXEEXT): $(staprun_OBJECTS) $(staprun_DEPENDENCIES) 
 	@rm -f staprun$(EXEEXT)
 	$(LINK) $(staprun_LDFLAGS) $(staprun_OBJECTS) $(staprun_LDADD) $(LIBS)
+stp_parse$(EXEEXT): $(stp_parse_OBJECTS) $(stp_parse_DEPENDENCIES) 
+	@rm -f stp_parse$(EXEEXT)
+	$(LINK) $(stp_parse_LDFLAGS) $(stp_parse_OBJECTS) $(stp_parse_LDADD) $(LIBS)
+stp_server$(EXEEXT): $(stp_server_OBJECTS) $(stp_server_DEPENDENCIES) 
+	@rm -f stp_server$(EXEEXT)
+	$(LINK) $(stp_server_LDFLAGS) $(stp_server_OBJECTS) $(stp_server_LDADD) $(LIBS)
 install-pkglibexecSCRIPTS: $(pkglibexec_SCRIPTS)
 	@$(NORMAL_INSTALL)
 	test -z "$(pkglibexecdir)" || $(mkdir_p) "$(DESTDIR)$(pkglibexecdir)"
@@ -418,6 +437,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librelay.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loc2c_test-loc2c-test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loc2c_test-loc2c.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbtree.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-buildrun.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-elaborate.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-loc2c.Po@am__quote@
@@ -426,7 +446,11 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-staptree.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapsets.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-translate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stp_parse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stp_server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stp_utt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stpd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utt.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@@ -512,6 +536,76 @@ librelay.obj: runtime/stpd/librelay.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o librelay.obj `if test -f 'runtime/stpd/librelay.c'; then $(CYGPATH_W) 'runtime/stpd/librelay.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/librelay.c'; fi`
 
+stp_utt.o: runtime/stpd/stp_utt.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stp_utt.o -MD -MP -MF "$(DEPDIR)/stp_utt.Tpo" -c -o stp_utt.o `test -f 'runtime/stpd/stp_utt.c' || echo '$(srcdir)/'`runtime/stpd/stp_utt.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/stp_utt.Tpo" "$(DEPDIR)/stp_utt.Po"; else rm -f "$(DEPDIR)/stp_utt.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/stp_utt.c' object='stp_utt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stp_utt.o `test -f 'runtime/stpd/stp_utt.c' || echo '$(srcdir)/'`runtime/stpd/stp_utt.c
+
+stp_utt.obj: runtime/stpd/stp_utt.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stp_utt.obj -MD -MP -MF "$(DEPDIR)/stp_utt.Tpo" -c -o stp_utt.obj `if test -f 'runtime/stpd/stp_utt.c'; then $(CYGPATH_W) 'runtime/stpd/stp_utt.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/stp_utt.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/stp_utt.Tpo" "$(DEPDIR)/stp_utt.Po"; else rm -f "$(DEPDIR)/stp_utt.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/stp_utt.c' object='stp_utt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stp_utt.obj `if test -f 'runtime/stpd/stp_utt.c'; then $(CYGPATH_W) 'runtime/stpd/stp_utt.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/stp_utt.c'; fi`
+
+utt.o: runtime/stpd/utt.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utt.o -MD -MP -MF "$(DEPDIR)/utt.Tpo" -c -o utt.o `test -f 'runtime/stpd/utt.c' || echo '$(srcdir)/'`runtime/stpd/utt.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/utt.Tpo" "$(DEPDIR)/utt.Po"; else rm -f "$(DEPDIR)/utt.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/utt.c' object='utt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utt.o `test -f 'runtime/stpd/utt.c' || echo '$(srcdir)/'`runtime/stpd/utt.c
+
+utt.obj: runtime/stpd/utt.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT utt.obj -MD -MP -MF "$(DEPDIR)/utt.Tpo" -c -o utt.obj `if test -f 'runtime/stpd/utt.c'; then $(CYGPATH_W) 'runtime/stpd/utt.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/utt.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/utt.Tpo" "$(DEPDIR)/utt.Po"; else rm -f "$(DEPDIR)/utt.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/utt.c' object='utt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o utt.obj `if test -f 'runtime/stpd/utt.c'; then $(CYGPATH_W) 'runtime/stpd/utt.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/utt.c'; fi`
+
+stp_parse.o: runtime/stpd/stp_parse.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stp_parse.o -MD -MP -MF "$(DEPDIR)/stp_parse.Tpo" -c -o stp_parse.o `test -f 'runtime/stpd/stp_parse.c' || echo '$(srcdir)/'`runtime/stpd/stp_parse.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/stp_parse.Tpo" "$(DEPDIR)/stp_parse.Po"; else rm -f "$(DEPDIR)/stp_parse.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/stp_parse.c' object='stp_parse.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stp_parse.o `test -f 'runtime/stpd/stp_parse.c' || echo '$(srcdir)/'`runtime/stpd/stp_parse.c
+
+stp_parse.obj: runtime/stpd/stp_parse.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stp_parse.obj -MD -MP -MF "$(DEPDIR)/stp_parse.Tpo" -c -o stp_parse.obj `if test -f 'runtime/stpd/stp_parse.c'; then $(CYGPATH_W) 'runtime/stpd/stp_parse.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/stp_parse.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/stp_parse.Tpo" "$(DEPDIR)/stp_parse.Po"; else rm -f "$(DEPDIR)/stp_parse.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/stp_parse.c' object='stp_parse.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stp_parse.obj `if test -f 'runtime/stpd/stp_parse.c'; then $(CYGPATH_W) 'runtime/stpd/stp_parse.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/stp_parse.c'; fi`
+
+rbtree.o: runtime/stpd/rbtree.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rbtree.o -MD -MP -MF "$(DEPDIR)/rbtree.Tpo" -c -o rbtree.o `test -f 'runtime/stpd/rbtree.c' || echo '$(srcdir)/'`runtime/stpd/rbtree.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/rbtree.Tpo" "$(DEPDIR)/rbtree.Po"; else rm -f "$(DEPDIR)/rbtree.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/rbtree.c' object='rbtree.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rbtree.o `test -f 'runtime/stpd/rbtree.c' || echo '$(srcdir)/'`runtime/stpd/rbtree.c
+
+rbtree.obj: runtime/stpd/rbtree.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rbtree.obj -MD -MP -MF "$(DEPDIR)/rbtree.Tpo" -c -o rbtree.obj `if test -f 'runtime/stpd/rbtree.c'; then $(CYGPATH_W) 'runtime/stpd/rbtree.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/rbtree.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/rbtree.Tpo" "$(DEPDIR)/rbtree.Po"; else rm -f "$(DEPDIR)/rbtree.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/rbtree.c' object='rbtree.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rbtree.obj `if test -f 'runtime/stpd/rbtree.c'; then $(CYGPATH_W) 'runtime/stpd/rbtree.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/rbtree.c'; fi`
+
+stp_server.o: runtime/stpd/stp_server.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stp_server.o -MD -MP -MF "$(DEPDIR)/stp_server.Tpo" -c -o stp_server.o `test -f 'runtime/stpd/stp_server.c' || echo '$(srcdir)/'`runtime/stpd/stp_server.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/stp_server.Tpo" "$(DEPDIR)/stp_server.Po"; else rm -f "$(DEPDIR)/stp_server.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/stp_server.c' object='stp_server.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stp_server.o `test -f 'runtime/stpd/stp_server.c' || echo '$(srcdir)/'`runtime/stpd/stp_server.c
+
+stp_server.obj: runtime/stpd/stp_server.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stp_server.obj -MD -MP -MF "$(DEPDIR)/stp_server.Tpo" -c -o stp_server.obj `if test -f 'runtime/stpd/stp_server.c'; then $(CYGPATH_W) 'runtime/stpd/stp_server.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/stp_server.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/stp_server.Tpo" "$(DEPDIR)/stp_server.Po"; else rm -f "$(DEPDIR)/stp_server.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='runtime/stpd/stp_server.c' object='stp_server.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stp_server.obj `if test -f 'runtime/stpd/stp_server.c'; then $(CYGPATH_W) 'runtime/stpd/stp_server.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stpd/stp_server.c'; fi`
+
 .cxx.o:
 @am__fastdepCXX_TRUE@	if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
 @am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/buildrun.cxx src/buildrun.cxx
--- src-orig/buildrun.cxx	2006-09-26 16:41:37.000000000 -0500
+++ src/buildrun.cxx	2006-10-06 14:45:56.000000000 -0500
@@ -130,7 +130,8 @@ run_pass (systemtap_session& s)
     + string(BINDIR) + "/staprun "
     + (s.verbose>1 ? "" : "-q ")
     + "-u " + username + " "
-    + (s.output_file.empty() ? "" : "-o " + s.output_file + " ");
+    + (s.output_file.empty() ? "" : "-o " + s.output_file + " ")
+    + (s.host.empty() ? "" : "-n " + s.host + " ");
   
   staprun_cmd += "-d " + stringify(getpid()) + " ";
   
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/main.cxx src/main.cxx
--- src-orig/main.cxx	2006-09-27 20:48:59.000000000 -0500
+++ src/main.cxx	2006-10-06 14:45:56.000000000 -0500
@@ -68,6 +68,8 @@ usage (systemtap_session& s, int exitcod
     << "   -u         unoptimized translation" << (s.unoptimized ? " [set]" : "") << endl
     << "   -g         guru mode" << (s.guru_mode ? " [set]" : "") << endl
     << "   -b         bulk (relayfs) mode" << (s.bulk_mode ? " [set]" : "") << endl
+    << "   -l         bulk (UTT) mode" << (s.utt_mode ? " [set]" : "") << endl
+    << "   -n HOST    send trace output to HOST (UTT mode only)" << endl
     << "   -M         Don't merge per-cpu files for bulk (relayfs) mode" << (s.merge ? "" : " [set]") << endl
     << "   -s NUM     buffer size in megabytes, instead of "
     << s.buffer_size << endl
@@ -130,6 +132,8 @@ main (int argc, char * const argv [])
   s.timing = 0;
   s.guru_mode = false;
   s.bulk_mode = false;
+  s.utt_mode = false;
+  s.host = ""; // -n HOST
   s.unoptimized = false;
   s.buffer_size = 0;
   s.last_pass = 5;
@@ -161,7 +165,7 @@ main (int argc, char * const argv [])
 
   while (true)
     {
-      int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgc:x:D:bs:u");
+      int grc = getopt (argc, argv, "hVMvtp:I:e:o:n:R:r:m:kgc:x:D:blts:u");
       if (grc < 0)
         break;
       switch (grc)
@@ -234,6 +238,14 @@ main (int argc, char * const argv [])
           s.bulk_mode = true;
           break;
 
+        case 'l':
+          s.utt_mode = true;
+          break;
+
+        case 'n':
+          s.host = string (optarg);
+          break;
+
 	case 'u':
 	  s.unoptimized = true;
 	  break;
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/print.c src/runtime/print.c
--- src-orig/runtime/print.c	2006-09-26 16:39:52.000000000 -0500
+++ src/runtime/print.c	2006-10-06 14:45:56.000000000 -0500
@@ -111,6 +111,14 @@ static void * _stp_reserve_bytes (int nu
 	_stp_print_flush();
 	return relay_reserve(_stp_chan, numbytes);
 }
+#elif defined(CONFIG_UTT) && defined(STP_UTT)
+static void * _stp_reserve_bytes (int numbytes)
+{
+	if (unlikely(numbytes == 0))
+		return NULL;
+	_stp_print_flush();
+	return relay_reserve(_stp_utt->rchan, numbytes);
+}
 #else
 static void * _stp_reserve_bytes (int numbytes)
 {
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/Makefile src/runtime/stpd/Makefile
--- src-orig/runtime/stpd/Makefile	2006-09-26 16:38:35.000000000 -0500
+++ src/runtime/stpd/Makefile	2006-10-06 14:45:56.000000000 -0500
@@ -1,7 +1,7 @@
-all: staprun stp_merge stp_dump
+all: staprun stp_merge stp_dump stp_parse stp_server
 
-staprun: stpd.c librelay.c ../transport/transport_msgs.h librelay.h
-	gcc -Wall -O3 -o staprun stpd.c librelay.c -lpthread
+staprun: stpd.c librelay.c stp_utt.c utt.c ../transport/transport_msgs.h librelay.h
+	gcc -Wall -O3 -D_GNU_SOURCE -o staprun stpd.c librelay.c stp_utt.c utt.c -lpthread
 
 stp_merge: stp_merge.c
 	gcc -Wall -O3 -o stp_merge stp_merge.c
@@ -9,8 +9,14 @@ stp_merge: stp_merge.c
 stp_dump: stp_dump.c
 	gcc -Wall -O3 -o stp_dump stp_dump.c
 
+stp_parse: stp_parse.c
+	gcc -Wall -O3 -o stp_parse stp_parse.c rbtree.c
+
+stp_server: stp_server.c utt.c
+	gcc -Wall -O3 -D_GNU_SOURCE -o stp_server stp_server.c utt.c -lpthread
+
 debug: stpd.c librelay.c ../transport/transport_msgs.h librelay.h
 	gcc -Wall -g -D DEBUG  -o staprun stpd.c librelay.c -lpthread	
 
 clean:
-	/bin/rm -f staprun stp_merge *.o *~
+	/bin/rm -f staprun stp_merge stp_utt stp_parse *.o *~
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/barrier.h src/runtime/stpd/barrier.h
--- src-orig/runtime/stpd/barrier.h	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/barrier.h	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,18 @@
+#ifndef BARRIER_H
+#define BARRIER_H
+
+#if defined(__ia64__)
+#define store_barrier()         asm volatile ("mf" ::: "memory")
+#elif defined(__x86_64__)
+#define store_barrier()         asm volatile("sfence" ::: "memory")
+#elif defined(__i386__)
+#define store_barrier()         asm volatile ("": : :"memory")
+#elif defined(__ppc__) || defined(__powerpc__)
+#define store_barrier()         asm volatile ("eieio" : : : "memory")
+#elif defined(__s390__) || defined(__s390x__)
+#define store_barrier()         asm volatile ("bcr 15,0" : : : "memory")
+#else
+#error Define store_barrier() for your CPU
+#endif
+
+#endif
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/librelay.c src/runtime/stpd/librelay.c
--- src-orig/runtime/stpd/librelay.c	2006-09-26 16:38:35.000000000 -0500
+++ src/runtime/stpd/librelay.c	2006-10-06 14:45:56.000000000 -0500
@@ -42,6 +42,7 @@
 #include <sys/statfs.h>
 #include <stdint.h>
 #include "librelay.h"
+#include "stp_utt.h"
 
 /* stp_check script */
 #ifdef PKGLIBDIR
@@ -54,13 +55,7 @@ char *stp_check="stp_check";
 #define NR_CPUS 256
 
 /* relayfs parameters */
-static struct params
-{
-	unsigned subbuf_size;
-	unsigned n_subbufs;
-	int merge;
-	char relay_filebase[256];
-} params;
+struct params params;
 
 /* temporary per-cpu output written here for relayfs, filebase0...N */
 static char *percpu_tmpfilebase = "stpd_cpu";
@@ -73,6 +68,7 @@ static int proc_file[NR_CPUS];
 /* if no output file name is specified, use this */
 #define DEFAULT_RELAYFS_OUTFILE_NAME "probe.out"
 extern char *outfile_name;
+extern char *host;
 
 /* internal variables */
 static int transport_mode;
@@ -111,19 +107,6 @@ static struct buf_status
 } status[NR_CPUS];
 
 /**
- *	streaming - is the current transport mode streaming or not?
- *
- *	Returns 1 if in streaming mode, 0 otherwise.
- */
-static int streaming(void)
-{
-	if (transport_mode == STP_TRANSPORT_PROC)
-		return 1;
-
-	return 0;
-}
-
-/**
  *	send_request - send request to kernel over control channel
  *	@type: the relay-app command id
  *	@data: pointer to the data to be sent
@@ -187,7 +170,7 @@ static void close_all_relayfs_files(void
 {
 	int i;
 
-	if (!streaming()) {
+	if (transport_mode == STP_TRANSPORT_RELAYFS) {
 		for (i = 0; i < ncpus; i++)
 			close_relayfs_files(i);
 	}
@@ -654,6 +637,8 @@ static int merge_output(void)
 	return 0;
 }
 
+extern pthread_t utt;
+
 static void cleanup_and_exit (int closed)
 {
 	char tmpbuf[128];
@@ -687,9 +672,18 @@ static void cleanup_and_exit (int closed
 		}
 	}
 
+	if (transport_mode == STP_TRANSPORT_UTT) {
+//		fprintf(stdout, "calling utt_stop\n");
+		utt_stop();
+//		fprintf(stdout, "called_utt_stop, joining utt\n");
+		pthread_join(utt, NULL);
+//		fprintf(stdout, "joined utt\n");
+	}
+
 	dbug("closing control channel\n");
 	close(control_channel);
 
+	dbug("rmmoding\n");
 	if (!closed) {
 		snprintf(tmpbuf, sizeof(tmpbuf), "/sbin/rmmod -w %s", modname);
 		if (system(tmpbuf)) {
@@ -698,17 +692,25 @@ static void cleanup_and_exit (int closed
 			exit(1);
 		}
 	}
+	dbug("rmmoded, exiting now\n");
 	exit(0);
 }
 
 static void sigproc(int signum)
 {
+//	fprintf(stdout, "librelay sigproc\n");
+	
 	if (signum == SIGCHLD) {
 		pid_t pid = waitpid(-1, NULL, WNOHANG);
 		if (pid != target_pid)
 			return;
 	}
 	send_request(STP_EXIT, NULL, 0);
+	if (transport_mode == STP_TRANSPORT_UTT) {
+//		fprintf(stdout, "calling utt_stop\n");
+		utt_stop();
+//		fprintf(stdout, "called_utt_stop\n");
+	}
 }
 
 static void driver_poll (int signum __attribute__((unused)))
@@ -724,7 +726,6 @@ static void driver_poll (int signum __at
 	}
 }
 
-
 /**
  *	stp_main_loop - loop forever reading data
  */
@@ -785,12 +786,19 @@ int stp_main_loop(void)
 				fprintf(stderr,"TRANSPORT_INFO recvd: PROC with %d Mbyte buffers.\n", 
 					 info->buf_size); 
 #endif
-			if (!streaming()) {
+			if (transport_mode == STP_TRANSPORT_RELAYFS) {
 				rc = init_relayfs();
 				if (rc < 0) {
 					fprintf(stderr, "ERROR: couldn't init relayfs, exiting\n");
 					cleanup_and_exit(0);
 				}
+			} else if (transport_mode == STP_TRANSPORT_UTT) {
+//				fprintf(stdout, "calling stp_start_utt, outfile_name: %s\n", outfile_name);
+				rc = stp_start_utt(outfile_name, host);
+				if (rc < 0) {
+					fprintf(stderr, "ERROR: couldn't start utt, exiting\n");
+					cleanup_and_exit(0);
+				}
 			} else if (outfile_name) {
 				ofp = fopen (outfile_name, "w");
 				if (!ofp) {
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/librelay.h src/runtime/stpd/librelay.h
--- src-orig/runtime/stpd/librelay.h	2006-09-13 17:46:09.000000000 -0500
+++ src/runtime/stpd/librelay.h	2006-10-06 14:45:56.000000000 -0500
@@ -6,6 +6,15 @@
 #define dbug(args...) ;
 #endif /* DEBUG */
 
+/* relayfs parameters */
+struct params
+{
+	unsigned subbuf_size;
+	unsigned n_subbufs;
+	int merge;
+	char relay_filebase[256];
+};
+
 /*
  * stp external API functions
  */
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/rbtree.c src/runtime/stpd/rbtree.c
--- src-orig/runtime/stpd/rbtree.c	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/rbtree.c	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,386 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+  (C) 2002  David Woodhouse <dwmw2@infradead.org>
+  
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  linux/lib/rbtree.c
+*/
+
+#include "rbtree.h"
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *right = node->rb_right;
+
+	if ((node->rb_right = right->rb_left))
+		right->rb_left->rb_parent = node;
+	right->rb_left = node;
+
+	if ((right->rb_parent = node->rb_parent))
+	{
+		if (node == node->rb_parent->rb_left)
+			node->rb_parent->rb_left = right;
+		else
+			node->rb_parent->rb_right = right;
+	}
+	else
+		root->rb_node = right;
+	node->rb_parent = right;
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *left = node->rb_left;
+
+	if ((node->rb_left = left->rb_right))
+		left->rb_right->rb_parent = node;
+	left->rb_right = node;
+
+	if ((left->rb_parent = node->rb_parent))
+	{
+		if (node == node->rb_parent->rb_right)
+			node->rb_parent->rb_right = left;
+		else
+			node->rb_parent->rb_left = left;
+	}
+	else
+		root->rb_node = left;
+	node->rb_parent = left;
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *parent, *gparent;
+
+	while ((parent = node->rb_parent) && parent->rb_color == RB_RED)
+	{
+		gparent = parent->rb_parent;
+
+		if (parent == gparent->rb_left)
+		{
+			{
+				register struct rb_node *uncle = gparent->rb_right;
+				if (uncle && uncle->rb_color == RB_RED)
+				{
+					uncle->rb_color = RB_BLACK;
+					parent->rb_color = RB_BLACK;
+					gparent->rb_color = RB_RED;
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_right == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_left(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			parent->rb_color = RB_BLACK;
+			gparent->rb_color = RB_RED;
+			__rb_rotate_right(gparent, root);
+		} else {
+			{
+				register struct rb_node *uncle = gparent->rb_left;
+				if (uncle && uncle->rb_color == RB_RED)
+				{
+					uncle->rb_color = RB_BLACK;
+					parent->rb_color = RB_BLACK;
+					gparent->rb_color = RB_RED;
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_left == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_right(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			parent->rb_color = RB_BLACK;
+			gparent->rb_color = RB_RED;
+			__rb_rotate_left(gparent, root);
+		}
+	}
+
+	root->rb_node->rb_color = RB_BLACK;
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+			     struct rb_root *root)
+{
+	struct rb_node *other;
+
+	while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node)
+	{
+		if (parent->rb_left == node)
+		{
+			other = parent->rb_right;
+			if (other->rb_color == RB_RED)
+			{
+				other->rb_color = RB_BLACK;
+				parent->rb_color = RB_RED;
+				__rb_rotate_left(parent, root);
+				other = parent->rb_right;
+			}
+			if ((!other->rb_left ||
+			     other->rb_left->rb_color == RB_BLACK)
+			    && (!other->rb_right ||
+				other->rb_right->rb_color == RB_BLACK))
+			{
+				other->rb_color = RB_RED;
+				node = parent;
+				parent = node->rb_parent;
+			}
+			else
+			{
+				if (!other->rb_right ||
+				    other->rb_right->rb_color == RB_BLACK)
+				{
+					register struct rb_node *o_left;
+					if ((o_left = other->rb_left))
+						o_left->rb_color = RB_BLACK;
+					other->rb_color = RB_RED;
+					__rb_rotate_right(other, root);
+					other = parent->rb_right;
+				}
+				other->rb_color = parent->rb_color;
+				parent->rb_color = RB_BLACK;
+				if (other->rb_right)
+					other->rb_right->rb_color = RB_BLACK;
+				__rb_rotate_left(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+		else
+		{
+			other = parent->rb_left;
+			if (other->rb_color == RB_RED)
+			{
+				other->rb_color = RB_BLACK;
+				parent->rb_color = RB_RED;
+				__rb_rotate_right(parent, root);
+				other = parent->rb_left;
+			}
+			if ((!other->rb_left ||
+			     other->rb_left->rb_color == RB_BLACK)
+			    && (!other->rb_right ||
+				other->rb_right->rb_color == RB_BLACK))
+			{
+				other->rb_color = RB_RED;
+				node = parent;
+				parent = node->rb_parent;
+			}
+			else
+			{
+				if (!other->rb_left ||
+				    other->rb_left->rb_color == RB_BLACK)
+				{
+					register struct rb_node *o_right;
+					if ((o_right = other->rb_right))
+						o_right->rb_color = RB_BLACK;
+					other->rb_color = RB_RED;
+					__rb_rotate_left(other, root);
+					other = parent->rb_left;
+				}
+				other->rb_color = parent->rb_color;
+				parent->rb_color = RB_BLACK;
+				if (other->rb_left)
+					other->rb_left->rb_color = RB_BLACK;
+				__rb_rotate_right(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+	}
+	if (node)
+		node->rb_color = RB_BLACK;
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *child, *parent;
+	int color;
+
+	if (!node->rb_left)
+		child = node->rb_right;
+	else if (!node->rb_right)
+		child = node->rb_left;
+	else
+	{
+		struct rb_node *old = node, *left;
+
+		node = node->rb_right;
+		while ((left = node->rb_left) != NULL)
+			node = left;
+		child = node->rb_right;
+		parent = node->rb_parent;
+		color = node->rb_color;
+
+		if (child)
+			child->rb_parent = parent;
+		if (parent)
+		{
+			if (parent->rb_left == node)
+				parent->rb_left = child;
+			else
+				parent->rb_right = child;
+		}
+		else
+			root->rb_node = child;
+
+		if (node->rb_parent == old)
+			parent = node;
+		node->rb_parent = old->rb_parent;
+		node->rb_color = old->rb_color;
+		node->rb_right = old->rb_right;
+		node->rb_left = old->rb_left;
+
+		if (old->rb_parent)
+		{
+			if (old->rb_parent->rb_left == old)
+				old->rb_parent->rb_left = node;
+			else
+				old->rb_parent->rb_right = node;
+		} else
+			root->rb_node = node;
+
+		old->rb_left->rb_parent = node;
+		if (old->rb_right)
+			old->rb_right->rb_parent = node;
+		goto color;
+	}
+
+	parent = node->rb_parent;
+	color = node->rb_color;
+
+	if (child)
+		child->rb_parent = parent;
+	if (parent)
+	{
+		if (parent->rb_left == node)
+			parent->rb_left = child;
+		else
+			parent->rb_right = child;
+	}
+	else
+		root->rb_node = child;
+
+ color:
+	if (color == RB_BLACK)
+		__rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_left)
+		n = n->rb_left;
+	return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_right)
+		n = n->rb_right;
+	return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+	/* If we have a right-hand child, go down and then left as far
+	   as we can. */
+	if (node->rb_right) {
+		node = node->rb_right; 
+		while (node->rb_left)
+			node=node->rb_left;
+		return node;
+	}
+
+	/* No right-hand children.  Everything down and left is
+	   smaller than us, so any 'next' node must be in the general
+	   direction of our parent. Go up the tree; any time the
+	   ancestor is a right-hand child of its parent, keep going
+	   up. First time it's a left-hand child of its parent, said
+	   parent is our 'next' node. */
+	while (node->rb_parent && node == node->rb_parent->rb_right)
+		node = node->rb_parent;
+
+	return node->rb_parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+	/* If we have a left-hand child, go down and then right as far
+	   as we can. */
+	if (node->rb_left) {
+		node = node->rb_left; 
+		while (node->rb_right)
+			node=node->rb_right;
+		return node;
+	}
+
+	/* No left-hand children. Go up till we find an ancestor which
+	   is a right-hand child of its parent */
+	while (node->rb_parent && node == node->rb_parent->rb_left)
+		node = node->rb_parent;
+
+	return node->rb_parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+		     struct rb_root *root)
+{
+	struct rb_node *parent = victim->rb_parent;
+
+	/* Set the surrounding nodes to point to the replacement */
+	if (parent) {
+		if (victim == parent->rb_left)
+			parent->rb_left = new;
+		else
+			parent->rb_right = new;
+	} else {
+		root->rb_node = new;
+	}
+	if (victim->rb_left)
+		victim->rb_left->rb_parent = new;
+	if (victim->rb_right)
+		victim->rb_right->rb_parent = new;
+
+	/* Copy the pointers/colour from the victim to the replacement */
+	*new = *victim;
+}
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/rbtree.h src/runtime/stpd/rbtree.h
--- src-orig/runtime/stpd/rbtree.h	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/rbtree.h	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,151 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+  
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  linux/include/linux/rbtree.h
+
+  To use rbtrees you'll have to implement your own insert and search cores.
+  This will avoid us to use callbacks and to drop drammatically performances.
+  I know it's not the cleaner way,  but in C (not in C++) to get
+  performances and genericity...
+
+  Some example of insert and search follows here. The search is a plain
+  normal search over an ordered tree. The insert instead must be implemented
+  int two steps: as first thing the code must insert the element in
+  order as a red leaf in the tree, then the support library function
+  rb_insert_color() must be called. Such function will do the
+  not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+						 unsigned long offset)
+{
+	struct rb_node * n = inode->i_rb_page_cache.rb_node;
+	struct page * page;
+
+	while (n)
+	{
+		page = rb_entry(n, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			n = n->rb_left;
+		else if (offset > page->offset)
+			n = n->rb_right;
+		else
+			return page;
+	}
+	return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+						   unsigned long offset,
+						   struct rb_node * node)
+{
+	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+	struct rb_node * parent = NULL;
+	struct page * page;
+
+	while (*p)
+	{
+		parent = *p;
+		page = rb_entry(parent, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			p = &(*p)->rb_left;
+		else if (offset > page->offset)
+			p = &(*p)->rb_right;
+		else
+			return page;
+	}
+
+	rb_link_node(node, parent, p);
+
+	return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+						 unsigned long offset,
+						 struct rb_node * node)
+{
+	struct page * ret;
+	if ((ret = __rb_insert_page_cache(inode, offset, node)))
+		goto out;
+	rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+	return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef	_LINUX_RBTREE_H
+#define	_LINUX_RBTREE_H
+
+#include <stdlib.h>
+
+struct rb_node
+{
+	struct rb_node *rb_parent;
+	int rb_color;
+#define	RB_RED		0
+#define	RB_BLACK	1
+	struct rb_node *rb_right;
+	struct rb_node *rb_left;
+};
+
+struct rb_root
+{
+	struct rb_node *rb_node;
+};
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({                      \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define RB_ROOT	(struct rb_root) { NULL, }
+#define	rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+extern struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
+			    struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+				struct rb_node ** rb_link)
+{
+	node->rb_parent = parent;
+	node->rb_color = RB_RED;
+	node->rb_left = node->rb_right = NULL;
+
+	*rb_link = node;
+}
+
+#endif	/* _LINUX_RBTREE_H */
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/stp_parse.c src/runtime/stpd/stp_parse.c
--- src-orig/runtime/stpd/stp_parse.c	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/stp_parse.c	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,1329 @@
+/*
+ * stp tracing parse application
+ *
+ * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
+ *
+ * Derived from blkparse.c by Tom Zanussi, 2006
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <signal.h>
+#include <locale.h>
+#include <libgen.h>
+
+#include "rbtree.h"
+
+#include "stp_utt.h"
+
+static char stpparse_version[] = "0.00.1";
+
+struct skip_info {
+	unsigned long start, end;
+	struct skip_info *prev, *next;
+};
+
+struct per_dev_info {
+	dev_t dev;
+	char *name;
+
+	int backwards;
+	unsigned long long events;
+	unsigned long long first_reported_time;
+	unsigned long long last_reported_time;
+	unsigned long long last_read_time;
+
+	unsigned long skips;
+	unsigned long long seq_skips;
+	unsigned int max_depth[2];
+	unsigned int cur_depth[2];
+
+	int nfiles;
+	int ncpus;
+
+	unsigned long *cpu_map;
+	unsigned int cpu_map_max;
+
+	struct per_cpu_info *cpus;
+};
+
+#define S_OPTS	"i:o:b:w:vVD:d:"
+static struct option l_opts[] = {
+	{
+		.name = "input",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'i'
+	},
+	{
+		.name = "output",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'o'
+	},
+	{
+		.name = "batch",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'b'
+	},
+	{
+		.name = "quiet",
+		.has_arg = no_argument,
+		.flag = NULL,
+		.val = 'q'
+	},
+	{
+		.name = "stopwatch",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'w'
+	},
+	{
+		.name = "verbose",
+		.has_arg = no_argument,
+		.flag = NULL,
+		.val = 'v'
+	},
+	{
+		.name = "version",
+		.has_arg = no_argument,
+		.flag = NULL,
+		.val = 'V'
+	},
+	{
+		.name = "input-directory",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'D'
+	},
+	{
+		.name = "dump-binary",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'd'
+	},
+	{
+		.name = NULL,
+	}
+};
+
+/*
+ * for sorting the displayed output
+ */
+struct trace {
+	struct stp_trace *sit;
+	struct rb_node rb_node;
+	struct trace *next;
+	unsigned long read_sequence;
+};
+
+static struct rb_root rb_sort_root;
+static unsigned long rb_sort_entries;
+
+static struct trace *trace_list;
+
+/*
+ * allocation cache
+ */
+static struct stp_trace *sit_alloc_list;
+static struct trace *t_alloc_list;
+
+static int ndevices;
+static struct per_dev_info *devices;
+static char *get_dev_name(struct per_dev_info *, char *, int);
+static int trace_rb_insert_last(struct per_dev_info *, struct trace *);
+
+FILE *ofp = NULL;
+static char *output_name;
+static char *input_dir;
+
+static unsigned long long genesis_time;
+static unsigned long long last_allowed_time;
+static unsigned long long stopwatch_start;	/* start from zero by default */
+static unsigned long long stopwatch_end = -1ULL;	/* "infinity" */
+static unsigned long read_sequence;
+
+static int per_device_and_cpu_stats = 1;
+
+static int verbose;
+static int stats_printed;
+int data_is_native = -1;
+
+static int dump_fd;
+static char *dump_binary;
+
+static unsigned int t_alloc_cache;
+static unsigned int sit_alloc_cache;
+
+#define RB_BATCH_DEFAULT	(512)
+static unsigned int rb_batch = RB_BATCH_DEFAULT;
+
+static int pipeline;
+
+#define is_done()	(*(volatile int *)(&done))
+static volatile int done;
+
+#define CPUS_PER_LONG	(8 * sizeof(unsigned long))
+#define CPU_IDX(cpu)	((cpu) / CPUS_PER_LONG)
+#define CPU_BIT(cpu)	((cpu) & (CPUS_PER_LONG - 1))
+
+static void output_binary(void *buf, int len)
+{
+	if (dump_binary) {
+		int n = write(dump_fd, buf, len);
+		if (n != len) {
+			perror(dump_binary);
+			close(dump_fd);
+			dump_binary = NULL;
+		}
+	}
+}
+
+static void resize_cpu_info(struct per_dev_info *pdi, int cpu)
+{
+	struct per_cpu_info *cpus = pdi->cpus;
+	int ncpus = pdi->ncpus;
+	int new_count = cpu + 1;
+	int new_space, size;
+	char *new_start;
+
+	size = new_count * sizeof(struct per_cpu_info);
+	cpus = realloc(cpus, size);
+	if (!cpus) {
+		char name[20];
+		fprintf(stderr, "Out of memory, CPU info for device %s (%d)\n",
+			get_dev_name(pdi, name, sizeof(name)), size);
+		exit(1);
+	}
+
+	new_start = (char *)cpus + (ncpus * sizeof(struct per_cpu_info));
+	new_space = (new_count - ncpus) * sizeof(struct per_cpu_info);
+	memset(new_start, 0, new_space);
+
+	pdi->ncpus = new_count;
+	pdi->cpus = cpus;
+
+	for (new_count = 0; new_count < pdi->ncpus; new_count++) {
+		struct per_cpu_info *pci = &pdi->cpus[new_count];
+
+		if (!pci->fd) {
+			pci->fd = -1;
+			memset(&pci->rb_last, 0, sizeof(pci->rb_last));
+			pci->rb_last_entries = 0;
+			pci->last_sequence = -1;
+		}
+	}
+}
+
+static struct per_cpu_info *get_cpu_info(struct per_dev_info *pdi, int cpu)
+{
+	struct per_cpu_info *pci;
+
+	if (cpu >= pdi->ncpus)
+		resize_cpu_info(pdi, cpu);
+
+	pci = &pdi->cpus[cpu];
+	pci->cpu = cpu;
+	return pci;
+}
+
+
+static int resize_devices(char *name)
+{
+	int size = (ndevices + 1) * sizeof(struct per_dev_info);
+
+	devices = realloc(devices, size);
+	if (!devices) {
+		fprintf(stderr, "Out of memory, device %s (%d)\n", name, size);
+		return 1;
+	}
+	memset(&devices[ndevices], 0, sizeof(struct per_dev_info));
+	devices[ndevices].name = name;
+	ndevices++;
+	return 0;
+}
+
+static struct per_dev_info *get_dev_info(dev_t dev)
+{
+	struct per_dev_info *pdi;
+	int i;
+
+	for (i = 0; i < ndevices; i++) {
+		if (!devices[i].dev)
+			devices[i].dev = dev;
+		if (devices[i].dev == dev)
+			return &devices[i];
+	}
+
+	if (resize_devices(NULL))
+		return NULL;
+
+	pdi = &devices[ndevices - 1];
+	pdi->dev = dev;
+	pdi->first_reported_time = 0;
+	pdi->last_read_time = 0;
+
+	return pdi;
+}
+
+static void insert_skip(struct per_cpu_info *pci, unsigned long start,
+			unsigned long end)
+{
+	struct skip_info *sip;
+
+	for (sip = pci->skips_tail; sip != NULL; sip = sip->prev) {
+		if (end == (sip->start - 1)) {
+			sip->start = start;
+			return;
+		} else if (start == (sip->end + 1)) {
+			sip->end = end;
+			return;
+		}
+	}
+
+	sip = malloc(sizeof(struct skip_info));
+	sip->start = start;
+	sip->end = end;
+	sip->prev = sip->next = NULL;
+	if (pci->skips_tail == NULL)
+		pci->skips_head = pci->skips_tail = sip;
+	else {
+		sip->prev = pci->skips_tail;
+		pci->skips_tail->next = sip;
+		pci->skips_tail = sip;
+	}
+}
+
+static void remove_sip(struct per_cpu_info *pci, struct skip_info *sip)
+{
+	if (sip->prev == NULL) {
+		if (sip->next == NULL)
+			pci->skips_head = pci->skips_tail = NULL;
+		else {
+			pci->skips_head = sip->next;
+			sip->next->prev = NULL;
+		}
+	} else if (sip->next == NULL) {
+		pci->skips_tail = sip->prev;
+		sip->prev->next = NULL;
+	} else {
+		sip->prev->next = sip->next;
+		sip->next->prev = sip->prev;
+	}
+
+	sip->prev = sip->next = NULL;
+	free(sip);
+}
+
+#define IN_SKIP(sip,seq) (((sip)->start <= (seq)) && ((seq) <= sip->end))
+static int check_current_skips(struct per_cpu_info *pci, unsigned long seq)
+{
+	struct skip_info *sip;
+
+	for (sip = pci->skips_tail; sip != NULL; sip = sip->prev) {
+		if (IN_SKIP(sip, seq)) {
+			if (sip->start == seq) {
+				if (sip->end == seq)
+					remove_sip(pci, sip);
+				else
+					sip->start += 1;
+			} else if (sip->end == seq)
+				sip->end -= 1;
+			else {
+				sip->end = seq - 1;
+				insert_skip(pci, seq + 1, sip->end);
+			}
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void collect_pdi_skips(struct per_dev_info *pdi)
+{
+	struct skip_info *sip;
+	int cpu;
+
+	pdi->skips = 0;
+	pdi->seq_skips = 0;
+
+	for (cpu = 0; cpu < pdi->ncpus; cpu++) {
+		struct per_cpu_info *pci = &pdi->cpus[cpu];
+
+		for (sip = pci->skips_head; sip != NULL; sip = sip->next) {
+			pdi->skips++;
+			pdi->seq_skips += (sip->end - sip->start + 1);
+			if (verbose)
+				fprintf(stderr,"(%d,%d): skipping %lu -> %lu\n",
+					MAJOR(pdi->dev), MINOR(pdi->dev),
+					sip->start, sip->end);
+		}
+	}
+}
+
+static void cpu_mark_online(struct per_dev_info *pdi, unsigned int cpu)
+{
+	if (cpu >= pdi->cpu_map_max || !pdi->cpu_map) {
+		int new_max = (cpu + CPUS_PER_LONG) & ~(CPUS_PER_LONG - 1);
+		unsigned long *map = malloc(new_max / sizeof(long));
+
+		memset(map, 0, new_max / sizeof(long));
+
+		if (pdi->cpu_map) {
+			memcpy(map, pdi->cpu_map, pdi->cpu_map_max / sizeof(long));
+			free(pdi->cpu_map);
+		}
+
+		pdi->cpu_map = map;
+		pdi->cpu_map_max = new_max;
+	}
+
+	pdi->cpu_map[CPU_IDX(cpu)] |= (1UL << CPU_BIT(cpu));
+}
+
+static inline void cpu_mark_offline(struct per_dev_info *pdi, int cpu)
+{
+	pdi->cpu_map[CPU_IDX(cpu)] &= ~(1UL << CPU_BIT(cpu));
+}
+
+static inline int cpu_is_online(struct per_dev_info *pdi, int cpu)
+{
+	return (pdi->cpu_map[CPU_IDX(cpu)] & (1UL << CPU_BIT(cpu))) != 0;
+}
+
+/*
+ * struct trace and blktrace allocation cache, we do potentially
+ * millions of mallocs for these structures while only using at most
+ * a few thousand at the time
+ */
+static inline void t_free(struct trace *t)
+{
+	if (t_alloc_cache < 1024) {
+		t->next = t_alloc_list;
+		t_alloc_list = t;
+		t_alloc_cache++;
+	} else
+		free(t);
+}
+
+static inline struct trace *t_alloc(void)
+{
+	struct trace *t = t_alloc_list;
+
+	if (t) {
+		t_alloc_list = t->next;
+		t_alloc_cache--;
+		return t;
+	}
+
+	return malloc(sizeof(*t));
+}
+
+static inline void sit_free(struct stp_trace *sit)
+{
+	if (sit_alloc_cache < 1024 && !sit->pdu_len) {
+		/*
+		 * abuse a 64-bit field for a next pointer for the free item
+		 */
+		sit->time = (__u64) (unsigned long) sit_alloc_list;
+		sit_alloc_list = (struct stp_trace *) sit;
+		sit_alloc_cache++;
+	} else
+		free(sit);
+}
+
+static inline struct stp_trace *sit_alloc(void)
+{
+	struct stp_trace *sit = sit_alloc_list;
+
+	if (sit) {
+		sit_alloc_list = (struct stp_trace *) (unsigned long) \
+				 sit->time;
+		sit_alloc_cache--;
+		return sit;
+	}
+
+	return malloc(sizeof(*sit));
+}
+
+static inline void __put_trace_last(struct per_dev_info *pdi, struct trace *t)
+{
+	struct per_cpu_info *pci = get_cpu_info(pdi, t->sit->cpu);
+
+	rb_erase(&t->rb_node, &pci->rb_last);
+	pci->rb_last_entries--;
+
+	sit_free(t->sit);
+	t_free(t);
+}
+
+static void put_trace(struct per_dev_info *pdi, struct trace *t)
+{
+	rb_erase(&t->rb_node, &rb_sort_root);
+	rb_sort_entries--;
+
+	trace_rb_insert_last(pdi, t);
+}
+
+static inline int trace_rb_insert(struct trace *t, struct rb_root *root)
+{
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct trace *__t;
+
+	while (*p) {
+		parent = *p;
+
+		__t = rb_entry(parent, struct trace, rb_node);
+
+		if (t->sit->time < __t->sit->time)
+			p = &(*p)->rb_left;
+		else if (t->sit->time > __t->sit->time)
+			p = &(*p)->rb_right;
+		else if (t->sit->device < __t->sit->device)
+			p = &(*p)->rb_left;
+		else if (t->sit->device > __t->sit->device)
+			p = &(*p)->rb_right;
+		else if (t->sit->sequence < __t->sit->sequence)
+			p = &(*p)->rb_left;
+		else	/* >= sequence */
+			p = &(*p)->rb_right;
+	}
+
+	rb_link_node(&t->rb_node, parent, p);
+	rb_insert_color(&t->rb_node, root);
+	return 0;
+}
+
+static inline int trace_rb_insert_sort(struct trace *t)
+{
+	if (!trace_rb_insert(t, &rb_sort_root)) {
+		rb_sort_entries++;
+		return 0;
+	}
+
+	return 1;
+}
+
+static int trace_rb_insert_last(struct per_dev_info *pdi, struct trace *t)
+{
+	struct per_cpu_info *pci = get_cpu_info(pdi, t->sit->cpu);
+
+	if (trace_rb_insert(t, &pci->rb_last))
+		return 1;
+
+	pci->rb_last_entries++;
+
+	if (pci->rb_last_entries > rb_batch * pdi->nfiles) {
+		struct rb_node *n = rb_first(&pci->rb_last);
+
+		t = rb_entry(n, struct trace, rb_node);
+		__put_trace_last(pdi, t);
+	}
+
+	return 0;
+}
+
+static struct trace *trace_rb_find(dev_t device, unsigned long sequence,
+				   struct rb_root *root, int order)
+{
+	struct rb_node *n = root->rb_node;
+	struct rb_node *prev = NULL;
+	struct trace *__t;
+
+	while (n) {
+		__t = rb_entry(n, struct trace, rb_node);
+		prev = n;
+
+		if (device < __t->sit->device)
+			n = n->rb_left;
+		else if (device > __t->sit->device)
+			n = n->rb_right;
+		else if (sequence < __t->sit->sequence)
+			n = n->rb_left;
+		else if (sequence > __t->sit->sequence)
+			n = n->rb_right;
+		else
+			return __t;
+	}
+
+	/*
+	 * hack - the list may not be sequence ordered because some
+	 * events don't have sequence and time matched. so we end up
+	 * being a little off in the rb lookup here, because we don't
+	 * know the time we are looking for. compensate by browsing
+	 * a little ahead from the last entry to find the match
+	 */
+	if (order && prev) {
+		int max = 5;
+
+		while (((n = rb_next(prev)) != NULL) && max--) {
+			__t = rb_entry(n, struct trace, rb_node);
+
+			if (__t->sit->device == device &&
+			    __t->sit->sequence == sequence)
+				return __t;
+
+			prev = n;
+		}
+	}
+
+	return NULL;
+}
+
+static inline struct trace *trace_rb_find_last(struct per_dev_info *pdi,
+					       struct per_cpu_info *pci,
+					       unsigned long seq)
+{
+	return trace_rb_find(pdi->dev, seq, &pci->rb_last, 0);
+}
+
+static char *get_dev_name(struct per_dev_info *pdi, char *buffer, int size)
+{
+	if (pdi->name)
+		snprintf(buffer, size, "%s", pdi->name);
+	else
+		snprintf(buffer, size, "%d,%d",MAJOR(pdi->dev),MINOR(pdi->dev));
+	return buffer;
+}
+
+static void check_time(struct per_dev_info *pdi, struct stp_trace *sit)
+{
+	unsigned long long this = sit->time;
+	unsigned long long last = pdi->last_reported_time;
+
+	pdi->backwards = (this < last) ? 'B' : ' ';
+	pdi->last_reported_time = this;
+}
+
+static void dump_trace(struct stp_trace *t, struct per_cpu_info *pci __attribute ((unused)),
+		       struct per_dev_info *pdi)
+{
+	unsigned char *buf = (unsigned char *) t + sizeof(*t);
+
+	buf[t->pdu_len] = '\0';
+	fprintf(ofp, "%s", buf);
+
+	if (!pdi->events)
+		pdi->first_reported_time = t->time;
+
+	pdi->events++;
+
+	output_binary(t, sizeof(*t) + t->pdu_len);
+}
+
+static void show_device_and_cpu_stats(void)
+{
+	struct per_dev_info *pdi;
+	int i;
+	char line[3 + 8/*cpu*/ + 2 + 32/*dev*/ + 3];
+
+	for (pdi = devices, i = 0; i < ndevices; i++, pdi++) {
+		if (i > 0)
+			fprintf(ofp, "\n");
+		fprintf(ofp, "Events (%s): %'Lu entries\n",
+			get_dev_name(pdi, line, sizeof(line)), pdi->events);
+
+		collect_pdi_skips(pdi);
+		fprintf(ofp, "Skips: %'lu forward (%'llu - %5.1lf%%)\n",
+			pdi->skips,pdi->seq_skips,
+			100.0 * ((double)pdi->seq_skips /
+				(double)(pdi->events + pdi->seq_skips)));
+	}
+}
+
+static void find_genesis(void)
+{
+	struct trace *t = trace_list;
+
+	genesis_time = -1ULL;
+	while (t != NULL) {
+		if (t->sit->time < genesis_time)
+			genesis_time = t->sit->time;
+
+		t = t->next;
+	}
+}
+
+static inline int check_stopwatch(struct stp_trace *sit)
+{
+	if (sit->time < stopwatch_end &&
+	    sit->time >= stopwatch_start)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * return youngest entry read
+ */
+static int sort_entries(unsigned long long *youngest)
+{
+	struct per_dev_info *pdi = NULL;
+	struct per_cpu_info *pci = NULL;
+	struct trace *t;
+
+	if (!genesis_time)
+		find_genesis();
+
+	*youngest = 0;
+	while ((t = trace_list) != NULL) {
+		struct stp_trace *sit = t->sit;
+
+		trace_list = t->next;
+
+		sit->time -= genesis_time;
+
+		if (sit->time < *youngest || !*youngest)
+			*youngest = sit->time;
+
+		if (!pdi || pdi->dev != sit->device) {
+			pdi = get_dev_info(sit->device);
+			pci = NULL;
+		}
+
+		if (!pci || pci->cpu != sit->cpu)
+			pci = get_cpu_info(pdi, sit->cpu);
+
+		if (sit->sequence < pci->smallest_seq_read)
+			pci->smallest_seq_read = sit->sequence;
+
+		if (check_stopwatch(sit)) {
+			sit_free(sit);
+			t_free(t);
+			continue;
+		}
+
+		if (trace_rb_insert_sort(t))
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * to continue, we must have traces from all online cpus in the tree
+ */
+static int check_cpu_map(struct per_dev_info *pdi)
+{
+	unsigned long *cpu_map;
+	struct rb_node *n;
+	struct trace *__t;
+	unsigned int i;
+	int ret, cpu;
+
+	/*
+	 * create a map of the cpus we have traces for
+	 */
+	cpu_map = malloc(pdi->cpu_map_max / sizeof(long));
+	n = rb_first(&rb_sort_root);
+	while (n) {
+		__t = rb_entry(n, struct trace, rb_node);
+		cpu = __t->sit->cpu;
+
+		cpu_map[CPU_IDX(cpu)] |= (1UL << CPU_BIT(cpu));
+		n = rb_next(n);
+	}
+
+	/*
+	 * we can't continue if pdi->cpu_map has entries set that we don't
+	 * have in the sort rbtree. the opposite is not a problem, though
+	 */
+	ret = 0;
+	for (i = 0; i < pdi->cpu_map_max / CPUS_PER_LONG; i++) {
+		if (pdi->cpu_map[i] & ~(cpu_map[i])) {
+			ret = 1;
+			break;
+		}
+	}
+
+	free(cpu_map);
+	return ret;
+}
+
+static int check_sequence(struct per_dev_info *pdi, struct trace *t, int force)
+{
+	struct stp_trace *sit = t->sit;
+	unsigned long expected_sequence;
+	struct per_cpu_info *pci;
+	struct trace *__t;
+
+	pci = get_cpu_info(pdi, sit->cpu);
+	expected_sequence = pci->last_sequence + 1;
+
+	if (!expected_sequence) {
+		/*
+		 * 1 should be the first entry, just allow it
+		 */
+		if (sit->sequence == 1)
+			return 0;
+		if (sit->sequence == pci->smallest_seq_read)
+			return 0;
+
+		return check_cpu_map(pdi);
+	}
+
+	if (sit->sequence == expected_sequence)
+		return 0;
+
+	/*
+	 * we may not have seen that sequence yet. if we are not doing
+	 * the final run, break and wait for more entries.
+	 */
+	if (expected_sequence < pci->smallest_seq_read) {
+		__t = trace_rb_find_last(pdi, pci, expected_sequence);
+		if (!__t)
+			goto skip;
+
+		__put_trace_last(pdi, __t);
+		return 0;
+	} else if (!force) {
+		return 1;
+	} else {
+skip:
+		if (check_current_skips(pci, sit->sequence))
+			return 0;
+
+		if (expected_sequence < sit->sequence)
+			insert_skip(pci, expected_sequence, sit->sequence - 1);
+		return 0;
+	}
+}
+
+static void show_entries_rb(int force)
+{
+	struct per_dev_info *pdi = NULL;
+	struct per_cpu_info *pci = NULL;
+	struct stp_trace *sit;
+	struct rb_node *n;
+	struct trace *t;
+
+	while ((n = rb_first(&rb_sort_root)) != NULL) {
+		if (is_done() && !force && !pipeline)
+			break;
+
+		t = rb_entry(n, struct trace, rb_node);
+		sit = t->sit;
+
+		if (read_sequence - t->read_sequence < 1 && !force)
+			break;
+
+		if (!pdi || pdi->dev != sit->device) {
+			pdi = get_dev_info(sit->device);
+			pci = NULL;
+		}
+
+		if (!pdi) {
+			fprintf(stderr, "Unknown device ID? (%d,%d)\n",
+				MAJOR(sit->device), MINOR(sit->device));
+			break;
+		}
+
+		if (check_sequence(pdi, t, force))
+			break;
+
+		if (!force && sit->time > last_allowed_time)
+			break;
+
+		check_time(pdi, sit);
+
+		if (!pci || pci->cpu != sit->cpu)
+			pci = get_cpu_info(pdi, sit->cpu);
+
+		pci->last_sequence = sit->sequence;
+
+		pci->nelems++;
+
+		dump_trace(sit, pci, pdi);
+
+		put_trace(pdi, t);
+	}
+}
+
+static int read_data(int fd, void *buffer, int bytes, int block, int *fdblock)
+{
+	int ret, bytes_left, fl;
+	void *p;
+
+	if (block != *fdblock) {
+		fl = fcntl(fd, F_GETFL);
+
+		if (!block) {
+			*fdblock = 0;
+			fcntl(fd, F_SETFL, fl | O_NONBLOCK);
+		} else {
+			*fdblock = 1;
+			fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
+		}
+	}
+
+	bytes_left = bytes;
+	p = buffer;
+	while (bytes_left > 0) {
+		ret = read(fd, p, bytes_left);
+		if (!ret)
+			return 1;
+		else if (ret < 0) {
+			if (errno != EAGAIN) {
+				perror("read");
+				return -1;
+			}
+
+			/*
+			 * never do partial reads. we can return if we
+			 * didn't read anything and we should not block,
+			 * otherwise wait for data
+			 */
+			if ((bytes_left == bytes) && !block)
+				return 1;
+
+			usleep(10);
+			continue;
+		} else {
+			p += ret;
+			bytes_left -= ret;
+		}
+	}
+
+	return 0;
+}
+
+static inline __u16 get_pdulen(struct stp_trace *sit)
+{
+	if (data_is_native)
+		return sit->pdu_len;
+
+	return __bswap_16(sit->pdu_len);
+}
+
+static inline __u32 get_magic(struct stp_trace *sit)
+{
+	if (data_is_native)
+		return sit->magic;
+
+	return __bswap_32(sit->magic);
+}
+
+static int read_events(int fd, int always_block, int *fdblock)
+{
+	struct per_dev_info *pdi = NULL;
+	unsigned int events = 0;
+
+	while (!is_done() && events < rb_batch) {
+		struct stp_trace *sit;
+		struct trace *t;
+		int pdu_len, should_block, ret;
+		__u32 magic;
+
+		sit = sit_alloc();
+
+		should_block = !events || always_block;
+
+		ret = read_data(fd, sit, sizeof(*sit), should_block, fdblock);
+		if (ret) {
+			sit_free(sit);
+			if (!events && ret < 0)
+				events = ret;
+			break;
+		}
+
+		/*
+		 * look at first trace to check whether we need to convert
+		 * data in the future
+		 */
+		if (data_is_native == -1 && check_data_endianness(sit->magic))
+			break;
+
+		magic = get_magic(sit);
+		if ((magic & 0xffffff00) != UTT_TRACE_MAGIC) {
+			fprintf(stderr, "Bad magic %x\n", magic);
+			break;
+		}
+
+		pdu_len = get_pdulen(sit);
+		if (pdu_len) {
+			void *ptr = realloc(sit, sizeof(*sit) + pdu_len);
+
+			if (read_data(fd, ptr + sizeof(*sit), pdu_len, 1, fdblock)) {
+				sit_free(ptr);
+				break;
+			}
+
+			sit = ptr;
+		}
+
+		trace_to_cpu(sit);
+
+		if (verify_trace((struct utt_header *)sit)) {
+			sit_free(sit);
+			continue;
+		}
+
+		t = t_alloc();
+		memset(t, 0, sizeof(*t));
+		t->sit = sit;
+		t->read_sequence = read_sequence;
+
+		t->next = trace_list;
+		trace_list = t;
+
+		if (!pdi || pdi->dev != sit->device)
+			pdi = get_dev_info(sit->device);
+
+		if (sit->time > pdi->last_read_time)
+			pdi->last_read_time = sit->time;
+
+		events++;
+	}
+
+	return events;
+}
+
+static int do_file(void)
+{
+	struct per_cpu_info *pci;
+	struct per_dev_info *pdi;
+	int i, j, events, events_added;
+
+	/*
+	 * first prepare all files for reading
+	 */
+	for (i = 0; i < ndevices; i++) {
+		pdi = &devices[i];
+		pdi->nfiles = 0;
+
+		for (j = 0;; j++) {
+			struct stat st;
+			int len = 0;
+			char *p, *dname;
+
+			pci = get_cpu_info(pdi, j);
+			pci->cpu = j;
+			pci->fd = -1;
+			pci->fdblock = -1;
+	
+			p = strdup(pdi->name);
+			dname = dirname(p);
+			if (strcmp(dname, ".")) {
+				input_dir = dname;
+				p = strdup(pdi->name);
+				strcpy(pdi->name, basename(p));
+			}
+			free(p);
+
+			if (input_dir)
+				len = sprintf(pci->fname, "%s/", input_dir);
+
+			snprintf(pci->fname + len, sizeof(pci->fname)-1-len,
+				 "%s.systemtap.%d", pdi->name, pci->cpu);
+			if (stat(pci->fname, &st) < 0)
+				break;
+			if (st.st_size) {
+				pci->fd = open(pci->fname, O_RDONLY);
+				if (pci->fd < 0) {
+					perror(pci->fname);
+					continue;
+				}
+			}
+
+			printf("Input file %s added\n", pci->fname);
+			pdi->nfiles++;
+			cpu_mark_online(pdi, pci->cpu);
+		}
+	}
+
+	/*
+	 * now loop over the files reading in the data
+	 */
+	do {
+		unsigned long long youngest;
+
+		events_added = 0;
+		last_allowed_time = -1ULL;
+		read_sequence++;
+
+		for (i = 0; i < ndevices; i++) {
+			pdi = &devices[i];
+			pdi->last_read_time = -1ULL;
+
+			for (j = 0; j < pdi->nfiles; j++) {
+
+				pci = get_cpu_info(pdi, j);
+
+				if (pci->fd == -1)
+					continue;
+
+				pci->smallest_seq_read = -1;
+
+				events = read_events(pci->fd, 1, &pci->fdblock);
+				if (events <= 0) {
+					cpu_mark_offline(pdi, pci->cpu);
+					close(pci->fd);
+					pci->fd = -1;
+					continue;
+				}
+
+				if (pdi->last_read_time < last_allowed_time)
+					last_allowed_time = pdi->last_read_time;
+
+				events_added += events;
+			}
+		}
+
+		if (sort_entries(&youngest))
+			break;
+
+		if (youngest > stopwatch_end)
+			break;
+
+		show_entries_rb(0);
+
+	} while (events_added);
+
+	if (rb_sort_entries)
+		show_entries_rb(1);
+
+	return 0;
+}
+
+static int do_stdin(void)
+{
+	unsigned long long youngest;
+	int fd, events, fdblock;
+
+	last_allowed_time = -1ULL;
+	fd = dup(STDIN_FILENO);
+	if (fd == -1) {
+		perror("dup stdin");
+		return -1;
+	}
+
+	fdblock = -1;
+	while ((events = read_events(fd, 0, &fdblock)) > 0) {
+		read_sequence++;
+	
+#if 0
+		smallest_seq_read = -1U;
+#endif
+
+		if (sort_entries(&youngest))
+			break;
+
+		if (youngest > stopwatch_end)
+			break;
+
+		show_entries_rb(0);
+	}
+
+	if (rb_sort_entries)
+		show_entries_rb(1);
+
+	close(fd);
+	return 0;
+}
+
+static void show_stats(void)
+{
+	if (!ofp)
+		return;
+	if (stats_printed)
+		return;
+
+	stats_printed = 1;
+
+	if (per_device_and_cpu_stats)
+		show_device_and_cpu_stats();
+
+	fflush(ofp);
+}
+
+static void handle_sigint(__attribute__((__unused__)) int sig)
+{
+	done = 1;
+}
+
+/*
+ * Extract start and duration times from a string, allowing
+ * us to specify a time interval of interest within a trace.
+ * Format: "duration" (start is zero) or "start:duration".
+ */
+static int find_stopwatch_interval(char *string)
+{
+	double value;
+	char *sp;
+
+	value = strtod(string, &sp);
+	if (sp == string) {
+		fprintf(stderr,"Invalid stopwatch timer: %s\n", string);
+		return 1;
+	}
+	if (*sp == ':') {
+		stopwatch_start = DOUBLE_TO_NANO_ULL(value);
+		string = sp + 1;
+		value = strtod(string, &sp);
+		if (sp == string || *sp != '\0') {
+			fprintf(stderr,"Invalid stopwatch duration time: %s\n",
+				string);
+			return 1;
+		}
+	} else if (*sp != '\0') {
+		fprintf(stderr,"Invalid stopwatch start timer: %s\n", string);
+		return 1;
+	}
+	stopwatch_end = DOUBLE_TO_NANO_ULL(value);
+	if (stopwatch_end <= stopwatch_start) {
+		fprintf(stderr, "Invalid stopwatch interval: %Lu -> %Lu\n",
+			stopwatch_start, stopwatch_end);
+		return 1;
+	}
+
+	return 0;
+}
+
+static char usage_str[] = \
+	"[ -i <input name> ] [-o <output name>\n" \
+	"[ -w start:stop ] [ -v] \n\n" \
+	"\t-i Input file containing trace data, or '-' for stdin\n" \
+	"\t-D Directory to prepend to input file names\n" \
+	"\t-o Output file. If not given, output is stdout\n" \
+	"\t-d Output file. If specified, binary data is written to file\n" \
+	"\t-b stdin read batching\n" \
+	"\t-w Only parse data between the given time interval in seconds.\n" \
+	"\t   If 'start' isn't given, blkparse defaults the start time to 0\n" \
+	"\t-v More verbose for marginal errors\n" \
+	"\t-V Print program version info\n\n";
+
+static void usage(char *prog)
+{
+	fprintf(stderr, "Usage: %s %s %s", prog, stpparse_version, usage_str);
+}
+
+int main(int argc, char *argv[])
+{
+	char *ofp_buffer;
+	int c, ret, mode;
+
+	while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
+		switch (c) {
+		case 'i':
+			if (!strcmp(optarg, "-") && !pipeline) {
+				pipeline = 1;
+			}
+			else if (resize_devices(optarg) != 0)
+				return 1;
+			break;
+		case 'D':
+			input_dir = optarg;
+			break;
+		case 'o':
+			output_name = optarg;
+			break;
+		case 'b':
+			rb_batch = atoi(optarg);
+			if (rb_batch <= 0)
+				rb_batch = RB_BATCH_DEFAULT;
+			break;
+		case 'w':
+			if (find_stopwatch_interval(optarg) != 0)
+				return 1;
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'V':
+			printf("%s version %s\n", argv[0], stpparse_version);
+			return 0;
+		case 'd':
+			dump_binary = optarg;
+			break;
+		default:
+			usage(argv[0]);
+			return 1;
+		}
+	}
+
+	while (optind < argc) {
+		if (!strcmp(argv[optind], "-") && !pipeline)
+			pipeline = 1;
+		else if (resize_devices(argv[optind]) != 0)
+			return 1;
+		optind++;
+	}
+
+	if (!pipeline && !ndevices) {
+		usage(argv[0]);
+		return 1;
+	}
+
+	memset(&rb_sort_root, 0, sizeof(rb_sort_root));
+
+	signal(SIGINT, handle_sigint);
+	signal(SIGHUP, handle_sigint);
+	signal(SIGTERM, handle_sigint);
+
+	setlocale(LC_NUMERIC, "en_US");
+
+	if (!output_name) {
+		ofp = fdopen(STDOUT_FILENO, "w");
+		mode = _IOLBF;
+	} else {
+		char ofname[128];
+
+		snprintf(ofname, sizeof(ofname) - 1, "%s", output_name);
+		ofp = fopen(ofname, "w");
+		mode = _IOFBF;
+	}
+
+	if (!ofp) {
+		perror("fopen");
+		return 1;
+	}
+
+	ofp_buffer = malloc(4096);	
+	if (setvbuf(ofp, ofp_buffer, mode, 4096)) {
+		perror("setvbuf");
+		return 1;
+	}
+
+	if (dump_binary) {
+		dump_fd = creat(dump_binary, 0666);
+		if (dump_fd < 0) {
+			perror(dump_binary);
+			dump_binary = NULL;
+			return 1;
+		}
+	}
+
+	if (pipeline)
+		ret = do_stdin();
+	else
+		ret = do_file();
+
+	show_stats();
+	free(ofp_buffer);
+	return ret;
+}
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/stp_server.c src/runtime/stpd/stp_server.c
--- src-orig/runtime/stpd/stp_server.c	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/stp_server.c	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,100 @@
+/*
+ * systemtap utt server
+ *
+ * Copyright (C) 2006 Tom Zanussi <zanussi@us.ibm.com>
+ *
+ * Based on blktrace.c:
+ * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <locale.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/statfs.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/sendfile.h>
+
+#include "utt.h"
+
+static char stp_server_version[] = "0.00.1";
+
+static void show_usage(char *program)
+{
+	fprintf(stderr, "Usage: %s %s",program, stp_server_version);
+}
+
+static int stp_utt_trace_setup(void *private_data __attribute__ ((unused)),
+			       struct utt_trace_setup *utts __attribute__ ((unused)))
+{
+	return 0;
+}
+
+static int stp_utt_trace_start(void *private_data __attribute__ ((unused)))
+{
+	return 0;
+}
+
+static int stp_utt_trace_stop(void *private_data __attribute__ ((unused)))
+{
+	return 0;
+}
+
+static int stp_utt_trace_teardown(void *private_data __attribute__ ((unused)))
+{
+	return 0;
+}
+
+static struct utt_trace_ops stp_utt_trace_ops = {
+	.trace_setup = stp_utt_trace_setup,
+	.trace_start = stp_utt_trace_start,
+	.trace_stop = stp_utt_trace_stop,
+	.trace_teardown = stp_utt_trace_teardown,
+};
+
+int main(int argc __attribute__ ((unused)), char *argv[])
+{
+	utt_parse_arg('l', NULL);
+	
+	setlocale(LC_NUMERIC, "en_US");
+
+	if (utt_start(&stp_utt_trace_ops, 0, "systemtap")) {
+		show_usage(argv[0]);
+		return 1;
+	}
+
+	return 0;
+}
+
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/stp_utt.c src/runtime/stpd/stp_utt.c
--- src-orig/runtime/stpd/stp_utt.c	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/stp_utt.c	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,134 @@
+/*
+ * systemtap utt tracing application
+ *
+ * Copyright (C) 2006 Tom Zanussi <zanussi@us.ibm.com>
+ *
+ * Based on blktrace.c:
+ * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <locale.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/statfs.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/sendfile.h>
+
+#include "utt.h"
+#include "librelay.h"
+
+extern struct params params;
+
+static int stp_utt_trace_setup(void *private_data __attribute__ ((unused)),
+			       struct utt_trace_setup *utts)
+{
+	/* set utt's size params */
+	utts->buf_size = params.subbuf_size;
+	utts->buf_nr = params.n_subbufs;
+
+	return 0;
+}
+
+static int stp_utt_trace_start(void *private_data __attribute__ ((unused)))
+{
+	/* let stpd do this for now */
+	return 0;
+}
+
+static int stp_utt_trace_stop(void *private_data __attribute__ ((unused)))
+{
+	/* let stpd do this for now */
+	return 0;
+}
+
+static int stp_utt_trace_teardown(void *private_data __attribute__ ((unused)))
+{
+	/* let stpd do this for now */
+	return 0;
+}
+
+static struct utt_trace_ops stp_utt_trace_ops = {
+	.trace_setup = stp_utt_trace_setup,
+	.trace_start = stp_utt_trace_start,
+	.trace_stop = stp_utt_trace_stop,
+	.trace_teardown = stp_utt_trace_teardown,
+};
+
+static int stp_utt_add_trace(int pid)
+{
+	char buf[32];
+	
+//	sprintf(buf, "%d", pid);
+	// for now, don't use pid, files in debug/systemtap-utt/currprobe
+	sprintf(buf, "%s", "currprobe");
+	if (utt_add_trace("systemtap-utt", buf, NULL) != 0) {
+		fprintf(stderr, "Out of memory, pid %d\n", pid);
+		return 1;
+	}
+	return 0;
+}
+/**
+ *	utt_thread - utt thread
+ */
+static void *utt_thread(void *data __attribute__ ((unused)))
+{
+	if (stp_utt_add_trace(111) != 0)
+		return NULL;
+
+	if (utt_start(&stp_utt_trace_ops, 0, "systemtap")) {
+		fprintf(stdout, "utt_start err, exiting\n");
+		return NULL;
+	}
+
+	return NULL;
+}
+
+pthread_t utt;
+
+int stp_start_utt(char *outfile_name, char *host)
+{
+	if (outfile_name)
+		utt_parse_arg('o', outfile_name);
+	if (host)
+		utt_parse_arg('h', host);
+	/* create a thread for utt */
+	if (pthread_create(&utt, NULL, utt_thread, NULL) < 0) {
+		fprintf(stderr, "ERROR: Couldn't create utt thread\n");
+		return -1;
+	}
+	return 0;
+}
+
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/stp_utt.h src/runtime/stpd/stp_utt.h
--- src-orig/runtime/stpd/stp_utt.h	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/stp_utt.h	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,62 @@
+#ifndef STP_UTT_H
+#define STP_UTT_H
+
+#include <asm/types.h>
+#include "utt.h"
+#include "rbtree.h"
+
+//#define UTT_TRACE_MAGIC		0x65617401
+//#define UTT_TRACE_VERSION	0x01
+
+#define MINORBITS	20
+#define MINORMASK	((1U << MINORBITS) - 1)
+#define MAJOR(dev)	((unsigned int) ((dev) >> MINORBITS))
+#define MINOR(dev)	((unsigned int) ((dev) & MINORMASK))
+
+#define SECONDS(x) 		((unsigned long long)(x) / 1000000000)
+#define NANO_SECONDS(x)		((unsigned long long)(x) % 1000000000)
+#define DOUBLE_TO_NANO_ULL(d)	((unsigned long long)((d) * 1000000000))
+
+struct per_cpu_info {
+	unsigned int cpu;
+	unsigned int nelems;
+
+	int fd;
+	int fdblock;
+	char fname[128];
+
+	struct rb_root rb_last;
+	unsigned long rb_last_entries;
+	unsigned long last_sequence;
+	unsigned long smallest_seq_read;
+
+	struct skip_info *skips_head;
+	struct skip_info *skips_tail;
+};
+
+struct stp_trace {
+	__u32 magic;		/* MAGIC << 8 | version */
+	__u32 sequence;		/* event number */
+	__u64 time;		/* in nanoseconds */
+	__u32 cpu;		/* on what cpu did it happen */
+	__u32 device;		/* device identifier (dev_t) */
+	__u16 pdu_len;		/* length of data after this trace */
+	char *data;		/* variable-length event data */
+};
+
+static inline void trace_to_cpu(struct stp_trace *s)
+{
+	if (data_is_native)
+		return;
+
+	s->magic	= be32_to_cpu(s->magic);
+	s->sequence	= be32_to_cpu(s->sequence);
+	s->time		= be64_to_cpu(s->time);
+	s->cpu		= be16_to_cpu(s->cpu); // should be 32
+	s->device	= be32_to_cpu(s->device);
+	s->pdu_len	= be16_to_cpu(s->pdu_len);
+}
+
+extern int stp_start_utt(char *outfile_name, char *host);
+
+#endif
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/stpd.c src/runtime/stpd/stpd.c
--- src-orig/runtime/stpd/stpd.c	2006-09-26 16:38:35.000000000 -0500
+++ src/runtime/stpd/stpd.c	2006-10-06 14:45:56.000000000 -0500
@@ -44,6 +44,7 @@ char *modoptions[MAXMODOPTIONS];
 char *target_cmd = NULL;
 char *outfile_name = NULL;
 char *username = NULL;
+char *host = NULL;
 uid_t cmd_uid;
 gid_t cmd_gid;
 
@@ -58,6 +59,7 @@ static void usage(char *prog)
 	fprintf(stderr, "-t pid.  Sets _stp_target to pid.\n");
 	fprintf(stderr, "-d pid.  Pass the systemtap driver's pid.\n");
 	fprintf(stderr, "-o FILE. Send output to FILE.\n");
+	fprintf(stderr, "-n HOST. Send output to HOST.\n");
 	fprintf(stderr, "-u username. Run commands as username.\n");
 	fprintf(stderr, "-b buffer size. The systemtap module will specify a buffer size.\n");
 	fprintf(stderr, "   Setting one here will override that value. The value should be\n");
@@ -70,7 +72,7 @@ int main(int argc, char **argv)
 {
 	int c;
 	
-	while ((c = getopt(argc, argv, "mpqrb:n:t:d:c:vo:u:")) != EOF)
+	while ((c = getopt(argc, argv, "mpqrb:n:t:d:c:vo:n:u:")) != EOF)
 	{
 		switch (c) {
 		case 'm':
@@ -112,6 +114,9 @@ int main(int argc, char **argv)
 		case 'o':
 			outfile_name = optarg;
 			break;
+		case 'n':
+			host = optarg;
+			break;
 		case 'u':
 			username = optarg;
 			break;
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/utt-app.h src/runtime/stpd/utt-app.h
--- src-orig/runtime/stpd/utt-app.h	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/utt-app.h	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,12 @@
+#ifndef UTT_CONFIG_H
+#define UTT_CONFIG_H
+
+#include "stp_utt.h"
+
+#define UTT_TRACE_MAGIC		0x65617500
+#define UTT_TRACE_VERSION	0x01
+// we need this only for verify_trace(), get rid of it
+// the struct needs to have fields named magic, sequence, time, pdu_len
+#define UTT_HEADER		struct stp_trace
+
+#endif
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/utt.c src/runtime/stpd/utt.c
--- src-orig/runtime/stpd/utt.c	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/utt.c	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,1776 @@
+/*
+ * Unified Trace Transport tracing application
+ *
+ * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
+ *
+ * Moved to utt.c by Tom Zanussi, 2006
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <locale.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/statfs.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/sendfile.h>
+
+#include "utt.h"
+#include "barrier.h"
+
+static char default_debugfs_path[] = "/debug";
+static struct utt_trace_ops *trace_ops;
+static char *app_name;
+
+/*
+ * You may want to increase this even more, if you are logging at a high
+ * rate and see skipped/missed events
+ */
+#define BUF_SIZE	(512 * 1024)
+#define BUF_NR		(4)
+
+#define OFILE_BUF	(128 * 1024)
+
+#define DEBUGFS_TYPE	0x64626720
+
+struct tip_subbuf {
+	void *buf;
+	unsigned int len;
+	unsigned int max_len;
+};
+
+#define FIFO_SIZE	(1024)	/* should be plenty big! */
+#define CL_SIZE		(128)	/* cache line, any bigger? */
+
+struct tip_subbuf_fifo {
+	int tail __attribute__((aligned(CL_SIZE)));
+	int head __attribute__((aligned(CL_SIZE)));
+	struct tip_subbuf *q[FIFO_SIZE];
+};
+
+struct thread_information {
+	int cpu;
+	pthread_t thread;
+
+	int fd;
+	void *fd_buf;
+	char fn[MAXPATHLEN + 64];
+
+	FILE *ofile;
+	char *ofile_buffer;
+	off_t ofile_offset;
+	int ofile_stdout;
+	int ofile_mmap;
+
+	int (*get_subbuf)(struct thread_information *, unsigned int);
+	int (*flush_subbuf)(struct thread_information *, struct tip_subbuf *);
+	int (*read_data)(struct thread_information *, void *, unsigned int);
+
+	unsigned long events_processed;
+	unsigned long long data_read;
+	unsigned long long data_queued;
+	struct trace_information *trace;
+
+	int exited;
+
+	/*
+	 * piped fifo buffers
+	 */
+	struct tip_subbuf_fifo fifo;
+	struct tip_subbuf *leftover_ts;
+
+	/*
+	 * mmap controlled output files
+	 */
+	unsigned long long fs_size;
+	unsigned long long fs_max_size;
+	unsigned long fs_off;
+	void *fs_buf;
+	unsigned long fs_buf_len;
+
+	struct net_connection *nc;
+};
+
+struct trace_information {
+	void *private_data;
+	char root_name[UTT_TRACE_ROOT_NAME_SIZE];
+	char trace_name[UTT_TRACE_NAME_SIZE];
+	volatile int trace_started;
+	unsigned long drop_count;
+	struct thread_information *threads;
+	unsigned long buf_size;
+	unsigned long buf_nr;
+	unsigned int page_size;
+
+	struct cl_host *ch;
+	u32 cl_id;
+	time_t cl_connect_time;
+};
+
+static int ncpus;
+static struct thread_information *thread_information;
+static int ntraces;
+static struct trace_information *trace_information;
+
+/* command line option globals */
+static char *debugfs_path;
+static char *output_name;
+static char *output_dir;
+static int kill_running_trace;
+static unsigned long buf_size = BUF_SIZE;
+static unsigned long buf_nr = BUF_NR;
+static unsigned int page_size;
+
+#define is_done()	(*(volatile int *)(&done))
+static volatile int done;
+
+#define is_trace_stopped()	(*(volatile int *)(&trace_stopped))
+static volatile int trace_stopped;
+
+#define is_stat_shown()	(*(volatile int *)(&stat_shown))
+static volatile int stat_shown;
+
+int data_is_native = -1;
+
+static void exit_trace(int status);
+
+#define trip_tracing(trip)	(*(volatile int *)(&(trip)->trace_started))
+#define trip_set_tracing(trip, v)	((trip)->trace_started = (v))
+
+#define __for_each_trip(__d, __di, __e, __i)	\
+	for (__i = 0, __d = __di; __i < __e; __i++, __d++)
+
+#define for_each_trip(__d, __i)		\
+	__for_each_trip(__d, trace_information, ntraces, __i)
+#define for_each_nc_trip(__nc, __d, __i)		\
+	__for_each_trip(__d, (__nc)->ch->trace_information, (__nc)->ch->ntraces, __i)
+
+#define __for_each_tip(__d, __t, __ncpus, __j)	\
+	for (__j = 0, __t = (__d)->threads; __j < __ncpus; __j++, __t++)
+#define for_each_tip(__d, __t, __j)	\
+	__for_each_tip(__d, __t, ncpus, __j)
+#define for_each_cl_host(__c)	\
+	for (__c = cl_host_list; __c; __c = __c->list_next)
+
+/*
+ * networking stuff follows. we include a magic number so we know whether
+ * to endianness convert or not
+ */
+struct utt_trace_net_hdr {
+	u32 magic;		/* same as trace magic */
+	char trace_name[32];	/* trace name */
+	u32 cpu;		/* for which cpu */
+	u32 max_cpus;
+	u32 len;		/* length of following trace data */
+	u32 cl_id;		/* id for set of client per-cpu connections */
+	u32 buf_size;		/* client buf_size for this trace  */
+	u32 buf_nr;		/* client buf_nr for this trace  */
+	u32 page_size;		/* client page_size for this trace  */
+};
+
+#define TRACE_NET_PORT		(8462)
+
+enum {
+	Net_none = 0,
+	Net_server,
+	Net_client,
+};
+
+/*
+ * network cmd line params
+ */
+static char hostname[MAXHOSTNAMELEN];
+static int net_port = TRACE_NET_PORT;
+static int net_mode = 0;
+static int net_use_sendfile = 1;
+
+struct cl_host {
+	struct cl_host *list_next;
+	struct in_addr cl_in_addr;
+	struct net_connection *net_connections;
+	int nconn;
+	struct trace_information *trace_information;
+	int ntraces;
+	int ncpus;
+	int ntraces_done;
+};
+
+struct net_connection {
+	int in_fd;
+	struct pollfd pfd;
+	time_t connect_time;
+	struct cl_host *ch;
+	int ncpus;
+};
+
+#define NET_MAX_CL_HOSTS	(1024)
+static struct cl_host *cl_host_list;
+static int cl_hosts;
+static int net_connects;
+
+static int *net_out_fd;
+
+void utt_stop(void)
+{
+	struct trace_information *trip;
+	int i;
+	/*
+	 * stop trace so we can reap currently produced data
+	 */
+	for_each_trip(trip, i)
+		if (trace_ops->trace_stop(trip->private_data))
+			continue;
+
+	done = 1;
+}
+
+static void handle_sigint(__attribute__((__unused__)) int sig)
+{
+	utt_stop();
+}
+
+static int get_dropped_count(const char *root_name, const char *trace_name)
+{
+	int fd;
+	char tmp[MAXPATHLEN + 64];
+
+	snprintf(tmp, sizeof(tmp), "%s/%s/%s/dropped",
+		 debugfs_path, root_name, trace_name);
+
+	fd = open(tmp, O_RDONLY);
+	if (fd < 0) {
+		/*
+		 * this may be ok, if the kernel doesn't support dropped counts
+		 */
+		if (errno == ENOENT)
+			return 0;
+
+		fprintf(stderr, "Couldn't open dropped file %s\n", tmp);
+		return -1;
+	}
+
+	if (read(fd, tmp, sizeof(tmp)) < 0) {
+		perror(tmp);
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+
+	return atoi(tmp);
+}
+
+static int start_trace(struct trace_information *trip)
+{
+	struct utt_trace_setup utts;
+
+	memset(&utts, 0, sizeof(utts));
+	utts.buf_size = buf_size;
+	utts.buf_nr = buf_nr;
+	memcpy(utts.root, trip->root_name, sizeof(utts.root));
+	memcpy(utts.name, trip->trace_name, sizeof(utts.name));
+	trip->page_size = page_size;
+
+	if (trace_ops->trace_setup(trip->private_data, &utts))
+		return 1;
+
+	/* The size params may have changed */
+	buf_size = trip->buf_size = utts.buf_size;
+	buf_nr = trip->buf_nr = utts.buf_nr;
+	/* The trace name may have changed */
+	memcpy(trip->trace_name, utts.name, sizeof(trip->trace_name));
+
+	if (trace_ops->trace_start(trip->private_data))
+		return 1;
+
+	trip_set_tracing(trip, 1);
+	return 0;
+}
+
+static void stop_trace(struct trace_information *trip)
+{
+	if (trip_tracing(trip) || kill_running_trace) {
+		trip_set_tracing(trip, 0);
+		/*
+		 * should be stopped, just don't complain if it isn't
+		 */
+		trace_ops->trace_stop(trip->private_data);
+		trace_ops->trace_teardown(trip->private_data);
+	}
+}
+
+void stop_all_traces(void)
+{
+	struct trace_information *trip;
+	int i;
+
+	for_each_trip(trip, i) {
+		trip->drop_count = get_dropped_count(trip->root_name, trip->trace_name);
+		stop_trace(trip);
+	}
+}
+
+static void wait_for_data(struct thread_information *tip, int timeout)
+{
+	struct pollfd pfd = { .fd = tip->fd, .events = POLLIN };
+
+	while (!is_done()) {
+		if (poll(&pfd, 1, timeout) < 0) {
+			perror("poll");
+			break;
+		}
+		if (pfd.revents & POLLIN)
+			break;
+		if (tip->ofile_stdout)
+			break;
+	}
+}
+
+static int read_data_file(struct thread_information *tip, void *buf,
+			  unsigned int len)
+{
+	int ret = 0;
+
+	do {
+		wait_for_data(tip, 100);
+
+		ret = read(tip->fd, buf, len);
+		if (!ret)
+			continue;
+		else if (ret > 0)
+			return ret;
+		else {
+			if (errno != EAGAIN) {
+				perror(tip->fn);
+				fprintf(stderr,"Thread %d failed read of %s\n",
+					tip->cpu, tip->fn);
+				break;
+			}
+			continue;
+		}
+	} while (!is_done());
+
+	return ret;
+
+}
+
+static int read_data_net(struct thread_information *tip, void *buf,
+			 unsigned int len)
+{
+	struct net_connection *nc = tip->nc;
+	unsigned int bytes_left = len;
+	int ret = 0;
+
+	do {
+		ret = recv(nc->in_fd, buf, bytes_left, MSG_WAITALL);
+
+		if (!ret)
+			continue;
+		else if (ret < 0) {
+			if (errno != EAGAIN) {
+				perror(tip->fn);
+				fprintf(stderr, "server: failed read\n");
+				return 0;
+			}
+			continue;
+		} else {
+			buf += ret;
+			bytes_left -= ret;
+		}
+	} while (!is_done() && bytes_left);
+
+	return len - bytes_left;
+}
+
+static inline struct tip_subbuf *
+subbuf_fifo_dequeue(struct thread_information *tip)
+{
+	const int head = tip->fifo.head;
+	const int next = (head + 1) & (FIFO_SIZE - 1);
+
+	if (head != tip->fifo.tail) {
+		struct tip_subbuf *ts = tip->fifo.q[head];
+
+		store_barrier();
+		tip->fifo.head = next;
+		return ts;
+	}
+
+	return NULL;
+}
+
+static inline int subbuf_fifo_queue(struct thread_information *tip,
+				    struct tip_subbuf *ts)
+{
+	const int tail = tip->fifo.tail;
+	const int next = (tail + 1) & (FIFO_SIZE - 1);
+
+	if (next != tip->fifo.head) {
+		tip->fifo.q[tail] = ts;
+		store_barrier();
+		tip->fifo.tail = next;
+		return 0;
+	}
+
+	fprintf(stderr, "fifo too small!\n");
+	return 1;
+}
+
+/*
+ * For file output, truncate and mmap the file appropriately
+ */
+static int mmap_subbuf(struct thread_information *tip, unsigned int maxlen)
+{
+	int ofd = fileno(tip->ofile);
+	int ret;
+	unsigned long nr;
+
+	/*
+	 * extend file, if we have to. use chunks of 16 subbuffers.
+	 */
+	if (tip->fs_off + maxlen > tip->fs_buf_len) {
+		if (tip->fs_buf) {
+			munlock(tip->fs_buf, tip->fs_buf_len);
+			munmap(tip->fs_buf, tip->fs_buf_len);
+			tip->fs_buf = NULL;
+		}
+
+		tip->fs_off = tip->fs_size & (tip->trace->page_size - 1);
+		nr = max(16, tip->trace->buf_nr);
+		tip->fs_buf_len = (nr * tip->trace->buf_size) - tip->fs_off;
+		tip->fs_max_size += tip->fs_buf_len;
+
+		if (ftruncate(ofd, tip->fs_max_size) < 0) {
+			perror("ftruncate");
+			return -1;
+		}
+
+		tip->fs_buf = mmap(NULL, tip->fs_buf_len, PROT_WRITE,
+				   MAP_SHARED, ofd, tip->fs_size - tip->fs_off);
+		if (tip->fs_buf == MAP_FAILED) {
+			perror("mmap");
+			return -1;
+		}
+		mlock(tip->fs_buf, tip->fs_buf_len);
+	}
+
+	ret = tip->read_data(tip, tip->fs_buf + tip->fs_off, maxlen);
+	if (ret >= 0) {
+		tip->data_read += ret;
+		tip->fs_size += ret;
+		tip->fs_off += ret;
+		return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * Use the copy approach for pipes and network
+ */
+static int get_subbuf(struct thread_information *tip, unsigned int maxlen)
+{
+	struct tip_subbuf *ts = malloc(sizeof(*ts));
+	int ret;
+
+	ts->buf = malloc(tip->trace->buf_size);
+	ts->max_len = maxlen;
+
+	ret = tip->read_data(tip, ts->buf, ts->max_len);
+	if (ret > 0) {
+		ts->len = ret;
+		tip->data_read += ret;
+		if (subbuf_fifo_queue(tip, ts))
+			ret = -1;
+	}
+
+	if (ret <= 0) {
+		free(ts->buf);
+		free(ts);
+	}
+
+	return ret;
+}
+
+static void close_thread(struct thread_information *tip)
+{
+	if (tip->fd != -1)
+		close(tip->fd);
+	if (tip->ofile)
+		fclose(tip->ofile);
+	if (tip->ofile_buffer)
+		free(tip->ofile_buffer);
+	if (tip->fd_buf)
+		free(tip->fd_buf);
+
+	tip->fd = -1;
+	tip->ofile = NULL;
+	tip->ofile_buffer = NULL;
+	tip->fd_buf = NULL;
+}
+
+static void tip_ftrunc_final(struct thread_information *tip)
+{
+	/*
+	 * truncate to right size and cleanup mmap
+	 */
+	if (tip->ofile_mmap && tip->ofile) {
+		int ofd = fileno(tip->ofile);
+
+		if (tip->fs_buf)
+			munmap(tip->fs_buf, tip->fs_buf_len);
+
+		ftruncate(ofd, tip->fs_size);
+	}
+}
+
+static void *thread_main(void *arg)
+{
+	struct thread_information *tip = arg;
+	pid_t pid = getpid();
+	cpu_set_t cpu_mask;
+
+	CPU_ZERO(&cpu_mask);
+	CPU_SET((tip->cpu), &cpu_mask);
+
+	if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1) {
+		perror("sched_setaffinity");
+		exit_trace(1);
+	}
+
+	snprintf(tip->fn, sizeof(tip->fn), "%s/%s/%s/trace%d",
+			debugfs_path, tip->trace->root_name, tip->trace->trace_name, tip->cpu);
+	tip->fd = open(tip->fn, O_RDONLY);
+	if (tip->fd < 0) {
+		perror(tip->fn);
+		fprintf(stderr,"Thread %d failed open of %s\n", tip->cpu,
+			tip->fn);
+		exit_trace(1);
+	}
+
+	while (!is_done()) {
+		if (tip->get_subbuf(tip, tip->trace->buf_size) < 0)
+			break;
+	}
+
+	/*
+	 * trace is stopped, pull data until we get a short read
+	 */
+	while (tip->get_subbuf(tip, tip->trace->buf_size) > 0)
+		;
+
+	tip_ftrunc_final(tip);
+	tip->exited = 1;
+	return NULL;
+}
+
+static int write_data_net(int fd, void *buf, unsigned int buf_len)
+{
+	unsigned int bytes_left = buf_len;
+	int ret;
+
+	while (bytes_left) {
+		ret = send(fd, buf, bytes_left, 0);
+		if (ret < 0) {
+			perror("send");
+			return 1;
+		}
+
+		buf += ret;
+		bytes_left -= ret;
+	}
+
+	return 0;
+}
+
+static int net_send_header(struct thread_information *tip, unsigned int len)
+{
+	struct utt_trace_net_hdr hdr;
+
+	hdr.magic = UTT_TRACE_MAGIC;
+	strcpy(hdr.trace_name, tip->trace->trace_name);
+	hdr.cpu = tip->cpu;
+	hdr.max_cpus = ncpus;
+	hdr.len = len;
+	hdr.cl_id = getpid();
+	hdr.buf_size = tip->trace->buf_size;
+	hdr.buf_nr = tip->trace->buf_nr;
+	hdr.page_size = tip->trace->page_size;
+	
+	return write_data_net(net_out_fd[tip->cpu], &hdr, sizeof(hdr));
+}
+
+/*
+ * send header with 0 length to signal end-of-run
+ */
+static void net_client_send_close(void)
+{
+	struct trace_information *trip;
+	struct utt_trace_net_hdr hdr;
+	int i;
+
+	for_each_trip(trip, i) {
+		hdr.magic = UTT_TRACE_MAGIC;
+		hdr.max_cpus = ncpus;
+		hdr.len = 0;
+		strcpy(hdr.trace_name, trip->trace_name);
+		hdr.cpu = get_dropped_count(trip->root_name, trip->trace_name);
+		hdr.cl_id = getpid();
+		hdr.buf_size = trip->buf_size;
+		hdr.buf_nr = trip->buf_nr;
+		hdr.page_size = trip->page_size;
+
+		write_data_net(net_out_fd[0], &hdr, sizeof(hdr));
+	}
+
+}
+
+static int flush_subbuf_net(struct thread_information *tip,
+			    struct tip_subbuf *ts)
+{
+	if (net_send_header(tip, ts->len))
+		return -1;
+	if (write_data_net(net_out_fd[tip->cpu], ts->buf, ts->len))
+		return -1;
+
+	free(ts->buf);
+	free(ts);
+	return 1;
+}
+
+static int net_sendfile(struct thread_information *tip, struct tip_subbuf *ts)
+{
+	int ret = sendfile(net_out_fd[tip->cpu], tip->fd, NULL, ts->len);
+
+	if (ret < 0) {
+		perror("sendfile");
+		return 1;
+	} else if (ret < (int) ts->len) {
+		fprintf(stderr, "short sendfile send (%d of %d)\n", ret, ts->len);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int flush_subbuf_sendfile(struct thread_information *tip,
+				 struct tip_subbuf *ts)
+{
+	int ret = -1;
+
+	if (net_send_header(tip, ts->len))
+		goto err;
+	if (net_sendfile(tip, ts))
+		goto err;
+
+	tip->data_read += ts->len;
+	ret = 1;
+err:
+	free(ts);
+	return ret;
+}
+
+static int get_subbuf_sendfile(struct thread_information *tip,
+			       __attribute__((__unused__)) unsigned int maxlen)
+{
+	struct tip_subbuf *ts;
+	struct stat sb;
+	unsigned int ready;
+
+	wait_for_data(tip, -1);
+
+	if (fstat(tip->fd, &sb) < 0) {
+		perror("trace stat");
+		return -1;
+	}
+
+	ready = sb.st_size - tip->data_queued;
+	if (!ready) {
+		usleep(1000);
+		return 0;
+	}
+
+	ts = malloc(sizeof(*ts));
+	ts->buf = NULL;
+	ts->max_len = 0;
+	ts->len = ready;
+	tip->data_queued += ready;
+
+	if (flush_subbuf_sendfile(tip, ts) < 0)
+		return -1;
+
+	return ready;
+}
+
+static int write_data(struct thread_information *tip, void *buf,
+		      unsigned int buf_len)
+{
+	int ret;
+
+	if (!buf_len)
+		return 0;
+
+	ret = fwrite(buf, buf_len, 1, tip->ofile);
+	if (ferror(tip->ofile) || ret != 1) {
+		perror("fwrite");
+		clearerr(tip->ofile);
+		return 1;
+	}
+
+	if (tip->ofile_stdout)
+		fflush(tip->ofile);
+
+	return 0;
+}
+
+static int flush_subbuf_file(struct thread_information *tip,
+			     struct tip_subbuf *ts)
+{
+	unsigned int offset = 0;
+	UTT_HEADER *t;
+	int pdu_len, events = 0;
+
+	/*
+	 * surplus from last run
+	 */
+	if (tip->leftover_ts) {
+		struct tip_subbuf *prev_ts = tip->leftover_ts;
+
+		if (prev_ts->len + ts->len > prev_ts->max_len) {
+			prev_ts->max_len += ts->len;
+			prev_ts->buf = realloc(prev_ts->buf, prev_ts->max_len);
+		}
+
+		memcpy(prev_ts->buf + prev_ts->len, ts->buf, ts->len);
+		prev_ts->len += ts->len;
+
+		free(ts->buf);
+		free(ts);
+
+		ts = prev_ts;
+		tip->leftover_ts = NULL;
+	}
+
+	while (offset + sizeof(*t) <= ts->len) {
+		t = ts->buf + offset;
+
+		if (verify_trace((struct utt_header *)t)) {
+			write_data(tip, ts->buf, offset);
+			return -1;
+		}
+
+		pdu_len = t->pdu_len;
+
+		if (offset + sizeof(*t) + pdu_len > ts->len)
+			break;
+
+		offset += sizeof(*t) + pdu_len;
+		tip->events_processed++;
+		tip->data_read += sizeof(*t) + pdu_len;
+		events++;
+	}
+
+	if (write_data(tip, ts->buf, offset))
+		return -1;
+
+	/*
+	 * leftover bytes, save them for next time
+	 */
+	if (offset != ts->len) {
+		tip->leftover_ts = ts;
+		ts->len -= offset;
+		memmove(ts->buf, ts->buf + offset, ts->len);
+	} else {
+		free(ts->buf);
+		free(ts);
+	}
+
+	return events;
+}
+
+static int write_tip_events(struct thread_information *tip)
+{
+	struct tip_subbuf *ts = subbuf_fifo_dequeue(tip);
+
+	if (ts)
+		return tip->flush_subbuf(tip, ts);
+
+	return 0;
+}
+
+/*
+ * scans the tips we know and writes out the subbuffers we accumulate
+ */
+static void get_and_write_events(void)
+{
+	struct trace_information *trip;
+	struct thread_information *tip;
+	int i, j, events, ret, tips_running;
+
+	while (!is_done()) {
+		events = 0;
+
+		for_each_trip(trip, i) {
+			for_each_tip(trip, tip, j) {
+				ret = write_tip_events(tip);
+				if (ret > 0)
+					events += ret;
+			}
+		}
+
+		if (!events)
+			usleep(100000);
+	}
+
+	/*
+	 * reap stored events
+	 */
+	do {
+		events = 0;
+		tips_running = 0;
+		for_each_trip(trip, i) {
+			for_each_tip(trip, tip, j) {
+				ret = write_tip_events(tip);
+				if (ret > 0)
+					events += ret;
+				tips_running += !tip->exited;
+			}
+		}
+		usleep(10);
+	} while (events || tips_running);
+}
+
+static void wait_for_threads(void)
+{
+	/*
+	 * for piped or network output, poll and fetch data for writeout.
+	 * for files, we just wait around for trace threads to exit
+	 */
+	if ((output_name && !strcmp(output_name, "-")) ||
+	    ((net_mode == Net_client) && !net_use_sendfile))
+		get_and_write_events();
+	else {
+		struct trace_information *trip;
+		struct thread_information *tip;
+		int i, j, tips_running;
+
+		do {
+			tips_running = 0;
+			usleep(100000);
+
+			for_each_trip(trip, i)
+				for_each_tip(trip, tip, j)
+					tips_running += !tip->exited;
+		} while (tips_running);
+	}
+
+	if (net_mode == Net_client)
+		net_client_send_close();
+}
+
+static int fill_ofname(struct trace_information *trip,
+		       struct thread_information *tip, char *dst,
+		       char *trace_name)
+{
+	struct stat sb;
+	int len = 0;
+
+	if (output_dir)
+		len = sprintf(dst, "%s/", output_dir);
+	else
+		len = sprintf(dst, "./");
+
+	if (net_mode == Net_server) {
+		struct net_connection *nc = tip->nc;
+
+		len += sprintf(dst + len, "%s-", inet_ntoa(nc->ch->cl_in_addr));
+		len += strftime(dst + len, 64, "%F-%T/", gmtime(&trip->cl_connect_time));
+	}
+
+	if (stat(dst, &sb) < 0) {
+		if (errno != ENOENT) {
+			perror("stat");
+			return 1;
+		}
+		if (mkdir(dst, 0755) < 0) {
+			perror(dst);
+			fprintf(stderr, "Can't make output dir\n");
+			return 1;
+		}
+	}
+
+	if (output_name)
+		sprintf(dst + len, "%s.%s.%d", output_name, app_name, tip->cpu);
+	else
+		sprintf(dst + len, "%s.%s.%d", trace_name, app_name, tip->cpu);
+
+	return 0;
+}
+
+static void fill_ops(struct thread_information *tip)
+{
+	/*
+	 * setup ops
+	 */
+	if (net_mode == Net_client) {
+		if (net_use_sendfile) {
+			tip->get_subbuf = get_subbuf_sendfile;
+			tip->flush_subbuf = NULL;
+		} else {
+			tip->get_subbuf = get_subbuf;
+			tip->flush_subbuf = flush_subbuf_net;
+		}
+	} else {
+		if (tip->ofile_mmap)
+			tip->get_subbuf = mmap_subbuf;
+		else
+			tip->get_subbuf = get_subbuf;
+
+		tip->flush_subbuf = flush_subbuf_file;
+	}
+			
+	if (net_mode == Net_server)
+		tip->read_data = read_data_net;
+	else
+		tip->read_data = read_data_file;
+}
+
+static int tip_open_output(struct trace_information *trip,
+			   struct thread_information *tip)
+{
+	int pipeline = output_name && !strcmp(output_name, "-");
+	int mode, vbuf_size;
+	char op[128];
+
+	if (net_mode == Net_client) {
+		tip->ofile = NULL;
+		tip->ofile_stdout = 0;
+		tip->ofile_mmap = 0;
+		goto done;
+	} else if (pipeline) {
+		tip->ofile = fdopen(STDOUT_FILENO, "w");
+		tip->ofile_stdout = 1;
+		tip->ofile_mmap = 0;
+		mode = _IOLBF;
+		vbuf_size = 512;
+	} else {
+		if (fill_ofname(trip, tip, op, trip->trace_name))
+			return 1;
+		tip->ofile = fopen(op, "w+");
+		tip->ofile_stdout = 0;
+		tip->ofile_mmap = 1;
+		mode = _IOFBF;
+		vbuf_size = OFILE_BUF;
+	}
+
+	if (tip->ofile == NULL) {
+		perror(op);
+		return 1;
+	}
+
+	tip->ofile_buffer = malloc(vbuf_size);
+	if (setvbuf(tip->ofile, tip->ofile_buffer, mode, vbuf_size)) {
+		perror("setvbuf");
+		close_thread(tip);
+		return 1;
+	}
+
+done:
+	fill_ops(tip);
+	return 0;
+}
+
+static int start_threads(struct trace_information *trip)
+{
+	struct thread_information *tip;
+	int j;
+
+	for_each_tip(trip, tip, j) {
+		tip->cpu = j;
+		tip->trace = trip;
+		tip->events_processed = 0;
+		tip->fd = -1;
+		memset(&tip->fifo, 0, sizeof(tip->fifo));
+		tip->leftover_ts = NULL;
+
+		if (tip_open_output(trip, tip))
+			return 1;
+
+		if (pthread_create(&tip->thread, NULL, thread_main, tip)) {
+			perror("pthread_create");
+			close_thread(tip);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void stop_threads(struct trace_information *trip)
+{
+	struct thread_information *tip;
+	unsigned long ret;
+	int i;
+
+	for_each_tip(trip, tip, i) {
+		(void) pthread_join(tip->thread, (void *) &ret);
+		close_thread(tip);
+	}
+}
+
+static void stop_all_threads(void)
+{
+	struct trace_information *trip;
+	int i;
+
+	for_each_trip(trip, i)
+		stop_threads(trip);
+}
+
+static void stop_all_tracing(void)
+{
+	struct trace_information *trip;
+	int i;
+
+	for_each_trip(trip, i)
+		stop_trace(trip);
+}
+
+static void exit_trace(int status)
+{
+	if (!is_trace_stopped()) {
+		trace_stopped = 1;
+		stop_all_threads();
+		stop_all_tracing();
+	}
+
+	exit(status);
+}
+
+static int resize_traces(char *root, char *name, void *private_data)
+{
+	int size = (ntraces + 1) * sizeof(struct trace_information);
+
+	if (root == NULL)
+		return 1;
+	trace_information = realloc(trace_information, size);
+	if (!trace_information)
+		return 1;
+	strcpy(trace_information[ntraces].root_name, root);
+	if (name) /* client may set it */
+		strcpy(trace_information[ntraces].trace_name, name);
+	trace_information[ntraces].private_data = private_data;
+	ntraces++;
+	return 0;
+}
+
+static int start_traces(void)
+{
+	struct trace_information *trip;
+	int i, j, size;
+
+	size = ncpus * sizeof(struct thread_information);
+	thread_information = malloc(size * ntraces);
+	if (!thread_information) {
+		fprintf(stderr, "Out of memory, threads (%d)\n", size * ntraces);
+		return 1;
+	}
+
+	for_each_trip(trip, i) {
+		if (start_trace(trip))
+			break;
+	}
+
+	if (i != ntraces) {
+		__for_each_trip(trip, trace_information, i, j)
+			stop_trace(trip);
+
+		return 1;
+	}
+
+	for_each_trip(trip, i) {
+		trip->threads = thread_information + (i * ncpus);
+		if (start_threads(trip)) {
+			fprintf(stderr, "Failed to start worker threads\n");
+			break;
+		}
+	}
+
+	if (i != ntraces) {
+		__for_each_trip(trip, trace_information, i, j)
+			stop_threads(trip);
+		for_each_trip(trip, i)
+			stop_trace(trip);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static void show_stats(struct trace_information *trips, int ntrips, int cpus)
+{
+	struct trace_information *trip;
+	struct thread_information *tip;
+	unsigned long long events_processed, data_read;
+	unsigned long total_drops;
+	int i, j, no_stdout = 0;
+
+	if (is_stat_shown())
+		return;
+
+	if (output_name && !strcmp(output_name, "-"))
+		no_stdout = 1;
+
+	stat_shown = 1;
+
+	total_drops = 0;
+	__for_each_trip(trip, trips, ntrips, i) {
+		if (!no_stdout)
+			printf("Trace: %s\n", trip->trace_name);
+
+		events_processed = 0;
+		data_read = 0;
+		__for_each_tip(trip, tip, cpus, j) {
+			if (!no_stdout)
+				printf("  CPU%3d: %20lu events, %8llu KiB data\n",
+			       		tip->cpu, tip->events_processed,
+					(tip->data_read + 1023) >> 10);
+			events_processed += tip->events_processed;
+			data_read += tip->data_read;
+		}
+		total_drops += trip->drop_count;
+		if (!no_stdout)
+			printf("  Total:  %20llu events (dropped %lu), %8llu KiB data\n",
+					events_processed, trip->drop_count,
+					(data_read + 1023) >> 10);
+	}
+
+	if (total_drops)
+		fprintf(stderr, "You have dropped events, consider using a larger buffer size (-b)\n");
+}
+
+static struct trace_information *net_get_trip(struct net_connection *nc,
+					      struct utt_trace_net_hdr *utnh)
+{
+	struct trace_information *trip, *cl_trip = NULL;
+	struct cl_host *ch = nc->ch;
+	int i;
+
+	for (i = 0; i < ch->ntraces; i++) {
+		trip = &ch->trace_information[i];
+
+		if (!strcmp(trip->trace_name, utnh->trace_name))
+			return trip;
+
+		if (trip->cl_id == utnh->cl_id)
+			cl_trip = trip;
+	}
+
+	ch->trace_information = realloc(ch->trace_information, (ch->ntraces + 1) * sizeof(*trip));
+	trip = &ch->trace_information[ch->ntraces];
+	memset(trip, 0, sizeof(*trip));
+	trip->ch = ch;
+	trip->cl_id = utnh->cl_id;
+	trip->buf_size = utnh->buf_size;
+	trip->buf_nr = utnh->buf_nr;
+	trip->page_size = utnh->page_size;
+
+	if (cl_trip)
+		trip->cl_connect_time = cl_trip->cl_connect_time;
+	else
+		trip->cl_connect_time = nc->connect_time;
+	strcpy(trip->trace_name, utnh->trace_name);
+	trip->trace_started = 1;
+	ch->ntraces++;
+	trip->threads = malloc(nc->ncpus * sizeof(struct thread_information));
+	memset(trip->threads, 0, nc->ncpus * sizeof(struct thread_information));
+
+	/*
+	 * open all files
+	 */
+	for (i = 0; i < nc->ncpus; i++) {
+		struct thread_information *tip = &trip->threads[i];
+
+		tip->cpu = i;
+		tip->trace = trip;
+		tip->fd = -1;
+		tip->nc = nc;
+		
+		if (tip_open_output(trip, tip))
+			return NULL;
+
+		tip->nc = NULL;
+	}
+
+	return trip;
+}
+
+static struct thread_information *net_get_tip(struct net_connection *nc,
+					      struct utt_trace_net_hdr *utnh)
+{
+	struct trace_information *trip;
+	struct thread_information *tip;
+
+	trip = net_get_trip(nc, utnh);
+	if (!trip->trace_started) {
+		fprintf(stderr, "Events for closed traces %s\n", trip->trace_name);
+		return NULL;
+	}
+
+	tip = &trip->threads[utnh->cpu];
+	if (!tip->nc)
+		tip->nc = nc;
+	
+	return tip;
+}
+
+static int net_get_header(struct net_connection *nc,
+			  struct utt_trace_net_hdr *utnh)
+{
+	int fl = fcntl(nc->in_fd, F_GETFL);
+	int bytes_left, ret;
+	void *p = utnh;
+
+	fcntl(nc->in_fd, F_SETFL, fl | O_NONBLOCK);
+	bytes_left = sizeof(*utnh);
+	while (bytes_left && !is_done()) {
+		ret = recv(nc->in_fd, p, bytes_left, MSG_WAITALL);
+		if (ret < 0) {
+			if (errno != EAGAIN) {
+				perror("recv header");
+				return 1;
+			}
+			usleep(1000);
+			continue;
+		} else if (!ret) {
+			usleep(1000);
+			continue;
+		} else {
+			p += ret;
+			bytes_left -= ret;
+		}
+	}
+	fcntl(nc->in_fd, F_SETFL, fl & ~O_NONBLOCK);
+	return bytes_left;
+}
+
+/*
+ * finalize a net client: truncate files, show stats, cleanup, etc
+ */
+static void trace_done(struct net_connection *nc, struct trace_information *trip)
+{
+	struct thread_information *tip;
+	int i;
+
+	__for_each_tip(trip, tip, nc->ncpus, i)
+		tip_ftrunc_final(tip);
+
+	show_stats(trip, 1, nc->ncpus);
+
+	/*
+	 * cleanup for next run
+	 */
+	__for_each_tip(trip, tip, nc->ncpus, i) {
+		if (tip->ofile)
+			fclose(tip->ofile);
+	}
+
+	free(trip->threads);
+
+	close(nc->in_fd);
+	nc->in_fd = -1;
+
+	stat_shown = 0;
+}
+
+static inline int in_addr_eq(struct in_addr a, struct in_addr b)
+{
+	return a.s_addr == b.s_addr;
+}
+
+static void net_add_client_host(struct cl_host *ch)
+{
+	ch->list_next = cl_host_list;
+	cl_host_list = ch;
+	cl_hosts++;
+}
+
+static void net_remove_client_host(struct cl_host *ch)
+{
+	struct cl_host *p, *c;
+	
+	for (p = c = cl_host_list; c; c = c->list_next) {
+		if (c == ch) {
+			if (p == c)
+				cl_host_list = c->list_next;
+			else
+				p->list_next = c->list_next;
+			cl_hosts--;
+			return;
+		}
+		p = c;
+	}
+}
+
+static struct cl_host *net_find_client_host(struct in_addr cl_in_addr)
+{
+	struct cl_host *ch = cl_host_list;
+
+	while (ch) {
+		if (in_addr_eq(ch->cl_in_addr, cl_in_addr))
+			return ch;
+		ch = ch->list_next;
+	}
+
+	return NULL;
+}
+
+static void net_client_host_done(struct cl_host *ch)
+{
+	free(ch->trace_information);
+	free(ch->net_connections);
+	net_connects -= ch->nconn;
+	net_remove_client_host(ch);
+	free(ch);
+}
+
+/*
+ * handle incoming events from a net client
+ */
+static int net_client_data(struct net_connection *nc)
+{
+	struct thread_information *tip;
+	struct utt_trace_net_hdr utnh;
+
+	if (net_get_header(nc, &utnh))
+		return 1;
+
+	if (data_is_native == -1 && check_data_endianness(utnh.magic)) {
+		fprintf(stderr, "server: received data is bad\n");
+		return 1;
+	}
+
+	if (!data_is_native) {
+		utnh.magic = be32_to_cpu(utnh.magic);
+		utnh.cpu = be32_to_cpu(utnh.cpu);
+		utnh.max_cpus = be32_to_cpu(utnh.max_cpus);
+		utnh.len = be32_to_cpu(utnh.len);
+		utnh.cl_id = be32_to_cpu(utnh.cl_id);
+		utnh.buf_size = be32_to_cpu(utnh.buf_size);
+		utnh.buf_nr = be32_to_cpu(utnh.buf_nr);
+		utnh.page_size = be32_to_cpu(utnh.page_size);
+	}
+
+	if ((utnh.magic & 0xffffff00) != UTT_TRACE_MAGIC) {
+		fprintf(stderr, "server: bad data magic\n");
+		return 1;
+	}
+
+	if (nc->ncpus == -1)
+		nc->ncpus = utnh.max_cpus;
+
+	/*
+	 * len == 0 means that the other end signalled end-of-run
+	 */
+	if (!utnh.len) {
+		/*
+		 * overload cpu count with dropped events
+		 */
+		struct trace_information *trip;
+
+		trip = net_get_trip(nc, &utnh);
+		trip->drop_count = utnh.cpu;
+		trip->trace_started = 0;
+
+		printf("server: end of run for %s\n", trip->trace_name);
+
+		trace_done(nc, trip);
+
+		if (++nc->ch->ntraces_done == nc->ch->ntraces)
+			net_client_host_done(nc->ch);
+
+		return 0;
+	}
+
+	tip = net_get_tip(nc, &utnh);
+	if (!tip)
+		return 1;
+
+	if (mmap_subbuf(tip, utnh.len))
+		return 1;
+
+	return 0;
+}
+
+static void net_add_connection(int listen_fd, struct sockaddr_in *addr)
+{
+	socklen_t socklen = sizeof(*addr);
+	struct net_connection *nc;
+	struct cl_host *ch;
+	int in_fd;
+
+	in_fd = accept(listen_fd, (struct sockaddr *) addr, &socklen);
+	if (in_fd < 0) {
+		perror("accept");
+		return;
+	}
+
+	ch = net_find_client_host(addr->sin_addr);
+	if (!ch) {
+		if (cl_hosts == NET_MAX_CL_HOSTS) {
+			fprintf(stderr, "server: no more clients allowed\n");
+			return;
+		}
+		ch = malloc(sizeof(struct cl_host));
+		memset(ch, 0, sizeof(*ch));
+		ch->cl_in_addr = addr->sin_addr;
+		net_add_client_host(ch);
+
+		printf("server: connection from %s\n", inet_ntoa(addr->sin_addr));
+	}
+
+	ch->net_connections = realloc(ch->net_connections, (ch->nconn + 1) * sizeof(*nc));
+	nc = &ch->net_connections[ch->nconn++];
+	memset(nc, 0, sizeof(*nc));
+
+	time(&nc->connect_time);
+	nc->ch = ch;
+	nc->in_fd = in_fd;
+	nc->ncpus = -1;
+	net_connects++;
+}
+
+/*
+ * event driven loop, handle new incoming connections and data from
+ * existing connections
+ */
+static void net_server_handle_connections(int listen_fd,
+					  struct sockaddr_in *addr)
+{
+	struct pollfd *pfds = NULL;
+	struct net_connection **ncs = NULL;
+	int max_connects = 0;
+	int i, nconns, events;
+	struct cl_host *ch;
+	struct net_connection *nc;
+	
+	printf("server: waiting for connections...\n");
+
+	while (!is_done()) {
+		if (net_connects >= max_connects) {
+			pfds = realloc(pfds, (net_connects + 1) * sizeof(*pfds));
+			ncs = realloc(ncs, (net_connects + 1) * sizeof(*ncs));
+			max_connects = net_connects + 1;
+		}
+		/*
+		 * the zero entry is for incoming connections, remaining
+		 * entries for clients
+		 */
+		pfds[0].fd = listen_fd;
+		pfds[0].events = POLLIN;
+		nconns = 0;
+		for_each_cl_host(ch) {
+			for (i = 0; i < ch->nconn; i++) {
+				nc = &ch->net_connections[i];
+				pfds[nconns + 1].fd = nc->in_fd;
+				pfds[nconns + 1].events = POLLIN;
+				ncs[nconns++] = nc;
+			}
+		}
+
+		events = poll(pfds, 1 + nconns, -1);
+		if (events < 0) {
+			if (errno == EINTR)
+				continue;
+
+			perror("poll");
+			break;
+		} else if (!events)
+			continue;
+
+		if (pfds[0].revents & POLLIN) {
+			net_add_connection(listen_fd, addr);
+			events--;
+		}
+
+		for (i = 0; events && i < nconns; i++) {
+			if (pfds[i + 1].revents & POLLIN) {
+				net_client_data(ncs[i]);
+				events--;
+			}
+		}
+	}
+}
+
+/*
+ * Start here when we are in server mode - just fetch data from the network
+ * and dump to files
+ */
+static int net_server(void)
+{
+	struct sockaddr_in addr;
+	int fd, opt;
+
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (fd < 0) {
+		perror("server: socket");
+		return 1;
+	}
+
+	opt = 1;
+	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+		perror("setsockopt");
+		return 1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	addr.sin_port = htons(net_port);
+
+	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind");
+		return 1;
+	}
+
+	if (listen(fd, 1) < 0) {
+		perror("listen");
+		return 1;
+	}
+
+	net_server_handle_connections(fd, &addr);
+	return 0;
+}
+
+/*
+ * Setup outgoing network connection where we will transmit data
+ */
+static int net_setup_client_cpu(int i, struct sockaddr_in *addr)
+{
+	int fd;
+
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (fd < 0) {
+		perror("client: socket");
+		return 1;
+	}
+
+	if (connect(fd, (struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		perror("client: connect");
+		return 1;
+	}
+
+	net_out_fd[i] = fd;
+	return 0;
+}
+
+static int net_setup_client(void)
+{
+	struct sockaddr_in addr;
+	int i;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(net_port);
+
+	if (inet_aton(hostname, &addr.sin_addr) != 1) {
+		struct hostent *hent = gethostbyname(hostname);
+		if (!hent) {
+			perror("gethostbyname");
+			return 1;
+		}
+
+		memcpy(&addr.sin_addr, hent->h_addr, 4);
+		strcpy(hostname, hent->h_name);
+	}
+
+	printf("%s: connecting to %s\n", app_name, hostname);
+
+	net_out_fd = malloc(ncpus * sizeof(*net_out_fd));
+	for (i = 0; i < ncpus; i++) {
+		if (net_setup_client_cpu(i, &addr))
+			return 1;
+	}
+
+	printf("%s: connected!\n", app_name);
+	
+	return 0;
+}
+
+int utt_add_trace(char *root, char *name, void *private_data)
+{
+	if (resize_traces(root, name, private_data) != 0)
+		return 1;
+	return 0;
+}
+
+static int stop_watch;
+
+int utt_parse_arg(int c, char *_optarg)
+{
+	switch (c) {
+		case 'r':
+			debugfs_path = _optarg;
+			break;
+
+		case 'o':
+			output_name = _optarg;
+			break;
+		case 'k':
+			kill_running_trace = 1;
+			break;
+		case 'w':
+			stop_watch = atoi(_optarg);
+			if (stop_watch <= 0) {
+				fprintf(stderr,
+					"Invalid stopwatch value (%d secs)\n",
+					stop_watch);
+				return 1;
+			}
+			break;
+		case 'b':
+			buf_size = strtoul(_optarg, NULL, 10);
+			if (buf_size <= 0 || buf_size > 16*1024) {
+				fprintf(stderr,
+					"Invalid buffer size (%lu)\n",buf_size);
+				return 1;
+			}
+			buf_size <<= 10;
+			break;
+		case 'n':
+			buf_nr = strtoul(_optarg, NULL, 10);
+			if (buf_nr <= 0) {
+				fprintf(stderr,
+					"Invalid buffer nr (%lu)\n", buf_nr);
+				return 1;
+			}
+			break;
+		case 'D':
+			output_dir = _optarg;
+			break;
+		case 'h':
+			net_mode = Net_client;
+			strcpy(hostname, _optarg);
+			break;
+		case 'l':
+			net_mode = Net_server;
+			break;
+		case 'p':
+			net_port = atoi(_optarg);
+			break;
+		case 's':
+			net_use_sendfile = 0;
+			break;
+		default:
+			return 1;
+	}
+	return 0;
+}
+
+int utt_start(struct utt_trace_ops *ops, int handle_signals, char *appname)
+{
+	struct statfs st;
+
+	if (ops == NULL || appname == NULL)
+		return 1;
+	
+	trace_ops = ops;
+	app_name = appname;
+	
+	page_size = getpagesize();
+
+	if (net_mode == Net_server)
+		return net_server();
+
+	if (ntraces == 0)
+		return 1;
+
+	if (!debugfs_path)
+		debugfs_path = default_debugfs_path;
+
+	if (statfs(debugfs_path, &st) < 0) {
+		perror("statfs");
+		fprintf(stderr,"%s does not appear to be a valid path\n",
+			debugfs_path);
+		return 1;
+	} else if (st.f_type != (long) DEBUGFS_TYPE) {
+		fprintf(stderr,"%s does not appear to be a debug filesystem\n",
+			debugfs_path);
+		return 1;
+	}
+
+	if (kill_running_trace) {
+		stop_all_traces();
+		return 0;
+	}
+
+	ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+	if (ncpus < 0) {
+		fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
+		return 1;
+	}
+
+	if (handle_signals) {
+		signal(SIGINT, handle_sigint);
+		signal(SIGHUP, handle_sigint);
+		signal(SIGTERM, handle_sigint);
+		signal(SIGALRM, handle_sigint);
+		signal(SIGPIPE, SIG_IGN);
+	}
+
+	if (net_mode == Net_client && net_setup_client())
+		return 1;
+
+	if (start_traces() != 0)
+		return 1;
+
+	atexit(stop_all_tracing);
+
+	if (stop_watch)
+		alarm(stop_watch);
+
+	wait_for_threads();
+
+	if (!is_trace_stopped()) {
+		trace_stopped = 1;
+		stop_all_threads();
+		stop_all_traces();
+	}
+
+	show_stats(trace_information, ntraces, ncpus);
+
+	return 0;
+}
+
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/stpd/utt.h src/runtime/stpd/utt.h
--- src-orig/runtime/stpd/utt.h	1969-12-31 18:00:00.000000000 -0600
+++ src/runtime/stpd/utt.h	2006-10-06 14:45:56.000000000 -0500
@@ -0,0 +1,107 @@
+#ifndef UTT_H
+#define UTT_H
+
+#include <asm/types.h>
+#include <byteswap.h>
+
+#define UTT_TRACE_ROOT_NAME_SIZE	32	/* Largest string for a root dir identifier */
+#define UTT_TRACE_NAME_SIZE		32	/* Largest string for a trace identifier */
+
+/*
+ * User setup structure for UTT
+ */
+struct utt_trace_setup {
+	char root[UTT_TRACE_ROOT_NAME_SIZE];	/* input */
+	char name[UTT_TRACE_NAME_SIZE];		/* input */
+	__u32 buf_size;				/* input */
+	__u32 buf_nr;				/* input */
+	int err;				/* output */
+};
+
+/* from blktrace.h */
+typedef __u32 u32;
+typedef __u8 u8;
+
+#define min(a, b)       ((a) < (b) ? (a) : (b))
+#define max(a, b)       ((a) > (b) ? (a) : (b))
+
+struct utt_header {
+	__u32 magic;		/* MAGIC << 8 | version */
+	__u32 sequence;		/* event number */
+	__u64 time;		/* in nanoseconds */
+};
+
+extern int data_is_native;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define be16_to_cpu(x)		__bswap_16(x)
+#define be32_to_cpu(x)		__bswap_32(x)
+#define be64_to_cpu(x)		__bswap_64(x)
+#define cpu_to_be16(x)		__bswap_16(x)
+#define cpu_to_be32(x)		__bswap_32(x)
+#define cpu_to_be64(x)		__bswap_64(x)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define be16_to_cpu(x)		(x)
+#define be32_to_cpu(x)		(x)
+#define be64_to_cpu(x)		(x)
+#define cpu_to_be16(x)		(x)
+#define cpu_to_be32(x)		(x)
+#define cpu_to_be64(x)		(x)
+#else
+#error "Bad arch"
+#endif
+
+#include "utt-app.h"
+
+#define CHECK_MAGIC(t)		(((t)->magic & 0xffffff00) == UTT_TRACE_MAGIC)
+#define SUPPORTED_VERSION	(UTT_TRACE_VERSION)
+
+static inline int verify_trace(struct utt_header *t)
+{
+	if (!CHECK_MAGIC(t)) {
+		fprintf(stderr, "bad trace magic %x\n", t->magic);
+		return 1;
+	}
+	if ((t->magic & 0xff) != SUPPORTED_VERSION) {
+		fprintf(stderr, "unsupported trace version %x\n", 
+			t->magic & 0xff);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * check whether data is native or not
+ */
+static inline int check_data_endianness(u32 magic)
+{
+	if ((magic & 0xffffff00) == UTT_TRACE_MAGIC) {
+		data_is_native = 1;
+		return 0;
+	}
+
+	magic = __bswap_32(magic);
+	if ((magic & 0xffffff00) == UTT_TRACE_MAGIC) {
+		data_is_native = 0;
+		return 0;
+	}
+
+	return 1;
+}
+
+struct utt_trace_ops
+{
+	int (*trace_setup) (void *private_data,
+			    struct utt_trace_setup *utts);
+	int (*trace_start) (void *private_data);
+	int (*trace_stop) (void *private_data);
+	int (*trace_teardown) (void *private_data);
+};
+
+extern int utt_parse_arg(int c, char *optarg);
+extern int utt_add_trace(char *root, char *name, void *private_data);
+extern int utt_start(struct utt_trace_ops *ops, int handle_signals, char *appname);
+extern void utt_stop(void);
+
+#endif
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/transport/transport.c src/runtime/transport/transport.c
--- src-orig/runtime/transport/transport.c	2006-09-26 16:38:05.000000000 -0500
+++ src/runtime/transport/transport.c	2006-10-06 14:45:56.000000000 -0500
@@ -18,11 +18,15 @@
 #include "transport.h"
 #include "time.c"
 
-#ifdef STP_RELAYFS
+#if defined(STP_RELAYFS)
 #include "relayfs.c"
 static struct rchan *_stp_chan;
 static struct dentry *_stp_dir;
 int _stp_relay_flushing = 0;
+#elif defined(CONFIG_UTT) && defined(STP_UTT)
+#include <linux/utt.h>
+static struct utt_trace *_stp_utt;
+static unsigned int utt_seq __read_mostly = 1;
 #endif
 
 static atomic_t _stp_start_finished = ATOMIC_INIT (0);
@@ -57,7 +61,7 @@ int _stp_transport_send (int type, void 
 	return err;
 }
 
-#ifndef STP_RELAYFS
+#if !defined(STP_RELAYFS) && !(defined(CONFIG_UTT) && defined(STP_UTT))
 int _stp_transport_write (void *data, int len)  
 {
 	/* when _stp_exit_called is set, we are in probe_exit() and we can sleep */
@@ -88,6 +92,15 @@ static void _stp_handle_buf_info(int *cp
 }
 #endif
 
+#if defined(CONFIG_UTT) && defined(STP_UTT)
+int _stp_handle_start_utt(struct utt_trace *utt)
+{
+	if (!utt)
+		return 1;
+	return utt_trace_startstop(utt, 1, &utt_seq);
+}
+#endif
+
 /*
  *	_stp_handle_start - handle STP_START
  */
@@ -99,6 +112,9 @@ void _stp_handle_start (struct transport
 	st->pid = probe_start();
 	atomic_set(&_stp_start_finished,1);
 
+#if defined(CONFIG_UTT) && defined(STP_UTT)
+	_stp_handle_start_utt(_stp_utt);
+#endif
 	/* if probe_start() failed, suppress calling probe_exit() */
 	if (st->pid < 0)
 		_stp_exit_called = 1;
@@ -145,6 +161,12 @@ static void _stp_cleanup_and_exit (int d
 			_stp_relay_flushing = 1;
 			relay_flush(_stp_chan);
 		}
+#elif defined(CONFIG_UTT) && defined(STP_UTT)
+		if (_stp_transport_mode == STP_TRANSPORT_UTT) {
+			kbug("************** calling startstop 0 *************\n");
+			if (_stp_utt)
+				utt_trace_startstop(_stp_utt, 0, &utt_seq);
+		}
 #endif
 		kbug("transport_send STP_EXIT\n");
 		/* tell staprun to exit (if it is still there) */
@@ -180,6 +202,17 @@ static void _stp_work_queue (void *data)
 		queue_delayed_work(_stp_wq, &stp_exit, STP_WORK_TIMER);
 }
 
+#if defined(CONFIG_UTT) && defined(STP_UTT)
+static int _stp_utt_close(struct utt_trace *utt)
+{
+	kbug("************** utt_close *************\n");
+	if (!utt)
+		return 1;
+//	utt_trace_startstop(utt, 0, &utt_seq);
+	return utt_trace_remove(utt);
+}
+#endif
+
 /**
  *	_stp_transport_close - close proc and relayfs channels
  *
@@ -196,6 +229,9 @@ void _stp_transport_close()
 #ifdef STP_RELAYFS
 	if (_stp_transport_mode == STP_TRANSPORT_RELAYFS) 
 		_stp_relayfs_close(_stp_chan, _stp_dir);
+#elif defined(CONFIG_UTT) && defined(STP_UTT) 
+	if (_stp_transport_mode == STP_TRANSPORT_UTT) 
+		_stp_utt_close(_stp_utt);
 #endif
 	_stp_unregister_procfs();
 
@@ -222,6 +258,28 @@ void _stp_transport_close()
  *      message from staprun cmd.  It replies with a similar message
  *      containing the final parameters used.
  */
+#if defined(CONFIG_UTT) && defined(STP_UTT)
+static struct utt_trace *_stp_utt_open(unsigned n_subbufs,
+				       unsigned subbuf_size,
+				       int pid)
+{
+	struct utt_trace_setup utts;
+	struct utt_trace *utt;
+	
+	sprintf(utts.root, "systemtap-utt");
+	// for now, we need to use block
+//	sprintf(utts.root, "block");
+//	sprintf(utts.name, "%d", pid);
+	// for now, don't bother with pid, just allow 1
+	sprintf(utts.name, "currprobe");
+	utts.buf_size = subbuf_size;
+	utts.buf_nr = n_subbufs;
+
+	utt = utt_trace_setup(&utts);
+	
+	return utt;
+}
+#endif
 
 int _stp_transport_open(struct transport_info *info)
 {
@@ -233,8 +291,9 @@ int _stp_transport_open(struct transport
 	kbug("transport_mode=%d\n", info->transport_mode);
 	_stp_target = info->target;
 
-#ifdef STP_RELAYFS
-	if (_stp_transport_mode == STP_TRANSPORT_RELAYFS) {
+#if defined STP_RELAYFS || (defined(CONFIG_UTT) && defined(STP_UTT))
+	if (_stp_transport_mode == STP_TRANSPORT_RELAYFS ||
+	    _stp_transport_mode == STP_TRANSPORT_UTT) {
 		if (info->buf_size) {
 			unsigned size = info->buf_size * 1024 * 1024;
 			subbuf_size = ((size >> 2) + 1) * 65536;
@@ -246,16 +305,22 @@ int _stp_transport_open(struct transport
 #ifdef STP_RELAYFS_MERGE
 		info->merge = 1;
 #endif
-
-		_stp_chan = _stp_relayfs_open(n_subbufs, subbuf_size, _stp_pid, &_stp_dir);
-
-		if (!_stp_chan)
-			return -ENOMEM;
-		kbug ("stp_transport_open: %u Mb buffers, subbuf_size=%u, n_subbufs=%u\n",
-		      info->buf_size, subbuf_size, n_subbufs);
-	} else 
+#if defined STP_RELAYFS
+		if (_stp_transport_mode == STP_TRANSPORT_RELAYFS) {
+			_stp_chan = _stp_relayfs_open(n_subbufs, subbuf_size, _stp_pid, &_stp_dir);
+			if (!_stp_chan)
+				return -ENOMEM;
+		}
+#elif defined(CONFIG_UTT) && defined(STP_UTT)
+		if (_stp_transport_mode == STP_TRANSPORT_UTT) {
+			_stp_utt = _stp_utt_open(n_subbufs, subbuf_size, _stp_pid);
+			if (!_stp_utt)
+				return -ENOMEM;
+		}
+#endif
 #endif
-	{
+		kbug ("stp_transport_open: %u Mb buffers, subbuf_size=%u, n_subbufs=%u\n", info->buf_size, subbuf_size, n_subbufs);
+	} else {
 		if (info->buf_size) 
 			_stp_set_buffers(info->buf_size * 1024 * 1024 / STP_BUFFER_SIZE);
 	}
@@ -316,6 +381,53 @@ static int _stp_relay_write (const void 
 	
 	return length;
 }
+#elif defined(CONFIG_UTT) && defined(STP_UTT)
+#define UTT_TRACE_MAGIC		0x65617500
+#define UTT_TRACE_VERSION	0x01
+
+struct stp_trace {
+	__u32 magic;		/* MAGIC << 8 | version */
+	__u32 sequence;		/* event number */
+	__u64 time;		/* in nanoseconds */
+	__u32 cpu;		/* on what cpu did it happen */
+	__u32 device;		/* device identifier (dev_t) */
+	__u16 pdu_len;		/* length of data after this trace */
+	char *data;		/* variable-length event data */
+};
+
+// hack to work with current stp_parse
+#include <linux/kdev_t.h>
+#define STP_DEV (MKDEV(0x99,0x99))
+
+static int _stp_utt_write (const void *data, unsigned length)
+{
+	struct stp_trace *t;
+	unsigned long flags;
+	unsigned long *sequence;
+	pid_t pid;
+	int cpu;
+
+	if (unlikely(_stp_utt->trace_state != Utt_trace_running))
+		return 0;
+
+	t = relay_reserve(_stp_utt->rchan, sizeof(*t) + length);
+	if (t) {
+		cpu = smp_processor_id();
+		sequence = per_cpu_ptr(_stp_utt->sequence, cpu);
+
+		t->magic = UTT_TRACE_MAGIC | UTT_TRACE_VERSION;
+		t->sequence = ++(*sequence);
+		t->time = sched_clock() - per_cpu(utt_trace_cpu_offset, cpu);
+		t->cpu = cpu;
+		t->device = STP_DEV;
+		t->pdu_len = length;
+
+		if (length)
+			memcpy((void *) t + sizeof(*t), data, length);
+	}
+
+	return length + sizeof(*t);
+}
 #endif
 
 #endif /* _TRANSPORT_C_ */
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/transport/transport.h src/runtime/transport/transport.h
--- src-orig/runtime/transport/transport.h	2006-09-21 20:34:42.000000000 -0500
+++ src/runtime/transport/transport.h	2006-10-06 14:45:56.000000000 -0500
@@ -20,6 +20,11 @@ static unsigned n_subbufs = 16;
 static unsigned subbuf_size = 65536;
 #define _stp_transport_write(data, len)  _stp_relay_write(data, len)
 static int _stp_transport_mode = STP_TRANSPORT_RELAYFS;
+#elif defined(CONFIG_UTT) && defined(STP_UTT)
+static unsigned n_subbufs = 16;
+static unsigned subbuf_size = 65536;
+#define _stp_transport_write(data, len)  _stp_utt_write(data, len)
+static int _stp_transport_mode = STP_TRANSPORT_UTT;
 #else
 static int _stp_transport_mode = STP_TRANSPORT_PROC;
 #endif
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/runtime/transport/transport_msgs.h src/runtime/transport/transport_msgs.h
--- src-orig/runtime/transport/transport_msgs.h	2006-09-25 17:37:21.000000000 -0500
+++ src/runtime/transport/transport_msgs.h	2006-10-06 14:45:56.000000000 -0500
@@ -2,7 +2,8 @@
 enum
 {
 	STP_TRANSPORT_PROC = 1,
-	STP_TRANSPORT_RELAYFS
+	STP_TRANSPORT_RELAYFS,
+	STP_TRANSPORT_UTT
 };
 
 /* stp control channel command values */
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/session.h src/session.h
--- src-orig/session.h	2006-09-27 20:48:59.000000000 -0500
+++ src/session.h	2006-10-06 14:45:56.000000000 -0500
@@ -69,6 +69,7 @@ struct systemtap_session
   std::string module_name;
   std::string output_file;
   std::string cmd;
+  std::string host;
   int target_pid;
   int last_pass;
   unsigned verbose;
@@ -76,6 +77,7 @@ struct systemtap_session
   bool keep_tmpdir;
   bool guru_mode;
   bool bulk_mode;
+  bool utt_mode;
   bool unoptimized;
   bool merge;
   int buffer_size;
diff -urpN -X /usr/local/src/dontdiff.systemtap src-orig/translate.cxx src/translate.cxx
--- src-orig/translate.cxx	2006-09-18 11:55:01.000000000 -0500
+++ src/translate.cxx	2006-10-06 14:45:56.000000000 -0500
@@ -3792,6 +3792,11 @@ translate_pass (systemtap_session& s)
 	    s.op->newline() << "#define STP_RELAYFS_MERGE";
 	}
 
+      if (s.utt_mode)
+	{
+	  s.op->newline() << "#define STP_UTT";
+	}
+
       if (s.timing)
 	s.op->newline() << "#define STP_TIMING" << " " << s.timing ;
 
