diff mbox

[RFC,v3,1/3] Converting tracetool.sh to tracetool.py

Message ID 1326193179-19677-2-git-send-email-harsh@linux.vnet.ibm.com
State New
Headers show

Commit Message

Harsh Prateek Bora Jan. 10, 2012, 10:59 a.m. UTC
Signed-off-by: Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
---
 Makefile.objs        |    6 +-
 Makefile.target      |   10 +-
 configure            |    7 +-
 scripts/tracetool    |  643 --------------------------------------------------
 scripts/tracetool.py |  585 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 597 insertions(+), 654 deletions(-)
 delete mode 100755 scripts/tracetool
 create mode 100755 scripts/tracetool.py

Comments

Stefan Hajnoczi Jan. 10, 2012, 2:50 p.m. UTC | #1
On Tue, Jan 10, 2012 at 10:59 AM, Harsh Prateek Bora
<harsh@linux.vnet.ibm.com> wrote:
> diff --git a/scripts/tracetool.py b/scripts/tracetool.py
> new file mode 100755
> index 0000000..6874f66
> --- /dev/null
> +++ b/scripts/tracetool.py
> @@ -0,0 +1,585 @@
> +#!/usr/bin/env python
> +# Python based tracetool script (Code generator for trace events)

Nitpick: please don't use comments or names that reflect the fact that
you're changing something.  Once this is merged readers might not even
know there was a non-Python tracetool script.  "Code generator for
trace events" explains what this script does.  "Python based tracetool
script" doesn't add any information because the content is clearly in
Python and the filename is tracetool.

A related point is please don't put simpletrace "v2" into the code
because if we ever do a v3 all those references would need to be
renamed, even if the value stays the same.  (For example
ST_V2_REC_HDR_LEN.)  When changing code make it look like it was
written like this from day 1 rather than leaving visible marks where
things were modified - git log already provides the code change
history.  It's distracting and sometimes misleading when code contains
references to outdated things which have been replaced.

> +#
> +# Copyright IBM, Corp. 2011
> +#
> +# This work is licensed under the terms of the GNU GPL, version 2.  See
> +# the COPYING file in the top-level directory.
> +#
> +#
> +
> +import sys
> +import getopt
> +
> +def usage():
> +    print "Tracetool: Generate tracing code for trace events file on stdin"
> +    print "Usage:"
> +    print sys.argv[0], " --backend=[nop|simple|stderr|dtrace|ust] [-h|-c|-d|--stap]"

print 'a', 'b' puts a space between "a" and "b".  "--backend=..."
would work fine, space is not needed.

> +def calc_sizeofargs(line):
> +    args = get_args(line)
> +    argc = get_argc(line)
> +    strtype = ('const char*', 'char*', 'const char *', 'char *')

This is repeated elsewhere, please share is_string().

> +def trace_h_begin():
> +    print '''#ifndef TRACE_H
> +#define TRACE_H
> +
> +/* This file is autogenerated by tracetool, do not edit. */
> +
> +#include "qemu-common.h"'''
> +    return

A function that has no explicit return statement implicitly returns
None.  Please remove returns to keep the code concise.

> +
> +def trace_h_end():
> +    print '#endif /* TRACE_H */'
> +    return
> +
> +def trace_c_begin():
> +    print '/* This file is autogenerated by tracetool, do not edit. */'
> +    return
> +
> +def trace_c_end():
> +    # nop, required for trace_gen
> +    return

def trace_c_end():
    pass # nop, required for trace_gen

