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