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