> +def simple_c(events):
> +    rec_off = 0
> +    print '#include "trace.h"'
> +    print '#include "trace/simple.h"'
> +    print
> +    print 'TraceEvent trace_list[] = {'
> +    print
> +    eventlist = list(events)
> +    for event in eventlist:
> +        print '{.tp_name = "%(name)s", .state=0},' % {
> +    'name': event.name
> +}
> +        print
> +    print '};'
> +    print
> +    for event in eventlist:
> +        argc = event.argc
> +        print '''void trace_%(name)s(%(args)s)
> +{
> +    unsigned int tbuf_idx, rec_off;

  CC    trace.o
trace.c: In function ‘trace_slavio_misc_update_irq_raise’:
trace.c:3411:28: warning: variable ‘rec_off’ set but not used
[-Wunused-but-set-variable]

> +    uint64_t var64 __attribute__ ((unused));
> +    uint64_t pvar64 __attribute__ ((unused));
> +    uint32_t slen __attribute__ ((unused));
> +
> +    if (!trace_list[%(event_id)s].state) {
> +        return;
> +    }
> +''' % {
> +    'name': event.name,
> +    'args': event.args,
> +    'event_id': event.num,
> +}
> +        print '''
> +    tbuf_idx = trace_alloc_record(%(event_id)s, %(sizestr)s);
> +    rec_off = (tbuf_idx + ST_V2_REC_HDR_LEN) %% TRACE_BUF_LEN; /* seek record header */

This can be cleaned up with the following interface:

/**
 * Initialize a trace record and claim space for it in the buffer
 *
 * @arglen  number of bytes required for arguments
 */
void trace_record_start(TraceBufferRecord *rec, TraceEventID id, size_t arglen);

/**
 * Append a 64-bit argument to a trace record
 */
void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val);

/**
 * Append a string argument to a trace record
 */
void trace_record_write_str(TraceBufferRecord *rec, const char *s);

/**
 * Mark a trace record completed
 *
 * Don't append any more arguments to the trace record after calling this.
 */
void trace_record_finish(TraceBufferRecord *rec);

Then tracetool.py and trace.c don't need to manage offsets or worry
about temporary variables.  We also don't need to expose
ST_V2_REC_HDR_LEN here or wrap by TRACE_BUF_LEN.

The TraceBufferRecord encapsulates rec_off so that we don't need to
emit code that increments it.  Instead trace_record_write_*() handles
that.

> +def stderr_h(events):
> +    print '''#include <stdio.h>
> +#include "trace/stderr.h"
> +
> +extern TraceEvent trace_list[];'''
> +    for event in events:
> +        argnames = event.argnames
> +        if event.argc > 0:
> +            argnames = ', ' + event.argnames
> +        else:
> +            argnames = ''
> +        print '''
> +static inline void trace_%(name)s(%(args)s)
> +{
> +    if (trace_list[%(event_num)s].state != 0) {
> +        fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);
> +    }
> +}''' % {
> +    'name': event.name,
> +    'args': event.args,
> +    'event_num': event.num,
> +    'fmt': event.fmt.rstrip('\n'),

We shouldn't be parsing the input here, please move the .rstrip() to
where the trace-events input gets parsed.

> +def trace_stap_begin():
> +    global probeprefix
> +    if backend != "dtrace":
> +        print 'SystemTAP tapset generator not applicable to %s backend' % backend
> +        sys.exit(1)
> +    if binary == "":
> +        print '--binary is required for SystemTAP tapset generator'
> +        sys.exit(1)
> +    if ((probeprefix == "") and (targettype == "")):

The parentheses are unnecessary.  Here are two other ways of writing this:

if not probeprefix and not targettype:

or

if probeprefix == '' and targettype == '':

> +# Registry of backends and their converter functions
> +converters = {
> +    'simple': {
> +        'h': simple_h,
> +       'c': simple_c,

Missing space.

> +# Generator that yields Event objects given a trace-events file object
> +def read_events(fobj):
> +    event_num = 0
> +    for line in fobj:
> +        if not line.strip():
> +            continue
> +        if line.lstrip().startswith('#'):
> +           continue
> +       yield Event(event_num, line)
> +       event_num += 1

Indentation.

> +
> +backend = ""
> +output = ""
> +binary = ""
> +targettype = ""
> +targetarch = ""
> +probeprefix = ""
> +
> +def main():
> +    global backend, output, binary, targettype, targetarch, probeprefix

Please avoid the globals, it tempts people to hack in bad things in
the future.  The only globals that are hard to avoid are binary and
probeprefix.

If you move all the checks to main() before we start emitting output,
then there's no need to use most of these globals.  In a way it makes
sense to do checks that abort before entering the main program.
Lluís Vilanova Jan. 10, 2012, 9:45 p.m. UTC | #2
Harsh Prateek Bora writes:

> Signed-off-by: Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
> ---
>  Makefile.objs        |    6 +-
>  Makefile.target      |   10 +-
>  configure            |    7 +-
>  scripts/tracetool    |  643 --------------------------------------------------
>  scripts/tracetool.py |  585 +++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 597 insertions(+), 654 deletions(-)
>  delete mode 100755 scripts/tracetool
>  create mode 100755 scripts/tracetool.py

Cannot be applied on top of Stefan's tracing branch (AFAIK, it has only one
commit pending merge into upstream).

Stefan, are you waiting for more patches to accumulate before merging your
branch, or is it just waiting for a prediodical merge?


Thanks,
  Lluis
Lluís Vilanova Jan. 10, 2012, 10:51 p.m. UTC | #3
Harsh Prateek Bora writes:

> Signed-off-by: Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
> ---
>  Makefile.objs        |    6 +-
>  Makefile.target      |   10 +-
>  configure            |    7 +-
>  scripts/tracetool    |  643 --------------------------------------------------
>  scripts/tracetool.py |  585 +++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 597 insertions(+), 654 deletions(-)
>  delete mode 100755 scripts/tracetool
>  create mode 100755 scripts/tracetool.py

[...]
> diff --git a/scripts/tracetool.py b/scripts/tracetool.py
> new file mode 100755
> index 0000000..6874f66
> --- /dev/null
> +++ b/scripts/tracetool.py
> @@ -0,0 +1,585 @@
> +#!/usr/bin/env python
> +# Python based tracetool script (Code generator for trace events)
> +#
> +# Copyright IBM, Corp. 2011
> +#
> +# This work is licensed under the terms of the GNU GPL, version 2.  See
> +# the COPYING file in the top-level directory.
> +#
> +#
> +
> +import sys
> +import getopt
> +
> +def usage():
> +    print "Tracetool: Generate tracing code for trace events file on stdin"
> +    print "Usage:"
> +    print sys.argv[0], " --backend=[nop|simple|stderr|dtrace|ust] [-h|-c|-d|--stap]"
> +    print '''
> +Backends:
> +  --nop     Tracing disabled
> +  --simple  Simple built-in backend
> +  --stderr  Stderr built-in backend
> +  --dtrace  DTrace/SystemTAP backend
> +  --ust     LTTng User Space Tracing backend
> +
> +Output formats:
> +  -h     Generate .h file
> +  -c     Generate .c file
> +  -d     Generate .d file (DTrace only)
> +  --stap Generate .stp file (DTrace with SystemTAP only)
> +
> +Options:
> +  --binary       [path]    Full path to QEMU binary
> +  --target-arch  [arch]    QEMU emulator target arch
> +  --target-type  [type]    QEMU emulator target type ('system' or 'user')
> +  --probe-prefix [prefix]  Prefix for dtrace probe names
> +                           (default: qemu-targettype-targetarch)
> +'''
> +    sys.exit(1)
> +
> +def get_name(line, sep='('):
> +    head, sep, tail = line.partition(sep)
> +    return head
> +
> +def get_args(line, sep1='(', sep2=')'):
> +    head, sep1, tail = line.partition(sep1)
> +    args, sep2, fmt_str = tail.partition(sep2)
> +    return args
> +
> +def get_argnames(line, sep=','):
> +    nfields = 0
> +    str = []
> +    args = get_args(line)
> +    for field in args.split():
> +      nfields = nfields + 1
> +      # Drop pointer star
> +      type, ptr, tail = field.partition('*')
> +      if type != field:
> +        field = tail
> +
> +      name, sep, tail = field.partition(',')
> +
> +      if name == field:
> +        continue
> +      str.append(name)
> +      str.append(", ")
> +
> +    if nfields > 1:
> +      str.append(name)
> +      return ''.join(str)
> +    else:
> +      return ''
> +
> +def get_argc(line):
> +    argc = 0
> +    argnames = get_argnames(line)
> +    if argnames:
> +      for name in argnames.split(','):
> +        argc = argc + 1
> +    return argc
> +
> +def get_fmt(line, sep=')'):
> +    event, sep, fmt = line.partition(sep)
> +    return fmt
> +
> +def calc_sizeofargs(line):
> +    args = get_args(line)
> +    argc = get_argc(line)
> +    strtype = ('const char*', 'char*', 'const char *', 'char *')
> +    str = []
> +    newstr = ""
> +    if argc > 0:
> +      str = args.split(',')
> +      for elem in str:
> +        if elem.lstrip().startswith(strtype): #strings
> +          type, sep, var = elem.rpartition('*')
> +          newstr = newstr+"4 + strlen("+var.lstrip()+") + "
> +        #elif '*' in elem:
> +        #  newstr = newstr + "4 + " # pointer vars
> +        else:
> +          #type, sep, var = elem.rpartition(' ')
> +          #newstr = newstr+"sizeof("+type.lstrip()+") + "
> +          newstr = newstr + '8 + '
> +    newstr = newstr + '0' # for last +
> +    return newstr
> +
> +
> +def trace_h_begin():
> +    print '''#ifndef TRACE_H
> +#define TRACE_H
> +
> +/* This file is autogenerated by tracetool, do not edit. */
> +
> +#include "qemu-common.h"'''
> +    return
> +
> +def trace_h_end():
> +    print '#endif /* TRACE_H */'
> +    return
> +
> +def trace_c_begin():
> +    print '/* This file is autogenerated by tracetool, do not edit. */'
> +    return
> +
> +def trace_c_end():
> +    # nop, required for trace_gen
> +    return
> +
> +def nop_h(events):
> +    print
> +    for event in events:
> +        print '''static inline void trace_%(name)s(%(args)s)
> +{
> +}
> +''' % {
> +    'name': event.name,
> +    'args': event.args
> +}
> +    return
> +
> +def nop_c(events):
> +    # nop, reqd for converters
> +    return
> +
> +
> +def simple_h(events):
> +    print '#include "trace/simple.h"'
> +    print
> +    for event in events:
> +        print 'void trace_%(name)s(%(args)s);' % {
> +    'name': event.name,
> +    'args': event.args
> +}
> +    print
> +    print '#define NR_TRACE_EVENTS %d' % (event.num + 1)
> +    print 'extern TraceEvent trace_list[NR_TRACE_EVENTS];'
> +
> +    return
> +
> +def is_string(arg):
> +    strtype = ('const char*', 'char*', 'const char *', 'char *')
> +    if arg.lstrip().startswith(strtype):
> +        return True
> +    else:
> +        return False
> +
> +def simple_c(events):
> +    rec_off = 0
> +    print '#include "trace.h"'
> +    print '#include "trace/simple.h"'
> +    print
> +    print 'TraceEvent trace_list[] = {'
> +    print
> +    eventlist = list(events)
> +    for event in eventlist:
> +        print '{.tp_name = "%(name)s", .state=0},' % {
> +    'name': event.name
> +}
> +        print
> +    print '};'
> +    print
> +    for event in eventlist:
> +        argc = event.argc
> +        print '''void trace_%(name)s(%(args)s)
> +{
> +    unsigned int tbuf_idx, rec_off;
> +    uint64_t var64 __attribute__ ((unused));
> +    uint64_t pvar64 __attribute__ ((unused));
> +    uint32_t slen __attribute__ ((unused));
> +
> +    if (!trace_list[%(event_id)s].state) {
> +        return;
> +    }
> +''' % {
> +    'name': event.name,
> +    'args': event.args,
> +    'event_id': event.num,
> +}
> +        print '''
> +    tbuf_idx = trace_alloc_record(%(event_id)s, %(sizestr)s);
> +    rec_off = (tbuf_idx + ST_V2_REC_HDR_LEN) %% TRACE_BUF_LEN; /* seek record header */
> +''' % {'event_id': event.num, 'sizestr': event.sizestr,}
> +
> +        if argc > 0:
> +            str = event.arglist
> +            for elem in str:
> +                if is_string(elem): # if string
> +                    type, sep, var = elem.rpartition('*')
> +                    print '''
> +    slen = strlen(%(var)s);
> +    write_to_buffer(rec_off, (uint8_t*)&slen, sizeof(slen));
> +    rec_off += sizeof(slen);''' % {
> +    'var': var.lstrip()
> +}
> +                    print '''
> +    write_to_buffer(rec_off, (uint8_t*)%(var)s, slen);
> +    rec_off += slen;''' % {
> +    'var': var.lstrip()
> +}
> +                elif '*' in elem: # pointer var (not string)
> +                    type, sep, var = elem.rpartition('*')
> +                    print '''
> +    pvar64 = (uint64_t)(uint64_t*)%(var)s;
> +    write_to_buffer(rec_off, (uint8_t*)&pvar64, sizeof(uint64_t));
> +    rec_off += sizeof(uint64_t);''' % {
> +    'var': var.lstrip()
> +}
> +                else: # primitive data type
> +                    type, sep, var = elem.rpartition(' ')
> +                    print '''
> +    var64 = (uint64_t)%(var)s;
> +    write_to_buffer(rec_off, (uint8_t*)&var64, sizeof(uint64_t));
> +    rec_off += sizeof(uint64_t);''' % {
> +    'var': var.lstrip()
> +}
> +        print '''
> +    trace_mark_record_complete(tbuf_idx);'''
> +        print '}'
> +        print
> +
> +    return
> +
> +def stderr_h(events):
> +    print '''#include <stdio.h>
> +#include "trace/stderr.h"
> +
> +extern TraceEvent trace_list[];'''
> +    for event in events:
> +        argnames = event.argnames
> +        if event.argc > 0:
> +            argnames = ', ' + event.argnames
> +        else:
> +            argnames = ''
> +        print '''
> +static inline void trace_%(name)s(%(args)s)
> +{
> +    if (trace_list[%(event_num)s].state != 0) {
> +        fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);
> +    }
> +}''' % {
> +    'name': event.name,
> +    'args': event.args,
> +    'event_num': event.num,
> +    'fmt': event.fmt.rstrip('\n'),
> +    'argnames': argnames
> +}
> +    print
> +    print '#define NR_TRACE_EVENTS %d' % (event.num + 1)
> +
> +def stderr_c(events):
> +    print '''#include "trace.h"
> +
> +TraceEvent trace_list[] = {
> +'''
> +    for event in events:
> +        print '{.tp_name = "%(name)s", .state=0},' % {
> +    'name': event.name
> +}
> +        print
> +    print '};'
> +
> +def ust_h(events):
> +    print '''#include <ust/tracepoint.h>
> +#undef mutex_lock
> +#undef mutex_unlock
> +#undef inline
> +#undef wmb'''
> +
> +    for event in events:
> +        if event.argc > 0:
> +            print '''
> +DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));
> +#define trace_%(name)s trace_ust_%(name)s''' % {
> +    'name': event.name,
> +    'args': event.args,
> +    'argnames': event.argnames
> +}
> +        else:
> +            print '''
> +_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);
> +#define trace_%(name)s trace_ust_%(name)s''' % {
> +    'name': event.name,
> +}
> +    print
> +    return
> +
> +def ust_c(events):
> +    print '''#include <ust/marker.h>
> +#undef mutex_lock
> +#undef mutex_unlock
> +#undef inline
> +#undef wmb
> +#include "trace.h"'''
> +    eventlist = list(events)
> +    for event in eventlist:
> +        argnames = event.argnames
> +        if event.argc > 0:
> +            argnames = ', ' + event.argnames
> +            print '''
> +DEFINE_TRACE(ust_%(name)s);
> +
> +static void ust_%(name)s_probe(%(args)s)
> +{
> +    trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);
> +}''' % {
> +    'name': event.name,
> +    'args': event.args,
> +    'fmt': event.fmt.rstrip('\n'),
> +    'argnames': argnames
> +}
> +        else:
> +            print '''
> +DEFINE_TRACE(ust_%(name)s);
> +
> +static void ust_%(name)s_probe(%(args)s)
> +{
> +    trace_mark(ust, %(name)s, UST_MARKER_NOARGS);
> +}''' % {
> +    'name': event.name,
> +    'args': event.args,
> +}
> +
> +    # register probes
> +    print '''
> +static void __attribute__((constructor)) trace_init(void)
> +{'''
> +    for event in eventlist:
> +        print '    register_trace_ust_%(name)s(ust_%(name)s_probe);' % {
> +    'name': event.name
> +}
> +    print '}'
> +
> +    return
> +
> +def dtrace_h(events):
> +    print '#include "trace-dtrace.h"'
> +    print
> +    for event in events:
> +        print '''static inline void trace_%(name)s(%(args)s) {
> +    if (QEMU_%(uppername)s_ENABLED()) {
> +        QEMU_%(uppername)s(%(argnames)s);
> +    }
> +}
> +''' % {
> +    'name': event.name,
> +    'args': event.args,
> +    'uppername': event.name.upper(),
> +    'argnames': event.argnames,
> +}
> +
> +def dtrace_c(events):
> +    return # No need for function definitions in dtrace backend
> +
> +def dtrace_d(events):
> +    print 'provider qemu {'
> +    for event in events:
> +        args = event.args
> +
> +        # DTrace provider syntax expects foo() for empty
> +        # params, not foo(void)
> +        if args == 'void':
> +            args = ''
> +
> +        # Define prototype for probe arguments
> +        print '''
> +        probe %(name)s(%(args)s);''' % {
> +        'name': event.name,
> +        'args': args
> +}
> +    print
> +    print '};'
> +    return
> +
> +def dtrace_stp(events):
> +    for event in events:
> +        # Define prototype for probe arguments
> +        print '''
> +probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")
> +{''' % {
> +    'probeprefix': probeprefix,
> +    'name': event.name,
> +    'binary': binary
> +}
> +        i = 1
> +        if event.argc > 0:
> +            for arg in event.argnames.split(','):
> +                # 'limit' is a reserved keyword
> +                if arg == 'limit':
> +                    arg = '_limit'
> +                print '  %s = $arg%d;' % (arg.lstrip(), i)
> +                i += 1
> +        print '}'
> +    print
> +    return
> +
> +def trace_stap_begin():
> +    global probeprefix
> +    if backend != "dtrace":
> +        print 'SystemTAP tapset generator not applicable to %s backend' % backend
> +        sys.exit(1)
> +    if binary == "":
> +        print '--binary is required for SystemTAP tapset generator'
> +        sys.exit(1)
> +    if ((probeprefix == "") and (targettype == "")):
> +        print '--target-type is required for SystemTAP tapset generator'
> +        sys.exit(1)
> +    if ((probeprefix == "") and (targetarch == "")):
> +        print '--target-arch is required for SystemTAP tapset generator'
> +        sys.exit(1)
> +    if probeprefix == "":
> +        probeprefix = 'qemu.' + targettype + '.' + targetarch
> +    print '/* This file is autogenerated by tracetool, do not edit. */'
> +    return
> +
> +def trace_stap_end():
> +    return #nop, reqd for trace_gen
> +
> +def trace_d_begin():
> +    if backend != 'dtrace':
> +        print 'DTrace probe generator not applicable to %s backend' % backend
> +        sys.exit(1)
> +    print '/* This file is autogenerated by tracetool, do not edit. */'
> +
> +def trace_d_end():
> +    return #nop, reqd for trace_gen
> +
> +
> +# Registry of backends and their converter functions
> +converters = {
> +    'simple': {
> +        'h': simple_h,
> +	'c': simple_c,
> +    },
> +
> +    'nop': {
> +        'h': nop_h,
> +        'c': nop_c,
> +    },
> +
> +    'stderr': {
> +        'h': stderr_h,
> +        'c': stderr_c,
> +    },
> +
> +    'dtrace': {
> +        'h': dtrace_h,
> +        'c': dtrace_c,
> +        'd': dtrace_d,
> +        'stap': dtrace_stp
> +    },
> +
> +    'ust': {
> +        'h': ust_h,
> +        'c': ust_c,
> +    },
> +
> +}
> +
> +# Trace file header and footer code generators
> +trace_gen = {
> +    'h': {
> +        'begin': trace_h_begin,
> +        'end': trace_h_end,
> +    },
> +    'c': {
> +        'begin': trace_c_begin,
> +        'end': trace_c_end,
> +    },
> +    'd': {
> +        'begin': trace_d_begin,
> +        'end': trace_d_end,
> +    },
> +    'stap': {
> +        'begin': trace_stap_begin,
> +        'end': trace_stap_end,
> +    },
> +}
> +
> +# A trace event
> +class Event(object):
> +    def __init__(self, num, line):
> +        self.num = num
> +        self.args = get_args(line)
> +        self.arglist = self.args.split(',')
> +        self.name = get_name(line)
> +        self.argc = get_argc(line)
> +        self.argnames = get_argnames(line)
> +        self.sizestr = calc_sizeofargs(line)
> +        self.fmt = get_fmt(line)

