]> git.proxmox.com Git - mirror_qemu.git/blob - scripts/tracetool
Allow controlling volume with PulseAudio backend
[mirror_qemu.git] / scripts / tracetool
1 #!/bin/sh
2 #
3 # Code generator for trace events
4 #
5 # Copyright IBM, Corp. 2010
6 #
7 # This work is licensed under the terms of the GNU GPL, version 2. See
8 # the COPYING file in the top-level directory.
9
10 # Disable pathname expansion, makes processing text with '*' characters simpler
11 set -f
12
13 usage()
14 {
15 cat >&2 <<EOF
16 usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
17 Generate tracing code for a file on stdin.
18
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
25
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)
31
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)
38
39 EOF
40 exit 1
41 }
42
43 # Print a line without interpreting backslash escapes
44 #
45 # The built-in echo command may interpret backslash escapes without an option
46 # to disable this behavior.
47 puts()
48 {
49 printf "%s\n" "$1"
50 }
51
52 # Get the name of a trace event
53 get_name()
54 {
55 local name
56 name=${1%%\(*}
57 echo "${name##* }"
58 }
59
60 # Get the given property of a trace event
61 # 1: trace-events line
62 # 2: property name
63 # -> return 0 if property is present, or 1 otherwise
64 has_property()
65 {
66 local props prop
67 props=${1%%\(*}
68 props=${props% *}
69 for prop in $props; do
70 if [ "$prop" = "$2" ]; then
71 return 0
72 fi
73 done
74 return 1
75 }
76
77 # Get the argument list of a trace event, including types and names
78 get_args()
79 {
80 local args
81 args=${1#*\(}
82 args=${args%%\)*}
83 echo "$args"
84
85 if (echo "$args" | grep "[ *]next\($\|[, ]\)" > /dev/null 2>&1); then
86 echo -e "\n#error 'next' is a bad argument name (clash with systemtap keyword)\n "
87 fi
88 }
89
90 # Get the argument name list of a trace event
91 get_argnames()
92 {
93 local nfields field name sep
94 nfields=0
95 sep="$2"
96 for field in $(get_args "$1"); do
97 nfields=$((nfields + 1))
98
99 # Drop pointer star
100 field=${field#\*}
101
102 # Only argument names have commas at the end
103 name=${field%,}
104 test "$field" = "$name" && continue
105
106 printf "%s%s " $name $sep
107 done
108
109 # Last argument name
110 if [ "$nfields" -gt 1 ]
111 then
112 printf "%s" "$name"
113 fi
114 }
115
116 # Get the number of arguments to a trace event
117 get_argc()
118 {
119 local name argc
120 argc=0
121 for name in $(get_argnames "$1", ","); do
122 argc=$((argc + 1))
123 done
124 echo $argc
125 }
126
127 # Get the format string including double quotes for a trace event
128 get_fmt()
129 {
130 puts "${1#*)}"
131 }
132
133 linetoh_begin_nop()
134 {
135 return
136 }
137
138 linetoh_nop()
139 {
140 local name args
141 name=$(get_name "$1")
142 args=$(get_args "$1")
143
144 # Define an empty function for the trace event
145 cat <<EOF
146 static inline void trace_$name($args)
147 {
148 }
149 EOF
150 }
151
152 linetoh_end_nop()
153 {
154 return
155 }
156
157 linetoc_begin_nop()
158 {
159 return
160 }
161
162 linetoc_nop()
163 {
164 # No need for function definitions in nop backend
165 return
166 }
167
168 linetod_nop()
169 {
170 # Used when "disabled" events are processed
171 return
172 }
173
174 linetostap_nop()
175 {
176 # Used when "disabled" events are processed
177 return
178 }
179
180 linetoc_end_nop()
181 {
182 return
183 }
184
185 linetoh_begin_simple()
186 {
187 cat <<EOF
188 #include "trace/simple.h"
189 EOF
190
191 simple_event_num=0
192 }
193
194 cast_args_to_uint64_t()
195 {
196 local arg
197 for arg in $(get_argnames "$1", ","); do
198 printf "%s" "(uint64_t)(uintptr_t)$arg"
199 done
200 }
201
202 linetoh_simple()
203 {
204 local name args argc trace_args
205 name=$(get_name "$1")
206 args=$(get_args "$1")
207 argc=$(get_argc "$1")
208
209 trace_args="$simple_event_num"
210 if [ "$argc" -gt 0 ]
211 then
212 trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
213 fi
214
215 cat <<EOF
216 static inline void trace_$name($args)
217 {
218 trace$argc($trace_args);
219 }
220 EOF
221
222 simple_event_num=$((simple_event_num + 1))
223 }
224
225 linetoh_end_simple()
226 {
227 cat <<EOF
228 #define NR_TRACE_EVENTS $simple_event_num
229 extern TraceEvent trace_list[NR_TRACE_EVENTS];
230 EOF
231 }
232
233 linetoc_begin_simple()
234 {
235 cat <<EOF
236 #include "trace.h"
237
238 TraceEvent trace_list[] = {
239 EOF
240 simple_event_num=0
241
242 }
243
244 linetoc_simple()
245 {
246 local name
247 name=$(get_name "$1")
248 cat <<EOF
249 {.tp_name = "$name", .state=0},
250 EOF
251 simple_event_num=$((simple_event_num + 1))
252 }
253
254 linetoc_end_simple()
255 {
256 cat <<EOF
257 };
258 EOF
259 }
260
261 #STDERR
262 linetoh_begin_stderr()
263 {
264 cat <<EOF
265 #include <stdio.h>
266 #include "trace/stderr.h"
267
268 extern TraceEvent trace_list[];
269 EOF
270
271 stderr_event_num=0
272 }
273
274 linetoh_stderr()
275 {
276 local name args argnames argc fmt
277 name=$(get_name "$1")
278 args=$(get_args "$1")
279 argnames=$(get_argnames "$1" ",")
280 argc=$(get_argc "$1")
281 fmt=$(get_fmt "$1")
282
283 if [ "$argc" -gt 0 ]; then
284 argnames=", $argnames"
285 fi
286
287 cat <<EOF
288 static inline void trace_$name($args)
289 {
290 if (trace_list[$stderr_event_num].state != 0) {
291 fprintf(stderr, "$name " $fmt "\n" $argnames);
292 }
293 }
294 EOF
295 stderr_event_num=$((stderr_event_num + 1))
296
297 }
298
299 linetoh_end_stderr()
300 {
301 cat <<EOF
302 #define NR_TRACE_EVENTS $stderr_event_num
303 EOF
304 }
305
306 linetoc_begin_stderr()
307 {
308 cat <<EOF
309 #include "trace.h"
310
311 TraceEvent trace_list[] = {
312 EOF
313 stderr_event_num=0
314 }
315
316 linetoc_stderr()
317 {
318 local name
319 name=$(get_name "$1")
320 cat <<EOF
321 {.tp_name = "$name", .state=0},
322 EOF
323 stderr_event_num=$(($stderr_event_num + 1))
324 }
325
326 linetoc_end_stderr()
327 {
328 cat <<EOF
329 };
330 EOF
331 }
332 #END OF STDERR
333
334 # Clean up after UST headers which pollute the namespace
335 ust_clean_namespace() {
336 cat <<EOF
337 #undef mutex_lock
338 #undef mutex_unlock
339 #undef inline
340 #undef wmb
341 EOF
342 }
343
344 linetoh_begin_ust()
345 {
346 echo "#include <ust/tracepoint.h>"
347 ust_clean_namespace
348 }
349
350 linetoh_ust()
351 {
352 local name args argnames
353 name=$(get_name "$1")
354 args=$(get_args "$1")
355 argnames=$(get_argnames "$1", ",")
356
357 cat <<EOF
358 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
359 #define trace_$name trace_ust_$name
360 EOF
361 }
362
363 linetoh_end_ust()
364 {
365 return
366 }
367
368 linetoc_begin_ust()
369 {
370 cat <<EOF
371 #include <ust/marker.h>
372 $(ust_clean_namespace)
373 #include "trace.h"
374 EOF
375 }
376
377 linetoc_ust()
378 {
379 local name args argnames fmt
380 name=$(get_name "$1")
381 args=$(get_args "$1")
382 argnames=$(get_argnames "$1", ",")
383 [ -z "$argnames" ] || argnames=", $argnames"
384 fmt=$(get_fmt "$1")
385
386 cat <<EOF
387 DEFINE_TRACE(ust_$name);
388
389 static void ust_${name}_probe($args)
390 {
391 trace_mark(ust, $name, $fmt$argnames);
392 }
393 EOF
394
395 # Collect names for later
396 names="$names $name"
397 }
398
399 linetoc_end_ust()
400 {
401 cat <<EOF
402 static void __attribute__((constructor)) trace_init(void)
403 {
404 EOF
405
406 for name in $names; do
407 cat <<EOF
408 register_trace_ust_$name(ust_${name}_probe);
409 EOF
410 done
411
412 echo "}"
413 }
414
415 linetoh_begin_dtrace()
416 {
417 cat <<EOF
418 #include "trace-dtrace.h"
419 EOF
420 }
421
422 linetoh_dtrace()
423 {
424 local name args argnames nameupper
425 name=$(get_name "$1")
426 args=$(get_args "$1")
427 argnames=$(get_argnames "$1", ",")
428
429 nameupper=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
430
431 # Define an empty function for the trace event
432 cat <<EOF
433 static inline void trace_$name($args) {
434 QEMU_${nameupper}($argnames);
435 }
436 EOF
437 }
438
439 linetoh_end_dtrace()
440 {
441 return
442 }
443
444 linetoc_begin_dtrace()
445 {
446 return
447 }
448
449 linetoc_dtrace()
450 {
451 # No need for function definitions in dtrace backend
452 return
453 }
454
455 linetoc_end_dtrace()
456 {
457 return
458 }
459
460 linetod_begin_dtrace()
461 {
462 cat <<EOF
463 provider qemu {
464 EOF
465 }
466
467 linetod_dtrace()
468 {
469 local name args
470 name=$(get_name "$1")
471 args=$(get_args "$1")
472
473 # DTrace provider syntax expects foo() for empty
474 # params, not foo(void)
475 if [ "$args" = "void" ]; then
476 args=""
477 fi
478
479 # Define prototype for probe arguments
480 cat <<EOF
481 probe $name($args);
482 EOF
483 }
484
485 linetod_end_dtrace()
486 {
487 cat <<EOF
488 };
489 EOF
490 }
491
492 linetostap_begin_dtrace()
493 {
494 return
495 }
496
497 linetostap_dtrace()
498 {
499 local i arg name args arglist
500 name=$(get_name "$1")
501 args=$(get_args "$1")
502 arglist=$(get_argnames "$1", "")
503
504 # Define prototype for probe arguments
505 cat <<EOF
506 probe $probeprefix.$name = process("$binary").mark("$name")
507 {
508 EOF
509
510 i=1
511 for arg in $arglist
512 do
513 # postfix reserved words with '_'
514 case "$arg" in
515 limit|in|next|self)
516 arg="${arg}_"
517 ;;
518 esac
519 cat <<EOF
520 $arg = \$arg$i;
521 EOF
522 i="$((i+1))"
523 done
524
525 cat <<EOF
526 }
527 EOF
528 }
529
530 linetostap_end_dtrace()
531 {
532 return
533 }
534
535 # Process stdin by calling begin, line, and end functions for the backend
536 convert()
537 {
538 local begin process_line end str name NAME enabled
539 begin="lineto$1_begin_$backend"
540 process_line="lineto$1_$backend"
541 end="lineto$1_end_$backend"
542
543 "$begin"
544
545 while read -r str; do
546 # Skip comments and empty lines
547 test -z "${str%%#*}" && continue
548
549 echo
550 # Process the line. The nop backend handles disabled lines.
551 if has_property "$str" "disable"; then
552 "lineto$1_nop" "$str"
553 enabled=0
554 else
555 "$process_line" "$str"
556 enabled=1
557 fi
558 if [ "$1" = "h" ]; then
559 name=$(get_name "$str")
560 NAME=$(echo $name | LC_ALL=C tr '[a-z]' '[A-Z]')
561 echo "#define TRACE_${NAME}_ENABLED ${enabled}"
562 fi
563 done
564
565 echo
566 "$end"
567 }
568
569 tracetoh()
570 {
571 cat <<EOF
572 #ifndef TRACE_H
573 #define TRACE_H
574
575 /* This file is autogenerated by tracetool, do not edit. */
576
577 #include "qemu-common.h"
578 EOF
579 convert h
580 echo "#endif /* TRACE_H */"
581 }
582
583 tracetoc()
584 {
585 echo "/* This file is autogenerated by tracetool, do not edit. */"
586 convert c
587 }
588
589 tracetod()
590 {
591 if [ $backend != "dtrace" ]; then
592 echo "DTrace probe generator not applicable to $backend backend"
593 exit 1
594 fi
595 echo "/* This file is autogenerated by tracetool, do not edit. */"
596 convert d
597 }
598
599 tracetostap()
600 {
601 if [ $backend != "dtrace" ]; then
602 echo "SystemTAP tapset generator not applicable to $backend backend"
603 exit 1
604 fi
605 if [ -z "$binary" ]; then
606 echo "--binary is required for SystemTAP tapset generator"
607 exit 1
608 fi
609 if [ -z "$probeprefix" -a -z "$targettype" ]; then
610 echo "--target-type is required for SystemTAP tapset generator"
611 exit 1
612 fi
613 if [ -z "$probeprefix" -a -z "$targetarch" ]; then
614 echo "--target-arch is required for SystemTAP tapset generator"
615 exit 1
616 fi
617 if [ -z "$probeprefix" ]; then
618 probeprefix="qemu.$targettype.$targetarch";
619 fi
620 echo "/* This file is autogenerated by tracetool, do not edit. */"
621 convert stap
622 }
623
624
625 backend=
626 output=
627 binary=
628 targettype=
629 targetarch=
630 probeprefix=
631
632
633 until [ -z "$1" ]
634 do
635 case "$1" in
636 "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
637
638 "--binary") shift ; binary="$1" ;;
639 "--target-arch") shift ; targetarch="$1" ;;
640 "--target-type") shift ; targettype="$1" ;;
641 "--probe-prefix") shift ; probeprefix="$1" ;;
642
643 "-h" | "-c" | "-d") output="${1#-}" ;;
644 "--stap") output="${1#--}" ;;
645
646 "--check-backend") exit 0 ;; # used by ./configure to test for backend
647
648 "--list-backends") # used by ./configure to list available backends
649 echo "nop simple stderr ust dtrace"
650 exit 0
651 ;;
652
653 *)
654 usage;;
655 esac
656 shift
657 done
658
659 if [ "$backend" = "" -o "$output" = "" ]; then
660 usage
661 fi
662
663 gen="traceto$output"
664 "$gen"
665
666 exit 0