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