Statistics
| Branch: | Revision:

root / scripts / tracetool @ 8d3bc517

History | View | Annotate | Download (10.8 kB)

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
# Print a line without interpreting backslash escapes
44
#
45
# The built-in echo command may interpret backslash escapes without an option
46
# to disable this behavior.
47
puts()
48
{
49
    printf "%s\n" "$1"
50
}
51

    
52
# Get the name of a trace event
53
get_name()
54
{
55
    local name
56
    name=${1%%\(*}
57
    echo "${name##* }"
58
}
59

    
60
# Get the given property of a trace event
61
# 1: trace-events line
62
# 2: property name
63
# -> return 0 if property is present, or 1 otherwise
64
has_property()
65
{
66
    local props prop
67
    props=${1%%\(*}
68
    props=${props% *}
69
    for prop in $props; do
70
        if [ "$prop" = "$2" ]; then
71
            return 0
72
        fi
73
    done
74
    return 1
75
}
76

    
77
# Get the argument list of a trace event, including types and names
78
get_args()
79
{
80
    local args
81
    args=${1#*\(}
82
    args=${args%%\)*}
83
    echo "$args"
84
}
85

    
86
# Get the argument name list of a trace event
87
get_argnames()
88
{
89
    local nfields field name sep
90
    nfields=0
91
    sep="$2"
92
    for field in $(get_args "$1"); do
93
        nfields=$((nfields + 1))
94

    
95
        # Drop pointer star
96
        field=${field#\*}
97

    
98
        # Only argument names have commas at the end
99
        name=${field%,}
100
        test "$field" = "$name" && continue
101

    
102
        printf "%s%s " $name $sep
103
    done
104

    
105
    # Last argument name
106
    if [ "$nfields" -gt 1 ]
107
    then
108
        printf "%s" "$name"
109
    fi
110
}
111

    
112
# Get the number of arguments to a trace event
113
get_argc()
114
{
115
    local name argc
116
    argc=0
117
    for name in $(get_argnames "$1", ","); do
118
        argc=$((argc + 1))
119
    done
120
    echo $argc
121
}
122

    
123
# Get the format string including double quotes for a trace event
124
get_fmt()
125
{
126
    puts "${1#*)}"
127
}
128

    
129
linetoh_begin_nop()
130
{
131
    return
132
}
133

    
134
linetoh_nop()
135
{
136
    local name args
137
    name=$(get_name "$1")
138
    args=$(get_args "$1")
139

    
140
    # Define an empty function for the trace event
141
    cat <<EOF
142
static inline void trace_$name($args)
143
{
144
}
145
EOF
146
}
147

    
148
linetoh_end_nop()
149
{
150
    return
151
}
152

    
153
linetoc_begin_nop()
154
{
155
    return
156
}
157

    
158
linetoc_nop()
159
{
160
    # No need for function definitions in nop backend
161
    return
162
}
163

    
164
linetoc_end_nop()
165
{
166
    return
167
}
168

    
169
linetoh_begin_simple()
170
{
171
    cat <<EOF
172
#include "trace/simple.h"
173
EOF
174

    
175
    simple_event_num=0
176
}
177

    
178
cast_args_to_uint64_t()
179
{
180
    local arg
181
    for arg in $(get_argnames "$1", ","); do
182
        printf "%s" "(uint64_t)(uintptr_t)$arg"
183
    done
184
}
185

    
186
linetoh_simple()
187
{
188
    local name args argc trace_args
189
    name=$(get_name "$1")
190
    args=$(get_args "$1")
191
    argc=$(get_argc "$1")
192

    
193
    trace_args="$simple_event_num"
194
    if [ "$argc" -gt 0 ]
195
    then
196
        trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
197
    fi
198

    
199
    cat <<EOF
200
static inline void trace_$name($args)
201
{
202
    trace$argc($trace_args);
203
}
204
EOF
205

    
206
    simple_event_num=$((simple_event_num + 1))
207
}
208

    
209
linetoh_end_simple()
210
{
211
    cat <<EOF
212
#define NR_TRACE_EVENTS $simple_event_num
213
extern TraceEvent trace_list[NR_TRACE_EVENTS];
214
EOF
215
}
216

    
217
linetoc_begin_simple()
218
{
219
    cat <<EOF
220
#include "trace.h"
221

    
222
TraceEvent trace_list[] = {
223
EOF
224
    simple_event_num=0
225

    
226
}
227

    
228
linetoc_simple()
229
{
230
    local name
231
    name=$(get_name "$1")
232
    cat <<EOF
233
{.tp_name = "$name", .state=0},
234
EOF
235
    simple_event_num=$((simple_event_num + 1))
236
}
237

    
238
linetoc_end_simple()
239
{
240
    cat <<EOF
241
};
242
EOF
243
}
244

    
245
#STDERR
246
linetoh_begin_stderr()
247
{
248
    cat <<EOF
249
#include <stdio.h>
250
#include "trace/stderr.h"
251

    
252
extern TraceEvent trace_list[];
253
EOF
254

    
255
    stderr_event_num=0
256
}
257

    
258
linetoh_stderr()
259
{
260
    local name args argnames argc fmt
261
    name=$(get_name "$1")
262
    args=$(get_args "$1")
263
    argnames=$(get_argnames "$1" ",")
264
    argc=$(get_argc "$1")
265
    fmt=$(get_fmt "$1")
266

    
267
    if [ "$argc" -gt 0 ]; then
268
        argnames=", $argnames"
269
    fi
270

    
271
    cat <<EOF
272
static inline void trace_$name($args)
273
{
274
    if (trace_list[$stderr_event_num].state != 0) {
275
        fprintf(stderr, "$name " $fmt "\n" $argnames);
276
    }
277
}
278
EOF
279
    stderr_event_num=$((stderr_event_num + 1))
280

    
281
}
282

    
283
linetoh_end_stderr()
284
{
285
    cat <<EOF
286
#define NR_TRACE_EVENTS $stderr_event_num
287
EOF
288
}
289

    
290
linetoc_begin_stderr()
291
{
292
    cat <<EOF
293
#include "trace.h"
294

    
295
TraceEvent trace_list[] = {
296
EOF
297
    stderr_event_num=0
298
}
299

    
300
linetoc_stderr()
301
{
302
    local name
303
    name=$(get_name "$1")
304
    cat <<EOF
305
{.tp_name = "$name", .state=0},
306
EOF
307
    stderr_event_num=$(($stderr_event_num + 1))
308
}
309

    
310
linetoc_end_stderr()
311
{
312
    cat <<EOF
313
};
314
EOF
315
}
316
#END OF STDERR
317

    
318
# Clean up after UST headers which pollute the namespace
319
ust_clean_namespace() {
320
    cat <<EOF
321
#undef mutex_lock
322
#undef mutex_unlock
323
#undef inline
324
#undef wmb
325
EOF
326
}
327

    
328
linetoh_begin_ust()
329
{
330
    echo "#include <ust/tracepoint.h>"
331
    ust_clean_namespace
332
}
333

    
334
linetoh_ust()
335
{
336
    local name args argnames
337
    name=$(get_name "$1")
338
    args=$(get_args "$1")
339
    argnames=$(get_argnames "$1", ",")
340

    
341
    cat <<EOF
342
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
343
#define trace_$name trace_ust_$name
344
EOF
345
}
346

    
347
linetoh_end_ust()
348
{
349
    return
350
}
351

    
352
linetoc_begin_ust()
353
{
354
    cat <<EOF
355
#include <ust/marker.h>
356
$(ust_clean_namespace)
357
#include "trace.h"
358
EOF
359
}
360

    
361
linetoc_ust()
362
{
363
    local name args argnames fmt
364
    name=$(get_name "$1")
365
    args=$(get_args "$1")
366
    argnames=$(get_argnames "$1", ",")
367
    [ -z "$argnames" ] || argnames=", $argnames"
368
    fmt=$(get_fmt "$1")
369

    
370
    cat <<EOF
371
DEFINE_TRACE(ust_$name);
372

    
373
static void ust_${name}_probe($args)
374
{
375
    trace_mark(ust, $name, $fmt$argnames);
376
}
377
EOF
378

    
379
    # Collect names for later
380
    names="$names $name"
381
}
382

    
383
linetoc_end_ust()
384
{
385
    cat <<EOF
386
static void __attribute__((constructor)) trace_init(void)
387
{
388
EOF
389

    
390
    for name in $names; do
391
        cat <<EOF
392
    register_trace_ust_$name(ust_${name}_probe);
393
EOF
394
    done
395

    
396
    echo "}"
397
}
398

    
399
linetoh_begin_dtrace()
400
{
401
    cat <<EOF
402
#include "trace-dtrace.h"
403
EOF
404
}
405

    
406
linetoh_dtrace()
407
{
408
    local name args argnames nameupper
409
    name=$(get_name "$1")
410
    args=$(get_args "$1")
411
    argnames=$(get_argnames "$1", ",")
412

    
413
    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
414

    
415
    # Define an empty function for the trace event
416
    cat <<EOF
417
static inline void trace_$name($args) {
418
    if (QEMU_${nameupper}_ENABLED()) {
419
        QEMU_${nameupper}($argnames);
420
    }
421
}
422
EOF
423
}
424

    
425
linetoh_end_dtrace()
426
{
427
    return
428
}
429

    
430
linetoc_begin_dtrace()
431
{
432
    return
433
}
434

    
435
linetoc_dtrace()
436
{
437
    # No need for function definitions in dtrace backend
438
    return
439
}
440

    
441
linetoc_end_dtrace()
442
{
443
    return
444
}
445

    
446
linetod_begin_dtrace()
447
{
448
    cat <<EOF
449
provider qemu {
450
EOF
451
}
452

    
453
linetod_dtrace()
454
{
455
    local name args
456
    name=$(get_name "$1")
457
    args=$(get_args "$1")
458

    
459
    # DTrace provider syntax expects foo() for empty
460
    # params, not foo(void)
461
    if [ "$args" = "void" ]; then
462
       args=""
463
    fi
464

    
465
    # Define prototype for probe arguments
466
    cat <<EOF
467
        probe $name($args);
468
EOF
469
}
470

    
471
linetod_end_dtrace()
472
{
473
    cat <<EOF
474
};
475
EOF
476
}
477

    
478
linetostap_begin_dtrace()
479
{
480
    return
481
}
482

    
483
linetostap_dtrace()
484
{
485
    local i arg name args arglist
486
    name=$(get_name "$1")
487
    args=$(get_args "$1")
488
    arglist=$(get_argnames "$1", "")
489

    
490
    # Define prototype for probe arguments
491
    cat <<EOF
492
probe $probeprefix.$name = process("$binary").mark("$name")
493
{
494
EOF
495

    
496
    i=1
497
    for arg in $arglist
498
    do
499
        # 'limit' is a reserved keyword
500
        if [ "$arg" = "limit" ]; then
501
          arg="_limit"
502
        fi
503
        cat <<EOF
504
  $arg = \$arg$i;
505
EOF
506
        i="$((i+1))"
507
    done
508

    
509
    cat <<EOF
510
}
511
EOF
512
}
513

    
514
linetostap_end_dtrace()
515
{
516
    return
517
}
518

    
519
# Process stdin by calling begin, line, and end functions for the backend
520
convert()
521
{
522
    local begin process_line end str disable
523
    begin="lineto$1_begin_$backend"
524
    process_line="lineto$1_$backend"
525
    end="lineto$1_end_$backend"
526

    
527
    "$begin"
528

    
529
    while read -r str; do
530
        # Skip comments and empty lines
531
        test -z "${str%%#*}" && continue
532

    
533
        echo
534
        # Process the line.  The nop backend handles disabled lines.
535
        if has_property "$str" "disable"; then
536
            "lineto$1_nop" "$str"
537
        else
538
            "$process_line" "$str"
539
        fi
540
    done
541

    
542
    echo
543
    "$end"
544
}
545

    
546
tracetoh()
547
{
548
    cat <<EOF
549
#ifndef TRACE_H
550
#define TRACE_H
551

    
552
/* This file is autogenerated by tracetool, do not edit. */
553

    
554
#include "qemu-common.h"
555
EOF
556
    convert h
557
    echo "#endif /* TRACE_H */"
558
}
559

    
560
tracetoc()
561
{
562
    echo "/* This file is autogenerated by tracetool, do not edit. */"
563
    convert c
564
}
565

    
566
tracetod()
567
{
568
    if [ $backend != "dtrace" ]; then
569
       echo "DTrace probe generator not applicable to $backend backend"
570
       exit 1
571
    fi
572
    echo "/* This file is autogenerated by tracetool, do not edit. */"
573
    convert d
574
}
575

    
576
tracetostap()
577
{
578
    if [ $backend != "dtrace" ]; then
579
       echo "SystemTAP tapset generator not applicable to $backend backend"
580
       exit 1
581
    fi
582
    if [ -z "$binary" ]; then
583
       echo "--binary is required for SystemTAP tapset generator"
584
       exit 1
585
    fi
586
    if [ -z "$probeprefix" -a -z "$targettype" ]; then
587
       echo "--target-type is required for SystemTAP tapset generator"
588
       exit 1
589
    fi
590
    if [ -z "$probeprefix" -a -z "$targetarch" ]; then
591
       echo "--target-arch is required for SystemTAP tapset generator"
592
       exit 1
593
    fi
594
    if [ -z "$probeprefix" ]; then
595
        probeprefix="qemu.$targettype.$targetarch";
596
    fi
597
    echo "/* This file is autogenerated by tracetool, do not edit. */"
598
    convert stap
599
}
600

    
601

    
602
backend=
603
output=
604
binary=
605
targettype=
606
targetarch=
607
probeprefix=
608

    
609

    
610
until [ -z "$1" ]
611
do
612
  case "$1" in
613
    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
614

    
615
    "--binary") shift ; binary="$1" ;;
616
    "--target-arch") shift ; targetarch="$1" ;;
617
    "--target-type") shift ; targettype="$1" ;;
618
    "--probe-prefix") shift ; probeprefix="$1" ;;
619

    
620
    "-h" | "-c" | "-d") output="${1#-}" ;;
621
    "--stap") output="${1#--}" ;;
622

    
623
    "--check-backend") exit 0 ;; # used by ./configure to test for backend
624

    
625
    "--list-backends") # used by ./configure to list available backends
626
          echo "nop simple stderr ust dtrace"
627
          exit 0
628
          ;;
629

    
630
    *)
631
      usage;;
632
  esac
633
  shift
634
done
635

    
636
if [ "$backend" = "" -o "$output" = "" ]; then
637
  usage
638
fi
639

    
640
gen="traceto$output"
641
"$gen"
642

    
643
exit 0