Merge remote-tracking branch 'qmp/queue/qmp' into staging
[qemu.git] / scripts / tracetool
blob743d2462893c8626bd4b72f4e6bd87544dab61cd
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
225 name=$(get_name "$1")
226 cat <<EOF
227 {.tp_name = "$name", .state=0},
229 simple_event_num=$((simple_event_num + 1))
232 linetoc_end_simple()
234 cat <<EOF
239 #STDERR
240 linetoh_begin_stderr()
242 cat <<EOF
243 #include <stdio.h>
244 #include "trace/stderr.h"
246 extern TraceEvent trace_list[];
249 stderr_event_num=0
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 if (trace_list[$stderr_event_num].state != 0) {
269 fprintf(stderr, "$name $fmt\n" $argnames);
273 stderr_event_num=$((stderr_event_num + 1))
277 linetoh_end_stderr()
279 cat <<EOF
280 #define NR_TRACE_EVENTS $stderr_event_num
284 linetoc_begin_stderr()
286 cat <<EOF
287 #include "trace.h"
289 TraceEvent trace_list[] = {
291 stderr_event_num=0
294 linetoc_stderr()
296 local name
297 name=$(get_name "$1")
298 cat <<EOF
299 {.tp_name = "$name", .state=0},
301 stderr_event_num=$(($stderr_event_num + 1))
304 linetoc_end_stderr()
306 cat <<EOF
310 #END OF STDERR
312 # Clean up after UST headers which pollute the namespace
313 ust_clean_namespace() {
314 cat <<EOF
315 #undef mutex_lock
316 #undef mutex_unlock
317 #undef inline
318 #undef wmb
322 linetoh_begin_ust()
324 echo "#include <ust/tracepoint.h>"
325 ust_clean_namespace
328 linetoh_ust()
330 local name args argnames
331 name=$(get_name "$1")
332 args=$(get_args "$1")
333 argnames=$(get_argnames "$1", ",")
335 cat <<EOF
336 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
337 #define trace_$name trace_ust_$name
341 linetoh_end_ust()
343 return
346 linetoc_begin_ust()
348 cat <<EOF
349 #include <ust/marker.h>
350 $(ust_clean_namespace)
351 #include "trace.h"
355 linetoc_ust()
357 local name args argnames fmt
358 name=$(get_name "$1")
359 args=$(get_args "$1")
360 argnames=$(get_argnames "$1", ",")
361 [ -z "$argnames" ] || argnames=", $argnames"
362 fmt=$(get_fmt "$1")
364 cat <<EOF
365 DEFINE_TRACE(ust_$name);
367 static void ust_${name}_probe($args)
369 trace_mark(ust, $name, "$fmt"$argnames);
373 # Collect names for later
374 names="$names $name"
377 linetoc_end_ust()
379 cat <<EOF
380 static void __attribute__((constructor)) trace_init(void)
384 for name in $names; do
385 cat <<EOF
386 register_trace_ust_$name(ust_${name}_probe);
388 done
390 echo "}"
393 linetoh_begin_dtrace()
395 cat <<EOF
396 #include "trace-dtrace.h"
400 linetoh_dtrace()
402 local name args argnames nameupper
403 name=$(get_name "$1")
404 args=$(get_args "$1")
405 argnames=$(get_argnames "$1", ",")
407 nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
409 # Define an empty function for the trace event
410 cat <<EOF
411 static inline void trace_$name($args) {
412 if (QEMU_${nameupper}_ENABLED()) {
413 QEMU_${nameupper}($argnames);
419 linetoh_end_dtrace()
421 return
424 linetoc_begin_dtrace()
426 return
429 linetoc_dtrace()
431 # No need for function definitions in dtrace backend
432 return
435 linetoc_end_dtrace()
437 return
440 linetod_begin_dtrace()
442 cat <<EOF
443 provider qemu {
447 linetod_dtrace()
449 local name args
450 name=$(get_name "$1")
451 args=$(get_args "$1")
453 # DTrace provider syntax expects foo() for empty
454 # params, not foo(void)
455 if [ "$args" = "void" ]; then
456 args=""
459 # Define prototype for probe arguments
460 cat <<EOF
461 probe $name($args);
465 linetod_end_dtrace()
467 cat <<EOF
472 linetostap_begin_dtrace()
474 return
477 linetostap_dtrace()
479 local i arg name args arglist
480 name=$(get_name "$1")
481 args=$(get_args "$1")
482 arglist=$(get_argnames "$1", "")
484 # Define prototype for probe arguments
485 cat <<EOF
486 probe $probeprefix.$name = process("$binary").mark("$name")
491 for arg in $arglist
493 # 'limit' is a reserved keyword
494 if [ "$arg" = "limit" ]; then
495 arg="_limit"
497 cat <<EOF
498 $arg = \$arg$i;
500 i="$((i+1))"
501 done
503 cat <<EOF
508 linetostap_end_dtrace()
510 return
513 # Process stdin by calling begin, line, and end functions for the backend
514 convert()
516 local begin process_line end str disable
517 begin="lineto$1_begin_$backend"
518 process_line="lineto$1_$backend"
519 end="lineto$1_end_$backend"
521 "$begin"
523 while read -r str; do
524 # Skip comments and empty lines
525 test -z "${str%%#*}" && continue
527 echo
528 # Process the line. The nop backend handles disabled lines.
529 if has_property "$str" "disable"; then
530 "lineto$1_nop" "$str"
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