trace: generalize the "property" concept in the trace-events file
[qemu/ar7.git] / scripts / tracetool
blobe649a5b807796902ec170b4c7f3ec795f9dc688a
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 local name
47 name=${1%%\(*}
48 echo "${name##* }"
51 # Get the given property of a trace event
52 # 1: trace-events line
53 # 2: property name
54 # -> return 0 if property is present, or 1 otherwise
55 has_property()
57 local props prop
58 props=${1%%\(*}
59 props=${props% *}
60 for prop in $props; do
61 if [ "$prop" = "$2" ]; then
62 return 0
64 done
65 return 1
68 # Get the argument list of a trace event, including types and names
69 get_args()
71 local args
72 args=${1#*\(}
73 args=${args%%\)*}
74 echo "$args"
77 # Get the argument name list of a trace event
78 get_argnames()
80 local nfields field name sep
81 nfields=0
82 sep="$2"
83 for field in $(get_args "$1"); do
84 nfields=$((nfields + 1))
86 # Drop pointer star
87 field=${field#\*}
89 # Only argument names have commas at the end
90 name=${field%,}
91 test "$field" = "$name" && continue
93 printf "%s%s " $name $sep
94 done
96 # Last argument name
97 if [ "$nfields" -gt 1 ]
98 then
99 printf "%s" "$name"
103 # Get the number of arguments to a trace event
104 get_argc()
106 local name argc
107 argc=0
108 for name in $(get_argnames "$1", ","); do
109 argc=$((argc + 1))
110 done
111 echo $argc
114 # Get the format string for a trace event
115 get_fmt()
117 local fmt
118 fmt=${1#*\"}
119 fmt=${fmt%\"*}
120 echo "$fmt"
123 linetoh_begin_nop()
125 return
128 linetoh_nop()
130 local name args
131 name=$(get_name "$1")
132 args=$(get_args "$1")
134 # Define an empty function for the trace event
135 cat <<EOF
136 static inline void trace_$name($args)
142 linetoh_end_nop()
144 return
147 linetoc_begin_nop()
149 return
152 linetoc_nop()
154 # No need for function definitions in nop backend
155 return
158 linetoc_end_nop()
160 return
163 linetoh_begin_simple()
165 cat <<EOF
166 #include "trace/simple.h"
169 simple_event_num=0
172 cast_args_to_uint64_t()
174 local arg
175 for arg in $(get_argnames "$1", ","); do
176 printf "%s" "(uint64_t)(uintptr_t)$arg"
177 done
180 linetoh_simple()
182 local name args argc trace_args
183 name=$(get_name "$1")
184 args=$(get_args "$1")
185 argc=$(get_argc "$1")
187 trace_args="$simple_event_num"
188 if [ "$argc" -gt 0 ]
189 then
190 trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
193 cat <<EOF
194 static inline void trace_$name($args)
196 trace$argc($trace_args);
200 simple_event_num=$((simple_event_num + 1))
203 linetoh_end_simple()
205 cat <<EOF
206 #define NR_TRACE_EVENTS $simple_event_num
207 extern TraceEvent trace_list[NR_TRACE_EVENTS];
211 linetoc_begin_simple()
213 cat <<EOF
214 #include "trace.h"
216 TraceEvent trace_list[] = {
218 simple_event_num=0
222 linetoc_simple()
224 local name state
225 name=$(get_name "$1")
226 if has_property "$1" "disable"; then
227 state="0"
228 else
229 state="1"
231 cat <<EOF
232 {.tp_name = "$name", .state=$state},
234 simple_event_num=$((simple_event_num + 1))
237 linetoc_end_simple()
239 cat <<EOF
244 #STDERR
245 linetoh_begin_stderr()
247 cat <<EOF
248 #include <stdio.h>
252 linetoh_stderr()
254 local name args argnames argc fmt
255 name=$(get_name "$1")
256 args=$(get_args "$1")
257 argnames=$(get_argnames "$1" ",")
258 argc=$(get_argc "$1")
259 fmt=$(get_fmt "$1")
261 if [ "$argc" -gt 0 ]; then
262 argnames=", $argnames"
265 cat <<EOF
266 static inline void trace_$name($args)
268 fprintf(stderr, "$name $fmt\n" $argnames);
273 linetoh_end_stderr()
275 return
278 linetoc_begin_stderr()
280 return
283 linetoc_stderr()
285 return
288 linetoc_end_stderr()
290 return
292 #END OF STDERR
294 # Clean up after UST headers which pollute the namespace
295 ust_clean_namespace() {
296 cat <<EOF
297 #undef mutex_lock
298 #undef mutex_unlock
299 #undef inline
300 #undef wmb
304 linetoh_begin_ust()
306 echo "#include <ust/tracepoint.h>"
307 ust_clean_namespace
310 linetoh_ust()
312 local name args argnames
313 name=$(get_name "$1")
314 args=$(get_args "$1")
315 argnames=$(get_argnames "$1", ",")
317 cat <<EOF
318 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
319 #define trace_$name trace_ust_$name
323 linetoh_end_ust()
325 return
328 linetoc_begin_ust()
330 cat <<EOF
331 #include <ust/marker.h>
332 $(ust_clean_namespace)
333 #include "trace.h"
337 linetoc_ust()
339 local name args argnames fmt
340 name=$(get_name "$1")
341 args=$(get_args "$1")
342 argnames=$(get_argnames "$1", ",")
343 [ -z "$argnames" ] || argnames=", $argnames"
344 fmt=$(get_fmt "$1")
346 cat <<EOF
347 DEFINE_TRACE(ust_$name);
349 static void ust_${name}_probe($args)
351 trace_mark(ust, $name, "$fmt"$argnames);
355 # Collect names for later
356 names="$names $name"
359 linetoc_end_ust()
361 cat <<EOF
362 static void __attribute__((constructor)) trace_init(void)
366 for name in $names; do
367 cat <<EOF
368 register_trace_ust_$name(ust_${name}_probe);
370 done
372 echo "}"
375 linetoh_begin_dtrace()
377 cat <<EOF
378 #include "trace-dtrace.h"
382 linetoh_dtrace()
384 local name args argnames nameupper
385 name=$(get_name "$1")
386 args=$(get_args "$1")
387 argnames=$(get_argnames "$1", ",")
389 nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
391 # Define an empty function for the trace event
392 cat <<EOF
393 static inline void trace_$name($args) {
394 if (QEMU_${nameupper}_ENABLED()) {
395 QEMU_${nameupper}($argnames);
401 linetoh_end_dtrace()
403 return
406 linetoc_begin_dtrace()
408 return
411 linetoc_dtrace()
413 # No need for function definitions in dtrace backend
414 return
417 linetoc_end_dtrace()
419 return
422 linetod_begin_dtrace()
424 cat <<EOF
425 provider qemu {
429 linetod_dtrace()
431 local name args
432 name=$(get_name "$1")
433 args=$(get_args "$1")
435 # DTrace provider syntax expects foo() for empty
436 # params, not foo(void)
437 if [ "$args" = "void" ]; then
438 args=""
441 # Define prototype for probe arguments
442 cat <<EOF
443 probe $name($args);
447 linetod_end_dtrace()
449 cat <<EOF
454 linetostap_begin_dtrace()
456 return
459 linetostap_dtrace()
461 local i arg name args arglist
462 name=$(get_name "$1")
463 args=$(get_args "$1")
464 arglist=$(get_argnames "$1", "")
466 # Define prototype for probe arguments
467 cat <<EOF
468 probe $probeprefix.$name = process("$binary").mark("$name")
473 for arg in $arglist
475 # 'limit' is a reserved keyword
476 if [ "$arg" = "limit" ]; then
477 arg="_limit"
479 cat <<EOF
480 $arg = \$arg$i;
482 i="$((i+1))"
483 done
485 cat <<EOF
490 linetostap_end_dtrace()
492 return
495 # Process stdin by calling begin, line, and end functions for the backend
496 convert()
498 local begin process_line end str disable
499 begin="lineto$1_begin_$backend"
500 process_line="lineto$1_$backend"
501 end="lineto$1_end_$backend"
503 "$begin"
505 while read -r str; do
506 # Skip comments and empty lines
507 test -z "${str%%#*}" && continue
509 # Process the line. The nop backend handles disabled lines.
510 disable="0"
511 if has_property "$str" "disable"; then
512 disable="1"
514 echo
515 if [ "$disable" = "1" ]; then
516 # Pass the disabled state as an arg for the simple
517 # or DTrace backends which handle it dynamically.
518 # For all other backends, call lineto$1_nop()
519 if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
520 "$process_line" "$str"
521 else
522 "lineto$1_nop" "${str##disable }"
524 else
525 "$process_line" "$str"
527 done
529 echo
530 "$end"
533 tracetoh()
535 cat <<EOF
536 #ifndef TRACE_H
537 #define TRACE_H
539 /* This file is autogenerated by tracetool, do not edit. */
541 #include "qemu-common.h"
543 convert h
544 echo "#endif /* TRACE_H */"
547 tracetoc()
549 echo "/* This file is autogenerated by tracetool, do not edit. */"
550 convert c
553 tracetod()
555 if [ $backend != "dtrace" ]; then
556 echo "DTrace probe generator not applicable to $backend backend"
557 exit 1
559 echo "/* This file is autogenerated by tracetool, do not edit. */"
560 convert d
563 tracetostap()
565 if [ $backend != "dtrace" ]; then
566 echo "SystemTAP tapset generator not applicable to $backend backend"
567 exit 1
569 if [ -z "$binary" ]; then
570 echo "--binary is required for SystemTAP tapset generator"
571 exit 1
573 if [ -z "$probeprefix" -a -z "$targettype" ]; then
574 echo "--target-type is required for SystemTAP tapset generator"
575 exit 1
577 if [ -z "$probeprefix" -a -z "$targetarch" ]; then
578 echo "--target-arch is required for SystemTAP tapset generator"
579 exit 1
581 if [ -z "$probeprefix" ]; then
582 probeprefix="qemu.$targettype.$targetarch";
584 echo "/* This file is autogenerated by tracetool, do not edit. */"
585 convert stap
589 backend=
590 output=
591 binary=
592 targettype=
593 targetarch=
594 probeprefix=
597 until [ -z "$1" ]
599 case "$1" in
600 "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
602 "--binary") shift ; binary="$1" ;;
603 "--target-arch") shift ; targetarch="$1" ;;
604 "--target-type") shift ; targettype="$1" ;;
605 "--probe-prefix") shift ; probeprefix="$1" ;;
607 "-h" | "-c" | "-d") output="${1#-}" ;;
608 "--stap") output="${1#--}" ;;
610 "--check-backend") exit 0 ;; # used by ./configure to test for backend
612 "--list-backends") # used by ./configure to list available backends
613 echo "nop simple stderr ust dtrace"
614 exit 0
618 usage;;
619 esac
620 shift
621 done
623 if [ "$backend" = "" -o "$output" = "" ]; then
624 usage
627 gen="traceto$output"
628 "$gen"
630 exit 0