Statistics
| Branch: | Revision:

root / tracetool @ 4addb112

History | View | Annotate | Download (7.7 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 | --ust] [-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
  --ust     LTTng User Space Tracing backend
23
  --dtrace  DTrace/SystemTAP backend
24

    
25
Output formats:
26
  -h    Generate .h file
27
  -c    Generate .c file
28
  -d    Generate .d file (DTrace only)
29
EOF
30
    exit 1
31
}
32

    
33
# Get the name of a trace event
34
get_name()
35
{
36
    echo ${1%%\(*}
37
}
38

    
39
# Get the argument list of a trace event, including types and names
40
get_args()
41
{
42
    local args
43
    args=${1#*\(}
44
    args=${args%\)*}
45
    echo "$args"
46
}
47

    
48
# Get the argument name list of a trace event
49
get_argnames()
50
{
51
    local nfields field name sep
52
    nfields=0
53
    sep="$2"
54
    for field in $(get_args "$1"); do
55
        nfields=$((nfields + 1))
56

    
57
        # Drop pointer star
58
        field=${field#\*}
59

    
60
        # Only argument names have commas at the end
61
        name=${field%,}
62
        test "$field" = "$name" && continue
63

    
64
        printf "%s%s " $name $sep
65
    done
66

    
67
    # Last argument name
68
    if [ "$nfields" -gt 1 ]
69
    then
70
        printf "%s" "$name"
71
    fi
72
}
73

    
74
# Get the number of arguments to a trace event
75
get_argc()
76
{
77
    local name argc
78
    argc=0
79
    for name in $(get_argnames "$1", ","); do
80
        argc=$((argc + 1))
81
    done
82
    echo $argc
83
}
84

    
85
# Get the format string for a trace event
86
get_fmt()
87
{
88
    local fmt
89
    fmt=${1#*\"}
90
    fmt=${fmt%\"*}
91
    echo "$fmt"
92
}
93

    
94
# Get the state of a trace event
95
get_state()
96
{
97
    local str disable state
98
    str=$(get_name "$1")
99
    disable=${str##disable }
100
    if [ "$disable" = "$str" ] ; then
101
        state=1
102
    else
103
        state=0
104
    fi
105
    echo "$state"
106
}
107

    
108
linetoh_begin_nop()
109
{
110
    return
111
}
112

    
113
linetoh_nop()
114
{
115
    local name args
116
    name=$(get_name "$1")
117
    args=$(get_args "$1")
118

    
119
    # Define an empty function for the trace event
120
    cat <<EOF
121
static inline void trace_$name($args)
122
{
123
}
124
EOF
125
}
126

    
127
linetoh_end_nop()
128
{
129
    return
130
}
131

    
132
linetoc_begin_nop()
133
{
134
    return
135
}
136

    
137
linetoc_nop()
138
{
139
    # No need for function definitions in nop backend
140
    return
141
}
142

    
143
linetoc_end_nop()
144
{
145
    return
146
}
147

    
148
linetoh_begin_simple()
149
{
150
    cat <<EOF
151
#include "simpletrace.h"
152
EOF
153

    
154
    simple_event_num=0
155
}
156

    
157
cast_args_to_uint64_t()
158
{
159
    local arg
160
    for arg in $(get_argnames "$1", ","); do
161
        printf "%s" "(uint64_t)(uintptr_t)$arg"
162
    done
163
}
164

    
165
linetoh_simple()
166
{
167
    local name args argc trace_args state
168
    name=$(get_name "$1")
169
    args=$(get_args "$1")
170
    argc=$(get_argc "$1")
171
    state=$(get_state "$1")
172
    if [ "$state" = "0" ]; then
173
        name=${name##disable }
174
    fi
175

    
176
    trace_args="$simple_event_num"
177
    if [ "$argc" -gt 0 ]
178
    then
179
        trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
180
    fi
181

    
182
    cat <<EOF
183
static inline void trace_$name($args)
184
{
185
    trace$argc($trace_args);
186
}
187
EOF
188

    
189
    simple_event_num=$((simple_event_num + 1))
190
}
191

    
192
linetoh_end_simple()
193
{
194
    cat <<EOF
195
#define NR_TRACE_EVENTS $simple_event_num
196
extern TraceEvent trace_list[NR_TRACE_EVENTS];
197
EOF
198
}
199

    
200
linetoc_begin_simple()
201
{
202
    cat <<EOF
203
#include "trace.h"
204

    
205
TraceEvent trace_list[] = {
206
EOF
207
    simple_event_num=0
208

    
209
}
210

    
211
linetoc_simple()
212
{
213
    local name state
214
    name=$(get_name "$1")
215
    state=$(get_state "$1")
216
    if [ "$state" = "0" ] ; then
217
        name=${name##disable }
218
    fi
219
    cat <<EOF
220
{.tp_name = "$name", .state=$state},
221
EOF
222
    simple_event_num=$((simple_event_num + 1))
223
}
224

    
225
linetoc_end_simple()
226
{
227
    cat <<EOF
228
};
229
EOF
230
}
231

    
232
# Clean up after UST headers which pollute the namespace
233
ust_clean_namespace() {
234
    cat <<EOF
235
#undef mutex_lock
236
#undef mutex_unlock
237
#undef inline
238
#undef wmb
239
EOF
240
}
241

    
242
linetoh_begin_ust()
243
{
244
    echo "#include <ust/tracepoint.h>"
245
    ust_clean_namespace
246
}
247

    
248
linetoh_ust()
249
{
250
    local name args argnames
251
    name=$(get_name "$1")
252
    args=$(get_args "$1")
253
    argnames=$(get_argnames "$1", ",")
254

    
255
    cat <<EOF
256
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
257
#define trace_$name trace_ust_$name
258
EOF
259
}
260

    
261
linetoh_end_ust()
262
{
263
    return
264
}
265

    
266
linetoc_begin_ust()
267
{
268
    cat <<EOF
269
#include <ust/marker.h>
270
$(ust_clean_namespace)
271
#include "trace.h"
272
EOF
273
}
274

    
275
linetoc_ust()
276
{
277
    local name args argnames fmt
278
    name=$(get_name "$1")
279
    args=$(get_args "$1")
280
    argnames=$(get_argnames "$1", ",")
281
    fmt=$(get_fmt "$1")
282

    
283
    cat <<EOF
284
DEFINE_TRACE(ust_$name);
285

    
286
static void ust_${name}_probe($args)
287
{
288
    trace_mark(ust, $name, "$fmt", $argnames);
289
}
290
EOF
291

    
292
    # Collect names for later
293
    names="$names $name"
294
}
295

    
296
linetoc_end_ust()
297
{
298
    cat <<EOF
299
static void __attribute__((constructor)) trace_init(void)
300
{
301
EOF
302

    
303
    for name in $names; do
304
        cat <<EOF
305
    register_trace_ust_$name(ust_${name}_probe);
306
EOF
307
    done
308

    
309
    echo "}"
310
}
311

    
312
linetoh_begin_dtrace()
313
{
314
    cat <<EOF
315
#include "trace-dtrace.h"
316
EOF
317
}
318

    
319
linetoh_dtrace()
320
{
321
    local name args argnames state nameupper
322
    name=$(get_name "$1")
323
    args=$(get_args "$1")
324
    argnames=$(get_argnames "$1", ",")
325
    state=$(get_state "$1")
326
    if [ "$state" = "0" ] ; then
327
        name=${name##disable }
328
    fi
329

    
330
    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
331

    
332
    # Define an empty function for the trace event
333
    cat <<EOF
334
static inline void trace_$name($args) {
335
    if (QEMU_${nameupper}_ENABLED()) {
336
        QEMU_${nameupper}($argnames);
337
    }
338
}
339
EOF
340
}
341

    
342
linetoh_end_dtrace()
343
{
344
    return
345
}
346

    
347
linetoc_begin_dtrace()
348
{
349
    return
350
}
351

    
352
linetoc_dtrace()
353
{
354
    # No need for function definitions in dtrace backend
355
    return
356
}
357

    
358
linetoc_end_dtrace()
359
{
360
    return
361
}
362

    
363
linetod_begin_dtrace()
364
{
365
    cat <<EOF
366
provider qemu {
367
EOF
368
}
369

    
370
linetod_dtrace()
371
{
372
    local name args state
373
    name=$(get_name "$1")
374
    args=$(get_args "$1")
375
    state=$(get_state "$1")
376
    if [ "$state" = "0" ] ; then
377
        name=${name##disable }
378
    fi
379

    
380
    # Define prototype for probe arguments
381
    cat <<EOF
382
        probe $name($args);
383
EOF
384
}
385

    
386
linetod_end_dtrace()
387
{
388
    cat <<EOF
389
};
390
EOF
391
}
392

    
393
# Process stdin by calling begin, line, and end functions for the backend
394
convert()
395
{
396
    local begin process_line end str disable
397
    begin="lineto$1_begin_$backend"
398
    process_line="lineto$1_$backend"
399
    end="lineto$1_end_$backend"
400

    
401
    "$begin"
402

    
403
    while read -r str; do
404
        # Skip comments and empty lines
405
        test -z "${str%%#*}" && continue
406

    
407
        # Process the line.  The nop backend handles disabled lines.
408
        disable=${str%%disable *}
409
        echo
410
        if test -z "$disable"; then
411
            # Pass the disabled state as an arg for the simple
412
            # or DTrace backends which handle it dynamically.
413
            # For all other backends, call lineto$1_nop()
414
            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
415
                "$process_line" "$str"
416
            else
417
                "lineto$1_nop" "${str##disable }"
418
            fi
419
        else
420
            "$process_line" "$str"
421
        fi
422
    done
423

    
424
    echo
425
    "$end"
426
}
427

    
428
tracetoh()
429
{
430
    cat <<EOF
431
#ifndef TRACE_H
432
#define TRACE_H
433

    
434
/* This file is autogenerated by tracetool, do not edit. */
435

    
436
#include "qemu-common.h"
437
EOF
438
    convert h
439
    echo "#endif /* TRACE_H */"
440
}
441

    
442
tracetoc()
443
{
444
    echo "/* This file is autogenerated by tracetool, do not edit. */"
445
    convert c
446
}
447

    
448
tracetod()
449
{
450
    if [ $backend != "dtrace" ]; then
451
       echo "DTrace probe generator not applicable to $backend backend"
452
       exit 1
453
    fi
454
    echo "/* This file is autogenerated by tracetool, do not edit. */"
455
    convert d
456
}
457

    
458
# Choose backend
459
case "$1" in
460
"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
461
*) usage ;;
462
esac
463
shift
464

    
465
case "$1" in
466
"-h") tracetoh ;;
467
"-c") tracetoc ;;
468
"-d") tracetod ;;
469
"--check-backend") exit 0 ;; # used by ./configure to test for backend
470
*) usage ;;
471
esac
472

    
473
exit 0