From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3955 invoked by alias); 21 Feb 2011 13:57:50 -0000 Mailing-List: contact archer-commits-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: Received: (qmail 3927 invoked by uid 9514); 21 Feb 2011 13:57:49 -0000 Date: Mon, 21 Feb 2011 13:57:00 -0000 Message-ID: <20110221135749.3912.qmail@sourceware.org> From: pmuldoon@sourceware.org To: archer-commits@sourceware.org Subject: [SCM] archer-pmuldoon-python-backtrace: Add Tom Tromey's remodelled backtrace reference implementation as extracted from archer-tromey-python and patches to the list. X-Git-Refname: refs/heads/archer-pmuldoon-python-backtrace X-Git-Reftype: branch X-Git-Oldrev: 09363f5ea451879d3bc391b32385a58c58021ebb X-Git-Newrev: 130e8c86b268f68bf0b73615c9d0446a87377c62 X-SW-Source: 2011-q1/txt/msg00143.txt.bz2 List-Id: The branch, archer-pmuldoon-python-backtrace has been updated via 130e8c86b268f68bf0b73615c9d0446a87377c62 (commit) from 09363f5ea451879d3bc391b32385a58c58021ebb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit 130e8c86b268f68bf0b73615c9d0446a87377c62 Author: Phil Muldoon Date: Mon Feb 21 13:56:23 2011 +0000 Add Tom Tromey's remodelled backtrace reference implementation as extracted from archer-tromey-python and patches to the list. ----------------------------------------------------------------------- Summary of changes: gdb/python/lib/gdb/command/backtrace.py | 151 +++++++++++++++++++ gdb/python/lib/gdb/command/upto.py | 128 +++++++++++++++++ gdb/python/lib/gdb/frame.py | 238 +++++++++++++++++++++++++++++++ 3 files changed, 517 insertions(+), 0 deletions(-) create mode 100644 gdb/python/lib/gdb/command/backtrace.py create mode 100644 gdb/python/lib/gdb/command/upto.py create mode 100644 gdb/python/lib/gdb/frame.py First 500 lines of diff: diff --git a/gdb/python/lib/gdb/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py new file mode 100644 index 0000000..f739d1c --- /dev/null +++ b/gdb/python/lib/gdb/command/backtrace.py @@ -0,0 +1,151 @@ +# New backtrace command. + +# Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + +# 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 3 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 . + +import gdb +import gdb.frame +import itertools +import sys + +class ReverseBacktraceParameter(gdb.Parameter): + """The new-backtrace command can show backtraces in 'reverse' order. +This means that the innermost frame will be printed last. +Note that reverse backtraces are more expensive to compute.""" + + set_doc = "Enable or disable reverse backtraces." + show_doc = "Show whether backtraces will be printed in reverse order." + + def __init__(self): + super(ReverseBacktraceParameter, self).__init__("reverse-backtrace", + gdb.COMMAND_STACK, + gdb.PARAM_BOOLEAN) + + # Default to compatibility with gdb. + self.value = False + +class FilteringBacktrace(gdb.Command): + """Print backtrace of all stack frames, or innermost COUNT frames. + +Usage: new-backtrace [COUNT|QUALIFIER]... + +With a negative argument, print outermost -COUNT frames. + +Valid qualifiers are: + + full Also print the values of the local variables. + raw Avoid any filtering by loadable modules. + reverse Reverse the stack trace. If a reverse trace was + already selected by `set reverse-backtrace', then an + ordinary stack trace is done. Note that reverse + backtraces are more expensive to compute. + all Show frames that have been filtered out. + +""" + + def __init__(self): + # FIXME: this is not working quite well enough to replace + # "backtrace" yet. + super(FilteringBacktrace, self).__init__("new-backtrace", + gdb.COMMAND_STACK) + + self.reverse = ReverseBacktraceParameter() + + def reverse_iter(self, iter): + result = list(iter) + result.reverse() + return result + + def final_n(self, iter, x): + result = list(iter) + return result[x:] + + def invoke(self, arg, from_tty): + i = 0 + count = 0 + filter = True + full = False + reverse = self.reverse.value + showall = False + + for word in arg.split(" "): + if word == '': + continue + elif word == 'raw': + filter = False + elif word == 'full': + full = True + elif word == 'reverse': + reverse = not reverse + elif word == 'all': + showall = True + else: + count = int(word) + + # FIXME: try/catch and wrap in gdb error + newest_frame = gdb.newest_frame() + iter = itertools.imap(gdb.frame.FrameWrapper, + gdb.frame.FrameIterator(newest_frame)) + + if filter: + iter = gdb.frame.create_frame_filter(iter) + + # Now wrap in an iterator that numbers the frames. + iter = itertools.izip(itertools.count(0), iter) + + # Reverse if the user wanted that. + if reverse: + iter = self.reverse_iter(iter) + + # Extract sub-range user wants. + if count < 0: + iter = self.final_n(iter, count) + elif count > 0: + iter = itertools.islice(iter, 0, count) + + for pair in iter: + sys.stdout.write("#%-2d" % pair[0]) + gdb.frame.print_frame(pair[1], sys.stdout, full) + if showall: + for f in pair[1].children(): + gdb.frame.print_frame(f, sys.stdout, full, ' ') + + +FilteringBacktrace() + + +def lame(): + class _Holder(gdb.Command): + def __init__(self, what): + super(_Holder, self).__init__(what + " backtrace filter", + gdb.COMMAND_STACK, + prefix = True) + + def invoke(self, arg, from_tty): + # FIXME + pass + + _Holder("set") + _Holder("show") + + class ShowFilter(gdb.Command): + def __init__(self): + super(ShowFilter, self).__init__("show backtrace filters", + gdb.COMMAND_STACK) + + def invoke(self, arg, from_tty): + gdb.frame.print_filters() + + ShowFilter() diff --git a/gdb/python/lib/gdb/command/upto.py b/gdb/python/lib/gdb/command/upto.py new file mode 100644 index 0000000..5126531 --- /dev/null +++ b/gdb/python/lib/gdb/command/upto.py @@ -0,0 +1,128 @@ +# upto command. + +# Copyright (C) 2009, 2010 Free Software Foundation, Inc. + +# 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 3 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 . + +import gdb +import gdb.frame +import re + +class UptoPrefix (gdb.Command): + def __init__ (self): + super (UptoPrefix, self).__init__ ("upto", gdb.COMMAND_STACK, + prefix = True) + +class UptoImplementation (gdb.Command): + def __init__ (self, subcommand): + super (UptoImplementation, self).__init__ ("upto " + subcommand, + gdb.COMMAND_STACK) + + def search (self): + saved = gdb.selected_frame () + iter = gdb.frame.FrameIterator (saved) + found = False + try: + for frame in iter: + frame.select () + try: + if self.filter (frame): + wrapper = gdb.frame.FrameWrapper (frame) + gdb.frame.print_frame(wrapper, sys.stdout) + return + except: + pass + except: + pass + saved.select () + raise RuntimeError, 'Could not find a matching frame' + + def invoke (self, arg, from_tty): + self.rx = re.compile (arg) + self.search () + +class UptoSymbolCommand (UptoImplementation): + """Select and print some calling stack frame, based on symbol. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose symbol matches the regular +expression.""" + + def __init__ (self): + super (UptoSymbolCommand, self).__init__ ("symbol") + + def filter (self, frame): + name = frame.name () + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoSourceCommand (UptoImplementation): + """Select and print some calling stack frame, based on source file. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose source file name matches the +regular expression.""" + + def __init__ (self): + super (UptoSourceCommand, self).__init__ ("source") + + def filter (self, frame): + name = frame.find_sal ().symtab.filename + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoObjectCommand (UptoImplementation): + """Select and print some calling stack frame, based on object file. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose object file name matches the +regular expression.""" + + def __init__ (self): + super (UptoObjectCommand, self).__init__ ("object") + + def filter (self, frame): + name = frame.find_sal ().symtab.objfile.filename + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoWhereCommand (UptoImplementation): + """Select and print some calling stack frame, based on expression. +The argument is an expression. This command moves up the stack, +parsing and evaluating the expression in each frame. This stops when +the expression evaluates to a non-zero (true) value.""" + + def __init__ (self): + super (UptoWhereCommand, self).__init__ ("where") + + def filter (self, frame): + try: + if gdb.parse_and_eval (self.expression): + return True + except: + pass + return False + + def invoke (self, arg, from_tty): + self.expression = arg + self.search () + +UptoPrefix () +UptoSymbolCommand () +UptoSourceCommand () +UptoObjectCommand () +UptoWhereCommand () diff --git a/gdb/python/lib/gdb/frame.py b/gdb/python/lib/gdb/frame.py new file mode 100644 index 0000000..4743cd9 --- /dev/null +++ b/gdb/python/lib/gdb/frame.py @@ -0,0 +1,238 @@ +# Frame-related utilities. + +# Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + +# 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 3 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 . + +import gdb +import cStringIO + +class FrameIterator(object): + """An iterator that iterates over frames.""" + + def __init__ (self, frame): + "Initialize a FrameIterator. FRAME is the starting frame." + super(FrameIterator, self).__init__() + self.frame = frame + + def __iter__ (self): + return self + + def next (self): + result = self.frame + if result is None: + raise StopIteration + self.frame = result.older () + return result + +class _SymWrapper(object): + def __init__(self, frame, block, sym): + super(_SymWrapper, self).__init__() + self.frame = frame + self.block = block + if len(sym.linkage_name): + nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block) + if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER: + sym = nsym + self.sym = sym + + def name(self): + return self.sym.print_name + + def value(self): + try: + return self.frame.read_var(self.sym) + except RuntimeError, text: + return text + +class _BlockIterator(object): + def __init__(self, frame, block, just_args): + super(_BlockIterator, self).__init__() + self.frame = frame + self.block = block + self.just_args = just_args + self.iter = iter(self.block) + + def __iter__(self): + return self + + def next(self): + while True: + try: + result = self.iter.next() + if result.is_argument == self.just_args: + return _SymWrapper(self.frame, self.block, result) + except StopIteration: + if self.block.function is not None: + raise StopIteration + self.block = self.block.superblock + self.iter = iter(self.block) + +class FrameWrapper(object): + """A wrapper for a gdb.Frame object that presents a simpler interface. +A FrameWrapper forwards most methods to the underlying Frame. +It omits a few methods, and adds some others. +Any object conforming to this interface may be returned by a frame filter.""" + + def __init__(self, frame): + super(FrameWrapper, self).__init__() + self.frame = frame + + def name(self): + name = self.frame.name() + if name is None: + name = '??' + return name + + def type(self): + return self.frame.type() + + def older(self): + return self.frame.older() + + def arguments(self): + try: + block = self.frame.block() + return _BlockIterator(self.frame, block, True) + except RuntimeError: + # It is ok if block() fails. + return [] + + def locals(self): + try: + block = self.frame.block() + return _BlockIterator(self.frame, block, False) + except RuntimeError: + # It is ok if block() fails. + return [] + + def children(self): + if hasattr(self.frame, 'children'): + return self.frame.children() + return [] + + def file_and_line(self): + sal = self.frame.find_sal() + if sal.symtab and sal.symtab.filename: + return (sal.symtab.filename, sal.line) + return (None, None) + + def library(self): + pc = self.frame.pc() + return gdb.solib_name(pc) + +def _print_symbol(stream, sym, sep): + stream.write(sym.name()) + stream.write(sep) + val = sym.value() + if val is None: + stream.write('???') + else: + stream.write(str(val)) + +def _print_args(frame, stream): + stream.write(' (') + first = True + for arg in frame.arguments(): + if not first: + stream.write(', ') + first = False + _print_symbol(stream, arg, '=') + stream.write(')') + +def _print_locals(frame, stream): + for var in frame.locals(): + _print_symbol(stream, var, ' = ') + stream.write('\n') + +def print_frame(frame, stream, full = False, spaces = ''): + stream.write(spaces) + if frame.type() == gdb.DUMMY_FRAME: + stream.write(" \n") + elif frame.type() == gdb.SIGTRAMP_FRAME: + stream.write(" \n") + elif frame.type() == gdb.ARCH_FRAME: + stream.write(" \n") + else: + stream.write(' ') + stream.write(frame.name()) + _print_args(frame, stream) + (filename, line) = frame.file_and_line() + if filename is not None: + stream.write('\n') + stream.write(spaces) + stream.write(' at ') + stream.write(filename) + stream.write(':') + stream.write(str(line)) + else: + lib = frame.library() + if lib is not None: + stream.write(' from ') + stream.write(lib) + stream.write('\n') + if full: + nstr = cStringIO.StringIO() + _print_locals(frame, nstr) + for line in nstr.getvalue().splitlines(): + stream.write(spaces) + stream.write(' ') + stream.write(line) + stream.write('\n') + nstr.close() + +_frame_filters = {} + +class FrameFilter(gdb.Parameter): + def __init__(self, name): + super(FrameFilter, self).__init__('backtrace filter ' + name, + gdb.COMMAND_STACK, + gdb.PARAM_ZINTEGER) + self.name = name + self.value = 1 hooks/post-receive -- Repository for Project Archer.