[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
- Re: [Qemu-devel] [PATCH 3/3] scripts/qemu-gdb: Add support for printing trace events,
Paolo Bonzini <=