This is not not extracting the event properties (e.g., disable). A set of
strings should suffice.

Arguments could be converted to an Arguments class (or similar, like
ArgumentList) and derive the rest from there using methods (e.g., names, types,
sizestr, arglist, etc.).

If you want, I can send a patch on top of this one with that.


> +
> +# Generator that yields Event objects given a trace-events file object
> +def read_events(fobj):
> +    event_num = 0
> +    for line in fobj:
> +        if not line.strip():
> +            continue
> +        if line.lstrip().startswith('#'):
> +	    continue
> +	yield Event(event_num, line)
> +	event_num += 1
> +
> +backend = ""
> +output = ""
> +binary = ""
> +targettype = ""
> +targetarch = ""
> +probeprefix = ""
> +
> +def main():
> +    global backend, output, binary, targettype, targetarch, probeprefix
> +    supported_backends = ["simple", "nop", "stderr", "dtrace", "ust"]
> +    short_options = "hcd"
> +    long_options = ["stap", "backend=", "binary=", "target-arch=", "target-type=", "probe-prefix=", "list-backends", "check-backend"]
> +    try:
> +        opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
> +    except getopt.GetoptError, err:
> +        # print help information and exit:
> +        print str(err) # will print something like "option -a not recognized"
> +        usage()
> +        sys.exit(2)
> +    for opt, arg in opts:
> +        if opt == '-h':
> +            output = 'h'
> +        elif opt == '-c':
> +            output = 'c'
> +        elif opt == '-d':
> +            output = 'd'
> +        elif opt == '--stap':
> +            output = 'stap'
> +        elif opt == '--backend':
> +            backend = arg
> +        elif opt == '--binary':
> +            binary = arg
> +        elif opt == '--target-arch':
> +            targetarch = arg
> +        elif opt == '--target-type':
> +            targettype = arg
> +        elif opt == '--probe-prefix':
> +            probeprefix = arg
> +        elif opt == '--list-backends':
> +            print 'simple, nop, stderr, dtrace'
> +            sys.exit(0)
> +        elif opt == "--check-backend":
> +            if any(backend in s for s in supported_backends):
> +                sys.exit(0)
> +            else:
> +                sys.exit(1)
> +        else:
> +            #assert False, "unhandled option"
> +            print "unhandled option: ", opt
> +            usage()
> +
> +    if backend == "" or output == "":
> +        usage()
> +        sys.exit(0)
> +
> +    events = read_events(sys.stdin)
> +    trace_gen[output]['begin']()
> +    converters[backend][output](events)

This should use the "disable" property to establish whether to use output or
"nop".

> +    trace_gen[output]['end']()
> +    return
> +
> +if __name__ == "__main__":
> +    main()
> +
> -- 
> 1.7.1.1

Lluis
Harsh Prateek Bora Jan. 11, 2012, 6:25 a.m. UTC | #4
Hi Stefan,

Thanks for an early review, I shall address your comments in next version.

Also, please confirm, whether I should work on top for qemu.git or your 
tracing branch on repo.or.cz/stefanha.git ?

regards,
Harsh

