Patchwork Add a DTrace tracing backend targetted for SystemTAP compatability

login
register
mail settings
Submitter Daniel P. Berrange
Date Oct. 18, 2010, 2:04 p.m.
Message ID <1287410646-10129-1-git-send-email-berrange@redhat.com>
Download mbox | patch
Permalink /patch/68194/
State New
Headers show

Comments

Daniel P. Berrange - Oct. 18, 2010, 2:04 p.m.
This introduces a new tracing backend that targets the SystemTAP
implementation of DTrace userspace tracing. The core functionality
should be applicable and standard across any DTrace implementation
on Solaris, OS-X, *BSD, but the Makefile rules will likely need
some small additional changes to cope with OS specific build
requirements.

This backend builds a little differently from the other tracing
backends. Specifically there is no 'trace.c' file, because the
'dtrace' command line tool generates a '.o' file directly from
the dtrace probe definition file. The probe definition is usually
named with a '.d' extension but QEMU uses '.d' files for its
external makefile dependancy tracking, so this uses '.dtrace' as
the extension for the probe definition file.

The 'tracetool' program gains the ability to generate a trace.h
file for DTrace, and also to generate the trace.d file containing
the dtrace probe definition, and finally a qemu.stp file which is
a wrapper around the probe definition providing more convenient
access from SystemTAP scripts.

eg, instead of

  probe process("qemu").mark("qemu_malloc") {
    printf("Malloc %d %p\n", $arg1, $arg2);
  }

The addition of qemu.stp to /usr/share/systemtap/tapset/
lets users write

  probe qemu.qemu_malloc {
    printf("Malloc %d %p\n", size, ptr);
  }

* .gitignore: Ignore trace-dtrace.*
* Makefile: Extra rules for generating DTrace files
* Makefile.obj: Don't build trace.o for DTrace, use
  trace-dtrace.o generated by 'dtrace' instead
* tracetool: Support for generating DTrace/SystemTAP
  data files

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 .gitignore    |    3 +
 Makefile      |   31 ++++++++++
 Makefile.objs |    4 +
 tracetool     |  175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 211 insertions(+), 2 deletions(-)
Stefan Hajnoczi - Oct. 19, 2010, 10 a.m.
On Mon, Oct 18, 2010 at 3:04 PM, Daniel P. Berrange <berrange@redhat.com> wrote:
> This introduces a new tracing backend that targets the SystemTAP
> implementation of DTrace userspace tracing. The core functionality
> should be applicable and standard across any DTrace implementation
> on Solaris, OS-X, *BSD, but the Makefile rules will likely need
> some small additional changes to cope with OS specific build
> requirements.

Cool, I will try this patch out shortly.  Here a few comments:

DTrace detection in ./configure would help users trying out
--trace-backend=dtrace on systems without SystemTAP installed.
Perhaps running dtrace(1) is a sufficient test?  If SystemTAP is not
installed then an error message from ./configure will save users time.

