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