On 01/10/2012 08:20 PM, Stefan Hajnoczi wrote:
> On Tue, Jan 10, 2012 at 10:59 AM, Harsh Prateek Bora
> <harsh@linux.vnet.ibm.com>  wrote:
>> diff --git a/scripts/tracetool.py b/scripts/tracetool.py
>> new file mode 100755
>> index 0000000..6874f66
>> --- /dev/null
>> +++ b/scripts/tracetool.py
>> @@ -0,0 +1,585 @@
>> +#!/usr/bin/env python
>> +# Python based tracetool script (Code generator for trace events)
>
> Nitpick: please don't use comments or names that reflect the fact that
> you're changing something.  Once this is merged readers might not even
> know there was a non-Python tracetool script.  "Code generator for
> trace events" explains what this script does.  "Python based tracetool
> script" doesn't add any information because the content is clearly in
> Python and the filename is tracetool.
>
> A related point is please don't put simpletrace "v2" into the code
> because if we ever do a v3 all those references would need to be
> renamed, even if the value stays the same.  (For example
> ST_V2_REC_HDR_LEN.)  When changing code make it look like it was
> written like this from day 1 rather than leaving visible marks where
> things were modified - git log already provides the code change
> history.  It's distracting and sometimes misleading when code contains
> references to outdated things which have been replaced.
>
>> +#
>> +# Copyright IBM, Corp. 2011
>> +#
>> +# This work is licensed under the terms of the GNU GPL, version 2.  See
>> +# the COPYING file in the top-level directory.
>> +#
>> +#
>> +
>> +import sys
>> +import getopt
>> +
>> +def usage():
>> +    print "Tracetool: Generate tracing code for trace events file on stdin"
>> +    print "Usage:"
>> +    print sys.argv[0], " --backend=[nop|simple|stderr|dtrace|ust] [-h|-c|-d|--stap]"
>
> print 'a', 'b' puts a space between "a" and "b".  "--backend=..."
> would work fine, space is not needed.
>
>> +def calc_sizeofargs(line):
>> +    args = get_args(line)
>> +    argc = get_argc(line)
>> +    strtype = ('const char*', 'char*', 'const char *', 'char *')
>
> This is repeated elsewhere, please share is_string().
>
>> +def trace_h_begin():
>> +    print '''#ifndef TRACE_H
>> +#define TRACE_H
>> +
>> +/* This file is autogenerated by tracetool, do not edit. */
>> +
>> +#include "qemu-common.h"'''
>> +    return
>
> A function that has no explicit return statement implicitly returns
> None.  Please remove returns to keep the code concise.
>
>> +
>> +def trace_h_end():
>> +    print '#endif /* TRACE_H */'
>> +    return
>> +
>> +def trace_c_begin():
>> +    print '/* This file is autogenerated by tracetool, do not edit. */'
>> +    return
>> +
>> +def trace_c_end():
>> +    # nop, required for trace_gen
>> +    return
>
> def trace_c_end():
>      pass # nop, required for trace_gen
>
>> +def simple_c(events):
>> +    rec_off = 0
>> +    print '#include "trace.h"'
>> +    print '#include "trace/simple.h"'
>> +    print
>> +    print 'TraceEvent trace_list[] = {'
>> +    print
>> +    eventlist = list(events)
>> +    for event in eventlist:
>> +        print '{.tp_name = "%(name)s", .state=0},' % {
>> +    'name': event.name
>> +}
>> +        print
>> +    print '};'
>> +    print
>> +    for event in eventlist:
>> +        argc = event.argc
>> +        print '''void trace_%(name)s(%(args)s)
>> +{
>> +    unsigned int tbuf_idx, rec_off;
>
>    CC    trace.o
> trace.c: In function ‘trace_slavio_misc_update_irq_raise’:
> trace.c:3411:28: warning: variable ‘rec_off’ set but not used
> [-Wunused-but-set-variable]
>
>> +    uint64_t var64 __attribute__ ((unused));
>> +    uint64_t pvar64 __attribute__ ((unused));
>> +    uint32_t slen __attribute__ ((unused));
>> +
>> +    if (!trace_list[%(event_id)s].state) {
>> +        return;
>> +    }
>> +''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'event_id': event.num,
>> +}
>> +        print '''
>> +    tbuf_idx = trace_alloc_record(%(event_id)s, %(sizestr)s);
>> +    rec_off = (tbuf_idx + ST_V2_REC_HDR_LEN) %% TRACE_BUF_LEN; /* seek record header */
>
> This can be cleaned up with the following interface:
>
> /**
>   * Initialize a trace record and claim space for it in the buffer
>   *
>   * @arglen  number of bytes required for arguments
>   */
> void trace_record_start(TraceBufferRecord *rec, TraceEventID id, size_t arglen);
>
> /**
>   * Append a 64-bit argument to a trace record
>   */
> void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val);
>
> /**
>   * Append a string argument to a trace record
>   */
> void trace_record_write_str(TraceBufferRecord *rec, const char *s);
>
> /**
>   * Mark a trace record completed
>   *
>   * Don't append any more arguments to the trace record after calling this.
>   */
> void trace_record_finish(TraceBufferRecord *rec);
>
> Then tracetool.py and trace.c don't need to manage offsets or worry
> about temporary variables.  We also don't need to expose
> ST_V2_REC_HDR_LEN here or wrap by TRACE_BUF_LEN.
>
> The TraceBufferRecord encapsulates rec_off so that we don't need to
> emit code that increments it.  Instead trace_record_write_*() handles
> that.
>
>> +def stderr_h(events):
>> +    print '''#include<stdio.h>
>> +#include "trace/stderr.h"
>> +
>> +extern TraceEvent trace_list[];'''
>> +    for event in events:
>> +        argnames = event.argnames
>> +        if event.argc>  0:
>> +            argnames = ', ' + event.argnames
>> +        else:
>> +            argnames = ''
>> +        print '''
>> +static inline void trace_%(name)s(%(args)s)
>> +{
>> +    if (trace_list[%(event_num)s].state != 0) {
>> +        fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);
>> +    }
>> +}''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'event_num': event.num,
>> +    'fmt': event.fmt.rstrip('\n'),
>
> We shouldn't be parsing the input here, please move the .rstrip() to
> where the trace-events input gets parsed.
>
>> +def trace_stap_begin():
>> +    global probeprefix
>> +    if backend != "dtrace":
>> +        print 'SystemTAP tapset generator not applicable to %s backend' % backend
>> +        sys.exit(1)
>> +    if binary == "":
>> +        print '--binary is required for SystemTAP tapset generator'
>> +        sys.exit(1)
>> +    if ((probeprefix == "") and (targettype == "")):
>
> The parentheses are unnecessary.  Here are two other ways of writing this:
>
> if not probeprefix and not targettype:
>
> or
>
> if probeprefix == '' and targettype == '':
>
>> +# Registry of backends and their converter functions
>> +converters = {
>> +    'simple': {
>> +        'h': simple_h,
>> +       'c': simple_c,
>
> Missing space.
>
>> +# Generator that yields Event objects given a trace-events file object
>> +def read_events(fobj):
>> +    event_num = 0
>> +    for line in fobj:
>> +        if not line.strip():
>> +            continue
>> +        if line.lstrip().startswith('#'):
>> +           continue
>> +       yield Event(event_num, line)
>> +       event_num += 1
>
> Indentation.
>
>> +
>> +backend = ""
>> +output = ""
>> +binary = ""
>> +targettype = ""
>> +targetarch = ""
>> +probeprefix = ""
>> +
>> +def main():
>> +    global backend, output, binary, targettype, targetarch, probeprefix
>
> Please avoid the globals, it tempts people to hack in bad things in
> the future.  The only globals that are hard to avoid are binary and
> probeprefix.
>
> If you move all the checks to main() before we start emitting output,
> then there's no need to use most of these globals.  In a way it makes
> sense to do checks that abort before entering the main program.
>
Harsh Prateek Bora Jan. 11, 2012, 6:38 a.m. UTC | #5
On 01/11/2012 04:21 AM, Lluís Vilanova wrote:
> Harsh Prateek Bora writes:
>
>> Signed-off-by: Harsh Prateek Bora<harsh@linux.vnet.ibm.com>
>> ---
>>   Makefile.objs        |    6 +-
>>   Makefile.target      |   10 +-
>>   configure            |    7 +-
>>   scripts/tracetool    |  643 --------------------------------------------------
>>   scripts/tracetool.py |  585 +++++++++++++++++++++++++++++++++++++++++++++
>>   5 files changed, 597 insertions(+), 654 deletions(-)
>>   delete mode 100755 scripts/tracetool
>>   create mode 100755 scripts/tracetool.py
>
> [...]
>> diff --git a/scripts/tracetool.py b/scripts/tracetool.py
>> new file mode 100755
>> index 0000000..6874f66
>> --- /dev/null
>> +++ b/scripts/tracetool.py
>> @@ -0,0 +1,585 @@
>> +#!/usr/bin/env python
>> +# Python based tracetool script (Code generator for trace events)
>> +#
>> +# Copyright IBM, Corp. 2011
>> +#
>> +# This work is licensed under the terms of the GNU GPL, version 2.  See
>> +# the COPYING file in the top-level directory.
>> +#
>> +#
>> +
>> +import sys
>> +import getopt
>> +
>> +def usage():
>> +    print "Tracetool: Generate tracing code for trace events file on stdin"
>> +    print "Usage:"
>> +    print sys.argv[0], " --backend=[nop|simple|stderr|dtrace|ust] [-h|-c|-d|--stap]"
>> +    print '''
>> +Backends:
>> +  --nop     Tracing disabled
>> +  --simple  Simple built-in backend
>> +  --stderr  Stderr built-in backend
>> +  --dtrace  DTrace/SystemTAP backend
>> +  --ust     LTTng User Space Tracing backend
>> +
>> +Output formats:
>> +  -h     Generate .h file
>> +  -c     Generate .c file
>> +  -d     Generate .d file (DTrace only)
>> +  --stap Generate .stp file (DTrace with SystemTAP only)
>> +
>> +Options:
>> +  --binary       [path]    Full path to QEMU binary
>> +  --target-arch  [arch]    QEMU emulator target arch
>> +  --target-type  [type]    QEMU emulator target type ('system' or 'user')
>> +  --probe-prefix [prefix]  Prefix for dtrace probe names
>> +                           (default: qemu-targettype-targetarch)
>> +'''
>> +    sys.exit(1)
>> +
>> +def get_name(line, sep='('):
>> +    head, sep, tail = line.partition(sep)
>> +    return head
>> +
>> +def get_args(line, sep1='(', sep2=')'):
>> +    head, sep1, tail = line.partition(sep1)
>> +    args, sep2, fmt_str = tail.partition(sep2)
>> +    return args
>> +
>> +def get_argnames(line, sep=','):
>> +    nfields = 0
>> +    str = []
>> +    args = get_args(line)
>> +    for field in args.split():
>> +      nfields = nfields + 1
>> +      # Drop pointer star
>> +      type, ptr, tail = field.partition('*')
>> +      if type != field:
>> +        field = tail
>> +
>> +      name, sep, tail = field.partition(',')
>> +
>> +      if name == field:
>> +        continue
>> +      str.append(name)
>> +      str.append(", ")
>> +
>> +    if nfields>  1:
>> +      str.append(name)
>> +      return ''.join(str)
>> +    else:
>> +      return ''
>> +
>> +def get_argc(line):
>> +    argc = 0
>> +    argnames = get_argnames(line)
>> +    if argnames:
>> +      for name in argnames.split(','):
>> +        argc = argc + 1
>> +    return argc
>> +
>> +def get_fmt(line, sep=')'):
>> +    event, sep, fmt = line.partition(sep)
>> +    return fmt
>> +
>> +def calc_sizeofargs(line):
>> +    args = get_args(line)
>> +    argc = get_argc(line)
>> +    strtype = ('const char*', 'char*', 'const char *', 'char *')
>> +    str = []
>> +    newstr = ""
>> +    if argc>  0:
>> +      str = args.split(',')
>> +      for elem in str:
>> +        if elem.lstrip().startswith(strtype): #strings
>> +          type, sep, var = elem.rpartition('*')
>> +          newstr = newstr+"4 + strlen("+var.lstrip()+") + "
>> +        #elif '*' in elem:
>> +        #  newstr = newstr + "4 + " # pointer vars
>> +        else:
>> +          #type, sep, var = elem.rpartition(' ')
>> +          #newstr = newstr+"sizeof("+type.lstrip()+") + "
>> +          newstr = newstr + '8 + '
>> +    newstr = newstr + '0' # for last +
>> +    return newstr
>> +
>> +
>> +def trace_h_begin():
>> +    print '''#ifndef TRACE_H
>> +#define TRACE_H
>> +
>> +/* This file is autogenerated by tracetool, do not edit. */
>> +
>> +#include "qemu-common.h"'''
>> +    return
>> +
>> +def trace_h_end():
>> +    print '#endif /* TRACE_H */'
>> +    return
>> +
>> +def trace_c_begin():
>> +    print '/* This file is autogenerated by tracetool, do not edit. */'
>> +    return
>> +
>> +def trace_c_end():
>> +    # nop, required for trace_gen
>> +    return
>> +
>> +def nop_h(events):
>> +    print
>> +    for event in events:
>> +        print '''static inline void trace_%(name)s(%(args)s)
>> +{
>> +}
>> +''' % {
>> +    'name': event.name,
>> +    'args': event.args
>> +}
>> +    return
>> +
>> +def nop_c(events):
>> +    # nop, reqd for converters
>> +    return
>> +
>> +
>> +def simple_h(events):
>> +    print '#include "trace/simple.h"'
>> +    print
>> +    for event in events:
>> +        print 'void trace_%(name)s(%(args)s);' % {
>> +    'name': event.name,
>> +    'args': event.args
>> +}
>> +    print
>> +    print '#define NR_TRACE_EVENTS %d' % (event.num + 1)
>> +    print 'extern TraceEvent trace_list[NR_TRACE_EVENTS];'
>> +
>> +    return
>> +
>> +def is_string(arg):
>> +    strtype = ('const char*', 'char*', 'const char *', 'char *')
>> +    if arg.lstrip().startswith(strtype):
>> +        return True
>> +    else:
>> +        return False
>> +
>> +def simple_c(events):
>> +    rec_off = 0
>> +    print '#include "trace.h"'
>> +    print '#include "trace/simple.h"'
>> +    print
>> +    print 'TraceEvent trace_list[] = {'
>> +    print
>> +    eventlist = list(events)
>> +    for event in eventlist:
>> +        print '{.tp_name = "%(name)s", .state=0},' % {
>> +    'name': event.name
>> +}
>> +        print
>> +    print '};'
>> +    print
>> +    for event in eventlist:
>> +        argc = event.argc
>> +        print '''void trace_%(name)s(%(args)s)
>> +{
>> +    unsigned int tbuf_idx, rec_off;
>> +    uint64_t var64 __attribute__ ((unused));
>> +    uint64_t pvar64 __attribute__ ((unused));
>> +    uint32_t slen __attribute__ ((unused));
>> +
>> +    if (!trace_list[%(event_id)s].state) {
>> +        return;
>> +    }
>> +''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'event_id': event.num,
>> +}
>> +        print '''
>> +    tbuf_idx = trace_alloc_record(%(event_id)s, %(sizestr)s);
>> +    rec_off = (tbuf_idx + ST_V2_REC_HDR_LEN) %% TRACE_BUF_LEN; /* seek record header */
>> +''' % {'event_id': event.num, 'sizestr': event.sizestr,}
>> +
>> +        if argc>  0:
>> +            str = event.arglist
>> +            for elem in str:
>> +                if is_string(elem): # if string
>> +                    type, sep, var = elem.rpartition('*')
>> +                    print '''
>> +    slen = strlen(%(var)s);
>> +    write_to_buffer(rec_off, (uint8_t*)&slen, sizeof(slen));
>> +    rec_off += sizeof(slen);''' % {
>> +    'var': var.lstrip()
>> +}
>> +                    print '''
>> +    write_to_buffer(rec_off, (uint8_t*)%(var)s, slen);
>> +    rec_off += slen;''' % {
>> +    'var': var.lstrip()
>> +}
>> +                elif '*' in elem: # pointer var (not string)
>> +                    type, sep, var = elem.rpartition('*')
>> +                    print '''
>> +    pvar64 = (uint64_t)(uint64_t*)%(var)s;
>> +    write_to_buffer(rec_off, (uint8_t*)&pvar64, sizeof(uint64_t));
>> +    rec_off += sizeof(uint64_t);''' % {
>> +    'var': var.lstrip()
>> +}
>> +                else: # primitive data type
>> +                    type, sep, var = elem.rpartition(' ')
>> +                    print '''
>> +    var64 = (uint64_t)%(var)s;
>> +    write_to_buffer(rec_off, (uint8_t*)&var64, sizeof(uint64_t));
>> +    rec_off += sizeof(uint64_t);''' % {
>> +    'var': var.lstrip()
>> +}
>> +        print '''
>> +    trace_mark_record_complete(tbuf_idx);'''
>> +        print '}'
>> +        print
>> +
>> +    return
>> +
>> +def stderr_h(events):
>> +    print '''#include<stdio.h>
>> +#include "trace/stderr.h"
>> +
>> +extern TraceEvent trace_list[];'''
>> +    for event in events:
>> +        argnames = event.argnames
>> +        if event.argc>  0:
>> +            argnames = ', ' + event.argnames
>> +        else:
>> +            argnames = ''
>> +        print '''
>> +static inline void trace_%(name)s(%(args)s)
>> +{
>> +    if (trace_list[%(event_num)s].state != 0) {
>> +        fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);
>> +    }
>> +}''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'event_num': event.num,
>> +    'fmt': event.fmt.rstrip('\n'),
>> +    'argnames': argnames
>> +}
>> +    print
>> +    print '#define NR_TRACE_EVENTS %d' % (event.num + 1)
>> +
>> +def stderr_c(events):
>> +    print '''#include "trace.h"
>> +
>> +TraceEvent trace_list[] = {
>> +'''
>> +    for event in events:
>> +        print '{.tp_name = "%(name)s", .state=0},' % {
>> +    'name': event.name
>> +}
>> +        print
>> +    print '};'
>> +
>> +def ust_h(events):
>> +    print '''#include<ust/tracepoint.h>
>> +#undef mutex_lock
>> +#undef mutex_unlock
>> +#undef inline
>> +#undef wmb'''
>> +
>> +    for event in events:
>> +        if event.argc>  0:
>> +            print '''
>> +DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));
>> +#define trace_%(name)s trace_ust_%(name)s''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'argnames': event.argnames
>> +}
>> +        else:
>> +            print '''
>> +_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);
>> +#define trace_%(name)s trace_ust_%(name)s''' % {
>> +    'name': event.name,
>> +}
>> +    print
>> +    return
>> +
>> +def ust_c(events):
>> +    print '''#include<ust/marker.h>
>> +#undef mutex_lock
>> +#undef mutex_unlock
>> +#undef inline
>> +#undef wmb
>> +#include "trace.h"'''
>> +    eventlist = list(events)
>> +    for event in eventlist:
>> +        argnames = event.argnames
>> +        if event.argc>  0:
>> +            argnames = ', ' + event.argnames
>> +            print '''
>> +DEFINE_TRACE(ust_%(name)s);
>> +
>> +static void ust_%(name)s_probe(%(args)s)
>> +{
>> +    trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);
>> +}''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'fmt': event.fmt.rstrip('\n'),
>> +    'argnames': argnames
>> +}
>> +        else:
>> +            print '''
>> +DEFINE_TRACE(ust_%(name)s);
>> +
>> +static void ust_%(name)s_probe(%(args)s)
>> +{
>> +    trace_mark(ust, %(name)s, UST_MARKER_NOARGS);
>> +}''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +}
>> +
>> +    # register probes
>> +    print '''
>> +static void __attribute__((constructor)) trace_init(void)
>> +{'''
>> +    for event in eventlist:
>> +        print '    register_trace_ust_%(name)s(ust_%(name)s_probe);' % {
>> +    'name': event.name
>> +}
>> +    print '}'
>> +
>> +    return
>> +
>> +def dtrace_h(events):
>> +    print '#include "trace-dtrace.h"'
>> +    print
>> +    for event in events:
>> +        print '''static inline void trace_%(name)s(%(args)s) {
>> +    if (QEMU_%(uppername)s_ENABLED()) {
>> +        QEMU_%(uppername)s(%(argnames)s);
>> +    }
>> +}
>> +''' % {
>> +    'name': event.name,
>> +    'args': event.args,
>> +    'uppername': event.name.upper(),
>> +    'argnames': event.argnames,
>> +}
>> +
>> +def dtrace_c(events):
>> +    return # No need for function definitions in dtrace backend
>> +
>> +def dtrace_d(events):
>> +    print 'provider qemu {'
>> +    for event in events:
>> +        args = event.args
>> +
>> +        # DTrace provider syntax expects foo() for empty
>> +        # params, not foo(void)
>> +        if args == 'void':
>> +            args = ''
>> +
>> +        # Define prototype for probe arguments
>> +        print '''
>> +        probe %(name)s(%(args)s);''' % {
>> +        'name': event.name,
>> +        'args': args
>> +}
>> +    print
>> +    print '};'
>> +    return
>> +
>> +def dtrace_stp(events):
>> +    for event in events:
>> +        # Define prototype for probe arguments
>> +        print '''
>> +probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")
>> +{''' % {
>> +    'probeprefix': probeprefix,
>> +    'name': event.name,
>> +    'binary': binary
>> +}
>> +        i = 1
>> +        if event.argc>  0:
>> +            for arg in event.argnames.split(','):
>> +                # 'limit' is a reserved keyword
>> +                if arg == 'limit':
>> +                    arg = '_limit'
>> +                print '  %s = $arg%d;' % (arg.lstrip(), i)
>> +                i += 1
>> +        print '}'
>> +    print
>> +    return
>> +
>> +def trace_stap_begin():
>> +    global probeprefix
>> +    if backend != "dtrace":
>> +        print 'SystemTAP tapset generator not applicable to %s backend' % backend
>> +        sys.exit(1)
>> +    if binary == "":
>> +        print '--binary is required for SystemTAP tapset generator'
>> +        sys.exit(1)
>> +    if ((probeprefix == "") and (targettype == "")):
>> +        print '--target-type is required for SystemTAP tapset generator'
>> +        sys.exit(1)
>> +    if ((probeprefix == "") and (targetarch == "")):
>> +        print '--target-arch is required for SystemTAP tapset generator'
>> +        sys.exit(1)
>> +    if probeprefix == "":
>> +        probeprefix = 'qemu.' + targettype + '.' + targetarch
>> +    print '/* This file is autogenerated by tracetool, do not edit. */'
>> +    return
>> +
>> +def trace_stap_end():
>> +    return #nop, reqd for trace_gen
>> +
>> +def trace_d_begin():
>> +    if backend != 'dtrace':
>> +        print 'DTrace probe generator not applicable to %s backend' % backend
>> +        sys.exit(1)
>> +    print '/* This file is autogenerated by tracetool, do not edit. */'
>> +
>> +def trace_d_end():
>> +    return #nop, reqd for trace_gen
>> +
>> +
>> +# Registry of backends and their converter functions
>> +converters = {
>> +    'simple': {
>> +        'h': simple_h,
>> +	'c': simple_c,
>> +    },
>> +
>> +    'nop': {
>> +        'h': nop_h,
>> +        'c': nop_c,
>> +    },
>> +
>> +    'stderr': {
>> +        'h': stderr_h,
>> +        'c': stderr_c,
>> +    },
>> +
>> +    'dtrace': {
>> +        'h': dtrace_h,
>> +        'c': dtrace_c,
>> +        'd': dtrace_d,
>> +        'stap': dtrace_stp
>> +    },
>> +
>> +    'ust': {
>> +        'h': ust_h,
>> +        'c': ust_c,
>> +    },
>> +
>> +}
>> +
>> +# Trace file header and footer code generators
>> +trace_gen = {
>> +    'h': {
>> +        'begin': trace_h_begin,
>> +        'end': trace_h_end,
>> +    },
>> +    'c': {
>> +        'begin': trace_c_begin,
>> +        'end': trace_c_end,
>> +    },
>> +    'd': {
>> +        'begin': trace_d_begin,
>> +        'end': trace_d_end,
>> +    },
>> +    'stap': {
>> +        'begin': trace_stap_begin,
>> +        'end': trace_stap_end,
>> +    },
>> +}
>> +
>> +# A trace event
>> +class Event(object):
>> +    def __init__(self, num, line):
>> +        self.num = num
>> +        self.args = get_args(line)
>> +        self.arglist = self.args.split(',')
>> +        self.name = get_name(line)
>> +        self.argc = get_argc(line)
>> +        self.argnames = get_argnames(line)
>> +        self.sizestr = calc_sizeofargs(line)
>> +        self.fmt = get_fmt(line)
>
> This is not not extracting the event properties (e.g., disable). A set of
> strings should suffice.
>

