From 113694c3cd79873bfb857bc2f8de15d3f37eb897 Mon Sep 17 00:00:00 2001
From: Jes Sorensen <Jes.Sorensen@redhat.com>
Date: Mon, 27 Dec 2010 16:48:10 -0200
Subject: [RHEL6 qemu-kvm PATCH 20/23] Add a DTrace tracing backend targetted for SystemTAP compatability

RH-Author: Jes Sorensen <Jes.Sorensen@redhat.com>
Message-id: <1293468492-25473-19-git-send-email-Jes.Sorensen@redhat.com>
Patchwork-id: 15301
O-Subject: [PATCH 18/20] Add a DTrace tracing backend targetted for SystemTAP
	compatability
Bugzilla: 632722
RH-Acked-by: Markus Armbruster <armbru@redhat.com>
RH-Acked-by: Gleb Natapov <gleb@redhat.com>
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
RH-Acked-by: Daniel P. Berrange <berrange@redhat.com>

From: Daniel P. Berrange <berrange@redhat.com>

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.

Example usage of a dtrace probe in systemtap looks like:

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

* .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 data files

Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b3d08c029dd78ded5e35b74eaaa3d361821f83a7)
---
 .gitignore |    3 ++
 Makefile   |   27 ++++++++++++++
 configure  |   14 +++++++-
 tracetool  |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 152 insertions(+), 8 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 .gitignore |    3 ++
 Makefile   |   27 ++++++++++++++
 configure  |   14 +++++++-
 tracetool  |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 152 insertions(+), 8 deletions(-)

diff --git a/.gitignore b/.gitignore
index ac04793..b318335 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,10 @@ config-host.*
 config-target.*
 trace.h
 trace.c
+trace-dtrace.h
+trace-dtrace.dtrace
 i386
+*-timestamp
 *-softmmu
 *-darwin-user
 *-linux-user
diff --git a/Makefile b/Makefile
index f5e9099..5ff17cc 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,9 @@
 
 # This needs to be defined before rules.mak
 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.
@@ -131,7 +134,11 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
 net-nested-$(CONFIG_VDE) += vde.o
 net-obj-y += $(addprefix net/, $(net-nested-y))
 
+ifeq ($(TRACE_BACKEND),dtrace)
+trace-obj-y = trace-dtrace.o
+else
 trace-obj-y = trace.o
+endif
 
 ######################################################################
 # shared-obj-y has the object that are shared by qemu binary and tools
@@ -249,7 +256,11 @@ bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
 libqemu_common.a: $(obj-y)
 
+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
@@ -261,6 +272,20 @@ 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
+
+trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
+	$(call quiet-command,dtrace -o $@ -G -s $<, "  GEN trace-dtrace.o")
+
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
@@ -290,6 +315,8 @@ clean:
 	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.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.dtrace-timestamp
+	rm -f trace-dtrace.h trace-dtrace.h-timestamp
 	$(MAKE) -C tests clean
 	for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser; do \
 	if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
diff --git a/configure b/configure
index 2a3d63a..7d649a4 100755
--- a/configure
+++ b/configure
@@ -829,7 +829,7 @@ echo "  --with-kvm-trace         enable building the KVM module with the kvm tra
 echo "  --disable-cpu-emulation  disables use of qemu cpu emulation code"
 echo "  --disable-vhost-net      disable vhost-net acceleration support"
 echo "  --enable-vhost-net       enable vhost-net acceleration support"
-echo "  --trace-backend=B        Trace backend nop"
+echo "  --trace-backend=B        Trace backend nop dtrace"
 echo "  --disable-fake-machine   disable -fake-machine option"
 echo "  --enable-fake-machine    enable -fake-machine option"
 echo ""
@@ -2022,6 +2022,18 @@ if test "$?" -ne 0 ; then
   exit 1
 fi
 
+##########################################
+# For 'dtrace' backend, test if 'dtrace' command is present
+if test "$trace_backend" = "dtrace"; then
+  if ! test -x "$(which dtrace 2>/dev/null)"; then
+    echo
+    echo "Error: dtrace command is not found in PATH $PATH"
+    echo
+    exit 1
+  fi
+fi
+
+##########################################
 # End of CC checks
 # After here, no more $cc or $ld runs
 
diff --git a/tracetool b/tracetool
index 4e8ef32..f5d6c60 100644
--- a/tracetool
+++ b/tracetool
@@ -17,11 +17,13 @@ usage: $0 --nop [-h | -c]
 Generate tracing code for a file on stdin.
 
 Backends:
-  --nop Tracing disabled
+  --nop     Tracing disabled
+  --dtrace  DTrace/SystemTAP backend
 
 Output formats:
   -h    Generate .h file
   -c    Generate .c file
+  -d    Generate .d file (DTrace only)
 EOF
     exit 1
 }
@@ -44,8 +46,9 @@ get_args()
 # Get the argument name list of a trace event
 get_argnames()
 {
-    local nfields field name
+    local nfields field name sep
     nfields=0
+    sep="$2"
     for field in $(get_args "$1"); do
         nfields=$((nfields + 1))
 
@@ -56,7 +59,7 @@ get_argnames()
         name=${field%,}
         test "$field" = "$name" && continue
 
-        printf "%s" "$name, "
+        printf "%s%s " $name $sep
     done
 
     # Last argument name
@@ -129,6 +132,93 @@ linetoc_end_nop()
     return
 }
 
+linetoh_begin_dtrace()
+{
+    cat <<EOF
+#include "trace-dtrace.h"
+EOF
+}
+
+linetoh_dtrace()
+{
+    local name args argnames state 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);
+    }
+}
+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
+
+    # DTrace provider syntax expects foo() for empty
+    # params, not foo(void)
+    if [ "$args" = "void" ]; then
+       args=""
+    fi
+
+    # Define prototype for probe arguments
+    cat <<EOF
+        probe $name($args);
+EOF
+}
+
+linetod_end_dtrace()
+{
+    cat <<EOF
+};
+EOF
+}
+
 # Process stdin by calling begin, line, and end functions for the backend
 convert()
 {
@@ -147,9 +237,10 @@ convert()
         disable=${str%%disable *}
         echo
         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
+            # Pass the disabled state as an arg for the simple
+            # or DTrace backends which handle it dynamically.
+            # For all other backends, call lineto$1_nop()
+            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
                 "$process_line" "$str"
             else
                 "lineto$1_nop" "${str##disable }"
@@ -183,9 +274,19 @@ 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
+}
+
 # Choose backend
 case "$1" in
-"--nop") backend="${1#--}" ;;
+"--nop" | "--dtrace") backend="${1#--}" ;;
 *) usage ;;
 esac
 shift
@@ -193,6 +294,7 @@ shift
 case "$1" in
 "-h") tracetoh ;;
 "-c") tracetoc ;;
+"-d") tracetod ;;
 "--check-backend") exit 0 ;; # used by ./configure to test for backend
 *) usage ;;
 esac
-- 
1.7.3.2

