qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 3/3] scripts/qemu-gdb: Add support for printing


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH 3/3] scripts/qemu-gdb: Add support for printing trace events
Date: Tue, 22 Sep 2015 16:52:26 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0


On 14/05/2015 18:43, Peter Maydell wrote:
> Add two new commands to our gdb support:
>  qemu trace-enable eventname
>  qemu trace-disable eventname
> 
> which allow dynamically enabling and disabling printing of QEMU
> trace events during a debugging session. These work with the
> "null" trace backend, by putting breakpoints on the stub
> trace_eventname() functions.
> 
> Signed-off-by: Peter Maydell <address@hidden>
> ---
>  scripts/qemu-gdb.py      |   4 +-
>  scripts/qemugdb/trace.py | 188 
> +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 191 insertions(+), 1 deletion(-)
>  create mode 100644 scripts/qemugdb/trace.py
> 
> diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py
> index 1c94b2a..6d27c06 100644
> --- a/scripts/qemu-gdb.py
> +++ b/scripts/qemu-gdb.py
> @@ -23,7 +23,7 @@ import os, sys
>  
>  sys.path.append(os.path.dirname(__file__))
>  
> -from qemugdb import mtree, coroutine
> +from qemugdb import mtree, coroutine, trace
>  
>  class QemuCommand(gdb.Command):
>      '''Prefix for QEMU debug support commands'''
> @@ -34,3 +34,5 @@ class QemuCommand(gdb.Command):
>  QemuCommand()
>  coroutine.CoroutineCommand()
>  mtree.MtreeCommand()
> +trace.TraceEnableCommand()
> +trace.TraceDisableCommand()
> diff --git a/scripts/qemugdb/trace.py b/scripts/qemugdb/trace.py
> new file mode 100644
> index 0000000..24543e1
> --- /dev/null
> +++ b/scripts/qemugdb/trace.py
> @@ -0,0 +1,188 @@
> +#!/usr/bin/python
> +
> +# GDB debugging support: selecting printing of trace events
> +#
> +# Copyright (c) 2015 Linaro Ltd
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License
> +# as published by the Free Software Foundation; either version 2
> +# of the License, or (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, see
> +# <http://www.gnu.org/licenses/gpl-2.0.html>
> +
> +# qemu trace-enable trace-event-name
> +# qemu trace-disable trace-event-name
> +#  * enable/disable printing of tracing for QEMU trace events (works
> +#    even if QEMU was built with the null trace backend; may not work
> +#    with non-debug QEMU builds)
> +
> +import gdb
> +import re, os
> +
> +# Assume the trace-events file is at ../../ relative to where we are
> +
> +trace_events_filename = os.path.join(os.path.dirname(__file__),
> +                                     os.pardir,os.pardir,
> +                                     "trace-events")
> +
> +def gdb_bp_list():
> +    '''Like gdb.breakpoints(), but return empty list if no bps, not None'''
> +    # The point is that this is always iterable
> +    bplist = gdb.breakpoints()
> +    if not bplist:
> +        return []
> +    return bplist
> +
> +class TraceEventInfo:
> +    def __init__(self, name, formatstring, arglist):
> +        self.name = name
> +        self.formatstring = formatstring
> +        self.arglist = arglist
> +        self.argstr = ", ".join(arglist)
> +        if self.argstr != "":
> +            self.argstr = ", " + self.argstr
> +
> +# Hash of trace events read in from the 'trace-events' file;
> +# values are TraceEventInfo objects
> +trace_events = {}
> +
> +def extract_identifier(s):
> +    '''Extract the identifier from a C argument declaration'''
> +    # That is, given "const char *filename" return "filename".
> +    r = re.sub(r'.*?([a-zA-Z_][a-zA-Z_0-9]*)\s*$', r'\1', s)
> +    if r == 'void':
> +        return None
> +    return r
> +
> +# Preprocessor symbols which we know about.
> +# These should work for both 32 bit and 64 bit Linux, at least.
> +# If we needed to, we could determine whether the target was
> +# 32 or 64 bit with
> +#     is_64bit = gdb.lookup_type('void').pointer().sizeof == 8
> +# but we can get away without it.
> +fmtstr_dict = {
> +    "PRIu8":"u",
> +    "PRIx32":"x",
> +    "PRIu32":"u",
> +    "PRId32":"d",
> +    "PRIx64":"llx",
> +    "PRIu64":"llu",
> +    "PRId64":"lld",
> +    "PRIxPTR":"llx",
> +}
> +
> +def fixup_fmtstr(s):
> +    # fmtstr needs to have leading space and " removed,
> +    # trailing " removed, and handling of interpolated PRIxfoo
> +    # dealt with (including trailing PRIxfoo)
> +    inquotes = False
> +    inescape = False
> +    new = ""
> +    sym = ""
> +    for c in s:
> +        if inquotes:
> +            if inescape:
> +                new = new + c
> +                inescape = False
> +            elif c == '\\':
> +                inescape = True
> +                new = new + c
> +            elif c == '"':
> +                inquotes = False
> +                sym = ""
> +            else:
> +                new = new + c
> +        else:
> +            if c == '"':
> +                # end of unquoted section
> +                sym = sym.strip()
> +                if sym != "":
> +                    new = new + fmtstr_dict[sym]
> +                inquotes = True
> +            else:
> +                sym = sym + c
> +
> +    # gdb printf doesn't understand the 'z' length modifier,
> +    # so convert to 'l'
> +    return re.sub(r'(?<!%)%z', r'%l', new)
> +    return new
> +
> +def read_trace_events_file(filename):
> +    '''Populate the trace_events dictionary from the specified file'''
> +    global trace_events
> +    trace_events = {}
> +    f = open(filename)
> +    for line in iter(f):
> +        try:
> +            line = line.strip()
> +            if line == "" or line.startswith('#'):
> +                continue
> +
> +            # Very ugly ad-hoc parsing
> +            (name, rest) = line.split('(', 1)
> +            (rest, fmtstr) = rest.split(')', 1)
> +
> +            fmtstr = fixup_fmtstr(fmtstr)
> +
> +            arglist = rest.split(',')
> +            arglist = [extract_identifier(x) for x in arglist]
> +            arglist = [x for x in arglist if x is not None]
> +            trace_events[name] = TraceEventInfo(name, fmtstr, arglist)
> +        except:
> +            gdb.write('Warning: ignoring line: %s\n' % line)
> +            raise
> +
> +class QemuTraceBreakpoint(gdb.Breakpoint):
> +    def __init__(self, eventname):
> +        self.event = trace_events[eventname]
> +        spec = "trace_" + eventname
> +        # might want to make these internal bps later
> +        gdb.Breakpoint.__init__(self, spec, gdb.BP_BREAKPOINT, False)
> +
> +    def stop(self):
> +        gdb.write('%s: ' % self.event.name)
> +        gdb.execute('printf "%s\\n"%s'
> +                    % (self.event.formatstring, self.event.argstr))
> +        # Tell gdb not to actually stop here
> +        return False
> +
> +class TraceEnableCommand(gdb.Command):
> +    '''Enable in-gdb tracing of the specified QEMU trace event'''
> +    def __init__(self):
> +        gdb.Command.__init__(self, 'qemu trace-enable', gdb.COMMAND_DATA,
> +                             gdb.COMPLETE_NONE)
> +
> +    def invoke(self, arg, from_tty):
> +        # place breakpoint on function trace_<eventname>
> +        # set up breakpoint to print info and continue
> +        # add bp to hash table with key being the event name
> +        if arg not in trace_events:
> +            gdb.write('Unknown trace event %s\n')
> +            return
> +        gdb.write("Enabled trace event %s\n" % arg)
> +        QemuTraceBreakpoint(arg)
> +
> +class TraceDisableCommand(gdb.Command):
> +    '''Disable in-gdb tracing of the specified QEMU trace event'''
> +    def __init__(self):
> +        gdb.Command.__init__(self, 'qemu trace-disable', gdb.COMMAND_DATA,
> +                             gdb.COMPLETE_NONE)
> +
> +    def invoke(self, arg, from_tty):
> +        # delete the bp set on trace_<eventname> by the enable command
> +        for bp in gdb_bp_list():
> +            if isinstance(bp,  QemuTraceBreakpoint) and bp.event.name == arg:
> +                bp.delete()
> +                gdb.write("Disabled trace event %s\n" % arg)
> +                return
> +        gdb.write("Can't disable trace event %s: unknown or not enabled\n" % 
> arg)
> +
> +read_trace_events_file(trace_events_filename)
> 

Hi Peter,

what happened to this patch?

Paolo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]