Ok, I had a misunderstanding about 'disable' being removed completely 
since all events were enabled by default. I will update the patch as 
required. Are there any other properties except 'disable' ?

> Arguments could be converted to an Arguments class (or similar, like
> ArgumentList) and derive the rest from there using methods (e.g., names, types,
> sizestr, arglist, etc.).
>
> If you want, I can send a patch on top of this one with that.

Any improvements are always welcome.

- Harsh

>
>
>> +
>> +# Generator that yields Event objects given a trace-events file object
>> +def read_events(fobj):
>> +    event_num = 0
>> +    for line in fobj:
>> +        if not line.strip():
>> +            continue
>> +        if line.lstrip().startswith('#'):
>> +	    continue
>> +	yield Event(event_num, line)
>> +	event_num += 1
>> +
>> +backend = ""
>> +output = ""
>> +binary = ""
>> +targettype = ""
>> +targetarch = ""
>> +probeprefix = ""
>> +
>> +def main():
>> +    global backend, output, binary, targettype, targetarch, probeprefix
>> +    supported_backends = ["simple", "nop", "stderr", "dtrace", "ust"]
>> +    short_options = "hcd"
>> +    long_options = ["stap", "backend=", "binary=", "target-arch=", "target-type=", "probe-prefix=", "list-backends", "check-backend"]
>> +    try:
>> +        opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
>> +    except getopt.GetoptError, err:
>> +        # print help information and exit:
>> +        print str(err) # will print something like "option -a not recognized"
>> +        usage()
>> +        sys.exit(2)
>> +    for opt, arg in opts:
>> +        if opt == '-h':
>> +            output = 'h'
>> +        elif opt == '-c':
>> +            output = 'c'
>> +        elif opt == '-d':
>> +            output = 'd'
>> +        elif opt == '--stap':
>> +            output = 'stap'
>> +        elif opt == '--backend':
>> +            backend = arg
>> +        elif opt == '--binary':
>> +            binary = arg
>> +        elif opt == '--target-arch':
>> +            targetarch = arg
>> +        elif opt == '--target-type':
>> +            targettype = arg
>> +        elif opt == '--probe-prefix':
>> +            probeprefix = arg
>> +        elif opt == '--list-backends':
>> +            print 'simple, nop, stderr, dtrace'
>> +            sys.exit(0)
>> +        elif opt == "--check-backend":
>> +            if any(backend in s for s in supported_backends):
>> +                sys.exit(0)
>> +            else:
>> +                sys.exit(1)
>> +        else:
>> +            #assert False, "unhandled option"
>> +            print "unhandled option: ", opt
>> +            usage()
>> +
>> +    if backend == "" or output == "":
>> +        usage()
>> +        sys.exit(0)
>> +
>> +    events = read_events(sys.stdin)
>> +    trace_gen[output]['begin']()
>> +    converters[backend][output](events)
>
> This should use the "disable" property to establish whether to use output or
> "nop".
>
>> +    trace_gen[output]['end']()
>> +    return
>> +
>> +if __name__ == "__main__":
>> +    main()
>> +
>> --
>> 1.7.1.1
>
> Lluis
>
>
Harsh Prateek Bora Jan. 11, 2012, 8:46 a.m. UTC | #6
On 01/11/2012 12:08 PM, Harsh Bora wrote:
> On 01/11/2012 04:21 AM, Lluís Vilanova wrote:
>> Harsh Prateek Bora writes:
>>
>>> Signed-off-by: Harsh Prateek Bora<harsh@linux.vnet.ibm.com>
>>> ---
>>> Makefile.objs | 6 +-
>>> Makefile.target | 10 +-
>>> configure | 7 +-
>>> scripts/tracetool | 643
>>> --------------------------------------------------
>>> scripts/tracetool.py | 585 +++++++++++++++++++++++++++++++++++++++++++++
>>> 5 files changed, 597 insertions(+), 654 deletions(-)
>>> delete mode 100755 scripts/tracetool
>>> create mode 100755 scripts/tracetool.py
>>

[...]

>>> +def main():
>>> + global backend, output, binary, targettype, targetarch, probeprefix
>>> + supported_backends = ["simple", "nop", "stderr", "dtrace", "ust"]
>>> + short_options = "hcd"
>>> + long_options = ["stap", "backend=", "binary=", "target-arch=",
>>> "target-type=", "probe-prefix=", "list-backends", "check-backend"]
>>> + try:
>>> + opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
>>> + except getopt.GetoptError, err:
>>> + # print help information and exit:
>>> + print str(err) # will print something like "option -a not recognized"
>>> + usage()
>>> + sys.exit(2)
>>> + for opt, arg in opts:
>>> + if opt == '-h':
>>> + output = 'h'
>>> + elif opt == '-c':
>>> + output = 'c'
>>> + elif opt == '-d':
>>> + output = 'd'
>>> + elif opt == '--stap':
>>> + output = 'stap'
>>> + elif opt == '--backend':
>>> + backend = arg
>>> + elif opt == '--binary':
>>> + binary = arg
>>> + elif opt == '--target-arch':
>>> + targetarch = arg
>>> + elif opt == '--target-type':
>>> + targettype = arg
>>> + elif opt == '--probe-prefix':
>>> + probeprefix = arg
>>> + elif opt == '--list-backends':
>>> + print 'simple, nop, stderr, dtrace'
>>> + sys.exit(0)
>>> + elif opt == "--check-backend":
>>> + if any(backend in s for s in supported_backends):
>>> + sys.exit(0)
>>> + else:
>>> + sys.exit(1)
>>> + else:
>>> + #assert False, "unhandled option"
>>> + print "unhandled option: ", opt
>>> + usage()
>>> +
>>> + if backend == "" or output == "":
>>> + usage()
>>> + sys.exit(0)
>>> +
>>> + events = read_events(sys.stdin)
>>> + trace_gen[output]['begin']()
>>> + converters[backend][output](events)
>>
>> This should use the "disable" property to establish whether to use
>> output or
>> "nop".

Will it be better to again break converters to their begin, 
process_line, end counterparts and call respective converters 
accordingly for enabled/disabled events, or let all the backends handle 
disabled events on their own ?

Stefan ?

- Harsh

>>
>>> + trace_gen[output]['end']()
>>> + return
>>> +
>>> +if __name__ == "__main__":
>>> + main()
>>> +
>>> --
>>> 1.7.1.1
>>
>> Lluis
>>
>>
>
>
Stefan Hajnoczi Jan. 11, 2012, 10:03 a.m. UTC | #7
On Wed, Jan 11, 2012 at 6:25 AM, Harsh Bora <harsh@linux.vnet.ibm.com> wrote:
> Also, please confirm, whether I should work on top for qemu.git or your
> tracing branch on repo.or.cz/stefanha.git ?

Please use https://github.com/stefanha/qemu/tree/tracing.  (I also
just sent a patch to update the git URL in MAINTAINERS.)

Stefan
Stefan Hajnoczi Jan. 11, 2012, 10:07 a.m. UTC | #8
On Tue, Jan 10, 2012 at 10:59 AM, Harsh Prateek Bora
<harsh@linux.vnet.ibm.com> wrote:
> +# Generator that yields Event objects given a trace-events file object
> +def read_events(fobj):
> +    event_num = 0
> +    for line in fobj:
> +        if not line.strip():
> +            continue
> +        if line.lstrip().startswith('#'):
> +           continue
> +       yield Event(event_num, line)
> +       event_num += 1

