|  | #!/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 | --ust] [-h | -c] | 
|  | Generate tracing code for a file on stdin. | 
|  |  | 
|  | Backends: | 
|  | --nop     Tracing disabled | 
|  | --simple  Simple built-in backend | 
|  | --ust     LTTng User Space Tracing backend | 
|  |  | 
|  | Output formats: | 
|  | -h    Generate .h file | 
|  | -c    Generate .c file | 
|  | 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 | 
|  | 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() | 
|  | { | 
|  | 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 | 
|  | } | 
|  |  | 
|  | # 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 "}" | 
|  | } | 
|  |  | 
|  | # 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 to lineto$1_simple(). | 
|  | # For all other cases, call lineto$1_nop() | 
|  | if [ $backend = "simple" ]; 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 | 
|  | } | 
|  |  | 
|  | # Choose backend | 
|  | case "$1" in | 
|  | "--nop" | "--simple" | "--ust") backend="${1#--}" ;; | 
|  | *) usage ;; | 
|  | esac | 
|  | shift | 
|  |  | 
|  | case "$1" in | 
|  | "-h") tracetoh ;; | 
|  | "-c") tracetoc ;; | 
|  | "--check-backend") exit 0 ;; # used by ./configure to test for backend | 
|  | *) usage ;; | 
|  | esac | 
|  |  | 
|  | exit 0 |