>
> This backend builds a little differently from the other tracing
> backends. Specifically there is no 'trace.c' file, because the
> 'dtrace' command line tool generates a '.o' file directly from
> the dtrace probe definition file. The probe definition is usually
> named with a '.d' extension but QEMU uses '.d' files for its
> external makefile dependancy tracking, so this uses '.dtrace' as
> the extension for the probe definition file.
>
> The 'tracetool' program gains the ability to generate a trace.h
> file for DTrace, and also to generate the trace.d file containing
> the dtrace probe definition, and finally a qemu.stp file which is
> a wrapper around the probe definition providing more convenient
> access from SystemTAP scripts.
>
> eg, instead of
>
>  probe process("qemu").mark("qemu_malloc") {
>    printf("Malloc %d %p\n", $arg1, $arg2);
>  }
>
> The addition of qemu.stp to /usr/share/systemtap/tapset/
> lets users write
>
>  probe qemu.qemu_malloc {
>    printf("Malloc %d %p\n", size, ptr);
>  }
>
> * .gitignore: Ignore trace-dtrace.*
> * Makefile: Extra rules for generating DTrace files
> * Makefile.obj: Don't build trace.o for DTrace, use
>  trace-dtrace.o generated by 'dtrace' instead
> * tracetool: Support for generating DTrace/SystemTAP
>  data files
>
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  .gitignore    |    3 +
>  Makefile      |   31 ++++++++++
>  Makefile.objs |    4 +
>  tracetool     |  175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 211 insertions(+), 2 deletions(-)
>
> diff --git a/.gitignore b/.gitignore
> index a43e4d1..0d27afd 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -4,6 +4,9 @@ config-host.*
>  config-target.*
>  trace.h
>  trace.c
> +trace-dtrace.h
> +trace-dtrace.dtrace
> +qemu.stp
>  *-timestamp
>  *-softmmu
>  *-darwin-user
> diff --git a/Makefile b/Makefile
> index 252c817..812b0d3 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1,6 +1,9 @@
>  # Makefile for QEMU.
>
>  GENERATED_HEADERS = config-host.h trace.h
> +ifeq ($(TRACE_BACKEND),dtrace)
> +GENERATED_HEADERS += trace-dtrace.h
> +endif
>
>  ifneq ($(wildcard config-host.mak),)
>  # Put the all: rule here so that config-host.mak can contain dependencies.
> @@ -106,7 +109,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>
>  bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
>
> +ifeq ($(TRACE_BACKEND),dtrace)
> +trace.h: trace.h-timestamp trace-dtrace.h
> +else
>  trace.h: trace.h-timestamp
> +endif
>  trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
>        $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
>        @cmp -s $@ trace.h || cp $@ trace.h
> @@ -118,6 +125,23 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
>
>  trace.o: trace.c $(GENERATED_HEADERS)
>
> +trace-dtrace.h: trace-dtrace.dtrace
> +       $(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")
> +
> +# Normal practice is to name DTrace probe file with a '.d' extension
> +# but that gets picked up by QEMU's Makefile as an external dependancy
> +# rule file. So we use '.dtrace' instead
> +trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
> +trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
> +       $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
> +       @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
> +ifdef CONFIG_LINUX
> +       $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -s < $< > qemu.stp,"  GEN   qemu.stp")
> +endif
> +
> +trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
> +       $(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
> +
>  simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
>
>  version.o: $(SRC_PATH)/version.rc config-host.mak
> @@ -154,6 +178,7 @@ clean:
>        rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
>        rm -f qemu-img-cmds.h
>        rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
> +       rm -f trace-dtrace.dtrace trace-dtrace.h trace-dtrace.h-timestamp qemu.stp
>        $(MAKE) -C tests clean
>        for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
>        if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
> @@ -214,6 +239,12 @@ ifneq ($(BLOBS),)
>                $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
>        done
>  endif
> +ifeq ($(TRACE_BACKEND),dtrace)
> +ifdef CONFIG_LINUX
> +       $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
> +       $(INSTALL_DATA) qemu.stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
> +endif
> +endif
>        $(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
>        set -e; for x in $(KEYMAPS); do \
>                $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
> diff --git a/Makefile.objs b/Makefile.objs
> index 816194a..ccecda0 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -273,10 +273,14 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
>  ######################################################################
>  # trace
>
> +ifeq ($(TRACE_BACKEND),dtrace)
> +trace-obj-y = trace-dtrace.o
> +else
>  trace-obj-y = trace.o
>  ifeq ($(TRACE_BACKEND),simple)
>  trace-obj-y += simpletrace.o
>  endif
> +endif
>
>  vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>
> diff --git a/tracetool b/tracetool
> index 7010858..59b66fd 100755
> --- a/tracetool
> +++ b/tracetool
> @@ -20,10 +20,13 @@ Backends:
>   --nop     Tracing disabled
>   --simple  Simple built-in backend
>   --ust     LTTng User Space Tracing backend
> +  --dtrace  DTrace/SystemTAP backend
>
>  Output formats:
>   -h    Generate .h file
>   -c    Generate .c file
> +  -d    Generate .d file (DTrace only)
> +  -s    Generate .stp file (DTrace with SystemTAP only)
>  EOF
>     exit 1
>  }
> @@ -68,6 +71,31 @@ get_argnames()
>     fi
>  }
>
> +# Get the argument name list of a trace event
> +get_arglist()

