 320fba2a1f
			
		
	
	
		320fba2a1f
		
	
	
	
	
		
			
			This backend sends trace events to standard error output during the emulation. Also add a "--list-backends" option to tracetool, so configure script can display the list of available backends. Signed-off-by: Fabien Chouteau <chouteau@adacore.com> Acked-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
		
			
				
	
	
		
			630 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			630 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/sh
 | |
| #
 | |
| # Code generator for trace events
 | |
| #
 | |
| # Copyright IBM, Corp. 2010
 | |
| #
 | |
| # This work is licensed under the terms of the GNU GPL, version 2.  See
 | |
| # the COPYING file in the top-level directory.
 | |
| 
 | |
| # Disable pathname expansion, makes processing text with '*' characters simpler
 | |
| set -f
 | |
| 
 | |
| usage()
 | |
| {
 | |
|     cat >&2 <<EOF
 | |
| usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
 | |
| Generate tracing code for a file on stdin.
 | |
| 
 | |
| Backends:
 | |
|   --nop     Tracing disabled
 | |
|   --simple  Simple built-in backend
 | |
|   --stderr  Stderr 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)
 | |
|   --stap Generate .stp file (DTrace with SystemTAP only)
 | |
| 
 | |
| Options:
 | |
|   --binary      [path]  Full path to QEMU binary
 | |
|   --target-arch [arch]  QEMU emulator target arch
 | |
|   --target-type [type]  QEMU emulator target type ('system' or 'user')
 | |
| 
 | |
| EOF
 | |
|     exit 1
 | |
| }
 | |
| 
 | |
| # Get the name of a trace event
 | |
| get_name()
 | |