Please use 4 space indentation.  There is also a use of tab on the
converters['simple']['c'] = simple_c line earlier on.
Stefan Hajnoczi Jan. 11, 2012, 10:50 a.m. UTC | #9
On Wed, Jan 11, 2012 at 8:46 AM, Harsh Bora <harsh@linux.vnet.ibm.com> wrote:
> On 01/11/2012 12:08 PM, Harsh Bora wrote:
>>
>> On 01/11/2012 04:21 AM, Lluís Vilanova wrote:
>>>
>>> Harsh Prateek Bora writes:
>>>
>>>> Signed-off-by: Harsh Prateek Bora<harsh@linux.vnet.ibm.com>
>>>> ---
>>>> Makefile.objs | 6 +-
>>>> Makefile.target | 10 +-
>>>> configure | 7 +-
>>>> scripts/tracetool | 643
>>>> --------------------------------------------------
>>>> scripts/tracetool.py | 585 +++++++++++++++++++++++++++++++++++++++++++++
>>>> 5 files changed, 597 insertions(+), 654 deletions(-)
>>>> delete mode 100755 scripts/tracetool
>>>> create mode 100755 scripts/tracetool.py
>>>
>>>
>
> [...]
>
>>>> +def main():
>>>> + global backend, output, binary, targettype, targetarch, probeprefix
>>>> + supported_backends = ["simple", "nop", "stderr", "dtrace", "ust"]
>>>> + short_options = "hcd"
>>>> + long_options = ["stap", "backend=", "binary=", "target-arch=",
>>>> "target-type=", "probe-prefix=", "list-backends", "check-backend"]
>>>> + try:
>>>> + opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
>>>> + except getopt.GetoptError, err:
>>>> + # print help information and exit:
>>>> + print str(err) # will print something like "option -a not recognized"
>>>> + usage()
>>>> + sys.exit(2)
>>>> + for opt, arg in opts:
>>>> + if opt == '-h':
>>>> + output = 'h'
>>>> + elif opt == '-c':
>>>> + output = 'c'
>>>> + elif opt == '-d':
>>>> + output = 'd'
>>>> + elif opt == '--stap':
>>>> + output = 'stap'
>>>> + elif opt == '--backend':
>>>> + backend = arg
>>>> + elif opt == '--binary':
>>>> + binary = arg
>>>> + elif opt == '--target-arch':
>>>> + targetarch = arg
>>>> + elif opt == '--target-type':
>>>> + targettype = arg
>>>> + elif opt == '--probe-prefix':
>>>> + probeprefix = arg
>>>> + elif opt == '--list-backends':
>>>> + print 'simple, nop, stderr, dtrace'
>>>> + sys.exit(0)
>>>> + elif opt == "--check-backend":
>>>> + if any(backend in s for s in supported_backends):
>>>> + sys.exit(0)
>>>> + else:
>>>> + sys.exit(1)
>>>> + else:
>>>> + #assert False, "unhandled option"
>>>> + print "unhandled option: ", opt
>>>> + usage()
>>>> +
>>>> + if backend == "" or output == "":
>>>> + usage()
>>>> + sys.exit(0)
>>>> +
>>>> + events = read_events(sys.stdin)
>>>> + trace_gen[output]['begin']()
>>>> + converters[backend][output](events)
>>>
>>>
>>> This should use the "disable" property to establish whether to use
>>> output or
>>> "nop".
>
>
> Will it be better to again break converters to their begin, process_line,
> end counterparts and call respective converters accordingly for
> enabled/disabled events, or let all the backends handle disabled events on
> their own ?
>
> Stefan ?

I suggest adding a Event.properties field.  For most events it will be
[] but for disabled events it will be ['disable'].  In the future we
could support new keywords.

Then we can filter out the disabled events in main():

disabled_events, enabled_events = [], []
for e in read_events(sys.stdin):
    if 'disable' in e.properties:
        disabled_events.append(e)
    else:
        enabled_events.append(e)

trace_gen[output]['begin']()
converters['nop'][output](disabled_events)
converters[backend][output](enabled_events)
trace_gen[output]['end']()
Stefan Hajnoczi Jan. 11, 2012, 5:14 p.m. UTC | #10
2012/1/10 Lluís Vilanova <vilanova@ac.upc.edu>:
> Harsh Prateek Bora writes:
>
>> Signed-off-by: Harsh Prateek Bora <harsh@linux.vnet.ibm.com>
>> ---
>>  Makefile.objs        |    6 +-
>>  Makefile.target      |   10 +-
>>  configure            |    7 +-
>>  scripts/tracetool    |  643 --------------------------------------------------
>>  scripts/tracetool.py |  585 +++++++++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 597 insertions(+), 654 deletions(-)
>>  delete mode 100755 scripts/tracetool
>>  create mode 100755 scripts/tracetool.py
>
> Cannot be applied on top of Stefan's tracing branch (AFAIK, it has only one
> commit pending merge into upstream).
>
> Stefan, are you waiting for more patches to accumulate before merging your
> branch, or is it just waiting for a prediodical merge?

Both.  I should have sent a pull request for the single commit but
forgot.  Now I'm going to wait for the simpletrace v2 patches before I
send the next pull request.

Stefan
Stefan Hajnoczi Jan. 12, 2012, 9:33 a.m. UTC | #11
2012/1/10 Lluís Vilanova <vilanova@ac.upc.edu>:
> Harsh Prateek Bora writes:
>> +class Event(object):
>> +    def __init__(self, num, line):
>> +        self.num = num
>> +        self.args = get_args(line)
>> +        self.arglist = self.args.split(',')
>> +        self.name = get_name(line)
>> +        self.argc = get_argc(line)
>> +        self.argnames = get_argnames(line)
>> +        self.sizestr = calc_sizeofargs(line)
>> +        self.fmt = get_fmt(line)
>
> This is not not extracting the event properties (e.g., disable). A set of
> strings should suffice.
>
> Arguments could be converted to an Arguments class (or similar, like
> ArgumentList) and derive the rest from there using methods (e.g., names, types,
> sizestr, arglist, etc.).

Yes, that would be nice.  This will separate the trace-events parsing
from the rest of the program, which can use the Event/Argument
interface instead of parsing strings.

Stefan
diff mbox

Patch

diff --git a/Makefile.objs b/Makefile.objs
index 804bc3c..984034a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -344,12 +344,12 @@  else
 trace.h: trace.h-timestamp
 endif
 trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
 	@cmp -s $@ trace.h || cp $@ trace.h
 
 trace.c: trace.c-timestamp
 trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
 	@cmp -s $@ trace.c || cp $@ trace.c
 
 trace.o: trace.c $(GENERATED_HEADERS)
@@ -362,7 +362,7 @@  trace-dtrace.h: trace-dtrace.dtrace
 # rule file. So we use '.dtrace' instead
 trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
 trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
 	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
 
 trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
diff --git a/Makefile.target b/Makefile.target
index 1e90df7..07b21d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -50,11 +50,11 @@  TARGET_TYPE=system
 endif
 
 $(QEMU_PROG).stp:
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \
-		--$(TRACE_BACKEND) \
-		--binary $(bindir)/$(QEMU_PROG) \
-		--target-arch $(TARGET_ARCH) \
-		--target-type $(TARGET_TYPE) \
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \
+		--backend=$(TRACE_BACKEND) \
+		--binary=$(bindir)/$(QEMU_PROG) \
+		--target-arch=$(TARGET_ARCH) \
+		--target-type=$(TARGET_TYPE) \
 		--stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   $(QEMU_PROG).stp")
 else
 stap:
diff --git a/configure b/configure
index 19e8394..40a18d8 100755
--- a/configure
+++ b/configure
@@ -1040,7 +1040,7 @@  echo "  --disable-docs           disable documentation build"
 echo "  --disable-vhost-net      disable vhost-net acceleration support"
 echo "  --enable-vhost-net       enable vhost-net acceleration support"
 echo "  --enable-trace-backend=B Set trace backend"
-echo "                           Available backends:" $("$source_path"/scripts/tracetool --list-backends)
+echo "                           Available backends:" $("$source_path"/scripts/tracetool.py --list-backends)
 echo "  --with-trace-file=NAME   Full PATH,NAME of file to store traces"
 echo "                           Default:trace-<pid>"
 echo "  --disable-spice          disable spice"
@@ -2477,7 +2477,7 @@  fi
 ##########################################
 # check if trace backend exists
 
-sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
+$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend  > /dev/null 2> /dev/null
 if test "$?" -ne 0 ; then
   echo
   echo "Error: invalid trace backend"
@@ -2495,7 +2495,8 @@  if test "$trace_backend" = "ust"; then
 int main(void) { return 0; }
 EOF
   if compile_prog "" "" ; then
-    LIBS="-lust $LIBS"
+    LIBS="-lust -lurcu-bp $LIBS"
+    libs_qga+="-lust -lurcu-bp"
   else
     echo
     echo "Error: Trace backend 'ust' missing libust header files"
