Statistics
| Branch: | Revision:

root / scripts / tracetool @ a4c075f1

History | View | Annotate | Download (10.9 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
# 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#*\(}
54
    args=${args%%\)*}
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", ",")
341
    [ -z "$argnames" ] || argnames=", $argnames"
342
    fmt=$(get_fmt "$1")
343

    
344
    cat <<EOF
345
DEFINE_TRACE(ust_$name);
346

    
347
static void ust_${name}_probe($args)
348
{
349
    trace_mark(ust, $name, "$fmt"$argnames);
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
478
probe $probeprefix.$name = process("$binary").mark("$name")
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
492
        i="$((i+1))"
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
580
    if [ -z "$probeprefix" -a -z "$targettype" ]; then
581
       echo "--target-type is required for SystemTAP tapset generator"
582
       exit 1
583
    fi
584
    if [ -z "$probeprefix" -a -z "$targetarch" ]; then
585
       echo "--target-arch is required for SystemTAP tapset generator"
586
       exit 1
587
    fi
588
    if [ -z "$probeprefix" ]; then
589
        probeprefix="qemu.$targettype.$targetarch";
590
    fi
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=
601
probeprefix=
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" ;;
612
    "--probe-prefix") shift ; probeprefix="$1" ;;
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