]> Git Repo - qemu.git/blob - scripts/tracetool
Merge remote-tracking branch 'stefanha/trivial-patches' into staging
[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     QEMU_${nameupper}($argnames);
419 }
420 EOF
421 }
422
423 linetoh_end_dtrace()
424 {
425     return
426 }
427
428 linetoc_begin_dtrace()
429 {
430     return
431 }
432
433 linetoc_dtrace()
434 {
435     # No need for function definitions in dtrace backend
436     return
437 }
438
439 linetoc_end_dtrace()
440 {
441     return
442 }
443
444 linetod_begin_dtrace()
445 {
446     cat <<EOF
447 provider qemu {
448 EOF
449 }
450
451 linetod_dtrace()
452 {
453     local name args
454     name=$(get_name "$1")
455     args=$(get_args "$1")
456
457     # DTrace provider syntax expects foo() for empty
458     # params, not foo(void)
459     if [ "$args" = "void" ]; then
460        args=""
461     fi
462
463     # Define prototype for probe arguments
464     cat <<EOF
465         probe $name($args);
466 EOF
467 }
468
469 linetod_end_dtrace()
470 {
471     cat <<EOF
472 };
473 EOF
474 }
475
476 linetostap_begin_dtrace()
477 {
478     return
479 }
480
481 linetostap_dtrace()
482 {
483     local i arg name args arglist
484     name=$(get_name "$1")
485     args=$(get_args "$1")
486     arglist=$(get_argnames "$1", "")
487
488     # Define prototype for probe arguments
489     cat <<EOF
490 probe $probeprefix.$name = process("$binary").mark("$name")
491 {
492 EOF
493
494     i=1
495     for arg in $arglist
496     do
497         # 'limit' is a reserved keyword
498         if [ "$arg" = "limit" ]; then
499           arg="_limit"
500         fi
501         cat <<EOF
502   $arg = \$arg$i;
503 EOF
504         i="$((i+1))"
505     done
506
507     cat <<EOF
508 }
509 EOF
510 }
511
512 linetostap_end_dtrace()
513 {
514     return
515 }
516
517 # Process stdin by calling begin, line, and end functions for the backend
518 convert()
519 {
520     local begin process_line end str name NAME enabled
521     begin="lineto$1_begin_$backend"
522     process_line="lineto$1_$backend"
523     end="lineto$1_end_$backend"
524
525     "$begin"
526
527     while read -r str; do
528         # Skip comments and empty lines
529         test -z "${str%%#*}" && continue
530
531         echo
532         # Process the line.  The nop backend handles disabled lines.
533         if has_property "$str" "disable"; then
534             "lineto$1_nop" "$str"
535             enabled=0
536         else
537             "$process_line" "$str"
538             enabled=1
539         fi
540         if [ "$1" = "h" ]; then
541             name=$(get_name "$str")
542             NAME=$(echo $name | tr '[:lower:]' '[:upper:]')
543             echo "#define TRACE_${NAME}_ENABLED ${enabled}"
544         fi
545     done
546
547     echo
548     "$end"
549 }
550
551 tracetoh()
552 {
553     cat <<EOF
554 #ifndef TRACE_H
555 #define TRACE_H
556
557 /* This file is autogenerated by tracetool, do not edit. */
558
559 #include "qemu-common.h"
560 EOF
561     convert h
562     echo "#endif /* TRACE_H */"
563 }
564
565 tracetoc()
566 {
567     echo "/* This file is autogenerated by tracetool, do not edit. */"
568     convert c
569 }
570
571 tracetod()
572 {
573     if [ $backend != "dtrace" ]; then
574        echo "DTrace probe generator not applicable to $backend backend"
575        exit 1
576     fi
577     echo "/* This file is autogenerated by tracetool, do not edit. */"
578     convert d
579 }
580
581 tracetostap()
582 {
583     if [ $backend != "dtrace" ]; then
584        echo "SystemTAP tapset generator not applicable to $backend backend"
585        exit 1
586     fi
587     if [ -z "$binary" ]; then
588        echo "--binary is required for SystemTAP tapset generator"
589        exit 1
590     fi
591     if [ -z "$probeprefix" -a -z "$targettype" ]; then
592        echo "--target-type is required for SystemTAP tapset generator"
593        exit 1
594     fi
595     if [ -z "$probeprefix" -a -z "$targetarch" ]; then
596        echo "--target-arch is required for SystemTAP tapset generator"
597        exit 1
598     fi
599     if [ -z "$probeprefix" ]; then
600         probeprefix="qemu.$targettype.$targetarch";
601     fi
602     echo "/* This file is autogenerated by tracetool, do not edit. */"
603     convert stap
604 }
605
606
607 backend=
608 output=
609 binary=
610 targettype=
611 targetarch=
612 probeprefix=
613
614
615 until [ -z "$1" ]
616 do
617   case "$1" in
618     "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
619
620     "--binary") shift ; binary="$1" ;;
621     "--target-arch") shift ; targetarch="$1" ;;
622     "--target-type") shift ; targettype="$1" ;;
623     "--probe-prefix") shift ; probeprefix="$1" ;;
624
625     "-h" | "-c" | "-d") output="${1#-}" ;;
626     "--stap") output="${1#--}" ;;
627
628     "--check-backend") exit 0 ;; # used by ./configure to test for backend
629
630     "--list-backends") # used by ./configure to list available backends
631           echo "nop simple stderr ust dtrace"
632           exit 0
633           ;;
634
635     *)
636       usage;;
637   esac
638   shift
639 done
640
641 if [ "$backend" = "" -o "$output" = "" ]; then
642   usage
643 fi
644
645 gen="traceto$output"
646 "$gen"
647
648 exit 0
This page took 0.059754 seconds and 4 git commands to generate.