diff --git a/scripts/tracetool b/scripts/tracetool
deleted file mode 100755
index 4c9951d..0000000
--- a/scripts/tracetool
+++ /dev/null
@@ -1,643 +0,0 @@ 
-#!/bin/sh
-#
-# Code generator for trace events
-#
-# Copyright IBM, Corp. 2010
-#
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
-
-# Disable pathname expansion, makes processing text with '*' characters simpler
-set -f
-
-usage()
-{
-    cat >&2 <<EOF
-usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
-Generate tracing code for a file on stdin.
-
-Backends:
-  --nop     Tracing disabled
-  --simple  Simple built-in backend
-  --stderr  Stderr built-in backend
-  --ust     LTTng User Space Tracing backend
-  --dtrace  DTrace/SystemTAP backend
-
-Output formats:
-  -h     Generate .h file
-  -c     Generate .c file
-  -d     Generate .d file (DTrace only)
-  --stap Generate .stp file (DTrace with SystemTAP only)
-
-Options:
-  --binary       [path]    Full path to QEMU binary
-  --target-arch  [arch]    QEMU emulator target arch
-  --target-type  [type]    QEMU emulator target type ('system' or 'user')
-  --probe-prefix [prefix]  Prefix for dtrace probe names
-                           (default: qemu-\$targettype-\$targetarch)
-
-EOF
-    exit 1
-}
-
-# Print a line without interpreting backslash escapes
-#
-# The built-in echo command may interpret backslash escapes without an option
-# to disable this behavior.
-puts()
-{
-    printf "%s\n" "$1"
-}
-
-# Get the name of a trace event
-get_name()
-{
-    local name
-    name=${1%%\(*}
-    echo "${name##* }"
-}
-
-# Get the given property of a trace event
-# 1: trace-events line
-# 2: property name
-# -> return 0 if property is present, or 1 otherwise
-has_property()
-{
-    local props prop
-    props=${1%%\(*}
-    props=${props% *}
-    for prop in $props; do
-        if [ "$prop" = "$2" ]; then
-            return 0
-        fi
-    done
-    return 1
-}
-
-# Get the argument list of a trace event, including types and names
-get_args()
-{
-    local args
-    args=${1#*\(}
-    args=${args%%\)*}
-    echo "$args"
-}
-
-# Get the argument name list of a trace event
-get_argnames()
-{
-    local nfields field name sep
-    nfields=0
-    sep="$2"
-    for field in $(get_args "$1"); do
-        nfields=$((nfields + 1))
-
-        # Drop pointer star
-        field=${field#\*}
-
-        # Only argument names have commas at the end
-        name=${field%,}
-        test "$field" = "$name" && continue
-
-        printf "%s%s " $name $sep
-    done
-
-    # Last argument name
-    if [ "$nfields" -gt 1 ]
-    then
-        printf "%s" "$name"
-    fi
-}
-
-# Get the number of arguments to a trace event
-get_argc()
-{
-    local name argc
-    argc=0
-    for name in $(get_argnames "$1", ","); do
-        argc=$((argc + 1))
-    done
-    echo $argc
-}
-
-# Get the format string including double quotes for a trace event
-get_fmt()
-{
-    puts "${1#*)}"
-}
-
-linetoh_begin_nop()
-{
-    return
-}
-
-linetoh_nop()
-{
-    local name args
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-
-    # Define an empty function for the trace event
-    cat <<EOF
-static inline void trace_$name($args)
-{
-}
-EOF
-}
-
-linetoh_end_nop()
-{
-    return
-}
-
-linetoc_begin_nop()
-{
-    return
-}
-
-linetoc_nop()
-{
-    # No need for function definitions in nop backend
-    return
-}
-
-linetoc_end_nop()
-{
-    return
-}
-
-linetoh_begin_simple()
-{
-    cat <<EOF
-#include "trace/simple.h"
-EOF
-
-    simple_event_num=0
-}
-
-cast_args_to_uint64_t()
-{
-    local arg
-    for arg in $(get_argnames "$1", ","); do
-        printf "%s" "(uint64_t)(uintptr_t)$arg"
-    done
-}
-
-linetoh_simple()
-{
-    local name args argc trace_args
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argc=$(get_argc "$1")
-
-    trace_args="$simple_event_num"
-    if [ "$argc" -gt 0 ]
-    then
-        trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
-    fi
-
-    cat <<EOF
-static inline void trace_$name($args)
-{
-    trace$argc($trace_args);
-}
-EOF
-
-    simple_event_num=$((simple_event_num + 1))
-}
-
-linetoh_end_simple()
-{
-    cat <<EOF
-#define NR_TRACE_EVENTS $simple_event_num
-extern TraceEvent trace_list[NR_TRACE_EVENTS];
-EOF
-}
-
-linetoc_begin_simple()
-{
-    cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
-    simple_event_num=0
-
-}
-
-linetoc_simple()
-{
-    local name
-    name=$(get_name "$1")
-    cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
-    simple_event_num=$((simple_event_num + 1))
-}
-
-linetoc_end_simple()
-{
-    cat <<EOF
-};
-EOF
-}
-
-#STDERR
-linetoh_begin_stderr()
-{
-    cat <<EOF
-#include <stdio.h>
-#include "trace/stderr.h"
-
-extern TraceEvent trace_list[];
-EOF
-
-    stderr_event_num=0
-}
-
-linetoh_stderr()
-{
-    local name args argnames argc fmt
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1" ",")
-    argc=$(get_argc "$1")
-    fmt=$(get_fmt "$1")
-
-    if [ "$argc" -gt 0 ]; then
-        argnames=", $argnames"
-    fi
-
-    cat <<EOF
-static inline void trace_$name($args)
-{
-    if (trace_list[$stderr_event_num].state != 0) {
-        fprintf(stderr, "$name " $fmt "\n" $argnames);
-    }
-}
-EOF
-    stderr_event_num=$((stderr_event_num + 1))
-
-}
-
-linetoh_end_stderr()
-{
-    cat <<EOF
-#define NR_TRACE_EVENTS $stderr_event_num
-EOF
-}
-
-linetoc_begin_stderr()
-{
-    cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
-    stderr_event_num=0
-}
-
-linetoc_stderr()
-{
-    local name
-    name=$(get_name "$1")
-    cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
-    stderr_event_num=$(($stderr_event_num + 1))
-}
-
-linetoc_end_stderr()
-{
-    cat <<EOF
-};
-EOF
-}
-#END OF STDERR
-
-# Clean up after UST headers which pollute the namespace
-ust_clean_namespace() {
-    cat <<EOF
-#undef mutex_lock
-#undef mutex_unlock
-#undef inline
-#undef wmb
-EOF
-}
-
-linetoh_begin_ust()
-{
-    echo "#include <ust/tracepoint.h>"
-    ust_clean_namespace
-}
-
-linetoh_ust()
-{
-    local name args argnames
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1", ",")
-
-    cat <<EOF
-DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
-#define trace_$name trace_ust_$name
-EOF
-}
-
-linetoh_end_ust()
-{
-    return
-}
-
-linetoc_begin_ust()
-{
-    cat <<EOF
-#include <ust/marker.h>
-$(ust_clean_namespace)
-#include "trace.h"
-EOF
-}
-
-linetoc_ust()
-{
-    local name args argnames fmt
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1", ",")
-    [ -z "$argnames" ] || argnames=", $argnames"
-    fmt=$(get_fmt "$1")
-
-    cat <<EOF
-DEFINE_TRACE(ust_$name);
-
-static void ust_${name}_probe($args)
-{
-    trace_mark(ust, $name, $fmt$argnames);
-}
-EOF
-
-    # Collect names for later
-    names="$names $name"
-}
-
-linetoc_end_ust()
-{
-    cat <<EOF
-static void __attribute__((constructor)) trace_init(void)
-{
-EOF
-
-    for name in $names; do
-        cat <<EOF
-    register_trace_ust_$name(ust_${name}_probe);
-EOF
-    done
-
-    echo "}"
-}
-
-linetoh_begin_dtrace()
-{
-    cat <<EOF
-#include "trace-dtrace.h"
-EOF
-}
-
-linetoh_dtrace()
-{
-    local name args argnames nameupper
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    argnames=$(get_argnames "$1", ",")
-
-    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
-
-    # Define an empty function for the trace event
-    cat <<EOF
-static inline void trace_$name($args) {
-    if (QEMU_${nameupper}_ENABLED()) {
-        QEMU_${nameupper}($argnames);
-    }
-}
-EOF
-}
-
-linetoh_end_dtrace()
-{
-    return
-}
-
-linetoc_begin_dtrace()
-{
-    return
-}
-
-linetoc_dtrace()
-{
-    # No need for function definitions in dtrace backend
-    return
-}
-
-linetoc_end_dtrace()
-{
-    return
-}
-
-linetod_begin_dtrace()
-{
-    cat <<EOF
-provider qemu {
-EOF
-}
-
-linetod_dtrace()
-{
-    local name args
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-
-    # DTrace provider syntax expects foo() for empty
-    # params, not foo(void)
-    if [ "$args" = "void" ]; then
-       args=""
-    fi
-
-    # Define prototype for probe arguments
-    cat <<EOF
-        probe $name($args);
-EOF
-}
-
-linetod_end_dtrace()
-{
-    cat <<EOF
-};
-EOF
-}
-
-linetostap_begin_dtrace()
-{
-    return
-}
-
-linetostap_dtrace()
-{
-    local i arg name args arglist
-    name=$(get_name "$1")
-    args=$(get_args "$1")
-    arglist=$(get_argnames "$1", "")
-
-    # Define prototype for probe arguments
-    cat <<EOF
-probe $probeprefix.$name = process("$binary").mark("$name")
-{
-EOF
-
-    i=1
-    for arg in $arglist
-    do
-        # 'limit' is a reserved keyword
-        if [ "$arg" = "limit" ]; then
-          arg="_limit"
-        fi
-        cat <<EOF
-  $arg = \$arg$i;
-EOF
-        i="$((i+1))"
-    done
-
-    cat <<EOF
-}
-EOF
-}
-
-linetostap_end_dtrace()
-{
-    return
-}
-
-# Process stdin by calling begin, line, and end functions for the backend
-convert()
-{
-    local begin process_line end str disable
-    begin="lineto$1_begin_$backend"
-    process_line="lineto$1_$backend"
-    end="lineto$1_end_$backend"
-
-    "$begin"
-
-    while read -r str; do
-        # Skip comments and empty lines
-        test -z "${str%%#*}" && continue
-
-        echo
-        # Process the line.  The nop backend handles disabled lines.
-        if has_property "$str" "disable"; then
-            "lineto$1_nop" "$str"
-        else
-            "$process_line" "$str"
-        fi
-    done
-
-    echo
-    "$end"
-}
-
-tracetoh()
-{
-    cat <<EOF
-#ifndef TRACE_H
-#define TRACE_H
-
-/* This file is autogenerated by tracetool, do not edit. */
-
-#include "qemu-common.h"
-EOF
-    convert h
-    echo "#endif /* TRACE_H */"
-}
-
-tracetoc()
-{
-    echo "/* This file is autogenerated by tracetool, do not edit. */"
-    convert c
-}
-
-tracetod()
-{
-    if [ $backend != "dtrace" ]; then
-       echo "DTrace probe generator not applicable to $backend backend"
-       exit 1
-    fi
-    echo "/* This file is autogenerated by tracetool, do not edit. */"
-    convert d
-}
-
-tracetostap()
-{
-    if [ $backend != "dtrace" ]; then
-       echo "SystemTAP tapset generator not applicable to $backend backend"
-       exit 1
-    fi
-    if [ -z "$binary" ]; then
-       echo "--binary is required for SystemTAP tapset generator"
-       exit 1
-    fi
-    if [ -z "$probeprefix" -a -z "$targettype" ]; then
-       echo "--target-type is required for SystemTAP tapset generator"
-       exit 1
-    fi
-    if [ -z "$probeprefix" -a -z "$targetarch" ]; then
-       echo "--target-arch is required for SystemTAP tapset generator"
-       exit 1
-    fi
-    if [ -z "$probeprefix" ]; then
-        probeprefix="qemu.$targettype.$targetarch";
-    fi
-    echo "/* This file is autogenerated by tracetool, do not edit. */"
-    convert stap
-}
-
-
-backend=
-output=
-binary=
-targettype=
-targetarch=
-probeprefix=
-
-
-until [ -z "$1" ]
-do
-  case "$1" in
-    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
-
-    "--binary") shift ; binary="$1" ;;
-    "--target-arch") shift ; targetarch="$1" ;;
-    "--target-type") shift ; targettype="$1" ;;
-    "--probe-prefix") shift ; probeprefix="$1" ;;
-
-    "-h" | "-c" | "-d") output="${1#-}" ;;
-    "--stap") output="${1#--}" ;;
-
-    "--check-backend") exit 0 ;; # used by ./configure to test for backend
-
-    "--list-backends") # used by ./configure to list available backends
-          echo "nop simple stderr ust dtrace"
-          exit 0
-          ;;
-
-    *)
-      usage;;
-  esac
-  shift
-done
-
-if [ "$backend" = "" -o "$output" = "" ]; then
-  usage
-fi
-
-gen="traceto$output"
-"$gen"
-
-exit 0
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
new file mode 100755
index 0000000..6874f66
--- /dev/null
+++ b/scripts/tracetool.py
@@ -0,0 +1,585 @@ 
+#!/usr/bin/env python
+# Python based tracetool script (Code generator for trace events)
+#
+# Copyright IBM, Corp. 2011
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+#
+
+import sys
+import getopt
+
+def usage():
+    print "Tracetool: Generate tracing code for trace events file on stdin"
+    print "Usage:"
+    print sys.argv[0], " --backend=[nop|simple|stderr|dtrace|ust] [-h|-c|-d|--stap]"
+    print '''
+Backends:
+  --nop     Tracing disabled
+  --simple  Simple built-in backend
+  --stderr  Stderr built-in backend
+  --dtrace  DTrace/SystemTAP backend
+  --ust     LTTng User Space Tracing backend
+
+Output formats:
+  -h     Generate .h file
+  -c     Generate .c file
+  -d     Generate .d file (DTrace only)
+  --stap Generate .stp file (DTrace with SystemTAP only)
+
+Options:
+  --binary       [path]    Full path to QEMU binary
+  --target-arch  [arch]    QEMU emulator target arch
+  --target-type  [type]    QEMU emulator target type ('system' or 'user')
+  --probe-prefix [prefix]  Prefix for dtrace probe names
+                           (default: qemu-targettype-targetarch)
+'''
+    sys.exit(1)
+
+def get_name(line, sep='('):
+    head, sep, tail = line.partition(sep)
+    return head
+
+def get_args(line, sep1='(', sep2=')'):
+    head, sep1, tail = line.partition(sep1)
+    args, sep2, fmt_str = tail.partition(sep2)
+    return args
+
+def get_argnames(line, sep=','):
+    nfields = 0
+    str = []
+    args = get_args(line)
+    for field in args.split():
+      nfields = nfields + 1
+      # Drop pointer star
+      type, ptr, tail = field.partition('*')
+      if type != field:
+        field = tail
+
+      name, sep, tail = field.partition(',')
+
+      if name == field:
+        continue
+      str.append(name)
+      str.append(", ")
+
+    if nfields > 1:
+      str.append(name)
+      return ''.join(str)
+    else:
+      return ''
+
+def get_argc(line):
+    argc = 0
+    argnames = get_argnames(line)
+    if argnames:
+      for name in argnames.split(','):
+        argc = argc + 1
+    return argc
+
+def get_fmt(line, sep=')'):
+    event, sep, fmt = line.partition(sep)
+    return fmt
+
+def calc_sizeofargs(line):
+    args = get_args(line)
+    argc = get_argc(line)
+    strtype = ('const char*', 'char*', 'const char *', 'char *')
+    str = []
+    newstr = ""
+    if argc > 0:
+      str = args.split(',')
+      for elem in str:
+        if elem.lstrip().startswith(strtype): #strings
+          type, sep, var = elem.rpartition('*')
+          newstr = newstr+"4 + strlen("+var.lstrip()+") + "
+        #elif '*' in elem:
+        #  newstr = newstr + "4 + " # pointer vars
+        else:
+          #type, sep, var = elem.rpartition(' ')
+          #newstr = newstr+"sizeof("+type.lstrip()+") + "
+          newstr = newstr + '8 + '
+    newstr = newstr + '0' # for last +
+    return newstr
+
+
+def trace_h_begin():
+    print '''#ifndef TRACE_H
+#define TRACE_H
+
+/* This file is autogenerated by tracetool, do not edit. */
+
+#include "qemu-common.h"'''
+    return
+
+def trace_h_end():
+    print '#endif /* TRACE_H */'
+    return
+
+def trace_c_begin():
+    print '/* This file is autogenerated by tracetool, do not edit. */'
+    return
+
+def trace_c_end():
+    # nop, required for trace_gen
+    return
+
+def nop_h(events):
+    print
+    for event in events:
+        print '''static inline void trace_%(name)s(%(args)s)
+{
+}
+''' % {
+    'name': event.name,
+    'args': event.args
+}
+    return
+
+def nop_c(events):
+    # nop, reqd for converters
+    return
+
+
+def simple_h(events):
+    print '#include "trace/simple.h"'
+    print
+    for event in events:
+        print 'void trace_%(name)s(%(args)s);' % {
+    'name': event.name,
+    'args': event.args
+}
+    print
+    print '#define NR_TRACE_EVENTS %d' % (event.num + 1)
+    print 'extern TraceEvent trace_list[NR_TRACE_EVENTS];'
+
+    return
+
+def is_string(arg):
+    strtype = ('const char*', 'char*', 'const char *', 'char *')
+    if arg.lstrip().startswith(strtype):
+        return True
+    else:
+        return False
+
+def simple_c(events):
+    rec_off = 0
+    print '#include "trace.h"'
+    print '#include "trace/simple.h"'
+    print
+    print 'TraceEvent trace_list[] = {'
+    print
+    eventlist = list(events)
+    for event in eventlist:
+        print '{.tp_name = "%(name)s", .state=0},' % {
+    'name': event.name
+}
+        print
+    print '};'
+    print
+    for event in eventlist:
+        argc = event.argc
+        print '''void trace_%(name)s(%(args)s)
+{
+    unsigned int tbuf_idx, rec_off;
+    uint64_t var64 __attribute__ ((unused));
+    uint64_t pvar64 __attribute__ ((unused));
+    uint32_t slen __attribute__ ((unused));
+
+    if (!trace_list[%(event_id)s].state) {
+        return;
+    }
+''' % {
+    'name': event.name,
+    'args': event.args,
+    'event_id': event.num,
+}
+        print '''
+    tbuf_idx = trace_alloc_record(%(event_id)s, %(sizestr)s);
+    rec_off = (tbuf_idx + ST_V2_REC_HDR_LEN) %% TRACE_BUF_LEN; /* seek record header */
+''' % {'event_id': event.num, 'sizestr': event.sizestr,}
+
+        if argc > 0:
+            str = event.arglist
+            for elem in str:
+                if is_string(elem): # if string
+                    type, sep, var = elem.rpartition('*')
+                    print '''
+    slen = strlen(%(var)s);
+    write_to_buffer(rec_off, (uint8_t*)&slen, sizeof(slen));
+    rec_off += sizeof(slen);''' % {
+    'var': var.lstrip()
+}
+                    print '''
+    write_to_buffer(rec_off, (uint8_t*)%(var)s, slen);
+    rec_off += slen;''' % {
+    'var': var.lstrip()
+}
+                elif '*' in elem: # pointer var (not string)
+                    type, sep, var = elem.rpartition('*')
+                    print '''
+    pvar64 = (uint64_t)(uint64_t*)%(var)s;
+    write_to_buffer(rec_off, (uint8_t*)&pvar64, sizeof(uint64_t));
+    rec_off += sizeof(uint64_t);''' % {
+    'var': var.lstrip()
+}
+                else: # primitive data type
+                    type, sep, var = elem.rpartition(' ')
+                    print '''
+    var64 = (uint64_t)%(var)s;
+    write_to_buffer(rec_off, (uint8_t*)&var64, sizeof(uint64_t));
+    rec_off += sizeof(uint64_t);''' % {
+    'var': var.lstrip()
+}
+        print '''
+    trace_mark_record_complete(tbuf_idx);'''
+        print '}'
+        print
+
+    return
+
+def stderr_h(events):
+    print '''#include <stdio.h>
+#include "trace/stderr.h"
+
+extern TraceEvent trace_list[];'''
+    for event in events:
+        argnames = event.argnames
+        if event.argc > 0:
+            argnames = ', ' + event.argnames
+        else:
+            argnames = ''
+        print '''
+static inline void trace_%(name)s(%(args)s)
+{
+    if (trace_list[%(event_num)s].state != 0) {
+        fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);
+    }
+}''' % {
+    'name': event.name,
+    'args': event.args,
+    'event_num': event.num,
+    'fmt': event.fmt.rstrip('\n'),
+    'argnames': argnames
+}
+    print
+    print '#define NR_TRACE_EVENTS %d' % (event.num + 1)
+
+def stderr_c(events):
+    print '''#include "trace.h"
+
+TraceEvent trace_list[] = {
+'''
+    for event in events:
+        print '{.tp_name = "%(name)s", .state=0},' % {
+    'name': event.name
+}
+        print
+    print '};'
+
+def ust_h(events):
+    print '''#include <ust/tracepoint.h>
+#undef mutex_lock
+#undef mutex_unlock
+#undef inline
+#undef wmb'''
+
+    for event in events:
+        if event.argc > 0:
+            print '''
+DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));
+#define trace_%(name)s trace_ust_%(name)s''' % {
+    'name': event.name,
+    'args': event.args,
+    'argnames': event.argnames
+}
+        else:
+            print '''
+_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);
+#define trace_%(name)s trace_ust_%(name)s''' % {
+    'name': event.name,
+}
+    print
+    return
+
+def ust_c(events):
+    print '''#include <ust/marker.h>
+#undef mutex_lock
+#undef mutex_unlock
+#undef inline
+#undef wmb
+#include "trace.h"'''
+    eventlist = list(events)
+    for event in eventlist:
+        argnames = event.argnames
+        if event.argc > 0:
+            argnames = ', ' + event.argnames
+            print '''
+DEFINE_TRACE(ust_%(name)s);
+
+static void ust_%(name)s_probe(%(args)s)
+{
+    trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);
+}''' % {
+    'name': event.name,
+    'args': event.args,
+    'fmt': event.fmt.rstrip('\n'),
+    'argnames': argnames
+}
+        else:
+            print '''
+DEFINE_TRACE(ust_%(name)s);
+
+static void ust_%(name)s_probe(%(args)s)
+{
+    trace_mark(ust, %(name)s, UST_MARKER_NOARGS);
+}''' % {
+    'name': event.name,
+    'args': event.args,
+}
+
+    # register probes
+    print '''
+static void __attribute__((constructor)) trace_init(void)
+{'''
+    for event in eventlist:
+        print '    register_trace_ust_%(name)s(ust_%(name)s_probe);' % {
+    'name': event.name
+}
+    print '}'
+
+    return
+
+def dtrace_h(events):
+    print '#include "trace-dtrace.h"'
+    print
+    for event in events:
+        print '''static inline void trace_%(name)s(%(args)s) {
+    if (QEMU_%(uppername)s_ENABLED()) {
+        QEMU_%(uppername)s(%(argnames)s);
+    }
+}
+''' % {
+    'name': event.name,
+    'args': event.args,
+    'uppername': event.name.upper(),
+    'argnames': event.argnames,
+}
+
+def dtrace_c(events):
+    return # No need for function definitions in dtrace backend
+
+def dtrace_d(events):
+    print 'provider qemu {'
+    for event in events:
+        args = event.args
+
+        # DTrace provider syntax expects foo() for empty
+        # params, not foo(void)
+        if args == 'void':
+            args = ''
+
+        # Define prototype for probe arguments
+        print '''
+        probe %(name)s(%(args)s);''' % {
+        'name': event.name,
+        'args': args
+}
+    print
+    print '};'
+    return
+
+def dtrace_stp(events):
+    for event in events:
+        # Define prototype for probe arguments
+        print '''
+probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")
+{''' % {
+    'probeprefix': probeprefix,
+    'name': event.name,
+    'binary': binary
+}
+        i = 1
+        if event.argc > 0:
+            for arg in event.argnames.split(','):
+                # 'limit' is a reserved keyword
+                if arg == 'limit':
+                    arg = '_limit'
+                print '  %s = $arg%d;' % (arg.lstrip(), i)
+                i += 1
+        print '}'
+    print
+    return
+
+def trace_stap_begin():
+    global probeprefix
+    if backend != "dtrace":
+        print 'SystemTAP tapset generator not applicable to %s backend' % backend
+        sys.exit(1)
+    if binary == "":
+        print '--binary is required for SystemTAP tapset generator'
+        sys.exit(1)
+    if ((probeprefix == "") and (targettype == "")):
+        print '--target-type is required for SystemTAP tapset generator'
+        sys.exit(1)
+    if ((probeprefix == "") and (targetarch == "")):
+        print '--target-arch is required for SystemTAP tapset generator'
+        sys.exit(1)
+    if probeprefix == "":
+        probeprefix = 'qemu.' + targettype + '.' + targetarch
+    print '/* This file is autogenerated by tracetool, do not edit. */'
+    return
+
+def trace_stap_end():
+    return #nop, reqd for trace_gen
+
+def trace_d_begin():
+    if backend != 'dtrace':
+        print 'DTrace probe generator not applicable to %s backend' % backend
+        sys.exit(1)
+    print '/* This file is autogenerated by tracetool, do not edit. */'
+
+def trace_d_end():
+    return #nop, reqd for trace_gen
+
+
+# Registry of backends and their converter functions
+converters = {
+    'simple': {
+        'h': simple_h,
+	'c': simple_c,
+    },
+
+    'nop': {
+        'h': nop_h,
+        'c': nop_c,
+    },
+
+    'stderr': {
+        'h': stderr_h,
+        'c': stderr_c,
+    },
+
+    'dtrace': {
+        'h': dtrace_h,
+        'c': dtrace_c,
+        'd': dtrace_d,
+        'stap': dtrace_stp
+    },
+
+    'ust': {
+        'h': ust_h,
+        'c': ust_c,
+    },
+
+}
+
+# Trace file header and footer code generators
+trace_gen = {
+    'h': {
+        'begin': trace_h_begin,
+        'end': trace_h_end,
+    },
+    'c': {
+        'begin': trace_c_begin,
+        'end': trace_c_end,
+    },
+    'd': {
+        'begin': trace_d_begin,
+        'end': trace_d_end,
+    },
+    'stap': {
+        'begin': trace_stap_begin,
+        'end': trace_stap_end,
+    },
+}
+
+# A trace event
+class Event(object):
+    def __init__(self, num, line):
+        self.num = num
+        self.args = get_args(line)
+        self.arglist = self.args.split(',')
+        self.name = get_name(line)
+        self.argc = get_argc(line)
+        self.argnames = get_argnames(line)
+        self.sizestr = calc_sizeofargs(line)
+        self.fmt = get_fmt(line)
+
+# Generator that yields Event objects given a trace-events file object
+def read_events(fobj):
+    event_num = 0
+    for line in fobj:
+        if not line.strip():
+            continue
+        if line.lstrip().startswith('#'):
+	    continue
+	yield Event(event_num, line)
+	event_num += 1
+
+backend = ""
+output = ""
+binary = ""
+targettype = ""
+targetarch = ""
+probeprefix = ""
+
+def main():
+    global backend, output, binary, targettype, targetarch, probeprefix
+    supported_backends = ["simple", "nop", "stderr", "dtrace", "ust"]
+    short_options = "hcd"
+    long_options = ["stap", "backend=", "binary=", "target-arch=", "target-type=", "probe-prefix=", "list-backends", "check-backend"]
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
+    except getopt.GetoptError, err:
+        # print help information and exit:
+        print str(err) # will print something like "option -a not recognized"
+        usage()
+        sys.exit(2)
+    for opt, arg in opts:
+        if opt == '-h':
+            output = 'h'
+        elif opt == '-c':
+            output = 'c'
+        elif opt == '-d':
+            output = 'd'
+        elif opt == '--stap':
+            output = 'stap'
+        elif opt == '--backend':
+            backend = arg
+        elif opt == '--binary':
+            binary = arg
+        elif opt == '--target-arch':
+            targetarch = arg
+        elif opt == '--target-type':
+            targettype = arg
+        elif opt == '--probe-prefix':
+            probeprefix = arg
+        elif opt == '--list-backends':
+            print 'simple, nop, stderr, dtrace'
+            sys.exit(0)
+        elif opt == "--check-backend":
+            if any(backend in s for s in supported_backends):
+                sys.exit(0)
+            else:
+                sys.exit(1)
+        else:
+            #assert False, "unhandled option"
+            print "unhandled option: ", opt
+            usage()
+
+    if backend == "" or output == "":
+        usage()
+        sys.exit(0)
+
+    events = read_events(sys.stdin)
+    trace_gen[output]['begin']()
+    converters[backend][output](events)
+    trace_gen[output]['end']()
+    return
+
+if __name__ == "__main__":
+    main()
+