The only difference between get_arglist() and get_argnames() is the
comma added on the end of each argument name.  Please reuse
get_argnames() instead of duplicating it.  One solution is to pass the
argument separator as a string into get_argnames().  Passing '"' would
produce the existing behavior and passing "" would produce the
get_arglist() behavior that you need.

> +{
> +    local nfields field name
> +    nfields=0
> +    for field in $(get_args "$1"); do
> +        nfields=$((nfields + 1))
> +
> +        # Drop pointer star
> +        field=${field#\*}
> +
> +        # Only argument names have commas at the end
> +        name=${field%,}
> +        test "$field" = "$name" && continue
> +
> +        printf "%s" "$name "
> +    done
> +
> +    # Last argument name
> +    if [ "$nfields" -gt 1 ]
> +    then
> +        printf "%s" "$name"
> +    fi
> +}
> +
>  # Get the number of arguments to a trace event
>  get_argc()
>  {
> @@ -306,6 +334,127 @@ EOF
>     echo "}"
>  }
>
> +linetoh_begin_dtrace()
> +{
> +    cat <<EOF
> +#include "trace-dtrace.h"
> +EOF
> +}
> +
> +linetoh_dtrace()
> +{
> +    local name args state

Missing argnames and nameupper.

> +    name=$(get_name "$1")
> +    args=$(get_args "$1")
> +    argnames=$(get_argnames "$1")
> +    state=$(get_state "$1")
> +    if [ "$state" = "0" ] ; then
> +        name=${name##disable }
> +    fi
> +
> +    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
> +
> +    # Define an empty function for the trace event
> +    cat <<EOF
> +static inline void trace_$name($args) {
> +  if (QEMU_${nameupper}_ENABLED())
> +    QEMU_${nameupper}($argnames);
> +}

Please follow QEMU coding style even for generated code.  4 space
indentation and curly braces for all if statements:
static inline void trace_$name($args) {
    if (QEMU_${nameupper}_ENABLED()) {
        QEMU_${nameupper}($argnames);
    }
}

> +EOF
> +}
> +
> +linetoh_end_dtrace()
> +{
> +    return
> +}
> +
> +linetoc_begin_dtrace()
> +{
> +    return
> +}
> +
> +linetoc_dtrace()
> +{
> +    # No need for function definitions in dtrace backend
> +    return
> +}
> +
> +linetoc_end_dtrace()
> +{
> +    return
> +}
> +
> +linetod_begin_dtrace()
> +{
> +    cat <<EOF
> +provider qemu {
> +EOF
> +}
> +
> +linetod_dtrace()
> +{
> +    local name args state
> +    name=$(get_name "$1")
> +    args=$(get_args "$1")
> +    state=$(get_state "$1")
> +    if [ "$state" = "0" ] ; then
> +        name=${name##disable }
> +    fi
> +
> +    # Define prototype for probe arguments
> +    cat <<EOF
> +        probe $name($args);
> +EOF
> +}
> +
> +linetod_end_dtrace()
> +{
> +    cat <<EOF
> +};
> +EOF
> +}
> +
> +linetos_begin_dtrace()
> +{
> +    return
> +}
> +
> +linetos_dtrace()
> +{
> +    local name args argnames state

Missing arglist.  argnames is unused.

> +    name=$(get_name "$1")
> +    args=$(get_args "$1")
> +    arglist=$(get_arglist "$1")
> +    state=$(get_state "$1")
> +    if [ "$state" = "0" ] ; then
> +        name=${name##disable }
> +    fi
> +
> +    # Define prototype for probe arguments
> +    cat <<EOF
> +probe qemu.$name = process("qemu").mark("$name")
> +{
> +EOF
> +
> +    i=1
> +    for arg in $arglist
> +    do
> +        cat <<EOF
> +  $arg = \$arg$i;
> +EOF
> +       i="$((i+1))"
> +    done
> +
> +    cat <<EOF
> +}
> +EOF
> +}
> +
> +linetos_end_dtrace()
> +{
> +    return
> +}
> +
>  # Process stdin by calling begin, line, and end functions for the backend
>  convert()
>  {
> @@ -326,7 +475,7 @@ convert()
>         if test -z "$disable"; then
>             # Pass the disabled state as an arg to lineto$1_simple().

This comment is not outdated.  Please update it or change it so the
backend is not explicitly named.

Stefan
Stefan Hajnoczi - Oct. 20, 2010, 1:50 p.m.
Please also add dtrace to the ./configure --help output:

echo "  --trace-backend=B        Trace backend nop simple ust dtrace"

Stefan
Daniel P. Berrange - Oct. 20, 2010, 2:10 p.m.
On Wed, Oct 20, 2010 at 02:50:12PM +0100, Stefan Hajnoczi wrote:
> Please also add dtrace to the ./configure --help output:
> 
> echo "  --trace-backend=B        Trace backend nop simple ust dtrace"

I've just sent a v2 that should include all your feedback so far.

Regards,
Daniel

Patch

diff --git a/.gitignore b/.gitignore
index a43e4d1..0d27afd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@  config-host.*
 config-target.*
 trace.h
 trace.c
+trace-dtrace.h
+trace-dtrace.dtrace
+qemu.stp
 *-timestamp
 *-softmmu
 *-darwin-user
diff --git a/Makefile b/Makefile
index 252c817..812b0d3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@ 
 # Makefile for QEMU.
 
 GENERATED_HEADERS = config-host.h trace.h
+ifeq ($(TRACE_BACKEND),dtrace)
+GENERATED_HEADERS += trace-dtrace.h
+endif
 
 ifneq ($(wildcard config-host.mak),)
 # Put the all: rule here so that config-host.mak can contain dependencies.
@@ -106,7 +109,11 @@  ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
+ifeq ($(TRACE_BACKEND),dtrace)
+trace.h: trace.h-timestamp trace-dtrace.h
+else
 trace.h: trace.h-timestamp
+endif
 trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
 	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
 	@cmp -s $@ trace.h || cp $@ trace.h
@@ -118,6 +125,23 @@  trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
 
 trace.o: trace.c $(GENERATED_HEADERS)
 
+trace-dtrace.h: trace-dtrace.dtrace
+	$(call quiet-command,dtrace -o $@ -h -s $<, "  GEN   trace-dtrace.h")
+
+# Normal practice is to name DTrace probe file with a '.d' extension
+# but that gets picked up by QEMU's Makefile as an external dependancy
+# rule file. So we use '.dtrace' instead
+trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
+	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
+ifdef CONFIG_LINUX
+	$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -s < $< > qemu.stp,"  GEN   qemu.stp")
+endif
+
+trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
+	$(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
+
 simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
 
 version.o: $(SRC_PATH)/version.rc config-host.mak
@@ -154,6 +178,7 @@  clean:
 	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
 	rm -f qemu-img-cmds.h
 	rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
+	rm -f trace-dtrace.dtrace trace-dtrace.h trace-dtrace.h-timestamp qemu.stp
 	$(MAKE) -C tests clean
 	for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
 	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
@@ -214,6 +239,12 @@  ifneq ($(BLOBS),)
 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
 	done
 endif
+ifeq ($(TRACE_BACKEND),dtrace)
+ifdef CONFIG_LINUX
+	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
+	$(INSTALL_DATA) qemu.stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+endif
+endif
 	$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
 	set -e; for x in $(KEYMAPS); do \
 		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
diff --git a/Makefile.objs b/Makefile.objs
index 816194a..ccecda0 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -273,10 +273,14 @@  libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
 ######################################################################
 # trace
 
+ifeq ($(TRACE_BACKEND),dtrace)
+trace-obj-y = trace-dtrace.o
+else
 trace-obj-y = trace.o
 ifeq ($(TRACE_BACKEND),simple)
 trace-obj-y += simpletrace.o
 endif
+endif
 
 vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
diff --git a/tracetool b/tracetool
index 7010858..59b66fd 100755
--- a/tracetool
+++ b/tracetool
@@ -20,10 +20,13 @@  Backends:
   --nop     Tracing disabled
   --simple  Simple built-in backend
   --ust     LTTng User Space Tracing backend
+  --dtrace  DTrace/SystemTAP backend
 
 Output formats:
   -h    Generate .h file
   -c    Generate .c file
+  -d    Generate .d file (DTrace only)
+  -s    Generate .stp file (DTrace with SystemTAP only)
 EOF
     exit 1
 }
@@ -68,6 +71,31 @@  get_argnames()
     fi
 }
 
+# Get the argument name list of a trace event
+get_arglist()
+{
+    local nfields field name
+    nfields=0
+    for field in $(get_args "$1"); do
+        nfields=$((nfields + 1))
+
+        # Drop pointer star
+        field=${field#\*}
+
+        # Only argument names have commas at the end
+        name=${field%,}
+        test "$field" = "$name" && continue
+
+        printf "%s" "$name "
+    done
+
+    # Last argument name
+    if [ "$nfields" -gt 1 ]
+    then
+        printf "%s" "$name"
+    fi
+}
+
 # Get the number of arguments to a trace event
 get_argc()
 {
@@ -306,6 +334,127 @@  EOF
     echo "}"
 }
 
+linetoh_begin_dtrace()
+{
+    cat <<EOF
+#include "trace-dtrace.h"
+EOF
+}
+
+linetoh_dtrace()
+{
+    local name args state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    argnames=$(get_argnames "$1")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
+
+    # Define an empty function for the trace event
+    cat <<EOF
+static inline void trace_$name($args) {
+  if (QEMU_${nameupper}_ENABLED())
+    QEMU_${nameupper}($argnames);
+}
+EOF
+}
+
+linetoh_end_dtrace()
+{
+    return
+}
+
+linetoc_begin_dtrace()
+{
+    return
+}
+
+linetoc_dtrace()
+{
+    # No need for function definitions in dtrace backend
+    return
+}
+
+linetoc_end_dtrace()
+{
+    return
+}
+
+linetod_begin_dtrace()
+{
+    cat <<EOF
+provider qemu {
+EOF
+}
+
+linetod_dtrace()
+{
+    local name args state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    # Define prototype for probe arguments
+    cat <<EOF
+        probe $name($args);
+EOF
+}
+
+linetod_end_dtrace()
+{
+    cat <<EOF
+};
+EOF
+}
+
+linetos_begin_dtrace()
+{
+    return
+}
+
+linetos_dtrace()
+{
+    local name args argnames state
+    name=$(get_name "$1")
+    args=$(get_args "$1")
+    arglist=$(get_arglist "$1")
+    state=$(get_state "$1")
+    if [ "$state" = "0" ] ; then
+        name=${name##disable }
+    fi
+
+    # Define prototype for probe arguments
+    cat <<EOF
+probe qemu.$name = process("qemu").mark("$name")
+{
+EOF
+
+    i=1
+    for arg in $arglist
+    do
+        cat <<EOF
+  $arg = \$arg$i;
+EOF
+	i="$((i+1))"
+    done
+
+    cat <<EOF
+}
+EOF
+}
+
+linetos_end_dtrace()
+{
+    return
+}
+
 # Process stdin by calling begin, line, and end functions for the backend
 convert()
 {
@@ -326,7 +475,7 @@  convert()
         if test -z "$disable"; then
             # Pass the disabled state as an arg to lineto$1_simple().
             # For all other cases, call lineto$1_nop()
-            if [ $backend = "simple" ]; then
+            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
                 "$process_line" "$str"
             else
                 "lineto$1_nop" "${str##disable }"
@@ -360,9 +509,29 @@  tracetoc()
     convert c
 }
 
+tracetod()
+{
+    if [ $backend != "dtrace" ]; then
+       echo "DTrace probe generator not applicable to $backend backend"
+       exit 1
+    fi
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert d
+}
+
+tracetos()
+{
+    if [ $backend != "dtrace" ]; then
+       echo "SystemTAP tapset generator not applicable to $backend backend"
+       exit 1
+    fi
+    echo "/* This file is autogenerated by tracetool, do not edit. */"
+    convert s
+}
+
 # Choose backend
 case "$1" in
-"--nop" | "--simple" | "--ust") backend="${1#--}" ;;
+"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
 *) usage ;;
 esac
 shift
@@ -370,6 +539,8 @@  shift
 case "$1" in
 "-h") tracetoh ;;
 "-c") tracetoc ;;
+"-d") tracetod ;;
+"-s") tracetos ;;
 "--check-backend") exit 0 ;; # used by ./configure to test for backend
 *) usage ;;
 esac