mirror of
https://github.com/xemu-project/xemu.git
synced 2024-12-12 22:16:19 +00:00
b7d66a761f
Adds a 'TRACE_${NAME}_ENABLED' preprocessor define for each tracing event in "trace.h". This lets the user conditionally compile code with a relatively high execution cost that is only necessary when producing the tracing information for an event that is enabled. Note that events using this define will probably have the "disable" property by default, in order to avoid such costs on regular builds. Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
651 lines
11 KiB
Bash
Executable File
651 lines
11 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')
|
|
--probe-prefix [prefix] Prefix for dtrace probe names
|
|
(default: qemu-\$targettype-\$targetarch)
|
|
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
# Print a line without interpreting backslash escapes
|
|
#
|
|
# The built-in echo command may interpret backslash escapes without an option
|
|
# to disable this behavior.
|
|
puts()
|
|
{
|
|
printf "%s\n" "$1"
|
|
}
|
|
|
|
# Get the name of a trace event
|
|
get_name()
|
|
{
|
|
local name
|
|
name=${1%%\(*}
|
|
echo "${name##* }"
|
|
}
|
|
|
|
# Get the given property of a trace event
|
|
# 1: trace-events line
|
|
# 2: property name
|
|
# -> return 0 if property is present, or 1 otherwise
|
|
has_property()
|
|
{
|
|
local props prop
|
|
props=${1%%\(*}
|
|
props=${props% *}
|
|
for prop in $props; do
|
|
if [ "$prop" = "$2" ]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 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 including double quotes for a trace event
|
|
get_fmt()
|
|
{
|
|
puts "${1#*)}"
|
|
}
|
|
|
|
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 "trace/simple.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
|
|
name=$(get_name "$1")
|
|
args=$(get_args "$1")
|
|
argc=$(get_argc "$1")
|
|
|
|
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
|
|
name=$(get_name "$1")
|
|
cat <<EOF
|
|
{.tp_name = "$name", .state=0},
|
|
EOF
|
|
simple_event_num=$((simple_event_num + 1))
|
|
}
|
|
|
|
linetoc_end_simple()
|
|
{
|
|
cat <<EOF
|
|
};
|
|
EOF
|
|
}
|
|
|
|
#STDERR
|
|
linetoh_begin_stderr()
|
|
{
|
|
cat <<EOF
|
|
#include <stdio.h>
|
|
#include "trace/stderr.h"
|
|
|
|
extern TraceEvent trace_list[];
|
|
EOF
|
|
|
|
stderr_event_num=0
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (trace_list[$stderr_event_num].state != 0) {
|
|
fprintf(stderr, "$name " $fmt "\n" $argnames);
|
|
}
|
|
}
|
|
EOF
|
|
stderr_event_num=$((stderr_event_num + 1))
|
|
|
|
}
|
|
|
|
linetoh_end_stderr()
|
|
{
|
|
cat <<EOF
|
|
#define NR_TRACE_EVENTS $stderr_event_num
|
|
EOF
|
|
}
|
|
|
|
linetoc_begin_stderr()
|
|
{
|
|
cat <<EOF
|
|
#include "trace.h"
|
|
|
|
TraceEvent trace_list[] = {
|
|
EOF
|
|
stderr_event_num=0
|
|
}
|
|
|
|
linetoc_stderr()
|
|
{
|
|
local name
|
|
name=$(get_name "$1")
|
|
cat <<EOF
|
|
{.tp_name = "$name", .state=0},
|
|
EOF
|
|
stderr_event_num=$(($stderr_event_num + 1))
|
|
}
|
|
|
|
linetoc_end_stderr()
|
|
{
|
|
cat <<EOF
|
|
};
|
|
EOF
|
|
}
|
|
#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", ",")
|
|
[ -z "$argnames" ] || argnames=", $argnames"
|
|
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 nameupper
|
|
name=$(get_name "$1")
|
|
args=$(get_args "$1")
|
|
argnames=$(get_argnames "$1", ",")
|
|
|
|
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
|
|
name=$(get_name "$1")
|
|
args=$(get_args "$1")
|
|
|
|
# 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
|
|
name=$(get_name "$1")
|
|
args=$(get_args "$1")
|
|
arglist=$(get_argnames "$1", "")
|
|
|
|
# Define prototype for probe arguments
|
|
cat <<EOF
|
|
probe $probeprefix.$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 name NAME enabled
|
|
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
|
|
|
|
echo
|
|
# Process the line. The nop backend handles disabled lines.
|
|
if has_property "$str" "disable"; then
|
|
"lineto$1_nop" "$str"
|
|
enabled=0
|
|
else
|
|
"$process_line" "$str"
|
|
enabled=1
|
|
fi
|
|
if [ "$1" = "h" ]; then
|
|
name=$(get_name "$str")
|
|
NAME=$(echo $name | tr '[:lower:]' '[:upper:]')
|
|
echo "#define TRACE_${NAME}_ENABLED ${enabled}"
|
|
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 "$probeprefix" -a -z "$targettype" ]; then
|
|
echo "--target-type is required for SystemTAP tapset generator"
|
|
exit 1
|
|
fi
|
|
if [ -z "$probeprefix" -a -z "$targetarch" ]; then
|
|
echo "--target-arch is required for SystemTAP tapset generator"
|
|
exit 1
|
|
fi
|
|
if [ -z "$probeprefix" ]; then
|
|
probeprefix="qemu.$targettype.$targetarch";
|
|
fi
|
|
echo "/* This file is autogenerated by tracetool, do not edit. */"
|
|
convert stap
|
|
}
|
|
|
|
|
|
backend=
|
|
output=
|
|
binary=
|
|
targettype=
|
|
targetarch=
|
|
probeprefix=
|
|
|
|
|
|
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" ;;
|
|
"--probe-prefix") shift ; probeprefix="$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
|