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
 |