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