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