Merge remote-tracking branch 'agraf/xen-next' into staging
[qemu.git] / scripts / tracetool
blob2155a57df2a02d3ec58321c544cf658245f25dae
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 | --stderr | --ust | --dtrace] [-h | -c]
17 Generate tracing code for a file on stdin.
19 Backends:
20 --nop Tracing disabled
21 --simple Simple built-in backend
22 --stderr Stderr built-in backend
23 --ust LTTng User Space Tracing backend
24 --dtrace DTrace/SystemTAP backend
26 Output formats:
27 -h Generate .h file
28 -c Generate .c file
29 -d Generate .d file (DTrace only)
30 --stap Generate .stp file (DTrace with SystemTAP only)
32 Options:
33 --binary [path] Full path to QEMU binary
34 --target-arch [arch] QEMU emulator target arch
35 --target-type [type] QEMU emulator target type ('system' or 'user')
36 --probe-prefix [prefix] Prefix for dtrace probe names
37 (default: qemu-\$targettype-\$targetarch)
39 EOF
40 exit 1
43 # Get the name of a trace event
44 get_name()
46 echo ${1%%\(*}
49 # Get the argument list of a trace event, including types and names
50 get_args()
52 local args
53 args=${1#*\(}
54 args=${args%%\)*}
55 echo "$args"
58 # Get the argument name list of a trace event
59 get_argnames()
61 local nfields field name sep
62 nfields=0
63 sep="$2"
64 for field in $(get_args "$1"); do
65 nfields=$((nfields + 1))
67 # Drop pointer star
68 field=${field#\*}
70 # Only argument names have commas at the end
71 name=${field%,}
72 test "$field" = "$name" && continue
74 printf "%s%s " $name $sep
75 done
77 # Last argument name
78 if [ "$nfields" -gt 1 ]
79 then
80 printf "%s" "$name"
84 # Get the number of arguments to a trace event
85 get_argc()
87 local name argc
88 argc=0
89 for name in $(get_argnames "$1", ","); do
90 argc=$((argc + 1))
91 done
92 echo $argc
95 # Get the format string for a trace event
96 get_fmt()
98 local fmt
99 fmt=${1#*\"}
100 fmt=${fmt%\"*}
101 echo "$fmt"
104 # Get the state of a trace event
105 get_state()
107 local str disable state
108 str=$(get_name "$1")
109 disable=${str##disable }
110 if [ "$disable" = "$str" ] ; then
111 state=1
112 else
113 state=0
115 echo "$state"
118 linetoh_begin_nop()
120 return
123 linetoh_nop()
125 local name args
126 name=$(get_name "$1")
127 args=$(get_args "$1")
129 # Define an empty function for the trace event
130 cat <<EOF
131 static inline void trace_$name($args)
137 linetoh_end_nop()
139 return
142 linetoc_begin_nop()
144 return
147 linetoc_nop()
149 # No need for function definitions in nop backend
150 return
153 linetoc_end_nop()
155 return
158 linetoh_begin_simple()
160 cat <<EOF
161 #include "simpletrace.h"
164 simple_event_num=0
167 cast_args_to_uint64_t()
169 local arg
170 for arg in $(get_argnames "$1", ","); do
171 printf "%s" "(uint64_t)(uintptr_t)$arg"
172 done
175 linetoh_simple()
177 local name args argc trace_args state
178 name=$(get_name "$1")
179 args=$(get_args "$1")
180 argc=$(get_argc "$1")
181 state=$(get_state "$1")
182 if [ "$state" = "0" ]; then
183 name=${name##disable }
186 trace_args="$simple_event_num"
187 if [ "$argc" -gt 0 ]
188 then
189 trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
192 cat <<EOF
193 static inline void trace_$name($args)
195 trace$argc($trace_args);
199 simple_event_num=$((simple_event_num + 1))
202 linetoh_end_simple()
204 cat <<EOF
205 #define NR_TRACE_EVENTS $simple_event_num
206 extern TraceEvent trace_list[NR_TRACE_EVENTS];
210 linetoc_begin_simple()
212 cat <<EOF
213 #include "trace.h"
215 TraceEvent trace_list[] = {
217 simple_event_num=0
221 linetoc_simple()
223 local name state
224 name=$(get_name "$1")
225 state=$(get_state "$1")
226 if [ "$state" = "0" ] ; then
227 name=${name##disable }
229 cat <<EOF
230 {.tp_name = "$name", .state=$state},
232 simple_event_num=$((simple_event_num + 1))
235 linetoc_end_simple()
237 cat <<EOF
242 #STDERR
243 linetoh_begin_stderr()
245 cat <<EOF
246 #include <stdio.h>
250 linetoh_stderr()
252 local name args argnames argc fmt
253 name=$(get_name "$1")
254 args=$(get_args "$1")
255 argnames=$(get_argnames "$1" ",")
256 argc=$(get_argc "$1")
257 fmt=$(get_fmt "$1")
259 if [ "$argc" -gt 0 ]; then
260 argnames=", $argnames"
263 cat <<EOF
264 static inline void trace_$name($args)
266 fprintf(stderr, "$name $fmt\n" $argnames);
271 linetoh_end_stderr()
273 return
276 linetoc_begin_stderr()
278 return
281 linetoc_stderr()
283 return
286 linetoc_end_stderr()
288 return
290 #END OF STDERR
292 # Clean up after UST headers which pollute the namespace
293 ust_clean_namespace() {
294 cat <<EOF
295 #undef mutex_lock
296 #undef mutex_unlock
297 #undef inline
298 #undef wmb
302 linetoh_begin_ust()
304 echo "#include <ust/tracepoint.h>"
305 ust_clean_namespace
308 linetoh_ust()
310 local name args argnames
311 name=$(get_name "$1")
312 args=$(get_args "$1")
313 argnames=$(get_argnames "$1", ",")
315 cat <<EOF
316 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
317 #define trace_$name trace_ust_$name
321 linetoh_end_ust()
323 return
326 linetoc_begin_ust()
328 cat <<EOF
329 #include <ust/marker.h>
330 $(ust_clean_namespace)
331 #include "trace.h"
335 linetoc_ust()
337 local name args argnames fmt
338 name=$(get_name "$1")
339 args=$(get_args "$1")
340 argnames=$(get_argnames "$1", ",")
341 [ -z "$argnames" ] || argnames=", $argnames"
342 fmt=$(get_fmt "$1")
344 cat <<EOF
345 DEFINE_TRACE(ust_$name);
347 static void ust_${name}_probe($args)
349 trace_mark(ust, $name, "$fmt"$argnames);
353 # Collect names for later
354 names="$names $name"
357 linetoc_end_ust()
359 cat <<EOF
360 static void __attribute__((constructor)) trace_init(void)
364 for name in $names; do
365 cat <<EOF
366 register_trace_ust_$name(ust_${name}_probe);
368 done
370 echo "}"
373 linetoh_begin_dtrace()
375 cat <<EOF
376 #include "trace-dtrace.h"
380 linetoh_dtrace()
382 local name args argnames state nameupper
383 name=$(get_name "$1")
384 args=$(get_args "$1")
385 argnames=$(get_argnames "$1", ",")
386 state=$(get_state "$1")
387 if [ "$state" = "0" ] ; then
388 name=${name##disable }
391 nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
393 # Define an empty function for the trace event
394 cat <<EOF
395 static inline void trace_$name($args) {
396 if (QEMU_${nameupper}_ENABLED()) {
397 QEMU_${nameupper}($argnames);
403 linetoh_end_dtrace()
405 return
408 linetoc_begin_dtrace()
410 return
413 linetoc_dtrace()
415 # No need for function definitions in dtrace backend
416 return
419 linetoc_end_dtrace()
421 return
424 linetod_begin_dtrace()
426 cat <<EOF
427 provider qemu {
431 linetod_dtrace()
433 local name args state
434 name=$(get_name "$1")
435 args=$(get_args "$1")
436 state=$(get_state "$1")
437 if [ "$state" = "0" ] ; then
438 name=${name##disable }
441 # DTrace provider syntax expects foo() for empty
442 # params, not foo(void)
443 if [ "$args" = "void" ]; then
444 args=""
447 # Define prototype for probe arguments
448 cat <<EOF
449 probe $name($args);
453 linetod_end_dtrace()
455 cat <<EOF
460 linetostap_begin_dtrace()
462 return
465 linetostap_dtrace()
467 local i arg name args arglist state
468 name=$(get_name "$1")
469 args=$(get_args "$1")
470 arglist=$(get_argnames "$1", "")
471 state=$(get_state "$1")
472 if [ "$state" = "0" ] ; then
473 name=${name##disable }
476 # Define prototype for probe arguments
477 cat <<EOF
478 probe $probeprefix.$name = process("$binary").mark("$name")
483 for arg in $arglist
485 # 'limit' is a reserved keyword
486 if [ "$arg" = "limit" ]; then
487 arg="_limit"
489 cat <<EOF
490 $arg = \$arg$i;
492 i="$((i+1))"
493 done
495 cat <<EOF
500 linetostap_end_dtrace()
502 return
505 # Process stdin by calling begin, line, and end functions for the backend
506 convert()
508 local begin process_line end str disable
509 begin="lineto$1_begin_$backend"
510 process_line="lineto$1_$backend"
511 end="lineto$1_end_$backend"
513 "$begin"
515 while read -r str; do
516 # Skip comments and empty lines
517 test -z "${str%%#*}" && continue
519 # Process the line. The nop backend handles disabled lines.
520 disable=${str%%disable *}
521 echo
522 if test -z "$disable"; then
523 # Pass the disabled state as an arg for the simple
524 # or DTrace backends which handle it dynamically.
525 # For all other backends, call lineto$1_nop()
526 if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
527 "$process_line" "$str"
528 else
529 "lineto$1_nop" "${str##disable }"
531 else
532 "$process_line" "$str"
534 done
536 echo
537 "$end"
540 tracetoh()
542 cat <<EOF
543 #ifndef TRACE_H
544 #define TRACE_H
546 /* This file is autogenerated by tracetool, do not edit. */
548 #include "qemu-common.h"
550 convert h
551 echo "#endif /* TRACE_H */"
554 tracetoc()
556 echo "/* This file is autogenerated by tracetool, do not edit. */"
557 convert c
560 tracetod()
562 if [ $backend != "dtrace" ]; then
563 echo "DTrace probe generator not applicable to $backend backend"
564 exit 1
566 echo "/* This file is autogenerated by tracetool, do not edit. */"
567 convert d
570 tracetostap()
572 if [ $backend != "dtrace" ]; then
573 echo "SystemTAP tapset generator not applicable to $backend backend"
574 exit 1
576 if [ -z "$binary" ]; then
577 echo "--binary is required for SystemTAP tapset generator"
578 exit 1
580 if [ -z "$probeprefix" -a -z "$targettype" ]; then
581 echo "--target-type is required for SystemTAP tapset generator"
582 exit 1
584 if [ -z "$probeprefix" -a -z "$targetarch" ]; then
585 echo "--target-arch is required for SystemTAP tapset generator"
586 exit 1
588 if [ -z "$probeprefix" ]; then
589 probeprefix="qemu.$targettype.$targetarch";
591 echo "/* This file is autogenerated by tracetool, do not edit. */"
592 convert stap
596 backend=
597 output=
598 binary=
599 targettype=
600 targetarch=
601 probeprefix=
604 until [ -z "$1" ]
606 case "$1" in
607 "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
609 "--binary") shift ; binary="$1" ;;
610 "--target-arch") shift ; targetarch="$1" ;;
611 "--target-type") shift ; targettype="$1" ;;
612 "--probe-prefix") shift ; probeprefix="$1" ;;
614 "-h" | "-c" | "-d") output="${1#-}" ;;
615 "--stap") output="${1#--}" ;;
617 "--check-backend") exit 0 ;; # used by ./configure to test for backend
619 "--list-backends") # used by ./configure to list available backends
620 echo "nop simple stderr ust dtrace"
621 exit 0
625 usage;;
626 esac
627 shift
628 done
630 if [ "$backend" = "" -o "$output" = "" ]; then
631 usage
634 gen="traceto$output"
635 "$gen"
637 exit 0