Merge remote branch 'spice/bugfix.2' into staging
[qemu.git] / tracetool
blobd797ab79a3e2aaff77870af017caee35ff9e4353
1 #!/bin/sh
3 # Code generator for trace events
5 # Copyright IBM, Corp. 2010
7 # This work is licensed under the terms of the GNU GPL, version 2. See
8 # the COPYING file in the top-level directory.
10 # Disable pathname expansion, makes processing text with '*' characters simpler
11 set -f
13 usage()
15 cat >&2 <<EOF
16 usage: $0 [--nop | --simple | --ust] [-h | -c]
17 Generate tracing code for a file on stdin.
19 Backends:
20 --nop Tracing disabled
21 --simple Simple built-in backend
22 --ust LTTng User Space Tracing backend
23 --dtrace DTrace/SystemTAP backend
25 Output formats:
26 -h Generate .h file
27 -c Generate .c file
28 -d Generate .d file (DTrace only)
29 -s Generate .stp file (DTrace with SystemTAP only)
31 Options:
32 --bindir [bindir] QEMU binary install location
33 --target [arch] QEMU target architecture
35 EOF
36 exit 1
39 # Get the name of a trace event
40 get_name()
42 echo ${1%%\(*}
45 # Get the argument list of a trace event, including types and names
46 get_args()
48 local args
49 args=${1#*\(}
50 args=${args%\)*}
51 echo "$args"
54 # Get the argument name list of a trace event
55 get_argnames()
57 local nfields field name sep
58 nfields=0
59 sep="$2"
60 for field in $(get_args "$1"); do
61 nfields=$((nfields + 1))
63 # Drop pointer star
64 field=${field#\*}
66 # Only argument names have commas at the end
67 name=${field%,}
68 test "$field" = "$name" && continue
70 printf "%s%s " $name $sep
71 done
73 # Last argument name
74 if [ "$nfields" -gt 1 ]
75 then
76 printf "%s" "$name"
80 # Get the number of arguments to a trace event
81 get_argc()
83 local name argc
84 argc=0
85 for name in $(get_argnames "$1", ","); do
86 argc=$((argc + 1))
87 done
88 echo $argc
91 # Get the format string for a trace event
92 get_fmt()
94 local fmt
95 fmt=${1#*\"}
96 fmt=${fmt%\"*}
97 echo "$fmt"
100 # Get the state of a trace event
101 get_state()
103 local str disable state
104 str=$(get_name "$1")
105 disable=${str##disable }
106 if [ "$disable" = "$str" ] ; then
107 state=1
108 else
109 state=0
111 echo "$state"
114 linetoh_begin_nop()
116 return
119 linetoh_nop()
121 local name args
122 name=$(get_name "$1")
123 args=$(get_args "$1")
125 # Define an empty function for the trace event
126 cat <<EOF
127 static inline void trace_$name($args)
133 linetoh_end_nop()
135 return
138 linetoc_begin_nop()
140 return
143 linetoc_nop()
145 # No need for function definitions in nop backend
146 return
149 linetoc_end_nop()
151 return
154 linetoh_begin_simple()
156 cat <<EOF
157 #include "simpletrace.h"
160 simple_event_num=0
163 cast_args_to_uint64_t()
165 local arg
166 for arg in $(get_argnames "$1", ","); do
167 printf "%s" "(uint64_t)(uintptr_t)$arg"
168 done
171 linetoh_simple()
173 local name args argc trace_args state
174 name=$(get_name "$1")
175 args=$(get_args "$1")
176 argc=$(get_argc "$1")
177 state=$(get_state "$1")
178 if [ "$state" = "0" ]; then
179 name=${name##disable }
182 trace_args="$simple_event_num"
183 if [ "$argc" -gt 0 ]
184 then
185 trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
188 cat <<EOF
189 static inline void trace_$name($args)
191 trace$argc($trace_args);
195 simple_event_num=$((simple_event_num + 1))
198 linetoh_end_simple()
200 cat <<EOF
201 #define NR_TRACE_EVENTS $simple_event_num
202 extern TraceEvent trace_list[NR_TRACE_EVENTS];
206 linetoc_begin_simple()
208 cat <<EOF
209 #include "trace.h"
211 TraceEvent trace_list[] = {
213 simple_event_num=0
217 linetoc_simple()
219 local name state
220 name=$(get_name "$1")
221 state=$(get_state "$1")
222 if [ "$state" = "0" ] ; then
223 name=${name##disable }
225 cat <<EOF
226 {.tp_name = "$name", .state=$state},
228 simple_event_num=$((simple_event_num + 1))
231 linetoc_end_simple()
233 cat <<EOF
238 # Clean up after UST headers which pollute the namespace
239 ust_clean_namespace() {
240 cat <<EOF
241 #undef mutex_lock
242 #undef mutex_unlock
243 #undef inline
244 #undef wmb
248 linetoh_begin_ust()
250 echo "#include <ust/tracepoint.h>"
251 ust_clean_namespace
254 linetoh_ust()
256 local name args argnames
257 name=$(get_name "$1")
258 args=$(get_args "$1")
259 argnames=$(get_argnames "$1", ",")
261 cat <<EOF
262 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
263 #define trace_$name trace_ust_$name
267 linetoh_end_ust()
269 return
272 linetoc_begin_ust()
274 cat <<EOF
275 #include <ust/marker.h>
276 $(ust_clean_namespace)
277 #include "trace.h"
281 linetoc_ust()
283 local name args argnames fmt
284 name=$(get_name "$1")
285 args=$(get_args "$1")
286 argnames=$(get_argnames "$1", ",")
287 fmt=$(get_fmt "$1")
289 cat <<EOF
290 DEFINE_TRACE(ust_$name);
292 static void ust_${name}_probe($args)
294 trace_mark(ust, $name, "$fmt", $argnames);
298 # Collect names for later
299 names="$names $name"
302 linetoc_end_ust()
304 cat <<EOF
305 static void __attribute__((constructor)) trace_init(void)
309 for name in $names; do
310 cat <<EOF
311 register_trace_ust_$name(ust_${name}_probe);
313 done
315 echo "}"
318 linetoh_begin_dtrace()
320 cat <<EOF
321 #include "trace-dtrace.h"
325 linetoh_dtrace()
327 local name args argnames state nameupper
328 name=$(get_name "$1")
329 args=$(get_args "$1")
330 argnames=$(get_argnames "$1", ",")
331 state=$(get_state "$1")
332 if [ "$state" = "0" ] ; then
333 name=${name##disable }
336 nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
338 # Define an empty function for the trace event
339 cat <<EOF
340 static inline void trace_$name($args) {
341 if (QEMU_${nameupper}_ENABLED()) {
342 QEMU_${nameupper}($argnames);
348 linetoh_end_dtrace()
350 return
353 linetoc_begin_dtrace()
355 return
358 linetoc_dtrace()
360 # No need for function definitions in dtrace backend
361 return
364 linetoc_end_dtrace()
366 return
369 linetod_begin_dtrace()
371 cat <<EOF
372 provider qemu {
376 linetod_dtrace()
378 local name args state
379 name=$(get_name "$1")
380 args=$(get_args "$1")
381 state=$(get_state "$1")
382 if [ "$state" = "0" ] ; then
383 name=${name##disable }
386 # Define prototype for probe arguments
387 cat <<EOF
388 probe $name($args);
392 linetod_end_dtrace()
394 cat <<EOF
399 linetos_begin_dtrace()
401 return
404 linetos_dtrace()
406 local name args arglist state
407 name=$(get_name "$1")
408 args=$(get_args "$1")
409 arglist=$(get_argnames "$1", "")
410 state=$(get_state "$1")
411 if [ "$state" = "0" ] ; then
412 name=${name##disable }
415 if [ "$target" = "i386" ]
416 then
417 binary="qemu"
418 else
419 binary="qemu-system-$target"
422 # Define prototype for probe arguments
423 cat <<EOF
424 probe qemu.system.$target.$name = process("$bindir/$binary").mark("$name")
429 for arg in $arglist
431 cat <<EOF
432 $arg = \$arg$i;
434 i="$((i+1))"
435 done
437 cat <<EOF
442 linetos_end_dtrace()
444 return
447 # Process stdin by calling begin, line, and end functions for the backend
448 convert()
450 local begin process_line end str disable
451 begin="lineto$1_begin_$backend"
452 process_line="lineto$1_$backend"
453 end="lineto$1_end_$backend"
455 "$begin"
457 while read -r str; do
458 # Skip comments and empty lines
459 test -z "${str%%#*}" && continue
461 # Process the line. The nop backend handles disabled lines.
462 disable=${str%%disable *}
463 echo
464 if test -z "$disable"; then
465 # Pass the disabled state as an arg for the simple
466 # or DTrace backends which handle it dynamically.
467 # For all other backends, call lineto$1_nop()
468 if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
469 "$process_line" "$str"
470 else
471 "lineto$1_nop" "${str##disable }"
473 else
474 "$process_line" "$str"
476 done
478 echo
479 "$end"
482 tracetoh()
484 cat <<EOF
485 #ifndef TRACE_H
486 #define TRACE_H
488 /* This file is autogenerated by tracetool, do not edit. */
490 #include "qemu-common.h"
492 convert h
493 echo "#endif /* TRACE_H */"
496 tracetoc()
498 echo "/* This file is autogenerated by tracetool, do not edit. */"
499 convert c
502 tracetod()
504 if [ $backend != "dtrace" ]; then
505 echo "DTrace probe generator not applicable to $backend backend"
506 exit 1
508 echo "/* This file is autogenerated by tracetool, do not edit. */"
509 convert d
512 tracetos()
514 if [ $backend != "dtrace" ]; then
515 echo "SystemTAP tapset generator not applicable to $backend backend"
516 exit 1
518 if [ -z "$target" ]; then
519 echo "--target is required for SystemTAP tapset generator"
520 exit 1
522 if [ -z "$bindir" ]; then
523 echo "--bindir is required for SystemTAP tapset generator"
524 exit 1
526 echo "/* This file is autogenerated by tracetool, do not edit. */"
527 convert s
530 # Choose backend
531 case "$1" in
532 "--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
533 *) usage ;;
534 esac
535 shift
537 bindir=
538 case "$1" in
539 "--bindir")
540 bindir=$2
541 shift
542 shift
544 esac
546 target=
547 case "$1" in
548 "--target")
549 target=$2
550 shift
551 shift
553 esac
556 case "$1" in
557 "-h") tracetoh ;;
558 "-c") tracetoc ;;
559 "-d") tracetod ;;
560 "-s") tracetos ;;
561 "--check-backend") exit 0 ;; # used by ./configure to test for backend
562 *) usage ;;
563 esac
565 exit 0