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