| {
 | |
|     echo ${1%%\(*}
 | |
| }
 | |
| 
 | |
| # Get the argument list of a trace event, including types and names
 | |
| get_args()
 | |
| {
 | |
|     local args
 | |
|     args=${1#*\(}
 | |
|     args=${args%\)*}
 | |
|     echo "$args"
 | |
| }
 | |
| 
 | |
| # Get the argument name list of a trace event
 | |
| get_argnames()
 | |
| {
 | |
|     local nfields field name sep
 | |
|     nfields=0
 | |
|     sep="$2"
 | |
|     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%s " $name $sep
 | |
|     done
 | |
| 
 | |
|     # Last argument name
 | |
|     if [ "$nfields" -gt 1 ]
 | |
|     then
 | |
|         printf "%s" "$name"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # Get the number of arguments to a trace event
 | |
| get_argc()
 | |
| {
 | |
|     local name argc
 | |
|     argc=0
 | |
|     for name in $(get_argnames "$1", ","); do
 | |
|         argc=$((argc + 1))
 | |
|     done
 | |
|     echo $argc
 | |
| }
 | |
| 
 | |
| # Get the format string for a trace event
 | |
| get_fmt()
 | |
| {
 | |
|     local fmt
 | |
|     fmt=${1#*\"}
 | |
|     fmt=${fmt%\"*}
 | |
|     echo "$fmt"
 | |
| }
 | |
| 
 | |
| # Get the state of a trace event
 | |
| get_state()
 | |
| {
 | |
|     local str disable state
 | |
|     str=$(get_name "$1")
 | |
|     disable=${str##disable }
 | |
|     if [ "$disable" = "$str" ] ; then
 | |
|         state=1
 | |
|     else
 | |
|         state=0
 | |
|     fi
 | |
|     echo "$state"
 | |
| }
 | |
| 
 | |
| linetoh_begin_nop()
 | |
| {
 | |
|     return
 | |
| }
 | |
| 
 | |
| linetoh_nop()
 | |
| {
 | |
|     local name args
 | |
|     name=$(get_name "$1")
 | |
|     args=$(get_args "$1")
 | |
| 
 | |
|     # Define an empty function for the trace event
 | |
|     cat <<EOF
 | |
| static inline void trace_$name($args)
 | |
| {
 | |
| }
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetoh_end_nop()
 | |
| {
 | |
|     return
 | |
| }
 | |
| 
 | |
| linetoc_begin_nop()
 | |
| {
 | |
|     return
 | |
| }
 | |
| 
 | |
| linetoc_nop()
 | |
| {
 | |
|     # No need for function definitions in nop backend
 | |
|     return
 | |
| }
 | |
| 
 | |
| linetoc_end_nop()
 | |
| {
 | |
|     return
 | |
| }
 | |
| 
 | |
| linetoh_begin_simple()
 | |
| {
 | |
|     cat <<EOF
 | |
| #include "simpletrace.h"
 | |
| EOF
 | |
| 
 | |
|     simple_event_num=0
 | |
| }
 | |
| 
 | |
| cast_args_to_uint64_t()
 | |
| {
 | |
|     local arg
 | |
|     for arg in $(get_argnames "$1", ","); do
 | |
|         printf "%s" "(uint64_t)(uintptr_t)$arg"
 | |
|     done
 | |
| }
 | |
| 
 | |
| linetoh_simple()
 | |
| {
 | |
|     local name args argc trace_args state
 | |
|     name=$(get_name "$1")
 | |
|     args=$(get_args "$1")
 | |
|     argc=$(get_argc "$1")
 | |
|     state=$(get_state "$1")
 | |
|     if [ "$state" = "0" ]; then
 | |
|         name=${name##disable }
 | |
|     fi
 | |
| 
 | |
|     trace_args="$simple_event_num"
 | |
|     if [ "$argc" -gt 0 ]
 | |
|     then
 | |
|         trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
 | |
|     fi
 | |
| 
 | |
|     cat <<EOF
 | |
| static inline void trace_$name($args)
 | |
| {
 | |
|     trace$argc($trace_args);
 | |
| }
 | |
| EOF
 | |
| 
 | |
|     simple_event_num=$((simple_event_num + 1))
 | |
| }
 | |
| 
 | |
| linetoh_end_simple()
 | |
| {
 | |
|     cat <<EOF
 | |
| #define NR_TRACE_EVENTS $simple_event_num
 | |
| extern TraceEvent trace_list[NR_TRACE_EVENTS];
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetoc_begin_simple()
 | |
| {
 | |
|     cat <<EOF
 | |
| #include "trace.h"
 | |
| 
 | |
| TraceEvent trace_list[] = {
 | |
| EOF
 | |
|     simple_event_num=0
 | |
| 
 | |
| }
 | |
| 
 | |
| linetoc_simple()
 | |
| {
 | |
|     local name state
 | |
|     name=$(get_name "$1")
 | |
|     state=$(get_state "$1")
 | |
|     if [ "$state" = "0" ] ; then
 | |
|         name=${name##disable }
 | |
|     fi
 | |
|     cat <<EOF
 | |
| {.tp_name = "$name", .state=$state},
 | |
| EOF
 | |
|     simple_event_num=$((simple_event_num + 1))
 | |
| }
 | |
| 
 | |
| linetoc_end_simple()
 | |
| {
 | |
|     cat <<EOF
 | |
| };
 | |
| EOF
 | |
| }
 | |
| 
 | |
| #STDERR
 | |
| linetoh_begin_stderr()
 | |
| {
 | |
|     cat <<EOF
 | |
| #include <stdio.h>
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetoh_stderr()
 | |
| {
 | |
|     local name args argnames argc fmt
 | |
|     name=$(get_name "$1")
 | |
|     args=$(get_args "$1")
 | |
|     argnames=$(get_argnames "$1" ",")
 | |
|     argc=$(get_argc "$1")
 | |
|     fmt=$(get_fmt "$1")
 | |
| 
 | |
|     if [ "$argc" -gt 0 ]; then
 | |
|         argnames=", $argnames"
 | |
|     fi
 | |
| 
 | |
|     cat <<EOF
 | |
| static inline void trace_$name($args)
 | |
| {
 | |
|     fprintf(stderr, "$name $fmt\n" $argnames);
 | |
| }
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetoh_end_stderr()
 | |
| {
 | |
| return
 | |
| }
 | |
| 
 | |
| linetoc_begin_stderr()
 | |
| {
 | |
| return
 | |
| }
 | |
| 
 | |
| linetoc_stderr()
 | |
| {
 | |
| return
 | |
| }
 | |
| 
 | |
| linetoc_end_stderr()
 | |
| {
 | |
| return
 | |
| }
 | |
| #END OF STDERR
 | |
| 
 | |
| # Clean up after UST headers which pollute the namespace
 | |
| ust_clean_namespace() {
 | |
|     cat <<EOF
 | |
| #undef mutex_lock
 | |
| #undef mutex_unlock
 | |
| #undef inline
 | |
| #undef wmb
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetoh_begin_ust()
 | |
| {
 | |
|     echo "#include <ust/tracepoint.h>"
 | |
|     ust_clean_namespace
 | |
| }
 | |
| 
 | |
| linetoh_ust()
 | |
| {
 | |
|     local name args argnames
 | |
|     name=$(get_name "$1")
 | |
|     args=$(get_args "$1")
 | |
|     argnames=$(get_argnames "$1", ",")
 | |
| 
 | |
|     cat <<EOF
 | |
| DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
 | |
| #define trace_$name trace_ust_$name
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetoh_end_ust()
 | |
| {
 | |
|     return
 | |
| }
 | |
| 
 | |
| linetoc_begin_ust()
 | |
| {
 | |
|     cat <<EOF
 | |
| #include <ust/marker.h>
 | |
| $(ust_clean_namespace)
 | |
| #include "trace.h"
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetoc_ust()
 | |
| {
 | |
|     local name args argnames fmt
 | |
|     name=$(get_name "$1")
 | |
|     args=$(get_args "$1")
 | |
|     argnames=$(get_argnames "$1", ",")
 | |
|     fmt=$(get_fmt "$1")
 | |
| 
 | |
|     cat <<EOF
 | |
| DEFINE_TRACE(ust_$name);
 | |
| 
 | |
| static void ust_${name}_probe($args)
 | |
| {
 | |
|     trace_mark(ust, $name, "$fmt", $argnames);
 | |
| }
 | |
| EOF
 | |
| 
 | |
|     # Collect names for later
 | |
|     names="$names $name"
 | |
| }
 | |
| 
 | |
| linetoc_end_ust()
 | |
| {
 | |
|     cat <<EOF
 | |
| static void __attribute__((constructor)) trace_init(void)
 | |
| {
 | |
| EOF
 | |
| 
 | |
|     for name in $names; do
 | |
|         cat <<EOF
 | |
|     register_trace_ust_$name(ust_${name}_probe);
 | |
| EOF
 | |
|     done
 | |
| 
 | |
|     echo "}"
 | |
| }
 | |
| 
 | |
| 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
 | |
| }
 | |
| 
 | |
| linetostap_begin_dtrace()
 | |
| {
 | |
|     return
 | |
| }
 | |
| 
 | |
| linetostap_dtrace()
 | |
| {
 | |
|     local i arg name args arglist state
 | |
|     name=$(get_name "$1")
 | |
|     args=$(get_args "$1")
 | |
|     arglist=$(get_argnames "$1", "")
 | |
|     state=$(get_state "$1")
 | |
|     if [ "$state" = "0" ] ; then
 | |
|         name=${name##disable }
 | |
|     fi
 | |
| 
 | |
|     # Define prototype for probe arguments
 | |
|     cat <<EOF
 | |
| probe qemu.$targettype.$targetarch.$name = process("$binary").mark("$name")
 | |
| {
 | |
| EOF
 | |
| 
 | |
|     i=1
 | |
|     for arg in $arglist
 | |
|     do
 | |
|         # 'limit' is a reserved keyword
 | |
|         if [ "$arg" = "limit" ]; then
 | |
|           arg="_limit"
 | |
|         fi
 | |
|         cat <<EOF
 | |
|   $arg = \$arg$i;
 | |
| EOF
 | |
| 	i="$((i+1))"
 | |
|     done
 | |
| 
 | |
|     cat <<EOF
 | |
| }
 | |
| EOF
 | |
| }
 | |
| 
 | |
| linetostap_end_dtrace()
 | |
| {
 | |
|     return
 | |
| }
 | |
| 
 | |
| # Process stdin by calling begin, line, and end functions for the backend
 | |
| convert()
 | |
| {
 | |
|     local begin process_line end str disable
 | |
|     begin="lineto$1_begin_$backend"
 | |
|     process_line="lineto$1_$backend"
 | |
|     end="lineto$1_end_$backend"
 | |
| 
 | |
|     "$begin"
 | |
| 
 | |
|     while read -r str; do
 | |
|         # Skip comments and empty lines
 | |
|         test -z "${str%%#*}" && continue
 | |
| 
 | |
|         # Process the line.  The nop backend handles disabled lines.
 | |
|         disable=${str%%disable *}
 | |
|         echo
 | |
|         if test -z "$disable"; 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 }"
 | |
|             fi
 | |
|         else
 | |
|             "$process_line" "$str"
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     echo
 | |
|     "$end"
 | |
| }
 | |
| 
 | |
| tracetoh()
 | |
| {
 | |
|     cat <<EOF
 | |
| #ifndef TRACE_H
 | |
| #define TRACE_H
 | |
| 
 | |
| /* This file is autogenerated by tracetool, do not edit. */
 | |
| 
 | |
| #include "qemu-common.h"
 | |
| EOF
 | |
|     convert h
 | |
|     echo "#endif /* TRACE_H */"
 | |
| }
 | |
| 
 | |
| tracetoc()
 | |
| {
 | |
|     echo "/* This file is autogenerated by tracetool, do not edit. */"
 | |
|     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
 | |
| }
 | |
| 
 | |
| tracetostap()
 | |
| {
 | |
|     if [ $backend != "dtrace" ]; then
 | |
|        echo "SystemTAP tapset generator not applicable to $backend backend"
 | |
|        exit 1
 | |
|     fi
 | |
|     if [ -z "$binary" ]; then
 | |
|        echo "--binary is required for SystemTAP tapset generator"
 | |
|        exit 1
 | |
|     fi
 | |
|     if [ -z "$targettype" ]; then
 | |
|        echo "--target-type is required for SystemTAP tapset generator"
 | |
|        exit 1
 | |
|     fi
 | |
|     if [ -z "$targetarch" ]; then
 | |
|        echo "--target-arch is required for SystemTAP tapset generator"
 | |
|        exit 1
 | |
|     fi
 | |
|     echo "/* This file is autogenerated by tracetool, do not edit. */"
 | |
|     convert stap
 | |
| }
 | |
| 
 | |
| 
 | |
| backend=
 | |
| output=
 | |
| binary=
 | |
| targettype=
 | |
| targetarch=
 | |
| 
 | |
| 
 | |
| until [ -z "$1" ]
 | |
| do
 | |
|   case "$1" in
 | |
|     "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
 | |
| 
 | |
|     "--binary") shift ; binary="$1" ;;
 | |
|     "--target-arch") shift ; targetarch="$1" ;;
 | |
|     "--target-type") shift ; targettype="$1" ;;
 | |
| 
 | |
|     "-h" | "-c" | "-d") output="${1#-}" ;;
 | |
|     "--stap") output="${1#--}" ;;
 | |
| 
 | |
|     "--check-backend") exit 0 ;; # used by ./configure to test for backend
 | |
| 
 | |
|     "--list-backends") # used by ./configure to list available backends
 | |
|           echo "nop simple stderr ust dtrace"
 | |
|           exit 0
 | |
|           ;;
 | |
| 
 | |
|     *)
 | |
|       usage;;
 | |
|   esac
 | |
|   shift
 | |
| done
 | |
| 
 | |
| if [ "$backend" = "" -o "$output" = "" ]; then
 | |
|   usage
 | |
| fi
 | |
| 
 | |
| gen="traceto$output"
 | |
| "$gen"
 | |
| 
 | |
| exit 0
 |