Statistics
| Branch: | Revision:

root / scripts / tracetool @ e323c93e

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
# 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
    fmt=$(get_fmt "$1")
342

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

    
346
static void ust_${name}_probe($args)
347
{
348
    trace_mark(ust, $name, "$fmt", $argnames);
349
}
350
EOF
351

    
352
    # Collect names for later
353
    names="$names $name"
354
}
355

    
356
linetoc_end_ust()
357
{
358
    cat <<EOF
359
static void __attribute__((constructor)) trace_init(void)
360
{
361
EOF
362

    
363
    for name in $names; do
364
        cat <<EOF
365
    register_trace_ust_$name(ust_${name}_probe);
366
EOF
367
    done
368

    
369
    echo "}"
370
}
371

    
372
linetoh_begin_dtrace()
373
{
374
    cat <<EOF
375
#include "trace-dtrace.h"
376
EOF
377
}
378

    
379
linetoh_dtrace()
380
{
381
    local name args argnames state nameupper
382
    name=$(get_name "$1")
383
    args=$(get_args "$1")
384
    argnames=$(get_argnames "$1", ",")
385
    state=$(get_state "$1")
386
    if [ "$state" = "0" ] ; then
387
        name=${name##disable }
388
    fi
389

    
390
    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
391

    
392
    # Define an empty function for the trace event
393
    cat <<EOF
394
static inline void trace_$name($args) {
395
    if (QEMU_${nameupper}_ENABLED()) {
396
        QEMU_${nameupper}($argnames);
397
    }
398
}
399
EOF
400
}
401

    
402
linetoh_end_dtrace()
403
{
404
    return
405
}
406

    
407
linetoc_begin_dtrace()
408
{
409
    return
410
}
411

    
412
linetoc_dtrace()
413
{
414
    # No need for function definitions in dtrace backend
415
    return
416
}
417

    
418
linetoc_end_dtrace()
419
{
420
    return
421
}
422

    
423
linetod_begin_dtrace()
424
{
425
    cat <<EOF
426
provider qemu {
427
EOF
428
}
429

    
430
linetod_dtrace()
431
{
432
    local name args state
433
    name=$(get_name "$1")
434
    args=$(get_args "$1")
435
    state=$(get_state "$1")
436
    if [ "$state" = "0" ] ; then
437
        name=${name##disable }
438
    fi
439

    
440
    # DTrace provider syntax expects foo() for empty
441
    # params, not foo(void)
442
    if [ "$args" = "void" ]; then
443
       args=""
444
    fi
445

    
446
    # Define prototype for probe arguments
447
    cat <<EOF
448
        probe $name($args);
449
EOF
450
}
451

    
452
linetod_end_dtrace()
453
{
454
    cat <<EOF
455
};
456
EOF
457
}
458

    
459
linetostap_begin_dtrace()
460
{
461
    return
462
}
463

    
464
linetostap_dtrace()
465
{
466
    local i arg name args arglist state
467
    name=$(get_name "$1")
468
    args=$(get_args "$1")
469
    arglist=$(get_argnames "$1", "")
470
    state=$(get_state "$1")
471
    if [ "$state" = "0" ] ; then
472
        name=${name##disable }
473
    fi
474

    
475
    # Define prototype for probe arguments
476
    cat <<EOF
477
probe $probeprefix.$name = process("$binary").mark("$name")
478
{
479
EOF
480

    
481
    i=1
482
    for arg in $arglist
483
    do
484
        # 'limit' is a reserved keyword
485
        if [ "$arg" = "limit" ]; then
486
          arg="_limit"
487
        fi
488
        cat <<EOF
489
  $arg = \$arg$i;
490
EOF
491
	i="$((i+1))"
492
    done
493

    
494
    cat <<EOF
495
}
496
EOF
497
}
498

    
499
linetostap_end_dtrace()
500
{
501
    return
502
}
503

    
504
# Process stdin by calling begin, line, and end functions for the backend
505
convert()
506
{
507
    local begin process_line end str disable
508
    begin="lineto$1_begin_$backend"
509
    process_line="lineto$1_$backend"
510
    end="lineto$1_end_$backend"
511

    
512
    "$begin"
513

    
514
    while read -r str; do
515
        # Skip comments and empty lines
516
        test -z "${str%%#*}" && continue
517

    
518
        # Process the line.  The nop backend handles disabled lines.
519
        disable=${str%%disable *}
520
        echo
521
        if test -z "$disable"; then
522
            # Pass the disabled state as an arg for the simple
523
            # or DTrace backends which handle it dynamically.
524
            # For all other backends, call lineto$1_nop()
525
            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
526
                "$process_line" "$str"
527
            else
528
                "lineto$1_nop" "${str##disable }"
529
            fi
530
        else
531
            "$process_line" "$str"
532
        fi
533
    done
534

    
535
    echo
536
    "$end"
537
}
538

    
539
tracetoh()
540
{
541
    cat <<EOF
542
#ifndef TRACE_H
543
#define TRACE_H
544

    
545
/* This file is autogenerated by tracetool, do not edit. */
546

    
547
#include "qemu-common.h"
548
EOF
549
    convert h
550
    echo "#endif /* TRACE_H */"
551
}
552

    
553
tracetoc()
554
{
555
    echo "/* This file is autogenerated by tracetool, do not edit. */"
556
    convert c
557
}
558

    
559
tracetod()
560
{
561
    if [ $backend != "dtrace" ]; then
562
       echo "DTrace probe generator not applicable to $backend backend"
563
       exit 1
564
    fi
565
    echo "/* This file is autogenerated by tracetool, do not edit. */"
566
    convert d
567
}
568

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

    
594

    
595
backend=
596
output=
597
binary=
598
targettype=
599
targetarch=
600
probeprefix=
601

    
602

    
603
until [ -z "$1" ]
604
do
605
  case "$1" in
606
    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
607

    
608
    "--binary") shift ; binary="$1" ;;
609
    "--target-arch") shift ; targetarch="$1" ;;
610
    "--target-type") shift ; targettype="$1" ;;
611
    "--probe-prefix") shift ; probeprefix="$1" ;;
612

    
613
    "-h" | "-c" | "-d") output="${1#-}" ;;
614
    "--stap") output="${1#--}" ;;
615

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

    
618
    "--list-backends") # used by ./configure to list available backends
619
          echo "nop simple stderr ust dtrace"
620
          exit 0
621
          ;;
622

    
623
    *)
624
      usage;;
625
  esac
626
  shift
627
done
628

    
629
if [ "$backend" = "" -o "$output" = "" ]; then
630
  usage
631
fi
632

    
633
gen="traceto$output"
634
"$gen"
635

    
636
exit 0