From 89fbbfccaf093284eadb1af638486ee5b1701a81 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: May 21 2013 11:54:33 +0000 Subject: Backported Python frame filters (Phil Muldoon). - Backported breakpoint conditions crash fix (Sergio Durigan Junior). --- diff --git a/gdb-6.3-gstack-20050411.patch b/gdb-6.3-gstack-20050411.patch index 5fe902c..b73eeff 100644 --- a/gdb-6.3-gstack-20050411.patch +++ b/gdb-6.3-gstack-20050411.patch @@ -4,11 +4,11 @@ to install and uninstall. * gstack.sh, gstack.1: New files. -Index: gdb-7.5.91.20130407/gdb/Makefile.in +Index: gdb-7.6/gdb/Makefile.in =================================================================== ---- gdb-7.5.91.20130407.orig/gdb/Makefile.in 2013-04-11 16:50:33.000000000 +0200 -+++ gdb-7.5.91.20130407/gdb/Makefile.in 2013-04-11 16:52:51.032280294 +0200 -@@ -1027,7 +1027,7 @@ info install-info clean-info dvi pdf ins +--- gdb-7.6.orig/gdb/Makefile.in 2013-05-21 13:26:33.496820763 +0200 ++++ gdb-7.6/gdb/Makefile.in 2013-05-21 13:26:33.609819579 +0200 +@@ -1029,7 +1029,7 @@ info install-info clean-info dvi pdf ins install: all @$(MAKE) $(FLAGS_TO_PASS) install-only @@ -17,7 +17,7 @@ Index: gdb-7.5.91.20130407/gdb/Makefile.in transformed_name=`t='$(program_transform_name)'; \ echo gdb | sed -e "$$t"` ; \ if test "x$$transformed_name" = x; then \ -@@ -1058,7 +1058,25 @@ install-only: $(CONFIG_INSTALL) +@@ -1060,7 +1060,25 @@ install-only: $(CONFIG_INSTALL) install-python: $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(GDB_DATADIR)/python/gdb @@ -44,7 +44,7 @@ Index: gdb-7.5.91.20130407/gdb/Makefile.in transformed_name=`t='$(program_transform_name)'; \ echo gdb | sed -e $$t` ; \ if test "x$$transformed_name" = x; then \ -@@ -1081,6 +1099,18 @@ uninstall: force $(CONFIG_UNINSTALL) +@@ -1083,6 +1101,18 @@ uninstall: force $(CONFIG_UNINSTALL) fi @$(MAKE) DO=uninstall "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do @@ -63,10 +63,10 @@ Index: gdb-7.5.91.20130407/gdb/Makefile.in # The C++ name parser can be built standalone for testing. test-cp-name-parser.o: cp-name-parser.c $(COMPILE) -DTEST_CPNAMES cp-name-parser.c -Index: gdb-7.5.91.20130407/gdb/gstack.sh +Index: gdb-7.6/gdb/gstack.sh =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gdb-7.5.91.20130407/gdb/gstack.sh 2013-04-11 16:52:22.093281616 +0200 ++++ gdb-7.6/gdb/gstack.sh 2013-05-21 13:26:55.434625908 +0200 @@ -0,0 +1,43 @@ +#!/bin/sh + @@ -101,7 +101,7 @@ Index: gdb-7.5.91.20130407/gdb/gstack.sh + +# Run GDB, strip out unwanted noise. +# --readnever is no longer used since .gdb_index is now in use. -+$GDB --quiet -nx /proc/$1/exe $1 <&1 | ++$GDB --quiet -nx $GDBARGS /proc/$1/exe $1 <&1 | +set width 0 +set height 0 +set pagination no @@ -111,10 +111,10 @@ Index: gdb-7.5.91.20130407/gdb/gstack.sh + -e 's/^\((gdb) \)*//' \ + -e '/^#/p' \ + -e '/^Thread/p' -Index: gdb-7.5.91.20130407/gdb/testsuite/gdb.base/gstack.exp +Index: gdb-7.6/gdb/testsuite/gdb.base/gstack.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gdb-7.5.91.20130407/gdb/testsuite/gdb.base/gstack.exp 2013-04-11 16:52:22.093281616 +0200 ++++ gdb-7.6/gdb/testsuite/gdb.base/gstack.exp 2013-05-21 13:26:55.434625908 +0200 @@ -0,0 +1,66 @@ +# Copyright (C) 2012 Free Software Foundation, Inc. + @@ -167,7 +167,7 @@ Index: gdb-7.5.91.20130407/gdb/testsuite/gdb.base/gstack.exp +# exiting the function. Still we could retry the gstack command if we fail. + +set test "spawn gstack" -+set command "sh -c GDB=$GDB\\ sh\\ ${srcdir}/../gstack.sh\\ $pid\\;echo\\ GSTACK-END" ++set command "sh -c GDB=$GDB\\ GDBARGS=-data-directory\\\\\\ $BUILD_DATA_DIRECTORY\\ sh\\ ${srcdir}/../gstack.sh\\ $pid\\;echo\\ GSTACK-END" +set res [remote_spawn host $command]; +if { $res < 0 || $res == "" } { + perror "Spawning $command failed." @@ -182,10 +182,10 @@ Index: gdb-7.5.91.20130407/gdb/testsuite/gdb.base/gstack.exp +gdb_exit + +remote_exec host "kill -9 $pid" -Index: gdb-7.5.91.20130407/gdb/testsuite/gdb.base/gstack.c +Index: gdb-7.6/gdb/testsuite/gdb.base/gstack.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gdb-7.5.91.20130407/gdb/testsuite/gdb.base/gstack.c 2013-04-11 16:52:22.093281616 +0200 ++++ gdb-7.6/gdb/testsuite/gdb.base/gstack.c 2013-05-21 13:26:33.610819569 +0200 @@ -0,0 +1,43 @@ +/* This testcase is part of GDB, the GNU debugger. + diff --git a/gdb-6.5-BEA-testsuite.patch b/gdb-6.5-BEA-testsuite.patch index 76d7566..7c5778c 100644 --- a/gdb-6.5-BEA-testsuite.patch +++ b/gdb-6.5-BEA-testsuite.patch @@ -1,9 +1,7 @@ -Index: ./gdb/testsuite/gdb.threads/threadcrash.c +Index: gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.c =================================================================== -RCS file: gdb/testsuite/gdb.threads/threadcrash.c -diff -N gdb/testsuite/gdb.threads/threadcrash.c ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ ./gdb/testsuite/gdb.threads/threadcrash.c 31 Oct 2006 17:54:38 -0000 +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.c 2013-05-21 13:35:45.592059786 +0200 @@ -0,0 +1,301 @@ +/* + * The point of this program is to crash in a multi-threaded app. @@ -306,12 +304,10 @@ diff -N gdb/testsuite/gdb.threads/threadcrash.c + + return 0; +} -Index: ./gdb/testsuite/gdb.threads/threadcrash.exp +Index: gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.exp =================================================================== -RCS file: gdb/testsuite/gdb.threads/threadcrash.exp -diff -N gdb/testsuite/gdb.threads/threadcrash.exp ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ ./gdb/testsuite/gdb.threads/threadcrash.exp 31 Oct 2006 17:54:38 -0000 +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.exp 2013-05-21 13:36:01.451056746 +0200 @@ -0,0 +1,37 @@ +# threadcrash.exp - The point of this program is to crash in a multi-threaded app. + @@ -337,7 +333,7 @@ diff -N gdb/testsuite/gdb.threads/threadcrash.exp +} + +# ${shellfile} argument must not contain any directories. -+set fd [open "|bash ${shellfile} ${binfile} $GDB -nw $GDBFLAGS" r] ++set fd [open "|bash ${shellfile} ${binfile} $GDB $INTERNAL_GDBFLAGS $GDBFLAGS [host_info gdb_opts]" r] +while { [gets $fd line] >= 0 } { + if [regexp " PASS: (.*)$" $line trash message] { + pass $message @@ -350,12 +346,10 @@ diff -N gdb/testsuite/gdb.threads/threadcrash.exp +} + +return 0 -Index: ./gdb/testsuite/gdb.threads/threadcrash.sh +Index: gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.sh =================================================================== -RCS file: gdb/testsuite/gdb.threads/threadcrash.sh -diff -N gdb/testsuite/gdb.threads/threadcrash.sh ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ ./gdb/testsuite/gdb.threads/threadcrash.sh 31 Oct 2006 17:54:38 -0000 +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.sh 2013-05-21 13:35:45.593059786 +0200 @@ -0,0 +1,324 @@ +#! /bin/bash + @@ -681,12 +675,10 @@ diff -N gdb/testsuite/gdb.threads/threadcrash.sh +rm -rf $WORKDIR + +exit $FAILURES -Index: ./gdb/testsuite/gdb.threads/threadcrash.sh-orig +Index: gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.sh-orig =================================================================== -RCS file: gdb/testsuite/gdb.threads/threadcrash.sh-orig -diff -N gdb/testsuite/gdb.threads/threadcrash.sh-orig ---- /dev/null 1 Jan 1970 00:00:00 -0000 -+++ ./gdb/testsuite/gdb.threads/threadcrash.sh-orig 31 Oct 2006 17:54:38 -0000 +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.threads/threadcrash.sh-orig 2013-05-21 13:35:45.593059786 +0200 @@ -0,0 +1,248 @@ +#! /bin/bash + diff --git a/gdb-archer.patch b/gdb-archer.patch index 4060cc0..ab0657f 100644 --- a/gdb-archer.patch +++ b/gdb-archer.patch @@ -2,7 +2,7 @@ http://sourceware.org/gdb/wiki/ProjectArcher http://sourceware.org/gdb/wiki/ArcherBranchManagement GIT snapshot: -commit 92cf2d53a9c69b4fb361de662de9100c6e72caa0 +commit b1f8c6821303f6eb087fb7f57405483ac8812227 branch jankratochvil/fedora19 - the merge of branches: jankratochvil/vla @@ -169,22 +169,17 @@ index ca8d89b..811ad72 100644 plongest (high_bound - low_bound + 1)); fprintf_filtered (stream, (is_vector ? ")))" : "]")); diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in -index d98ac77..e248399 100644 +index d98ac77..f6a4b99 100644 --- a/gdb/data-directory/Makefile.in +++ b/gdb/data-directory/Makefile.in -@@ -52,17 +52,28 @@ SYSCALLS_FILES = \ - PYTHON_DIR = python +@@ -53,16 +53,21 @@ PYTHON_DIR = python PYTHON_INSTALL_DIR = $(DESTDIR)$(GDB_DATADIR)/$(PYTHON_DIR) PYTHON_FILES = \ -+ gdb/FrameIterator.py \ -+ gdb/FrameWrapper.py \ gdb/__init__.py \ - gdb/types.py \ - gdb/printing.py \ - gdb/prompt.py \ -+ gdb/backtrace.py \ gdb/command/__init__.py \ -+ gdb/command/backtrace.py \ + gdb/command/ignore_errors.py \ + gdb/command/pahole.py \ gdb/command/type_printers.py \ @@ -194,8 +189,6 @@ index d98ac77..e248399 100644 gdb/function/__init__.py \ - gdb/function/strfns.py + gdb/function/strfns.py \ -+ gdb/command/require.py \ -+ gdb/command/upto.py \ + gdb/function/__init__.py \ + gdb/function/caller_is.py \ + gdb/function/in_scope.py \ @@ -3778,323 +3771,6 @@ index 155703d..545a615 100644 + observer_attach_mark_used (print_types_mark_used); +#endif } -diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py -new file mode 100644 -index 0000000..5654546 ---- /dev/null -+++ b/gdb/python/lib/gdb/FrameIterator.py -@@ -0,0 +1,33 @@ -+# Iterator over frames. -+ -+# Copyright (C) 2008, 2009 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 . -+ -+class FrameIterator: -+ """An iterator that iterates over frames.""" -+ -+ def __init__ (self, frame): -+ "Initialize a FrameIterator. FRAME is the starting frame." -+ 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 -diff --git a/gdb/python/lib/gdb/FrameWrapper.py b/gdb/python/lib/gdb/FrameWrapper.py -new file mode 100644 -index 0000000..b790a54 ---- /dev/null -+++ b/gdb/python/lib/gdb/FrameWrapper.py -@@ -0,0 +1,112 @@ -+# Wrapper API for frames. -+ -+# Copyright (C) 2008, 2009 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 -+ -+# FIXME: arguably all this should be on Frame somehow. -+class FrameWrapper: -+ def __init__ (self, frame): -+ self.frame = frame; -+ -+ def write_symbol (self, stream, sym, 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 -+ -+ stream.write (sym.print_name + "=") -+ try: -+ val = self.read_var (sym) -+ if val != None: -+ val = str (val) -+ # FIXME: would be nice to have a more precise exception here. -+ except RuntimeError, text: -+ val = text -+ if val == None: -+ stream.write ("???") -+ else: -+ stream.write (str (val)) -+ -+ def print_frame_locals (self, stream, func): -+ if not func: -+ return -+ -+ first = True -+ block = func.value -+ -+ for sym in block: -+ if sym.is_argument: -+ continue; -+ -+ self.write_symbol (stream, sym, block) -+ stream.write ('\n') -+ -+ def print_frame_args (self, stream, func): -+ if not func: -+ return -+ -+ first = True -+ block = func.value -+ -+ for sym in block: -+ if not sym.is_argument: -+ continue; -+ -+ if not first: -+ stream.write (", ") -+ -+ self.write_symbol (stream, sym, block) -+ first = False -+ -+ # FIXME: this should probably just be a method on gdb.Frame. -+ # But then we need stream wrappers. -+ def describe (self, stream, full): -+ if self.type () == gdb.DUMMY_FRAME: -+ stream.write (" \n") -+ elif self.type () == gdb.SIGTRAMP_FRAME: -+ stream.write (" \n") -+ else: -+ sal = self.find_sal () -+ pc = self.pc () -+ name = self.name () -+ if not name: -+ name = "??" -+ if pc != sal.pc or not sal.symtab: -+ stream.write (" 0x%08x in" % pc) -+ stream.write (" " + name + " (") -+ -+ func = self.function () -+ self.print_frame_args (stream, func) -+ -+ stream.write (")") -+ -+ if sal.symtab and sal.symtab.filename: -+ stream.write (" at " + sal.symtab.filename) -+ stream.write (":" + str (sal.line)) -+ -+ if not self.name () or (not sal.symtab or not sal.symtab.filename): -+ lib = gdb.solib_address (pc) -+ if lib: -+ stream.write (" from " + lib) -+ -+ stream.write ("\n") -+ -+ if full: -+ self.print_frame_locals (stream, func) -+ -+ def __getattr__ (self, name): -+ return getattr (self.frame, name) -diff --git a/gdb/python/lib/gdb/backtrace.py b/gdb/python/lib/gdb/backtrace.py -new file mode 100644 -index 0000000..6bb4fb1 ---- /dev/null -+++ b/gdb/python/lib/gdb/backtrace.py -@@ -0,0 +1,42 @@ -+# Filtering backtrace. -+ -+# Copyright (C) 2008, 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 itertools -+ -+# Our only exports. -+__all__ = ['push_frame_filter', 'create_frame_filter'] -+ -+frame_filter = None -+ -+def push_frame_filter (constructor): -+ """Register a new backtrace filter class with the 'backtrace' command. -+The filter will be passed an iterator as an argument. The iterator -+will return gdb.Frame-like objects. The filter should in turn act as -+an iterator returning such objects.""" -+ global frame_filter -+ if frame_filter == None: -+ frame_filter = constructor -+ else: -+ frame_filter = lambda iterator, filter = frame_filter: constructor (filter (iterator)) -+ -+def create_frame_filter (iter): -+ global frame_filter -+ if frame_filter is None: -+ return iter -+ return frame_filter (iter) -+ -diff --git a/gdb/python/lib/gdb/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py -new file mode 100644 -index 0000000..eeea909 ---- /dev/null -+++ b/gdb/python/lib/gdb/command/backtrace.py -@@ -0,0 +1,106 @@ -+# New backtrace command. -+ -+# Copyright (C) 2008, 2009, 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.backtrace -+import itertools -+from gdb.FrameIterator import FrameIterator -+from gdb.FrameWrapper import FrameWrapper -+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): -+ gdb.Parameter.__init__ (self, "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. -+With a negative argument, print outermost -COUNT frames. -+Use of the 'full' qualifier also prints the values of the local variables. -+Use of the 'raw' qualifier avoids any filtering by loadable modules. -+""" -+ -+ def __init__ (self): -+ # FIXME: this is not working quite well enough to replace -+ # "backtrace" yet. -+ gdb.Command.__init__ (self, "new-backtrace", gdb.COMMAND_STACK) -+ self.reverse = ReverseBacktraceParameter() -+ -+ def reverse_iter (self, iter): -+ result = [] -+ for item in iter: -+ result.append (item) -+ result.reverse() -+ return result -+ -+ def final_n (self, iter, x): -+ result = [] -+ for item in iter: -+ result.append (item) -+ return result[x:] -+ -+ def invoke (self, arg, from_tty): -+ i = 0 -+ count = 0 -+ filter = True -+ full = False -+ -+ for word in arg.split (" "): -+ if word == '': -+ continue -+ elif word == 'raw': -+ filter = False -+ elif word == 'full': -+ full = True -+ else: -+ count = int (word) -+ -+ # FIXME: provide option to start at selected frame -+ # However, should still number as if starting from newest -+ newest_frame = gdb.newest_frame() -+ iter = itertools.imap (FrameWrapper, -+ FrameIterator (newest_frame)) -+ if filter: -+ iter = gdb.backtrace.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 self.reverse.value: -+ 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]) -+ pair[1].describe (sys.stdout, full) -+ -+FilteringBacktrace() diff --git a/gdb/python/lib/gdb/command/ignore_errors.py b/gdb/python/lib/gdb/command/ignore_errors.py new file mode 100644 index 0000000..6fa48ff @@ -4225,204 +3901,6 @@ index 0000000..636f99d + self.pahole (type, 0, '') + +Pahole() -diff --git a/gdb/python/lib/gdb/command/require.py b/gdb/python/lib/gdb/command/require.py -new file mode 100644 -index 0000000..1fbc1e8 ---- /dev/null -+++ b/gdb/python/lib/gdb/command/require.py -@@ -0,0 +1,57 @@ -+# Demand-loading commands. -+ -+# Copyright (C) 2008, 2009 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 os -+ -+class RequireCommand (gdb.Command): -+ """Prefix command for requiring features.""" -+ -+ def __init__ (self): -+ super (RequireCommand, self).__init__ ("require", -+ gdb.COMMAND_SUPPORT, -+ gdb.COMPLETE_NONE, -+ True) -+ -+class RequireSubcommand (gdb.Command): -+ """Demand-load a command by name.""" -+ -+ def __init__ (self, name): -+ self.__doc__ = "Demand-load a %s by name." % name -+ super (RequireSubcommand, self).__init__ ("require %s" % name, -+ gdb.COMMAND_SUPPORT) -+ self.name = name -+ -+ def invoke (self, arg, from_tty): -+ for cmd in arg.split(): -+ exec ('import gdb.' + self.name + '.' + cmd, globals ()) -+ -+ def complete (self, text, word): -+ dir = gdb.pythondir + '/gdb/' + self.name -+ result = [] -+ for file in os.listdir(dir): -+ if not file.startswith (word) or not file.endswith ('.py'): -+ continue -+ feature = file[0:-3] -+ if feature == 'require' or feature == '__init__': -+ continue -+ result.append (feature) -+ return result -+ -+RequireCommand() -+RequireSubcommand("command") -+RequireSubcommand("function") -diff --git a/gdb/python/lib/gdb/command/upto.py b/gdb/python/lib/gdb/command/upto.py -new file mode 100644 -index 0000000..faf54ed ---- /dev/null -+++ b/gdb/python/lib/gdb/command/upto.py -@@ -0,0 +1,129 @@ -+# upto command. -+ -+# Copyright (C) 2009 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 re -+from gdb.FrameIterator import FrameIterator -+from gdb.FrameWrapper import FrameWrapper -+ -+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 = FrameIterator (saved) -+ found = False -+ try: -+ for frame in iter: -+ frame.select () -+ try: -+ if self.filter (frame): -+ wrapper = FrameWrapper (frame) -+ wrapper.describe (sys.stdout, False) -+ 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/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py new file mode 100644 index 0000000..2b9c5c7 diff --git a/gdb-upstream-framefilters-1of2.patch b/gdb-upstream-framefilters-1of2.patch new file mode 100644 index 0000000..d0ab188 --- /dev/null +++ b/gdb-upstream-framefilters-1of2.patch @@ -0,0 +1,5551 @@ +http://sourceware.org/ml/gdb-cvs/2013-05/msg00084.html + +### src/gdb/ChangeLog 2013/05/09 18:03:27 1.15539 +### src/gdb/ChangeLog 2013/05/10 10:26:01 1.15540 +## -1,3 +1,52 @@ ++2013-05-10 Phil Muldoon ++ ++ * stack.c (backtrace_command_1): Add "no-filters", and Python frame ++ filter logic. ++ (backtrace_command): Add "no-filters" option parsing. ++ (_initialize_stack): Alter help to reflect "no-filters" option. ++ * Makefile.in (SUBDIR_PYTHON_OBS): Add py-framefilter.o ++ (SUBDIR_PYTHON_SRCS): Add py-framefilter.c ++ (py-frame.o): Add target ++ * data-directory/Makefile.in (PYTHON_DIR): Add Python frame ++ filter files. ++ * python/python.h: Add new frame filter constants, and flag enum. ++ (apply_frame_filter): Add definition. ++ * python/python.c (apply_frame_filter): New non-Python ++ enabled function. ++ * python/py-utils.c (py_xdecref): New function. ++ (make_cleanup_py_xdecref): Ditto. ++ * python/py-objfile.c: Declare frame_filters dictionary. ++ (objfpy_dealloc): Add frame_filters dealloc. ++ (objfpy_new): Initialize frame_filters attribute. ++ (objfile_to_objfile_object): Ditto. ++ (objfpy_get_frame_filters): New function. ++ (objfpy_set_frame_filters): New function. ++ * python/py-progspace.c: Declare frame_filters dictionary. ++ (pspy_dealloc): Add frame_filters dealloc. ++ (pspy_new): Initialize frame_filters attribute. ++ (pspacee_to_pspace_object): Ditto. ++ (pspy_get_frame_filters): New function. ++ (pspy_set_frame_filters): New function. ++ * python/py-framefilter.c: New file. ++ * python/lib/gdb/command/frame_filters.py: New file. ++ * python/lib/gdb/frames.py: New file. ++ * python/lib/gdb/__init__.py: Initialize global frame_filters ++ dictionary ++ * python/lib/gdb/FrameDecorator.py: New file. ++ * python/lib/gdb/FrameIterator.py: New file. ++ * mi/mi-cmds.c (mi_cmds): Add frame filters command. ++ * mi/mi-cmds.h: Declare. ++ * mi/mi-cmd-stack.c (mi_cmd_stack_list_frames): Add ++ --no-frame-filter logic, and Python frame filter logic. ++ (stack_enable_frame_filters): New function. ++ (parse_no_frame_option): Ditto. ++ (mi_cmd_stack_list_frames): Add --no-frame-filter and Python frame ++ filter logic. ++ (mi_cmd_stack_list_locals): Ditto. ++ (mi_cmd_stack_list_args): Ditto. ++ (mi_cmd_stack_list_variables): Ditto. ++ * NEWS: Add frame filter note. ++ + 2013-05-09 Doug Evans + + * symfile.c (syms_from_objfile_1): Delete args offsets, num_offsets. +Index: gdb-7.6/gdb/Makefile.in +=================================================================== +--- gdb-7.6.orig/gdb/Makefile.in 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/Makefile.in 2013-05-20 22:25:52.096165773 +0200 +@@ -284,6 +284,7 @@ SUBDIR_PYTHON_OBS = \ + py-exitedevent.o \ + py-finishbreakpoint.o \ + py-frame.o \ ++ py-framefilter.o \ + py-function.o \ + py-gdb-readline.o \ + py-inferior.o \ +@@ -318,6 +319,7 @@ SUBDIR_PYTHON_SRCS = \ + python/py-exitedevent.c \ + python/py-finishbreakpoint.c \ + python/py-frame.c \ ++ python/py-framefilter.c \ + python/py-function.c \ + python/py-gdb-readline.c \ + python/py-inferior.c \ +@@ -2135,6 +2137,10 @@ py-frame.o: $(srcdir)/python/py-frame.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c + $(POSTCOMPILE) + ++py-framefilter.o: $(srcdir)/python/py-framefilter.c ++ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-framefilter.c ++ $(POSTCOMPILE) ++ + py-function.o: $(srcdir)/python/py-function.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c + $(POSTCOMPILE) +Index: gdb-7.6/gdb/NEWS +=================================================================== +--- gdb-7.6.orig/gdb/NEWS 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/NEWS 2013-05-20 22:25:52.097165772 +0200 +@@ -4,6 +4,10 @@ + * Newly installed $prefix/bin/gcore acts as a shell interface for the + GDB command gcore. + ++* Python scripting ++ ++ ** Frame filters and frame decorators have been added. ++ + *** Changes in GDB 7.6 + + * Target record has been renamed to record-full. +Index: gdb-7.6/gdb/stack.c +=================================================================== +--- gdb-7.6.orig/gdb/stack.c 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/stack.c 2013-05-20 22:25:52.098165772 +0200 +@@ -54,6 +54,7 @@ + + #include "psymtab.h" + #include "symfile.h" ++#include "python/python.h" + + void (*deprecated_selected_frame_level_changed_hook) (int); + +@@ -1655,13 +1656,15 @@ frame_info (char *addr_exp, int from_tty + frames. */ + + static void +-backtrace_command_1 (char *count_exp, int show_locals, int from_tty) ++backtrace_command_1 (char *count_exp, int show_locals, int no_filters, ++ int from_tty) + { + struct frame_info *fi; + int count; + int i; + struct frame_info *trailing; +- int trailing_level; ++ int trailing_level, py_start = 0, py_end = 0; ++ enum py_bt_status result = PY_BT_ERROR; + + if (!target_has_stack) + error (_("No stack.")); +@@ -1680,6 +1683,7 @@ backtrace_command_1 (char *count_exp, in + { + struct frame_info *current; + ++ py_start = count; + count = -count; + + current = trailing; +@@ -1701,9 +1705,17 @@ backtrace_command_1 (char *count_exp, in + + count = -1; + } ++ else ++ { ++ py_start = 0; ++ py_end = count; ++ } + } + else +- count = -1; ++ { ++ py_end = -1; ++ count = -1; ++ } + + if (info_verbose) + { +@@ -1723,16 +1735,40 @@ backtrace_command_1 (char *count_exp, in + } + } + +- for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi)) ++ if (! no_filters) + { +- QUIT; ++ int flags = PRINT_LEVEL | PRINT_FRAME_INFO | PRINT_ARGS; ++ enum py_frame_args arg_type; + +- /* Don't use print_stack_frame; if an error() occurs it probably +- means further attempts to backtrace would fail (on the other +- hand, perhaps the code does or could be fixed to make sure +- the frame->prev field gets set to NULL in that case). */ +- print_frame_info (fi, 1, LOCATION, 1); + if (show_locals) ++ flags |= PRINT_LOCALS; ++ ++ if (!strcmp (print_frame_arguments, "scalars")) ++ arg_type = CLI_SCALAR_VALUES; ++ else if (!strcmp (print_frame_arguments, "all")) ++ arg_type = CLI_ALL_VALUES; ++ else ++ arg_type = NO_VALUES; ++ ++ result = apply_frame_filter (get_current_frame (), flags, arg_type, ++ current_uiout, py_start, py_end); ++ ++ } ++ /* Run the inbuilt backtrace if there are no filters registered, or ++ "no-filters" has been specified from the command. */ ++ if (no_filters || result == PY_BT_NO_FILTERS) ++ { ++ for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi)) ++ { ++ QUIT; ++ ++ /* Don't use print_stack_frame; if an error() occurs it probably ++ means further attempts to backtrace would fail (on the other ++ hand, perhaps the code does or could be fixed to make sure ++ the frame->prev field gets set to NULL in that case). */ ++ ++ print_frame_info (fi, 1, LOCATION, 1); ++ if (show_locals) + { + struct frame_id frame_id = get_frame_id (fi); + +@@ -1748,24 +1784,25 @@ backtrace_command_1 (char *count_exp, in + } + } + +- /* Save the last frame to check for error conditions. */ +- trailing = fi; +- } ++ /* Save the last frame to check for error conditions. */ ++ trailing = fi; ++ } + +- /* If we've stopped before the end, mention that. */ +- if (fi && from_tty) +- printf_filtered (_("(More stack frames follow...)\n")); ++ /* If we've stopped before the end, mention that. */ ++ if (fi && from_tty) ++ printf_filtered (_("(More stack frames follow...)\n")); + +- /* If we've run out of frames, and the reason appears to be an error +- condition, print it. */ +- if (fi == NULL && trailing != NULL) +- { +- enum unwind_stop_reason reason; ++ /* If we've run out of frames, and the reason appears to be an error ++ condition, print it. */ ++ if (fi == NULL && trailing != NULL) ++ { ++ enum unwind_stop_reason reason; + +- reason = get_frame_unwind_stop_reason (trailing); +- if (reason >= UNWIND_FIRST_ERROR) +- printf_filtered (_("Backtrace stopped: %s\n"), +- frame_stop_reason_string (reason)); ++ reason = get_frame_unwind_stop_reason (trailing); ++ if (reason >= UNWIND_FIRST_ERROR) ++ printf_filtered (_("Backtrace stopped: %s\n"), ++ frame_stop_reason_string (reason)); ++ } + } + } + +@@ -1773,7 +1810,8 @@ static void + backtrace_command (char *arg, int from_tty) + { + struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); +- int fulltrace_arg = -1, arglen = 0, argc = 0; ++ int fulltrace_arg = -1, arglen = 0, argc = 0, no_filters = -1; ++ int user_arg = 0; + + if (arg) + { +@@ -1790,25 +1828,31 @@ backtrace_command (char *arg, int from_t + for (j = 0; j < strlen (argv[i]); j++) + argv[i][j] = tolower (argv[i][j]); + +- if (fulltrace_arg < 0 && subset_compare (argv[i], "full")) +- fulltrace_arg = argc; ++ if (no_filters < 0 && subset_compare (argv[i], "no-filters")) ++ no_filters = argc; + else + { +- arglen += strlen (argv[i]); +- argc++; ++ if (fulltrace_arg < 0 && subset_compare (argv[i], "full")) ++ fulltrace_arg = argc; ++ else ++ { ++ user_arg++; ++ arglen += strlen (argv[i]); ++ } + } ++ argc++; + } +- arglen += argc; +- if (fulltrace_arg >= 0) ++ arglen += user_arg; ++ if (fulltrace_arg >= 0 || no_filters >= 0) + { + if (arglen > 0) + { + arg = xmalloc (arglen + 1); + make_cleanup (xfree, arg); + arg[0] = 0; +- for (i = 0; i < (argc + 1); i++) ++ for (i = 0; i < argc; i++) + { +- if (i != fulltrace_arg) ++ if (i != fulltrace_arg && i != no_filters) + { + strcat (arg, argv[i]); + strcat (arg, " "); +@@ -1820,7 +1864,8 @@ backtrace_command (char *arg, int from_t + } + } + +- backtrace_command_1 (arg, fulltrace_arg >= 0 /* show_locals */, from_tty); ++ backtrace_command_1 (arg, fulltrace_arg >= 0 /* show_locals */, ++ no_filters >= 0 /* no frame-filters */, from_tty); + + do_cleanups (old_chain); + } +@@ -1828,7 +1873,7 @@ backtrace_command (char *arg, int from_t + static void + backtrace_full_command (char *arg, int from_tty) + { +- backtrace_command_1 (arg, 1 /* show_locals */, from_tty); ++ backtrace_command_1 (arg, 1 /* show_locals */, 0, from_tty); + } + + +@@ -2562,7 +2607,9 @@ It can be a stack frame number or the ad + add_com ("backtrace", class_stack, backtrace_command, _("\ + Print backtrace of all stack frames, or innermost COUNT frames.\n\ + With a negative argument, print outermost -COUNT frames.\nUse of the \ +-'full' qualifier also prints the values of the local variables.\n")); ++'full' qualifier also prints the values of the local variables.\n\ ++Use of the 'no-filters' qualifier prohibits frame filters from executing\n\ ++on this backtrace.\n")); + add_com_alias ("bt", "backtrace", class_stack, 0); + if (xdb_commands) + { +Index: gdb-7.6/gdb/data-directory/Makefile.in +=================================================================== +--- gdb-7.6.orig/gdb/data-directory/Makefile.in 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/data-directory/Makefile.in 2013-05-20 22:25:52.098165772 +0200 +@@ -53,7 +53,11 @@ PYTHON_DIR = python + PYTHON_INSTALL_DIR = $(DESTDIR)$(GDB_DATADIR)/$(PYTHON_DIR) + PYTHON_FILES = \ + gdb/__init__.py \ ++ gdb/frames.py \ ++ gdb/FrameIterator.py \ ++ gdb/FrameDecorator.py \ + gdb/command/__init__.py \ ++ gdb/command/frame_filters.py \ + gdb/command/ignore_errors.py \ + gdb/command/pahole.py \ + gdb/command/type_printers.py \ +Index: gdb-7.6/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-7.6.orig/gdb/doc/gdb.texinfo 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/doc/gdb.texinfo 2013-05-20 22:25:52.110165767 +0200 +@@ -6453,6 +6453,7 @@ currently executing frame and describes + @menu + * Frames:: Stack frames + * Backtrace:: Backtraces ++* Frame Filter Management:: Managing frame filters + * Selection:: Selecting a frame + * Frame Info:: Information on a frame + +@@ -6540,6 +6541,7 @@ line per frame, for many frames, startin + frame (frame zero), followed by its caller (frame one), and on up the + stack. + ++@anchor{backtrace-command} + @table @code + @kindex backtrace + @kindex bt @r{(@code{backtrace})} +@@ -6565,6 +6567,19 @@ Similar, but print only the outermost @v + @itemx bt full -@var{n} + Print the values of the local variables also. @var{n} specifies the + number of frames to print, as described above. ++ ++@item backtrace no-filters ++@itemx bt no-filters ++@itemx bt no-filters @var{n} ++@itemx bt no-filters -@var{n} ++@itemx bt no-filters full ++@itemx bt no-filters full @var{n} ++@itemx bt no-filters full -@var{n} ++Do not run Python frame filters on this backtrace. @xref{Frame ++Filter API}, for more information. Additionally use @ref{disable ++frame-filter all} to turn off all frame filters. This is only ++relevant when @value{GDBN} has been configured with @code{Python} ++support. + @end table + + @kindex where +@@ -6714,6 +6729,149 @@ Display an absolute filename. + Show the current way to display filenames. + @end table + ++@node Frame Filter Management ++@section Management of Frame Filters. ++@cindex managing frame filters ++ ++Frame filters are Python based utilities to manage and decorate the ++output of frames. @xref{Frame Filter API}, for further information. ++ ++Managing frame filters is performed by several commands available ++within @value{GDBN}, detailed here. ++ ++@table @code ++@kindex info frame-filter ++@item info frame-filter ++Print a list of installed frame filters from all dictionaries, showing ++their name, priority and enabled status. ++ ++@kindex disable frame-filter ++@anchor{disable frame-filter all} ++@item disable frame-filter @var{filter-dictionary} @var{filter-name} ++Disable a frame filter in the dictionary matching ++@var{filter-dictionary}, or @code{all}, and @var{filter-name}. ++@var{filter-dictionary} may be @code{all}, @code{global}, ++@code{progspace} or the name of the object file where the frame filter ++dictionary resides. When @code{all} is specified, all frame filters ++across all dictionaries are disabled. @var{filter-name} is the name ++of the frame filter and is used when @code{all} is not the option for ++@var{filter-dictionary}. A disabled frame-filter is not deleted, it ++may be enabled again later. ++ ++@kindex enable frame-filter ++@item enable frame-filter @var{filter-dictionary} @var{filter-name} ++Enable a frame filter in the dictionary matching ++@var{filter-dictionary}, or @code{all}, and @var{filter-name}. ++@var{filter-dictionary} may be @code{all}, @code{global}, ++@code{progspace} or the name of the object file where the frame filter ++dictionary resides. When @code{all} is specified, all frame filters across ++all dictionaries are enabled. @var{filter-name} is the name of the frame ++filter and is used when @code{all} is not the option for ++@var{filter-dictionary}. ++ ++Example: ++ ++@smallexample ++(gdb) info frame-filter ++ ++global frame-filters: ++ Priority Enabled Name ++ 1000 No PrimaryFunctionFilter ++ 100 Yes Reverse ++ ++progspace /build/test frame-filters: ++ Priority Enabled Name ++ 100 Yes ProgspaceFilter ++ ++objfile /build/test frame-filters: ++ Priority Enabled Name ++ 999 Yes BuildProgra Filter ++ ++(gdb) disable frame-filter /build/test BuildProgramFilter ++(gdb) info frame-filter ++ ++global frame-filters: ++ Priority Enabled Name ++ 1000 No PrimaryFunctionFilter ++ 100 Yes Reverse ++ ++progspace /build/test frame-filters: ++ Priority Enabled Name ++ 100 Yes ProgspaceFilter ++ ++objfile /build/test frame-filters: ++ Priority Enabled Name ++ 999 No BuildProgramFilter ++ ++(gdb) enable frame-filter global PrimaryFunctionFilter ++(gdb) info frame-filter ++ ++global frame-filters: ++ Priority Enabled Name ++ 1000 Yes PrimaryFunctionFilter ++ 100 Yes Reverse ++ ++progspace /build/test frame-filters: ++ Priority Enabled Name ++ 100 Yes ProgspaceFilter ++ ++objfile /build/test frame-filters: ++ Priority Enabled Name ++ 999 No BuildProgramFilter ++@end smallexample ++ ++@kindex set frame-filter priority ++@item set frame-filter priority @var{filter-dictionary} @var{filter-name} @var{priority} ++Set the @var{priority} of a frame filter in the dictionary matching ++@var{filter-dictionary}, and the frame filter name matching ++@var{filter-name}. @var{filter-dictionary} may be @code{global}, ++@code{progspace} or the name of the object file where the frame filter ++dictionary resides. @var{priority} is an integer. ++ ++@kindex show frame-filter priority ++@item show frame-filter priority @var{filter-dictionary} @var{filter-name} ++Show the @var{priority} of a frame filter in the dictionary matching ++@var{filter-dictionary}, and the frame filter name matching ++@var{filter-name}. @var{filter-dictionary} may be @code{global}, ++@code{progspace} or the name of the object file where the frame filter ++dictionary resides. ++ ++Example: ++ ++@smallexample ++(gdb) info frame-filter ++ ++global frame-filters: ++ Priority Enabled Name ++ 1000 Yes PrimaryFunctionFilter ++ 100 Yes Reverse ++ ++progspace /build/test frame-filters: ++ Priority Enabled Name ++ 100 Yes ProgspaceFilter ++ ++objfile /build/test frame-filters: ++ Priority Enabled Name ++ 999 No BuildProgramFilter ++ ++(gdb) set frame-filter priority global Reverse 50 ++(gdb) info frame-filter ++ ++global frame-filters: ++ Priority Enabled Name ++ 1000 Yes PrimaryFunctionFilter ++ 50 Yes Reverse ++ ++progspace /build/test frame-filters: ++ Priority Enabled Name ++ 100 Yes ProgspaceFilter ++ ++objfile /build/test frame-filters: ++ Priority Enabled Name ++ 999 No BuildProgramFilter ++@end smallexample ++@end table ++ + @node Selection + @section Selecting a Frame + +@@ -23065,6 +23223,9 @@ situation, a Python @code{KeyboardInterr + * Selecting Pretty-Printers:: How GDB chooses a pretty-printer. + * Writing a Pretty-Printer:: Writing a Pretty-Printer. + * Type Printing API:: Pretty-printing types. ++* Frame Filter API:: Filtering Frames. ++* Frame Decorator API:: Decorating Frames. ++* Writing a Frame Filter:: Writing a Frame Filter. + * Inferiors In Python:: Python representation of inferiors (processes) + * Events In Python:: Listening for events from @value{GDBN}. + * Threads In Python:: Accessing inferior threads from Python. +@@ -24415,6 +24576,636 @@ done then type printers would have to ma + order to avoid holding information that could become stale as the + inferior changed. + ++@node Frame Filter API ++@subsubsection Filtering Frames. ++@cindex frame filters api ++ ++Frame filters are Python objects that manipulate the visibility of a ++frame or frames when a backtrace (@pxref{Backtrace}) is printed by ++@value{GDBN}. ++ ++Only commands that print a backtrace, or, in the case of @sc{gdb/mi} ++commands (@pxref{GDB/MI}), those that return a collection of frames ++are affected. The commands that work with frame filters are: ++ ++@code{backtrace} (@pxref{backtrace-command,, The backtrace command}), ++@code{-stack-list-frames} ++(@pxref{-stack-list-frames,, The -stack-list-frames command}), ++@code{-stack-list-variables} (@pxref{-stack-list-variables,, The ++-stack-list-variables command}), @code{-stack-list-arguments} ++@pxref{-stack-list-arguments,, The -stack-list-arguments command}) and ++@code{-stack-list-locals} (@pxref{-stack-list-locals,, The ++-stack-list-locals command}). ++ ++A frame filter works by taking an iterator as an argument, applying ++actions to the contents of that iterator, and returning another ++iterator (or, possibly, the same iterator it was provided in the case ++where the filter does not perform any operations). Typically, frame ++filters utilize tools such as the Python's @code{itertools} module to ++work with and create new iterators from the source iterator. ++Regardless of how a filter chooses to apply actions, it must not alter ++the underlying @value{GDBN} frame or frames, or attempt to alter the ++call-stack within @value{GDBN}. This preserves data integrity within ++@value{GDBN}. Frame filters are executed on a priority basis and care ++should be taken that some frame filters may have been executed before, ++and that some frame filters will be executed after. ++ ++An important consideration when designing frame filters, and well ++worth reflecting upon, is that frame filters should avoid unwinding ++the call stack if possible. Some stacks can run very deep, into the ++tens of thousands in some cases. To search every frame when a frame ++filter executes may be too expensive at that step. The frame filter ++cannot know how many frames it has to iterate over, and it may have to ++iterate through them all. This ends up duplicating effort as ++@value{GDBN} performs this iteration when it prints the frames. If ++the filter can defer unwinding frames until frame decorators are ++executed, after the last filter has executed, it should. @xref{Frame ++Decorator API}, for more information on decorators. Also, there are ++examples for both frame decorators and filters in later chapters. ++@xref{Writing a Frame Filter}, for more information. ++ ++The Python dictionary @code{gdb.frame_filters} contains key/object ++pairings that comprise a frame filter. Frame filters in this ++dictionary are called @code{global} frame filters, and they are ++available when debugging all inferiors. These frame filters must ++register with the dictionary directly. In addition to the ++@code{global} dictionary, there are other dictionaries that are loaded ++with different inferiors via auto-loading (@pxref{Python ++Auto-loading}). The two other areas where frame filter dictionaries ++can be found are: @code{gdb.Progspace} which contains a ++@code{frame_filters} dictionary attribute, and each @code{gdb.Objfile} ++object which also contains a @code{frame_filters} dictionary ++attribute. ++ ++When a command is executed from @value{GDBN} that is compatible with ++frame filters, @value{GDBN} combines the @code{global}, ++@code{gdb.Progspace} and all @code{gdb.Objfile} dictionaries currently ++loaded. All of the @code{gdb.Objfile} dictionaries are combined, as ++several frames, and thus several object files, might be in use. ++@value{GDBN} then prunes any frame filter whose @code{enabled} ++attribute is @code{False}. This pruned list is then sorted according ++to the @code{priority} attribute in each filter. ++ ++Once the dictionaries are combined, pruned and sorted, @value{GDBN} ++creates an iterator which wraps each frame in the call stack in a ++@code{FrameDecorator} object, and calls each filter in order. The ++output from the previous filter will always be the input to the next ++filter, and so on. ++ ++Frame filters have a mandatory interface which each frame filter must ++implement, defined here: ++ ++@defun FrameFilter.filter (iterator) ++@value{GDBN} will call this method on a frame filter when it has ++reached the order in the priority list for that filter. ++ ++For example, if there are four frame filters: ++ ++@smallexample ++Name Priority ++ ++Filter1 5 ++Filter2 10 ++Filter3 100 ++Filter4 1 ++@end smallexample ++ ++The order that the frame filters will be called is: ++ ++@smallexample ++Filter3 -> Filter2 -> Filter1 -> Filter4 ++@end smallexample ++ ++Note that the output from @code{Filter3} is passed to the input of ++@code{Filter2}, and so on. ++ ++This @code{filter} method is passed a Python iterator. This iterator ++contains a sequence of frame decorators that wrap each ++@code{gdb.Frame}, or a frame decorator that wraps another frame ++decorator. The first filter that is executed in the sequence of frame ++filters will receive an iterator entirely comprised of default ++@code{FrameDecorator} objects. However, after each frame filter is ++executed, the previous frame filter may have wrapped some or all of ++the frame decorators with their own frame decorator. As frame ++decorators must also conform to a mandatory interface, these ++decorators can be assumed to act in a uniform manner (@pxref{Frame ++Decorator API}). ++ ++This method must return an object conforming to the Python iterator ++protocol. Each item in the iterator must be an object conforming to ++the frame decorator interface. If a frame filter does not wish to ++perform any operations on this iterator, it should return that ++iterator untouched. ++ ++This method is not optional. If it does not exist, @value{GDBN} will ++raise and print an error. ++@end defun ++ ++@defvar FrameFilter.name ++The @code{name} attribute must be Python string which contains the ++name of the filter displayed by @value{GDBN} (@pxref{Frame Filter ++Management}). This attribute may contain any combination of letters ++or numbers. Care should be taken to ensure that it is unique. This ++attribute is mandatory. ++@end defvar ++ ++@defvar FrameFilter.enabled ++The @code{enabled} attribute must be Python boolean. This attribute ++indicates to @value{GDBN} whether the frame filter is enabled, and ++should be considered when frame filters are executed. If ++@code{enabled} is @code{True}, then the frame filter will be executed ++when any of the backtrace commands detailed earlier in this chapter ++are executed. If @code{enabled} is @code{False}, then the frame ++filter will not be executed. This attribute is mandatory. ++@end defvar ++ ++@defvar FrameFilter.priority ++The @code{priority} attribute must be Python integer. This attribute ++controls the order of execution in relation to other frame filters. ++There are no imposed limits on the range of @code{priority} other than ++it must be a valid integer. The higher the @code{priority} attribute, ++the sooner the frame filter will be executed in relation to other ++frame filters. Although @code{priority} can be negative, it is ++recommended practice to assume zero is the lowest priority that a ++frame filter can be assigned. Frame filters that have the same ++priority are executed in unsorted order in that priority slot. This ++attribute is mandatory. ++@end defvar ++ ++@node Frame Decorator API ++@subsubsection Decorating Frames. ++@cindex frame decorator api ++ ++Frame decorators are sister objects to frame filters (@pxref{Frame ++Filter API}). Frame decorators are applied by a frame filter and can ++only be used in conjunction with frame filters. ++ ++The purpose of a frame decorator is to customize the printed content ++of each @code{gdb.Frame} in commands where frame filters are executed. ++This concept is called decorating a frame. Frame decorators decorate ++a @code{gdb.Frame} with Python code contained within each API call. ++This separates the actual data contained in a @code{gdb.Frame} from ++the decorated data produced by a frame decorator. This abstraction is ++necessary to maintain integrity of the data contained in each ++@code{gdb.Frame}. ++ ++Frame decorators have a mandatory interface, defined below. ++ ++@value{GDBN} already contains a frame decorator called ++@code{FrameDecorator}. This contains substantial amounts of ++boilerplate code to decorate the content of a @code{gdb.Frame}. It is ++recommended that other frame decorators inherit and extend this ++object, and only to override the methods needed. ++ ++@defun FrameDecorator.elided (self) ++ ++The @code{elided} method groups frames together in a hierarchical ++system. An example would be an interpreter, where multiple low-level ++frames make up a single call in the interpreted language. In this ++example, the frame filter would elide the low-level frames and present ++a single high-level frame, representing the call in the interpreted ++language, to the user. ++ ++The @code{elided} function must return an iterable and this iterable ++must contain the frames that are being elided wrapped in a suitable ++frame decorator. If no frames are being elided this function may ++return an empty iterable, or @code{None}. Elided frames are indented ++from normal frames in a @code{CLI} backtrace, or in the case of ++@code{GDB/MI}, are placed in the @code{children} field of the eliding ++frame. ++ ++It is the frame filter's task to also filter out the elided frames from ++the source iterator. This will avoid printing the frame twice. ++@end defun ++ ++@defun FrameDecorator.function (self) ++ ++This method returns the name of the function in the frame that is to ++be printed. ++ ++This method must return a Python string describing the function, or ++@code{None}. ++ ++If this function returns @code{None}, @value{GDBN} will not print any ++data for this field. ++@end defun ++ ++@defun FrameDecorator.address (self) ++ ++This method returns the address of the frame that is to be printed. ++ ++This method must return a Python numeric integer type of sufficient ++size to describe the address of the frame, or @code{None}. ++ ++If this function returns a @code{None}, @value{GDBN} will not print ++any data for this field. ++@end defun ++ ++@defun FrameDecorator.filename (self) ++ ++This method returns the filename and path associated with this frame. ++ ++This method must return a Python string containing the filename and ++the path to the object file backing the frame, or @code{None}. ++ ++If this function returns a @code{None}, @value{GDBN} will not print ++any data for this field. ++@end defun ++ ++@defun FrameDecorator.line (self): ++ ++This method returns the line number associated with the current ++position within the function addressed by this frame. ++ ++This method must return a Python integer type, or @code{None}. ++ ++If this function returns a @code{None}, @value{GDBN} will not print ++any data for this field. ++@end defun ++ ++@defun FrameDecorator.frame_args (self) ++@anchor{frame_args} ++ ++This method must return an iterable, or @code{None}. Returning an ++empty iterable, or @code{None} means frame arguments will not be ++printed for this frame. This iterable must contain objects that ++implement two methods, described here. ++ ++This object must implement a @code{argument} method which takes a ++single @code{self} parameter and must return a @code{gdb.Symbol} ++(@pxref{Symbols In Python}), or a Python string. The object must also ++implement a @code{value} method which takes a single @code{self} ++parameter and must return a @code{gdb.Value} (@pxref{Values From ++Inferior}), a Python value, or @code{None}. If the @code{value} ++method returns @code{None}, and the @code{argument} method returns a ++@code{gdb.Symbol}, @value{GDBN} will look-up and print the value of ++the @code{gdb.Symbol} automatically. ++ ++A brief example: ++ ++@smallexample ++class SymValueWrapper(): ++ ++ def __init__(self, symbol, value): ++ self.sym = symbol ++ self.val = value ++ ++ def value(self): ++ return self.val ++ ++ def symbol(self): ++ return self.sym ++ ++class SomeFrameDecorator() ++... ++... ++ def frame_args(self): ++ args = [] ++ try: ++ block = self.inferior_frame.block() ++ except: ++ return None ++ ++ # Iterate over all symbols in a block. Only add ++ # symbols that are arguments. ++ for sym in block: ++ if not sym.is_argument: ++ continue ++ args.append(SymValueWrapper(sym,None)) ++ ++ # Add example synthetic argument. ++ args.append(SymValueWrapper(``foo'', 42)) ++ ++ return args ++@end smallexample ++@end defun ++ ++@defun FrameDecorator.frame_locals (self) ++ ++This method must return an iterable or @code{None}. Returning an ++empty iterable, or @code{None} means frame local arguments will not be ++printed for this frame. ++ ++The object interface, the description of the various strategies for ++reading frame locals, and the example are largely similar to those ++described in the @code{frame_args} function, (@pxref{frame_args,,The ++frame filter frame_args function}). Below is a modified example: ++ ++@smallexample ++class SomeFrameDecorator() ++... ++... ++ def frame_locals(self): ++ vars = [] ++ try: ++ block = self.inferior_frame.block() ++ except: ++ return None ++ ++ # Iterate over all symbols in a block. Add all ++ # symbols, except arguments. ++ for sym in block: ++ if sym.is_argument: ++ continue ++ vars.append(SymValueWrapper(sym,None)) ++ ++ # Add an example of a synthetic local variable. ++ vars.append(SymValueWrapper(``bar'', 99)) ++ ++ return vars ++@end smallexample ++@end defun ++ ++@defun FrameDecorator.inferior_frame (self): ++ ++This method must return the underlying @code{gdb.Frame} that this ++frame decorator is decorating. @value{GDBN} requires the underlying ++frame for internal frame information to determine how to print certain ++values when printing a frame. ++@end defun ++ ++@node Writing a Frame Filter ++@subsubsection Writing a Frame Filter ++@cindex writing a frame filter ++ ++There are three basic elements that a frame filter must implement: it ++must correctly implement the documented interface (@pxref{Frame Filter ++API}), it must register itself with @value{GDBN}, and finally, it must ++decide if it is to work on the data provided by @value{GDBN}. In all ++cases, whether it works on the iterator or not, each frame filter must ++return an iterator. A bare-bones frame filter follows the pattern in ++the following example. ++ ++@smallexample ++import gdb ++ ++class FrameFilter(): ++ ++ def __init__(self): ++ # Frame filter attribute creation. ++ # ++ # 'name' is the name of the filter that GDB will display. ++ # ++ # 'priority' is the priority of the filter relative to other ++ # filters. ++ # ++ # 'enabled' is a boolean that indicates whether this filter is ++ # enabled and should be executed. ++ ++ self.name = "Foo" ++ self.priority = 100 ++ self.enabled = True ++ ++ # Register this frame filter with the global frame_filters ++ # dictionary. ++ gdb.frame_filters[self.name] = self ++ ++ def filter(self, frame_iter): ++ # Just return the iterator. ++ return frame_iter ++@end smallexample ++ ++The frame filter in the example above implements the three ++requirements for all frame filters. It implements the API, self ++registers, and makes a decision on the iterator (in this case, it just ++returns the iterator untouched). ++ ++The first step is attribute creation and assignment, and as shown in ++the comments the filter assigns the following attributes: @code{name}, ++@code{priority} and whether the filter should be enabled with the ++@code{enabled} attribute. ++ ++The second step is registering the frame filter with the dictionary or ++dictionaries that the frame filter has interest in. As shown in the ++comments, this filter just registers itself with the global dictionary ++@code{gdb.frame_filters}. As noted earlier, @code{gdb.frame_filters} ++is a dictionary that is initialized in the @code{gdb} module when ++@value{GDBN} starts. What dictionary a filter registers with is an ++important consideration. Generally, if a filter is specific to a set ++of code, it should be registered either in the @code{objfile} or ++@code{progspace} dictionaries as they are specific to the program ++currently loaded in @value{GDBN}. The global dictionary is always ++present in @value{GDBN} and is never unloaded. Any filters registered ++with the global dictionary will exist until @value{GDBN} exits. To ++avoid filters that may conflict, it is generally better to register ++frame filters against the dictionaries that more closely align with ++the usage of the filter currently in question. @xref{Python ++Auto-loading}, for further information on auto-loading Python scripts. ++ ++@value{GDBN} takes a hands-off approach to frame filter registration, ++therefore it is the frame filter's responsibility to ensure ++registration has occurred, and that any exceptions are handled ++appropriately. In particular, you may wish to handle exceptions ++relating to Python dictionary key uniqueness. It is mandatory that ++the dictionary key is the same as frame filter's @code{name} ++attribute. When a user manages frame filters (@pxref{Frame Filter ++Management}), the names @value{GDBN} will display are those contained ++in the @code{name} attribute. ++ ++The final step of this example is the implementation of the ++@code{filter} method. As shown in the example comments, we define the ++@code{filter} method and note that the method must take an iterator, ++and also must return an iterator. In this bare-bones example, the ++frame filter is not very useful as it just returns the iterator ++untouched. However this is a valid operation for frame filters that ++have the @code{enabled} attribute set, but decide not to operate on ++any frames. ++ ++In the next example, the frame filter operates on all frames and ++utilizes a frame decorator to perform some work on the frames. ++@xref{Frame Decorator API}, for further information on the frame ++decorator interface. ++ ++This example works on inlined frames. It highlights frames which are ++inlined by tagging them with an ``[inlined]'' tag. By applying a ++frame decorator to all frames with the Python @code{itertools imap} ++method, the example defers actions to the frame decorator. Frame ++decorators are only processed when @value{GDBN} prints the backtrace. ++ ++This introduces a new decision making topic: whether to perform ++decision making operations at the filtering step, or at the printing ++step. In this example's approach, it does not perform any filtering ++decisions at the filtering step beyond mapping a frame decorator to ++each frame. This allows the actual decision making to be performed ++when each frame is printed. This is an important consideration, and ++well worth reflecting upon when designing a frame filter. An issue ++that frame filters should avoid is unwinding the stack if possible. ++Some stacks can run very deep, into the tens of thousands in some ++cases. To search every frame to determine if it is inlined ahead of ++time may be too expensive at the filtering step. The frame filter ++cannot know how many frames it has to iterate over, and it would have ++to iterate through them all. This ends up duplicating effort as ++@value{GDBN} performs this iteration when it prints the frames. ++ ++In this example decision making can be deferred to the printing step. ++As each frame is printed, the frame decorator can examine each frame ++in turn when @value{GDBN} iterates. From a performance viewpoint, ++this is the most appropriate decision to make as it avoids duplicating ++the effort that the printing step would undertake anyway. Also, if ++there are many frame filters unwinding the stack during filtering, it ++can substantially delay the printing of the backtrace which will ++result in large memory usage, and a poor user experience. ++ ++@smallexample ++class InlineFilter(): ++ ++ def __init__(self): ++ self.name = "InlinedFrameFilter" ++ self.priority = 100 ++ self.enabled = True ++ gdb.frame_filters[self.name] = self ++ ++ def filter(self, frame_iter): ++ frame_iter = itertools.imap(InlinedFrameDecorator, ++ frame_iter) ++ return frame_iter ++@end smallexample ++ ++This frame filter is somewhat similar to the earlier example, except ++that the @code{filter} method applies a frame decorator object called ++@code{InlinedFrameDecorator} to each element in the iterator. The ++@code{imap} Python method is light-weight. It does not proactively ++iterate over the iterator, but rather creates a new iterator which ++wraps the existing one. ++ ++Below is the frame decorator for this example. ++ ++@smallexample ++class InlinedFrameDecorator(FrameDecorator): ++ ++ def __init__(self, fobj): ++ super(InlinedFrameDecorator, self).__init__(fobj) ++ ++ def function(self): ++ frame = fobj.inferior_frame() ++ name = str(frame.name()) ++ ++ if frame.type() == gdb.INLINE_FRAME: ++ name = name + " [inlined]" ++ ++ return name ++@end smallexample ++ ++This frame decorator only defines and overrides the @code{function} ++method. It lets the supplied @code{FrameDecorator}, which is shipped ++with @value{GDBN}, perform the other work associated with printing ++this frame. ++ ++The combination of these two objects create this output from a ++backtrace: ++ ++@smallexample ++#0 0x004004e0 in bar () at inline.c:11 ++#1 0x00400566 in max [inlined] (b=6, a=12) at inline.c:21 ++#2 0x00400566 in main () at inline.c:31 ++@end smallexample ++ ++So in the case of this example, a frame decorator is applied to all ++frames, regardless of whether they may be inlined or not. As ++@value{GDBN} iterates over the iterator produced by the frame filters, ++@value{GDBN} executes each frame decorator which then makes a decision ++on what to print in the @code{function} callback. Using a strategy ++like this is a way to defer decisions on the frame content to printing ++time. ++ ++@subheading Eliding Frames ++ ++It might be that the above example is not desirable for representing ++inlined frames, and a hierarchical approach may be preferred. If we ++want to hierarchically represent frames, the @code{elided} frame ++decorator interface might be preferable. ++ ++This example approaches the issue with the @code{elided} method. This ++example is quite long, but very simplistic. It is out-of-scope for ++this section to write a complete example that comprehensively covers ++all approaches of finding and printing inlined frames. However, this ++example illustrates the approach an author might use. ++ ++This example comprises of three sections. ++ ++@smallexample ++class InlineFrameFilter(): ++ ++ def __init__(self): ++ self.name = "InlinedFrameFilter" ++ self.priority = 100 ++ self.enabled = True ++ gdb.frame_filters[self.name] = self ++ ++ def filter(self, frame_iter): ++ return ElidingInlineIterator(frame_iter) ++@end smallexample ++ ++This frame filter is very similar to the other examples. The only ++difference is this frame filter is wrapping the iterator provided to ++it (@code{frame_iter}) with a custom iterator called ++@code{ElidingInlineIterator}. This again defers actions to when ++@value{GDBN} prints the backtrace, as the iterator is not traversed ++until printing. ++ ++The iterator for this example is as follows. It is in this section of ++the example where decisions are made on the content of the backtrace. ++ ++@smallexample ++class ElidingInlineIterator: ++ def __init__(self, ii): ++ self.input_iterator = ii ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ frame = next(self.input_iterator) ++ ++ if frame.inferior_frame().type() != gdb.INLINE_FRAME: ++ return frame ++ ++ try: ++ eliding_frame = next(self.input_iterator) ++ except StopIteration: ++ return frame ++ return ElidingFrameDecorator(eliding_frame, [frame]) ++@end smallexample ++ ++This iterator implements the Python iterator protocol. When the ++@code{next} function is called (when @value{GDBN} prints each frame), ++the iterator checks if this frame decorator, @code{frame}, is wrapping ++an inlined frame. If it is not, it returns the existing frame decorator ++untouched. If it is wrapping an inlined frame, it assumes that the ++inlined frame was contained within the next oldest frame, ++@code{eliding_frame}, which it fetches. It then creates and returns a ++frame decorator, @code{ElidingFrameDecorator}, which contains both the ++elided frame, and the eliding frame. ++ ++@smallexample ++class ElidingInlineDecorator(FrameDecorator): ++ ++ def __init__(self, frame, elided_frames): ++ super(ElidingInlineDecorator, self).__init__(frame) ++ self.frame = frame ++ self.elided_frames = elided_frames ++ ++ def elided(self): ++ return iter(self.elided_frames) ++@end smallexample ++ ++This frame decorator overrides one function and returns the inlined ++frame in the @code{elided} method. As before it lets ++@code{FrameDecorator} do the rest of the work involved in printing ++this frame. This produces the following output. ++ ++@smallexample ++#0 0x004004e0 in bar () at inline.c:11 ++#2 0x00400529 in main () at inline.c:25 ++ #1 0x00400529 in max (b=6, a=12) at inline.c:15 ++@end smallexample ++ ++In that output, @code{max} which has been inlined into @code{main} is ++printed hierarchically. Another approach would be to combine the ++@code{function} method, and the @code{elided} method to both print a ++marker in the inlined frame, and also show the hierarchical ++relationship. ++ + @node Inferiors In Python + @subsubsection Inferiors In Python + @cindex inferiors in Python +@@ -25245,6 +26036,11 @@ The @code{type_printers} attribute is a + @xref{Type Printing API}, for more information. + @end defvar + ++@defvar Progspace.frame_filters ++The @code{frame_filters} attribute is a dictionary of frame filter ++objects. @xref{Frame Filter API}, for more information. ++@end defvar ++ + @node Objfiles In Python + @subsubsection Objfiles In Python + +@@ -25295,6 +26091,11 @@ The @code{type_printers} attribute is a + @xref{Type Printing API}, for more information. + @end defvar + ++@defvar Objfile.frame_filters ++The @code{frame_filters} attribute is a dictionary of frame filter ++objects. @xref{Frame Filter API}, for more information. ++@end defvar ++ + A @code{gdb.Objfile} object has the following methods: + + @defun Objfile.is_valid () +@@ -26313,7 +27114,7 @@ No my-foo-pretty-printers.py + When reading an auto-loaded file, @value{GDBN} sets the + @dfn{current objfile}. This is available via the @code{gdb.current_objfile} + function (@pxref{Objfiles In Python}). This can be useful for +-registering objfile-specific pretty-printers. ++registering objfile-specific pretty-printers and frame-filters. + + @menu + * objfile-gdb.py file:: The @file{@var{objfile}-gdb.py} file +@@ -30184,6 +30985,22 @@ Is this going away???? + @node GDB/MI Stack Manipulation + @section @sc{gdb/mi} Stack Manipulation Commands + ++@subheading The @code{-enable-frame-filters} Command ++@findex -enable-frame-filters ++ ++@smallexample ++-enable-frame-filters ++@end smallexample ++ ++@value{GDBN} allows Python-based frame filters to affect the output of ++the MI commands relating to stack traces. As there is no way to ++implement this in a fully backward-compatible way, a front end must ++request that this functionality be enabled. ++ ++Once enabled, this feature cannot be disabled. ++ ++Note that if Python support has not been compiled into @value{GDBN}, ++this command will still succeed (and do nothing). + + @subheading The @code{-stack-info-frame} Command + @findex -stack-info-frame +@@ -30251,13 +31068,14 @@ For a stack with frame levels 0 through + (gdb) + @end smallexample + ++@anchor{-stack-list-arguments} + @subheading The @code{-stack-list-arguments} Command + @findex -stack-list-arguments + + @subsubheading Synopsis + + @smallexample +- -stack-list-arguments @var{print-values} ++ -stack-list-arguments [ --no-frame-filters ] @var{print-values} + [ @var{low-frame} @var{high-frame} ] + @end smallexample + +@@ -30274,7 +31092,9 @@ If @var{print-values} is 0 or @code{--no + the variables; if it is 1 or @code{--all-values}, print also their + values; and if it is 2 or @code{--simple-values}, print the name, + type and value for simple data types, and the name and type for arrays, +-structures and unions. ++structures and unions. If the option @code{--no-frame-filters} is ++supplied, then Python frame filters will not be executed. ++ + + Use of this command to obtain arguments in a single frame is + deprecated in favor of the @samp{-stack-list-variables} command. +@@ -30345,13 +31165,14 @@ args=[@{name="intarg",value="2"@}, + @c @subheading -stack-list-exception-handlers + + ++@anchor{-stack-list-frames} + @subheading The @code{-stack-list-frames} Command + @findex -stack-list-frames + + @subsubheading Synopsis + + @smallexample +- -stack-list-frames [ @var{low-frame} @var{high-frame} ] ++ -stack-list-frames [ --no-frame-filters @var{low-frame} @var{high-frame} ] + @end smallexample + + List the frames currently on the stack. For each frame it displays the +@@ -30381,7 +31202,9 @@ levels are between the two arguments (in + are equal, it shows the single frame at the corresponding level. It is + an error if @var{low-frame} is larger than the actual number of + frames. On the other hand, @var{high-frame} may be larger than the +-actual number of frames, in which case only existing frames will be returned. ++actual number of frames, in which case only existing frames will be ++returned. If the option @code{--no-frame-filters} is supplied, then ++Python frame filters will not be executed. + + @subsubheading @value{GDBN} Command + +@@ -30451,11 +31274,12 @@ Show a single frame: + + @subheading The @code{-stack-list-locals} Command + @findex -stack-list-locals ++@anchor{-stack-list-locals} + + @subsubheading Synopsis + + @smallexample +- -stack-list-locals @var{print-values} ++ -stack-list-locals [ --no-frame-filters ] @var{print-values} + @end smallexample + + Display the local variable names for the selected frame. If +@@ -30466,7 +31290,8 @@ type and value for simple data types, an + structures and unions. In this last case, a frontend can immediately + display the value of simple data types and create variable objects for + other data types when the user wishes to explore their values in +-more detail. ++more detail. If the option @code{--no-frame-filters} is supplied, then ++Python frame filters will not be executed. + + This command is deprecated in favor of the + @samp{-stack-list-variables} command. +@@ -30491,13 +31316,14 @@ This command is deprecated in favor of t + (gdb) + @end smallexample + ++@anchor{-stack-list-variables} + @subheading The @code{-stack-list-variables} Command + @findex -stack-list-variables + + @subsubheading Synopsis + + @smallexample +- -stack-list-variables @var{print-values} ++ -stack-list-variables [ --no-frame-filters ] @var{print-values} + @end smallexample + + Display the names of local variables and function arguments for the selected frame. If +@@ -30505,7 +31331,8 @@ Display the names of local variables and + the variables; if it is 1 or @code{--all-values}, print also their + values; and if it is 2 or @code{--simple-values}, print the name, + type and value for simple data types, and the name and type for arrays, +-structures and unions. ++structures and unions. If the option @code{--no-frame-filters} is ++supplied, then Python frame filters will not be executed. + + @subsubheading Example + +Index: gdb-7.6/gdb/mi/mi-cmd-stack.c +=================================================================== +--- gdb-7.6.orig/gdb/mi/mi-cmd-stack.c 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/mi/mi-cmd-stack.c 2013-05-20 22:25:52.111165767 +0200 +@@ -31,6 +31,10 @@ + #include "language.h" + #include "valprint.h" + #include "exceptions.h" ++#include "utils.h" ++#include "mi-getopt.h" ++#include "python/python.h" ++#include + + enum what_to_list { locals, arguments, all }; + +@@ -38,6 +42,28 @@ static void list_args_or_locals (enum wh + enum print_values values, + struct frame_info *fi); + ++/* True if we want to allow Python-based frame filters. */ ++static int frame_filters = 0; ++ ++void ++mi_cmd_enable_frame_filters (char *command, char **argv, int argc) ++{ ++ if (argc != 0) ++ error (_("-enable-frame-filters: no arguments allowed")); ++ frame_filters = 1; ++} ++ ++/* Parse the --no-frame-filters option in commands where we cannot use ++ mi_getopt. */ ++static int ++parse_no_frames_option (const char *arg) ++{ ++ if (arg && (strcmp (arg, "--no-frame-filters") == 0)) ++ return 1; ++ ++ return 0; ++} ++ + /* Print a list of the stack frames. Args can be none, in which case + we want to print the whole backtrace, or a pair of numbers + specifying the frame numbers at which to start and stop the +@@ -52,14 +78,46 @@ mi_cmd_stack_list_frames (char *command, + int i; + struct cleanup *cleanup_stack; + struct frame_info *fi; ++ enum py_bt_status result = PY_BT_ERROR; ++ int raw_arg = 0; ++ int oind = 0; ++ enum opt ++ { ++ NO_FRAME_FILTERS ++ }; ++ static const struct mi_opt opts[] = ++ { ++ {"-no-frame-filters", NO_FRAME_FILTERS, 0}, ++ { 0, 0, 0 } ++ }; ++ ++ /* Parse arguments. In this instance we are just looking for ++ --no-frame-filters. */ ++ while (1) ++ { ++ char *oarg; ++ int opt = mi_getopt ("-stack-list-frames", argc, argv, ++ opts, &oind, &oarg); ++ if (opt < 0) ++ break; ++ switch ((enum opt) opt) ++ { ++ case NO_FRAME_FILTERS: ++ raw_arg = oind; ++ break; ++ } ++ } + +- if (argc > 2 || argc == 1) +- error (_("-stack-list-frames: Usage: [FRAME_LOW FRAME_HIGH]")); ++ /* After the last option is parsed, there should either be low - ++ high range, or no further arguments. */ ++ if ((argc - oind != 0) && (argc - oind != 2)) ++ error (_("-stack-list-frames: Usage: [--no-frame-filters] [FRAME_LOW FRAME_HIGH]")); + +- if (argc == 2) ++ /* If there is a range, set it. */ ++ if (argc - oind == 2) + { +- frame_low = atoi (argv[0]); +- frame_high = atoi (argv[1]); ++ frame_low = atoi (argv[0 + oind]); ++ frame_high = atoi (argv[1 + oind]); + } + else + { +@@ -81,16 +139,37 @@ mi_cmd_stack_list_frames (char *command, + + cleanup_stack = make_cleanup_ui_out_list_begin_end (current_uiout, "stack"); + +- /* Now let's print the frames up to frame_high, or until there are +- frames in the stack. */ +- for (; +- fi && (i <= frame_high || frame_high == -1); +- i++, fi = get_prev_frame (fi)) ++ if (! raw_arg && frame_filters) + { +- QUIT; +- /* Print the location and the address always, even for level 0. +- If args is 0, don't print the arguments. */ +- print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ ); ++ int flags = PRINT_LEVEL | PRINT_FRAME_INFO; ++ int py_frame_low = frame_low; ++ ++ /* We cannot pass -1 to frame_low, as that would signify a ++ relative backtrace from the tail of the stack. So, in the case ++ of frame_low == -1, assign and increment it. */ ++ if (py_frame_low == -1) ++ py_frame_low++; ++ ++ result = apply_frame_filter (get_current_frame (), flags, ++ NO_VALUES, current_uiout, ++ py_frame_low, frame_high); ++ } ++ ++ /* Run the inbuilt backtrace if there are no filters registered, or ++ if "--no-frame-filters" has been specified from the command. */ ++ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) ++ { ++ /* Now let's print the frames up to frame_high, or until there are ++ frames in the stack. */ ++ for (; ++ fi && (i <= frame_high || frame_high == -1); ++ i++, fi = get_prev_frame (fi)) ++ { ++ QUIT; ++ /* Print the location and the address always, even for level 0. ++ If args is 0, don't print the arguments. */ ++ print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ ); ++ } + } + + do_cleanups (cleanup_stack); +@@ -147,13 +226,34 @@ void + mi_cmd_stack_list_locals (char *command, char **argv, int argc) + { + struct frame_info *frame; ++ int raw_arg = 0; ++ enum py_bt_status result = PY_BT_ERROR; ++ int print_value; ++ ++ if (argc > 0) ++ raw_arg = parse_no_frames_option (argv[0]); ++ ++ if (argc < 1 || argc > 2 || (argc == 2 && ! raw_arg) ++ || (argc == 1 && raw_arg)) ++ error (_("-stack-list-locals: Usage: [--no-frame-filters] PRINT_VALUES")); + +- if (argc != 1) +- error (_("-stack-list-locals: Usage: PRINT_VALUES")); +- +- frame = get_selected_frame (NULL); ++ frame = get_selected_frame (NULL); ++ print_value = parse_print_values (argv[raw_arg]); + +- list_args_or_locals (locals, parse_print_values (argv[0]), frame); ++ if (! raw_arg && frame_filters) ++ { ++ int flags = PRINT_LEVEL | PRINT_LOCALS; ++ ++ result = apply_frame_filter (frame, flags, print_value, ++ current_uiout, 0, 0); ++ } ++ ++ /* Run the inbuilt backtrace if there are no filters registered, or ++ if "--no-frame-filters" has been specified from the command. */ ++ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) ++ { ++ list_args_or_locals (locals, print_value, frame); ++ } + } + + /* Print a list of the arguments for the current frame. With argument +@@ -170,15 +270,20 @@ mi_cmd_stack_list_args (char *command, c + struct cleanup *cleanup_stack_args; + enum print_values print_values; + struct ui_out *uiout = current_uiout; ++ int raw_arg = 0; ++ enum py_bt_status result = PY_BT_ERROR; + +- if (argc < 1 || argc > 3 || argc == 2) +- error (_("-stack-list-arguments: Usage: " +- "PRINT_VALUES [FRAME_LOW FRAME_HIGH]")); ++ if (argc > 0) ++ raw_arg = parse_no_frames_option (argv[0]); + +- if (argc == 3) ++ if (argc < 1 || (argc > 3 && ! raw_arg) || (argc == 2 && ! raw_arg)) ++ error (_("-stack-list-arguments: Usage: " \ ++ "[--no-frame-filters] PRINT_VALUES [FRAME_LOW FRAME_HIGH]")); ++ ++ if (argc >= 3) + { +- frame_low = atoi (argv[1]); +- frame_high = atoi (argv[2]); ++ frame_low = atoi (argv[1 + raw_arg]); ++ frame_high = atoi (argv[2 + raw_arg]); + } + else + { +@@ -188,7 +293,7 @@ mi_cmd_stack_list_args (char *command, c + frame_high = -1; + } + +- print_values = parse_print_values (argv[0]); ++ print_values = parse_print_values (argv[raw_arg]); + + /* Let's position fi on the frame at which to start the + display. Could be the innermost frame if the whole stack needs +@@ -203,21 +308,41 @@ mi_cmd_stack_list_args (char *command, c + cleanup_stack_args + = make_cleanup_ui_out_list_begin_end (uiout, "stack-args"); + +- /* Now let's print the frames up to frame_high, or until there are +- frames in the stack. */ +- for (; +- fi && (i <= frame_high || frame_high == -1); +- i++, fi = get_prev_frame (fi)) ++ if (! raw_arg && frame_filters) + { +- struct cleanup *cleanup_frame; ++ int flags = PRINT_LEVEL | PRINT_ARGS; ++ int py_frame_low = frame_low; + +- QUIT; +- cleanup_frame = make_cleanup_ui_out_tuple_begin_end (uiout, "frame"); +- ui_out_field_int (uiout, "level", i); +- list_args_or_locals (arguments, print_values, fi); +- do_cleanups (cleanup_frame); ++ /* We cannot pass -1 to frame_low, as that would signify a ++ relative backtrace from the tail of the stack. So, in the case ++ of frame_low == -1, assign and increment it. */ ++ if (py_frame_low == -1) ++ py_frame_low++; ++ ++ result = apply_frame_filter (get_current_frame (), flags, ++ print_values, current_uiout, ++ py_frame_low, frame_high); + } + ++ /* Run the inbuilt backtrace if there are no filters registered, or ++ if "--no-frame-filters" has been specified from the command. */ ++ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) ++ { ++ /* Now let's print the frames up to frame_high, or until there are ++ frames in the stack. */ ++ for (; ++ fi && (i <= frame_high || frame_high == -1); ++ i++, fi = get_prev_frame (fi)) ++ { ++ struct cleanup *cleanup_frame; ++ ++ QUIT; ++ cleanup_frame = make_cleanup_ui_out_tuple_begin_end (uiout, "frame"); ++ ui_out_field_int (uiout, "level", i); ++ list_args_or_locals (arguments, print_values, fi); ++ do_cleanups (cleanup_frame); ++ } ++ } + do_cleanups (cleanup_stack_args); + } + +@@ -230,13 +355,35 @@ void + mi_cmd_stack_list_variables (char *command, char **argv, int argc) + { + struct frame_info *frame; ++ int raw_arg = 0; ++ enum py_bt_status result = PY_BT_ERROR; ++ int print_value; ++ ++ if (argc > 0) ++ raw_arg = parse_no_frames_option (argv[0]); ++ ++ if (argc < 1 || argc > 2 || (argc == 2 && ! raw_arg) ++ || (argc == 1 && raw_arg)) ++ error (_("-stack-list-variables: Usage: " \ ++ "[--no-frame-filters] PRINT_VALUES")); + +- if (argc != 1) +- error (_("Usage: PRINT_VALUES")); +- +- frame = get_selected_frame (NULL); ++ frame = get_selected_frame (NULL); ++ print_value = parse_print_values (argv[raw_arg]); + +- list_args_or_locals (all, parse_print_values (argv[0]), frame); ++ if (! raw_arg && frame_filters) ++ { ++ int flags = PRINT_LEVEL | PRINT_ARGS | PRINT_LOCALS; ++ ++ result = apply_frame_filter (frame, flags, print_value, ++ current_uiout, 0, 0); ++ } ++ ++ /* Run the inbuilt backtrace if there are no filters registered, or ++ if "--no-frame-filters" has been specified from the command. */ ++ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) ++ { ++ list_args_or_locals (all, print_value, frame); ++ } + } + + /* Print single local or argument. ARG must be already read in. For +Index: gdb-7.6/gdb/mi/mi-cmds.c +=================================================================== +--- gdb-7.6.orig/gdb/mi/mi-cmds.c 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/mi/mi-cmds.c 2013-05-20 22:25:52.111165767 +0200 +@@ -86,6 +86,7 @@ static struct mi_cmd mi_cmds[] = + mi_cmd_data_write_register_values), + DEF_MI_CMD_MI ("enable-timings", mi_cmd_enable_timings), + DEF_MI_CMD_MI ("enable-pretty-printing", mi_cmd_enable_pretty_printing), ++ DEF_MI_CMD_MI ("enable-frame-filters", mi_cmd_enable_frame_filters), + DEF_MI_CMD_MI ("environment-cd", mi_cmd_env_cd), + DEF_MI_CMD_MI ("environment-directory", mi_cmd_env_dir), + DEF_MI_CMD_MI ("environment-path", mi_cmd_env_path), +Index: gdb-7.6/gdb/mi/mi-cmds.h +=================================================================== +--- gdb-7.6.orig/gdb/mi/mi-cmds.h 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/mi/mi-cmds.h 2013-05-20 22:25:52.111165767 +0200 +@@ -118,6 +118,7 @@ extern mi_cmd_argv_ftype mi_cmd_var_show + extern mi_cmd_argv_ftype mi_cmd_var_show_format; + extern mi_cmd_argv_ftype mi_cmd_var_update; + extern mi_cmd_argv_ftype mi_cmd_enable_pretty_printing; ++extern mi_cmd_argv_ftype mi_cmd_enable_frame_filters; + extern mi_cmd_argv_ftype mi_cmd_var_set_update_range; + + /* Description of a single command. */ +Index: gdb-7.6/gdb/python/py-framefilter.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/python/py-framefilter.c 2013-05-20 22:26:53.029143068 +0200 +@@ -0,0 +1,1528 @@ ++/* Python frame filters ++ ++ Copyright (C) 2013 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ 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 . */ ++ ++#include "defs.h" ++#include "objfiles.h" ++#include "symtab.h" ++#include "language.h" ++#include "exceptions.h" ++#include "arch-utils.h" ++#include "python.h" ++#include "ui-out.h" ++#include "valprint.h" ++#include "annotate.h" ++#include "hashtab.h" ++#include "demangle.h" ++#include "mi/mi-cmds.h" ++#include "python-internal.h" ++ ++enum mi_print_types ++{ ++ MI_PRINT_ARGS, ++ MI_PRINT_LOCALS ++}; ++ ++/* Helper function to extract a symbol, a name and a language ++ definition from a Python object that conforms to the "Symbol Value" ++ interface. OBJ is the Python object to extract the values from. ++ NAME is a pass-through argument where the name of the symbol will ++ be written. NAME is allocated in this function, but the caller is ++ responsible for clean up. SYM is a pass-through argument where the ++ symbol will be written. In the case of the API returning a string, ++ this will be set to NULL. LANGUAGE is also a pass-through argument ++ denoting the language attributed to the Symbol. In the case of SYM ++ being NULL, this will be set to the current language. Returns ++ PY_BT_ERROR on error with the appropriate Python exception set, and ++ PY_BT_OK on success. */ ++ ++static enum py_bt_status ++extract_sym (PyObject *obj, char **name, struct symbol **sym, ++ const struct language_defn **language) ++{ ++ PyObject *result = PyObject_CallMethod (obj, "symbol", NULL); ++ ++ if (result == NULL) ++ return PY_BT_ERROR; ++ ++ /* For 'symbol' callback, the function can return a symbol or a ++ string. */ ++ if (gdbpy_is_string (result)) ++ { ++ *name = python_string_to_host_string (result); ++ Py_DECREF (result); ++ ++ if (*name == NULL) ++ return PY_BT_ERROR; ++ /* If the API returns a string (and not a symbol), then there is ++ no symbol derived language available and the frame filter has ++ either overridden the symbol with a string, or supplied a ++ entirely synthetic symbol/value pairing. In that case, use ++ python_language. */ ++ *language = python_language; ++ *sym = NULL; ++ } ++ else ++ { ++ /* This type checks 'result' during the conversion so we ++ just call it unconditionally and check the return. */ ++ *sym = symbol_object_to_symbol (result); ++ ++ Py_DECREF (result); ++ ++ if (*sym == NULL) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ _("Unexpected value. Expecting a " ++ "gdb.Symbol or a Python string.")); ++ return PY_BT_ERROR; ++ } ++ ++ /* Duplicate the symbol name, so the caller has consistency ++ in garbage collection. */ ++ *name = xstrdup (SYMBOL_PRINT_NAME (*sym)); ++ ++ /* If a symbol is specified attempt to determine the language ++ from the symbol. If mode is not "auto", then the language ++ has been explicitly set, use that. */ ++ if (language_mode == language_mode_auto) ++ *language = language_def (SYMBOL_LANGUAGE (*sym)); ++ else ++ *language = current_language; ++ } ++ ++ return PY_BT_OK; ++} ++ ++/* Helper function to extract a value from an object that conforms to ++ the "Symbol Value" interface. OBJ is the Python object to extract ++ the value from. VALUE is a pass-through argument where the value ++ will be written. If the object does not have the value attribute, ++ or provides the Python None for a value, VALUE will be set to NULL ++ and this function will return as successful. Returns PY_BT_ERROR ++ on error with the appropriate Python exception set, and PY_BT_OK on ++ success. */ ++ ++static enum py_bt_status ++extract_value (PyObject *obj, struct value **value) ++{ ++ if (PyObject_HasAttrString (obj, "value")) ++ { ++ PyObject *vresult = PyObject_CallMethod (obj, "value", NULL); ++ ++ if (vresult == NULL) ++ return PY_BT_ERROR; ++ ++ /* The Python code has returned 'None' for a value, so we set ++ value to NULL. This flags that GDB should read the ++ value. */ ++ if (vresult == Py_None) ++ { ++ Py_DECREF (vresult); ++ *value = NULL; ++ return PY_BT_OK; ++ } ++ else ++ { ++ *value = convert_value_from_python (vresult); ++ Py_DECREF (vresult); ++ ++ if (*value == NULL) ++ return PY_BT_ERROR; ++ ++ return PY_BT_OK; ++ } ++ } ++ else ++ *value = NULL; ++ ++ return PY_BT_OK; ++} ++ ++/* MI prints only certain values according to the type of symbol and ++ also what the user has specified. SYM is the symbol to check, and ++ MI_PRINT_TYPES is an enum specifying what the user wants emitted ++ for the MI command in question. */ ++static int ++mi_should_print (struct symbol *sym, enum mi_print_types type) ++{ ++ int print_me = 0; ++ ++ switch (SYMBOL_CLASS (sym)) ++ { ++ default: ++ case LOC_UNDEF: /* catches errors */ ++ case LOC_CONST: /* constant */ ++ case LOC_TYPEDEF: /* local typedef */ ++ case LOC_LABEL: /* local label */ ++ case LOC_BLOCK: /* local function */ ++ case LOC_CONST_BYTES: /* loc. byte seq. */ ++ case LOC_UNRESOLVED: /* unresolved static */ ++ case LOC_OPTIMIZED_OUT: /* optimized out */ ++ print_me = 0; ++ break; ++ ++ case LOC_ARG: /* argument */ ++ case LOC_REF_ARG: /* reference arg */ ++ case LOC_REGPARM_ADDR: /* indirect register arg */ ++ case LOC_LOCAL: /* stack local */ ++ case LOC_STATIC: /* static */ ++ case LOC_REGISTER: /* register */ ++ case LOC_COMPUTED: /* computed location */ ++ if (type == MI_PRINT_LOCALS) ++ print_me = ! SYMBOL_IS_ARGUMENT (sym); ++ else ++ print_me = SYMBOL_IS_ARGUMENT (sym); ++ } ++ return print_me; ++} ++ ++/* Helper function which outputs a type name extracted from VAL to a ++ "type" field in the output stream OUT. OUT is the ui-out structure ++ the type name will be output too, and VAL is the value that the ++ type will be extracted from. Returns PY_BT_ERROR on error, with ++ any GDB exceptions converted to a Python exception, or PY_BT_OK on ++ success. */ ++ ++static enum py_bt_status ++py_print_type (struct ui_out *out, struct value *val) ++{ ++ volatile struct gdb_exception except; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ struct type *type; ++ struct ui_file *stb; ++ struct cleanup *cleanup; ++ ++ stb = mem_fileopen (); ++ cleanup = make_cleanup_ui_file_delete (stb); ++ type = check_typedef (value_type (val)); ++ type_print (value_type (val), "", stb, -1); ++ ui_out_field_stream (out, "type", stb); ++ do_cleanups (cleanup); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ return PY_BT_ERROR; ++ } ++ ++ return PY_BT_OK; ++} ++ ++/* Helper function which outputs a value to an output field in a ++ stream. OUT is the ui-out structure the value will be output to, ++ VAL is the value that will be printed, OPTS contains the value ++ printing options, ARGS_TYPE is an enumerator describing the ++ argument format, and LANGUAGE is the language_defn that the value ++ will be printed with. Returns PY_BT_ERROR on error, with any GDB ++ exceptions converted to a Python exception, or PY_BT_OK on ++ success. */ ++ ++static enum py_bt_status ++py_print_value (struct ui_out *out, struct value *val, ++ const struct value_print_options *opts, ++ int indent, ++ enum py_frame_args args_type, ++ const struct language_defn *language) ++{ ++ int should_print = 0; ++ volatile struct gdb_exception except; ++ int local_indent = (4 * indent); ++ ++ /* Never set an indent level for common_val_print if MI. */ ++ if (ui_out_is_mi_like_p (out)) ++ local_indent = 0; ++ ++ /* MI does not print certain values, differentiated by type, ++ depending on what ARGS_TYPE indicates. Test type against option. ++ For CLI print all values. */ ++ if (args_type == MI_PRINT_SIMPLE_VALUES ++ || args_type == MI_PRINT_ALL_VALUES) ++ { ++ struct type *type = NULL; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ type = check_typedef (value_type (val)); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ return PY_BT_ERROR; ++ } ++ ++ if (args_type == MI_PRINT_ALL_VALUES) ++ should_print = 1; ++ else if (args_type == MI_PRINT_SIMPLE_VALUES ++ && TYPE_CODE (type) != TYPE_CODE_ARRAY ++ && TYPE_CODE (type) != TYPE_CODE_STRUCT ++ && TYPE_CODE (type) != TYPE_CODE_UNION) ++ should_print = 1; ++ } ++ else if (args_type != NO_VALUES) ++ should_print = 1; ++ ++ if (should_print) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ struct ui_file *stb; ++ struct cleanup *cleanup; ++ ++ stb = mem_fileopen (); ++ cleanup = make_cleanup_ui_file_delete (stb); ++ common_val_print (val, stb, indent, opts, language); ++ ui_out_field_stream (out, "value", stb); ++ do_cleanups (cleanup); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ return PY_BT_ERROR; ++ } ++ } ++ ++ return PY_BT_OK; ++} ++ ++/* Helper function to call a Python method and extract an iterator ++ from the result. If the function returns anything but an iterator ++ the exception is preserved and NULL is returned. FILTER is the ++ Python object to call, and FUNC is the name of the method. Returns ++ a PyObject, or NULL on error with the appropriate exception set. ++ This function can return an iterator, or NULL. */ ++ ++static PyObject * ++get_py_iter_from_func (PyObject *filter, char *func) ++{ ++ if (PyObject_HasAttrString (filter, func)) ++ { ++ PyObject *result = PyObject_CallMethod (filter, func, NULL); ++ ++ if (result != NULL) ++ { ++ if (result == Py_None) ++ { ++ return result; ++ } ++ else ++ { ++ PyObject *iterator = PyObject_GetIter (result); ++ ++ Py_DECREF (result); ++ return iterator; ++ } ++ } ++ } ++ else ++ Py_RETURN_NONE; ++ ++ return NULL; ++} ++ ++/* Helper function to output a single frame argument and value to an ++ output stream. This function will account for entry values if the ++ FV parameter is populated, the frame argument has entry values ++ associated with them, and the appropriate "set entry-value" ++ options are set. Will output in CLI or MI like format depending ++ on the type of output stream detected. OUT is the output stream, ++ SYM_NAME is the name of the symbol. If SYM_NAME is populated then ++ it must have an accompanying value in the parameter FV. FA is a ++ frame argument structure. If FA is populated, both SYM_NAME and ++ FV are ignored. OPTS contains the value printing options, ++ ARGS_TYPE is an enumerator describing the argument format, ++ PRINT_ARGS_FIELD is a flag which indicates if we output "ARGS=1" ++ in MI output in commands where both arguments and locals are ++ printed. Returns PY_BT_ERROR on error, with any GDB exceptions ++ converted to a Python exception, or PY_BT_OK on success. */ ++ ++static enum py_bt_status ++py_print_single_arg (struct ui_out *out, ++ const char *sym_name, ++ struct frame_arg *fa, ++ struct value *fv, ++ const struct value_print_options *opts, ++ enum py_frame_args args_type, ++ int print_args_field, ++ const struct language_defn *language) ++{ ++ struct value *val; ++ volatile struct gdb_exception except; ++ ++ if (fa != NULL) ++ { ++ language = language_def (SYMBOL_LANGUAGE (fa->sym)); ++ val = fa->val; ++ } ++ else ++ val = fv; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); ++ ++ /* MI has varying rules for tuples, but generally if there is only ++ one element in each item in the list, do not start a tuple. The ++ exception is -stack-list-variables which emits an ARGS="1" field ++ if the value is a frame argument. This is denoted in this ++ function with PRINT_ARGS_FIELD which is flag from the caller to ++ emit the ARGS field. */ ++ if (ui_out_is_mi_like_p (out)) ++ { ++ if (print_args_field || args_type != NO_VALUES) ++ make_cleanup_ui_out_tuple_begin_end (out, NULL); ++ } ++ ++ annotate_arg_begin (); ++ ++ /* If frame argument is populated, check for entry-values and the ++ entry value options. */ ++ if (fa != NULL) ++ { ++ struct ui_file *stb; ++ ++ stb = mem_fileopen (); ++ make_cleanup_ui_file_delete (stb); ++ fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym), ++ SYMBOL_LANGUAGE (fa->sym), ++ DMGL_PARAMS | DMGL_ANSI); ++ if (fa->entry_kind == print_entry_values_compact) ++ { ++ fputs_filtered ("=", stb); ++ ++ fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym), ++ SYMBOL_LANGUAGE (fa->sym), ++ DMGL_PARAMS | DMGL_ANSI); ++ } ++ if (fa->entry_kind == print_entry_values_only ++ || fa->entry_kind == print_entry_values_compact) ++ { ++ fputs_filtered ("@entry", stb); ++ } ++ ui_out_field_stream (out, "name", stb); ++ } ++ else ++ /* Otherwise, just output the name. */ ++ ui_out_field_string (out, "name", sym_name); ++ ++ annotate_arg_name_end (); ++ ++ if (! ui_out_is_mi_like_p (out)) ++ ui_out_text (out, "="); ++ ++ if (print_args_field) ++ ui_out_field_int (out, "arg", 1); ++ ++ /* For MI print the type, but only for simple values. This seems ++ weird, but this is how MI choose to format the various output ++ types. */ ++ if (args_type == MI_PRINT_SIMPLE_VALUES) ++ { ++ if (py_print_type (out, val) == PY_BT_ERROR) ++ { ++ do_cleanups (cleanups); ++ goto error; ++ } ++ } ++ ++ annotate_arg_value (value_type (val)); ++ ++ /* If the output is to the CLI, and the user option "set print ++ frame-arguments" is set to none, just output "...". */ ++ if (! ui_out_is_mi_like_p (out) && args_type == NO_VALUES) ++ ui_out_field_string (out, "value", "..."); ++ else ++ { ++ /* Otherwise, print the value for both MI and the CLI, except ++ for the case of MI_PRINT_NO_VALUES. */ ++ if (args_type != NO_VALUES) ++ { ++ if (py_print_value (out, val, opts, 0, args_type, language) ++ == PY_BT_ERROR) ++ { ++ do_cleanups (cleanups); ++ goto error; ++ } ++ } ++ } ++ ++ do_cleanups (cleanups); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ ++ return PY_BT_OK; ++ ++ error: ++ return PY_BT_ERROR; ++} ++ ++/* Helper function to loop over frame arguments provided by the ++ "frame_arguments" Python API. Elements in the iterator must ++ conform to the "Symbol Value" interface. ITER is the Python ++ iterable object, OUT is the output stream, ARGS_TYPE is an ++ enumerator describing the argument format, PRINT_ARGS_FIELD is a ++ flag which indicates if we output "ARGS=1" in MI output in commands ++ where both arguments and locals are printed, and FRAME is the ++ backing frame. Returns PY_BT_ERROR on error, with any GDB ++ exceptions converted to a Python exception, or PY_BT_OK on ++ success. */ ++ ++static enum py_bt_status ++enumerate_args (PyObject *iter, ++ struct ui_out *out, ++ enum py_frame_args args_type, ++ int print_args_field, ++ struct frame_info *frame) ++{ ++ PyObject *item; ++ struct value_print_options opts; ++ volatile struct gdb_exception except; ++ ++ get_user_print_options (&opts); ++ ++ if (args_type == CLI_SCALAR_VALUES) ++ { ++ /* True in "summary" mode, false otherwise. */ ++ opts.summary = 1; ++ } ++ ++ opts.deref_ref = 1; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ annotate_frame_args (); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ ++ /* Collect the first argument outside of the loop, so output of ++ commas in the argument output is correct. At the end of the ++ loop block collect another item from the iterator, and, if it is ++ not null emit a comma. */ ++ item = PyIter_Next (iter); ++ if (item == NULL && PyErr_Occurred ()) ++ goto error; ++ ++ while (item) ++ { ++ const struct language_defn *language; ++ char *sym_name; ++ struct symbol *sym; ++ struct value *val; ++ enum py_bt_status success = PY_BT_ERROR; ++ ++ success = extract_sym (item, &sym_name, &sym, &language); ++ if (success == PY_BT_ERROR) ++ { ++ Py_DECREF (item); ++ goto error; ++ } ++ ++ success = extract_value (item, &val); ++ if (success == PY_BT_ERROR) ++ { ++ xfree (sym_name); ++ Py_DECREF (item); ++ goto error; ++ } ++ ++ Py_DECREF (item); ++ item = NULL; ++ ++ if (sym && ui_out_is_mi_like_p (out) ++ && ! mi_should_print (sym, MI_PRINT_ARGS)) ++ { ++ xfree (sym_name); ++ continue; ++ } ++ ++ /* If the object did not provide a value, read it using ++ read_frame_args and account for entry values, if any. */ ++ if (val == NULL) ++ { ++ struct frame_arg arg, entryarg; ++ ++ /* If there is no value, and also no symbol, set error and ++ exit. */ ++ if (sym == NULL) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ _("No symbol or value provided.")); ++ xfree (sym_name); ++ goto error; ++ } ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ read_frame_arg (sym, frame, &arg, &entryarg); ++ } ++ if (except.reason < 0) ++ { ++ xfree (sym_name); ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ ++ /* The object has not provided a value, so this is a frame ++ argument to be read by GDB. In this case we have to ++ account for entry-values. */ ++ ++ if (arg.entry_kind != print_entry_values_only) ++ { ++ if (py_print_single_arg (out, NULL, &arg, ++ NULL, &opts, ++ args_type, ++ print_args_field, ++ NULL) == PY_BT_ERROR) ++ { ++ xfree (arg.error); ++ xfree (entryarg.error); ++ xfree (sym_name); ++ goto error; ++ } ++ } ++ ++ if (entryarg.entry_kind != print_entry_values_no) ++ { ++ if (arg.entry_kind != print_entry_values_only) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ ui_out_text (out, ", "); ++ ui_out_wrap_hint (out, " "); ++ } ++ if (except.reason < 0) ++ { ++ xfree (arg.error); ++ xfree (entryarg.error); ++ xfree (sym_name); ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ ++ if (py_print_single_arg (out, NULL, &entryarg, NULL, ++ &opts, args_type, ++ print_args_field, NULL) == PY_BT_ERROR) ++ { ++ xfree (arg.error); ++ xfree (entryarg.error); ++ xfree (sym_name); ++ goto error; ++ } ++ } ++ ++ xfree (arg.error); ++ xfree (entryarg.error); ++ } ++ else ++ { ++ /* If the object has provided a value, we just print that. */ ++ if (val != NULL) ++ { ++ if (py_print_single_arg (out, sym_name, NULL, val, &opts, ++ args_type, print_args_field, ++ language) == PY_BT_ERROR) ++ { ++ xfree (sym_name); ++ goto error; ++ } ++ } ++ } ++ ++ xfree (sym_name); ++ ++ /* Collect the next item from the iterator. If ++ this is the last item, do not print the ++ comma. */ ++ item = PyIter_Next (iter); ++ if (item != NULL) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ ui_out_text (out, ", "); ++ } ++ if (except.reason < 0) ++ { ++ Py_DECREF (item); ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ else if (PyErr_Occurred ()) ++ goto error; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ annotate_arg_end (); ++ } ++ if (except.reason < 0) ++ { ++ Py_DECREF (item); ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ ++ return PY_BT_OK; ++ ++ error: ++ return PY_BT_ERROR; ++} ++ ++ ++/* Helper function to loop over variables provided by the ++ "frame_locals" Python API. Elements in the iterable must conform ++ to the "Symbol Value" interface. ITER is the Python iterable ++ object, OUT is the output stream, INDENT is whether we should ++ indent the output (for CLI), ARGS_TYPE is an enumerator describing ++ the argument format, PRINT_ARGS_FIELD is flag which indicates ++ whether to output the ARGS field in the case of ++ -stack-list-variables and FRAME is the backing frame. Returns ++ PY_BT_ERROR on error, with any GDB exceptions converted to a Python ++ exception, or PY_BT_OK on success. */ ++ ++static enum py_bt_status ++enumerate_locals (PyObject *iter, ++ struct ui_out *out, ++ int indent, ++ enum py_frame_args args_type, ++ int print_args_field, ++ struct frame_info *frame) ++{ ++ PyObject *item; ++ struct value_print_options opts; ++ ++ get_user_print_options (&opts); ++ opts.deref_ref = 1; ++ ++ while ((item = PyIter_Next (iter))) ++ { ++ const struct language_defn *language; ++ char *sym_name; ++ struct value *val; ++ enum py_bt_status success = PY_BT_ERROR; ++ struct symbol *sym; ++ volatile struct gdb_exception except; ++ int local_indent = 8 + (8 * indent); ++ struct cleanup *locals_cleanups; ++ ++ locals_cleanups = make_cleanup_py_decref (item); ++ ++ success = extract_sym (item, &sym_name, &sym, &language); ++ if (success == PY_BT_ERROR) ++ { ++ do_cleanups (locals_cleanups); ++ goto error; ++ } ++ ++ make_cleanup (xfree, sym_name); ++ ++ success = extract_value (item, &val); ++ if (success == PY_BT_ERROR) ++ { ++ do_cleanups (locals_cleanups); ++ goto error; ++ } ++ ++ if (sym != NULL && ui_out_is_mi_like_p (out) ++ && ! mi_should_print (sym, MI_PRINT_LOCALS)) ++ { ++ do_cleanups (locals_cleanups); ++ continue; ++ } ++ ++ /* If the object did not provide a value, read it. */ ++ if (val == NULL) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ val = read_var_value (sym, frame); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ do_cleanups (locals_cleanups); ++ goto error; ++ } ++ } ++ ++ /* With PRINT_NO_VALUES, MI does not emit a tuple normally as ++ each output contains only one field. The exception is ++ -stack-list-variables, which always provides a tuple. */ ++ if (ui_out_is_mi_like_p (out)) ++ { ++ if (print_args_field || args_type != NO_VALUES) ++ make_cleanup_ui_out_tuple_begin_end (out, NULL); ++ } ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ if (! ui_out_is_mi_like_p (out)) ++ { ++ /* If the output is not MI we indent locals. */ ++ ui_out_spaces (out, local_indent); ++ } ++ ++ ui_out_field_string (out, "name", sym_name); ++ ++ if (! ui_out_is_mi_like_p (out)) ++ ui_out_text (out, " = "); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ do_cleanups (locals_cleanups); ++ goto error; ++ } ++ ++ if (args_type == MI_PRINT_SIMPLE_VALUES) ++ { ++ if (py_print_type (out, val) == PY_BT_ERROR) ++ { ++ do_cleanups (locals_cleanups); ++ goto error; ++ } ++ } ++ ++ /* CLI always prints values for locals. MI uses the ++ simple/no/all system. */ ++ if (! ui_out_is_mi_like_p (out)) ++ { ++ int val_indent = (indent + 1) * 4; ++ ++ if (py_print_value (out, val, &opts, val_indent, args_type, ++ language) == PY_BT_ERROR) ++ { ++ do_cleanups (locals_cleanups); ++ goto error; ++ } ++ } ++ else ++ { ++ if (args_type != NO_VALUES) ++ { ++ if (py_print_value (out, val, &opts, 0, args_type, ++ language) == PY_BT_ERROR) ++ { ++ do_cleanups (locals_cleanups); ++ goto error; ++ } ++ } ++ } ++ ++ do_cleanups (locals_cleanups); ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ ui_out_text (out, "\n"); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ ++ if (item == NULL && PyErr_Occurred ()) ++ goto error; ++ ++ return PY_BT_OK; ++ ++ error: ++ return PY_BT_ERROR; ++} ++ ++/* Helper function for -stack-list-variables. Returns PY_BT_ERROR on ++ error, or PY_BT_OK on success. */ ++ ++static enum py_bt_status ++py_mi_print_variables (PyObject *filter, struct ui_out *out, ++ struct value_print_options *opts, ++ enum py_frame_args args_type, ++ struct frame_info *frame) ++{ ++ struct cleanup *old_chain; ++ PyObject *args_iter; ++ PyObject *locals_iter; ++ ++ args_iter = get_py_iter_from_func (filter, "frame_args"); ++ old_chain = make_cleanup_py_xdecref (args_iter); ++ if (args_iter == NULL) ++ goto error; ++ ++ locals_iter = get_py_iter_from_func (filter, "frame_locals"); ++ if (locals_iter == NULL) ++ goto error; ++ ++ make_cleanup_py_decref (locals_iter); ++ make_cleanup_ui_out_list_begin_end (out, "variables"); ++ ++ if (args_iter != Py_None) ++ if (enumerate_args (args_iter, out, args_type, 1, frame) == PY_BT_ERROR) ++ goto error; ++ ++ if (locals_iter != Py_None) ++ if (enumerate_locals (locals_iter, out, 1, args_type, 1, frame) ++ == PY_BT_ERROR) ++ goto error; ++ ++ do_cleanups (old_chain); ++ return PY_BT_OK; ++ ++ error: ++ do_cleanups (old_chain); ++ return PY_BT_ERROR; ++} ++ ++/* Helper function for printing locals. This function largely just ++ creates the wrapping tuple, and calls enumerate_locals. Returns ++ PY_BT_ERROR on error, or PY_BT_OK on success.*/ ++ ++static enum py_bt_status ++py_print_locals (PyObject *filter, ++ struct ui_out *out, ++ enum py_frame_args args_type, ++ int indent, ++ struct frame_info *frame) ++{ ++ PyObject *locals_iter = get_py_iter_from_func (filter, ++ "frame_locals"); ++ struct cleanup *old_chain = make_cleanup_py_xdecref (locals_iter); ++ ++ if (locals_iter == NULL) ++ goto locals_error; ++ ++ make_cleanup_ui_out_list_begin_end (out, "locals"); ++ ++ if (locals_iter != Py_None) ++ if (enumerate_locals (locals_iter, out, indent, args_type, ++ 0, frame) == PY_BT_ERROR) ++ goto locals_error; ++ ++ do_cleanups (old_chain); ++ return PY_BT_OK;; ++ ++ locals_error: ++ do_cleanups (old_chain); ++ return PY_BT_ERROR; ++} ++ ++/* Helper function for printing frame arguments. This function ++ largely just creates the wrapping tuple, and calls enumerate_args. ++ Returns PY_BT_ERROR on error, with any GDB exceptions converted to ++ a Python exception, or PY_BT_OK on success. */ ++ ++static enum py_bt_status ++py_print_args (PyObject *filter, ++ struct ui_out *out, ++ enum py_frame_args args_type, ++ struct frame_info *frame) ++{ ++ PyObject *args_iter = get_py_iter_from_func (filter, "frame_args"); ++ struct cleanup *old_chain = make_cleanup_py_xdecref (args_iter); ++ volatile struct gdb_exception except; ++ ++ if (args_iter == NULL) ++ goto args_error; ++ ++ make_cleanup_ui_out_list_begin_end (out, "args"); ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ annotate_frame_args (); ++ if (! ui_out_is_mi_like_p (out)) ++ ui_out_text (out, " ("); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto args_error; ++ } ++ ++ if (args_iter != Py_None) ++ if (enumerate_args (args_iter, out, args_type, 0, frame) == PY_BT_ERROR) ++ goto args_error; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ if (! ui_out_is_mi_like_p (out)) ++ ui_out_text (out, ")"); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto args_error; ++ } ++ ++ do_cleanups (old_chain); ++ return PY_BT_OK; ++ ++ args_error: ++ do_cleanups (old_chain); ++ return PY_BT_ERROR; ++} ++ ++/* Print a single frame to the designated output stream, detecting ++ whether the output is MI or console, and formatting the output ++ according to the conventions of that protocol. FILTER is the ++ frame-filter associated with this frame. FLAGS is an integer ++ describing the various print options. The FLAGS variables is ++ described in "apply_frame_filter" function. ARGS_TYPE is an ++ enumerator describing the argument format. OUT is the output ++ stream to print, INDENT is the level of indention for this frame ++ (in the case of elided frames), and LEVELS_PRINTED is a hash-table ++ containing all the frames level that have already been printed. ++ If a frame level has been printed, do not print it again (in the ++ case of elided frames). Returns PY_BT_ERROR on error, with any ++ GDB exceptions converted to a Python exception, or PY_BT_COMPLETED ++ on success. */ ++ ++static enum py_bt_status ++py_print_frame (PyObject *filter, int flags, enum py_frame_args args_type, ++ struct ui_out *out, int indent, htab_t levels_printed) ++{ ++ int has_addr = 0; ++ CORE_ADDR address = 0; ++ struct gdbarch *gdbarch = NULL; ++ struct frame_info *frame = NULL; ++ struct cleanup *cleanup_stack = make_cleanup (null_cleanup, NULL); ++ struct value_print_options opts; ++ PyObject *py_inf_frame, *elided; ++ int print_level, print_frame_info, print_args, print_locals; ++ volatile struct gdb_exception except; ++ ++ /* Extract print settings from FLAGS. */ ++ print_level = (flags & PRINT_LEVEL) ? 1 : 0; ++ print_frame_info = (flags & PRINT_FRAME_INFO) ? 1 : 0; ++ print_args = (flags & PRINT_ARGS) ? 1 : 0; ++ print_locals = (flags & PRINT_LOCALS) ? 1 : 0; ++ ++ get_user_print_options (&opts); ++ ++ /* Get the underlying frame. This is needed to determine GDB ++ architecture, and also, in the cases of frame variables/arguments to ++ read them if they returned filter object requires us to do so. */ ++ py_inf_frame = PyObject_CallMethod (filter, "inferior_frame", NULL); ++ if (py_inf_frame == NULL) ++ goto error; ++ ++ frame = frame_object_to_frame_info (py_inf_frame);; ++ ++ Py_DECREF (py_inf_frame); ++ ++ if (frame == NULL) ++ goto error; ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ gdbarch = get_frame_arch (frame); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ ++ ++ /* stack-list-variables. */ ++ if (print_locals && print_args && ! print_frame_info) ++ { ++ if (py_mi_print_variables (filter, out, &opts, ++ args_type, frame) == PY_BT_ERROR) ++ goto error; ++ else ++ { ++ do_cleanups (cleanup_stack); ++ return PY_BT_COMPLETED; ++ } ++ } ++ ++ /* -stack-list-locals does not require a ++ wrapping frame attribute. */ ++ if (print_frame_info || (print_args && ! print_locals)) ++ make_cleanup_ui_out_tuple_begin_end (out, "frame"); ++ ++ if (print_frame_info) ++ { ++ /* Elided frames are also printed with this function (recursively) ++ and are printed with indention. */ ++ if (indent > 0) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ ui_out_spaces (out, indent*4); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ ++ /* The address is required for frame annotations, and also for ++ address printing. */ ++ if (PyObject_HasAttrString (filter, "address")) ++ { ++ PyObject *paddr = PyObject_CallMethod (filter, "address", NULL); ++ if (paddr != NULL) ++ { ++ if (paddr != Py_None) ++ { ++ address = PyLong_AsLong (paddr); ++ has_addr = 1; ++ } ++ Py_DECREF (paddr); ++ } ++ else ++ goto error; ++ } ++ } ++ ++ /* Print frame level. MI does not require the level if ++ locals/variables only are being printed. */ ++ if ((print_frame_info || print_args) && print_level) ++ { ++ struct frame_info **slot; ++ int level; ++ volatile struct gdb_exception except; ++ ++ slot = (struct frame_info **) htab_find_slot (levels_printed, ++ frame, INSERT); ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ level = frame_relative_level (frame); ++ ++ /* Check if this frame has already been printed (there are cases ++ where elided synthetic dummy-frames have to 'borrow' the frame ++ architecture from the eliding frame. If that is the case, do ++ not print 'level', but print spaces. */ ++ if (*slot == frame) ++ ui_out_field_skip (out, "level"); ++ else ++ { ++ *slot = frame; ++ annotate_frame_begin (print_level ? level : 0, ++ gdbarch, address); ++ ui_out_text (out, "#"); ++ ui_out_field_fmt_int (out, 2, ui_left, "level", ++ level); ++ } ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ ++ if (print_frame_info) ++ { ++ /* Print address to the address field. If an address is not provided, ++ print nothing. */ ++ if (opts.addressprint && has_addr) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ annotate_frame_address (); ++ ui_out_field_core_addr (out, "addr", gdbarch, address); ++ annotate_frame_address_end (); ++ ui_out_text (out, " in "); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ ++ /* Print frame function name. */ ++ if (PyObject_HasAttrString (filter, "function")) ++ { ++ PyObject *py_func = PyObject_CallMethod (filter, "function", NULL); ++ ++ if (py_func != NULL) ++ { ++ const char *function = NULL; ++ ++ if (gdbpy_is_string (py_func)) ++ { ++ function = PyString_AsString (py_func); ++ ++ if (function == NULL) ++ { ++ Py_DECREF (py_func); ++ goto error; ++ } ++ } ++ else if (PyLong_Check (py_func)) ++ { ++ CORE_ADDR addr = PyLong_AsUnsignedLongLong (py_func); ++ struct minimal_symbol *msymbol; ++ ++ if (PyErr_Occurred ()) ++ goto error; ++ ++ msymbol = lookup_minimal_symbol_by_pc (addr); ++ if (msymbol != NULL) ++ function = SYMBOL_PRINT_NAME (msymbol); ++ } ++ else if (py_func != Py_None) ++ { ++ PyErr_SetString (PyExc_RuntimeError, ++ _("FrameDecorator.function: expecting a " \ ++ "String, integer or None.")); ++ Py_DECREF (py_func); ++ goto error; ++ } ++ ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ annotate_frame_function_name (); ++ if (function == NULL) ++ ui_out_field_skip (out, "func"); ++ else ++ ui_out_field_string (out, "func", function); ++ } ++ if (except.reason < 0) ++ { ++ Py_DECREF (py_func); ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ Py_DECREF (py_func); ++ } ++ else ++ goto error; ++ } ++ ++ ++ /* Frame arguments. Check the result, and error if something went ++ wrong. */ ++ if (print_args) ++ { ++ if (py_print_args (filter, out, args_type, frame) == PY_BT_ERROR) ++ goto error; ++ } ++ ++ /* File name/source/line number information. */ ++ if (print_frame_info) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ annotate_frame_source_begin (); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ ++ if (PyObject_HasAttrString (filter, "filename")) ++ { ++ PyObject *py_fn = PyObject_CallMethod (filter, "filename", ++ NULL); ++ if (py_fn != NULL) ++ { ++ if (py_fn != Py_None) ++ { ++ char *filename = PyString_AsString (py_fn); ++ ++ if (filename == NULL) ++ { ++ Py_DECREF (py_fn); ++ goto error; ++ } ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ ui_out_wrap_hint (out, " "); ++ ui_out_text (out, " at "); ++ annotate_frame_source_file (); ++ ui_out_field_string (out, "file", filename); ++ annotate_frame_source_file_end (); ++ } ++ if (except.reason < 0) ++ { ++ Py_DECREF (py_fn); ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ Py_DECREF (py_fn); ++ } ++ else ++ goto error; ++ } ++ ++ if (PyObject_HasAttrString (filter, "line")) ++ { ++ PyObject *py_line = PyObject_CallMethod (filter, "line", NULL); ++ int line; ++ ++ if (py_line != NULL) ++ { ++ if (py_line != Py_None) ++ { ++ line = PyLong_AsLong (py_line); ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ ui_out_text (out, ":"); ++ annotate_frame_source_line (); ++ ui_out_field_int (out, "line", line); ++ } ++ if (except.reason < 0) ++ { ++ Py_DECREF (py_line); ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ Py_DECREF (py_line); ++ } ++ else ++ goto error; ++ } ++ } ++ ++ /* For MI we need to deal with the "children" list population of ++ elided frames, so if MI output detected do not send newline. */ ++ if (! ui_out_is_mi_like_p (out)) ++ { ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ annotate_frame_end (); ++ ui_out_text (out, "\n"); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ } ++ ++ if (print_locals) ++ { ++ if (py_print_locals (filter, out, args_type, indent, ++ frame) == PY_BT_ERROR) ++ goto error; ++ } ++ ++ /* Finally recursively print elided frames, if any. */ ++ elided = get_py_iter_from_func (filter, "elided"); ++ if (elided == NULL) ++ goto error; ++ ++ make_cleanup_py_decref (elided); ++ if (elided != Py_None) ++ { ++ PyObject *item; ++ ++ make_cleanup_ui_out_list_begin_end (out, "children"); ++ ++ if (! ui_out_is_mi_like_p (out)) ++ indent++; ++ ++ while ((item = PyIter_Next (elided))) ++ { ++ enum py_bt_status success = py_print_frame (item, flags, ++ args_type, out, ++ indent, ++ levels_printed); ++ ++ if (success == PY_BT_ERROR) ++ { ++ Py_DECREF (item); ++ goto error; ++ } ++ ++ Py_DECREF (item); ++ } ++ if (item == NULL && PyErr_Occurred ()) ++ goto error; ++ } ++ ++ ++ do_cleanups (cleanup_stack); ++ return PY_BT_COMPLETED; ++ ++ error: ++ do_cleanups (cleanup_stack); ++ return PY_BT_ERROR; ++} ++ ++/* Helper function to initiate frame filter invocation at starting ++ frame FRAME. */ ++ ++static PyObject * ++bootstrap_python_frame_filters (struct frame_info *frame, ++ int frame_low, int frame_high) ++{ ++ struct cleanup *cleanups = ++ make_cleanup (null_cleanup, NULL); ++ PyObject *module, *sort_func, *iterable, *frame_obj, *iterator; ++ PyObject *py_frame_low, *py_frame_high; ++ ++ frame_obj = frame_info_to_frame_object (frame); ++ if (frame_obj == NULL) ++ goto error; ++ make_cleanup_py_decref (frame_obj); ++ ++ module = PyImport_ImportModule ("gdb.frames"); ++ if (module == NULL) ++ goto error; ++ make_cleanup_py_decref (module); ++ ++ sort_func = PyObject_GetAttrString (module, "execute_frame_filters"); ++ if (sort_func == NULL) ++ goto error; ++ make_cleanup_py_decref (sort_func); ++ ++ py_frame_low = PyInt_FromLong (frame_low); ++ if (py_frame_low == NULL) ++ goto error; ++ make_cleanup_py_decref (py_frame_low); ++ ++ py_frame_high = PyInt_FromLong (frame_high); ++ if (py_frame_high == NULL) ++ goto error; ++ make_cleanup_py_decref (py_frame_high); ++ ++ iterable = PyObject_CallFunctionObjArgs (sort_func, frame_obj, ++ py_frame_low, ++ py_frame_high, ++ NULL); ++ if (iterable == NULL) ++ goto error; ++ ++ do_cleanups (cleanups); ++ ++ if (iterable != Py_None) ++ { ++ iterator = PyObject_GetIter (iterable); ++ Py_DECREF (iterable); ++ } ++ else ++ { ++ return iterable; ++ } ++ ++ return iterator; ++ ++ error: ++ do_cleanups (cleanups); ++ return NULL; ++} ++ ++/* This is the only publicly exported function in this file. FRAME ++ is the source frame to start frame-filter invocation. FLAGS is an ++ integer holding the flags for printing. The following elements of ++ the FRAME_FILTER_FLAGS enum denotes the make-up of FLAGS: ++ PRINT_LEVEL is a flag indicating whether to print the frame's ++ relative level in the output. PRINT_FRAME_INFO is a flag that ++ indicates whether this function should print the frame ++ information, PRINT_ARGS is a flag that indicates whether to print ++ frame arguments, and PRINT_LOCALS, likewise, with frame local ++ variables. ARGS_TYPE is an enumerator describing the argument ++ format, OUT is the output stream to print. FRAME_LOW is the ++ beginning of the slice of frames to print, and FRAME_HIGH is the ++ upper limit of the frames to count. Returns PY_BT_ERROR on error, ++ or PY_BT_COMPLETED on success.*/ ++ ++enum py_bt_status ++apply_frame_filter (struct frame_info *frame, int flags, ++ enum py_frame_args args_type, ++ struct ui_out *out, int frame_low, ++ int frame_high) ++ ++{ ++ struct gdbarch *gdbarch = NULL; ++ struct cleanup *cleanups; ++ enum py_bt_status success = PY_BT_ERROR; ++ PyObject *iterable; ++ volatile struct gdb_exception except; ++ PyObject *item; ++ htab_t levels_printed; ++ ++ cleanups = ensure_python_env (gdbarch, current_language); ++ ++ TRY_CATCH (except, RETURN_MASK_ALL) ++ { ++ gdbarch = get_frame_arch (frame); ++ } ++ if (except.reason < 0) ++ { ++ gdbpy_convert_exception (except); ++ goto error; ++ } ++ ++ iterable = bootstrap_python_frame_filters (frame, frame_low, frame_high); ++ ++ if (iterable == NULL) ++ goto error; ++ ++ /* If iterable is None, then there are no frame filters registered. ++ If this is the case, defer to default GDB printing routines in MI ++ and CLI. */ ++ make_cleanup_py_decref (iterable); ++ if (iterable == Py_None) ++ { ++ success = PY_BT_NO_FILTERS; ++ goto done; ++ } ++ ++ levels_printed = htab_create (20, ++ htab_hash_pointer, ++ htab_eq_pointer, ++ NULL); ++ make_cleanup_htab_delete (levels_printed); ++ ++ while ((item = PyIter_Next (iterable))) ++ { ++ success = py_print_frame (item, flags, args_type, out, 0, ++ levels_printed); ++ ++ /* Do not exit on error printing a single frame. Print the ++ error and continue with other frames. */ ++ if (success == PY_BT_ERROR) ++ gdbpy_print_stack (); ++ ++ Py_DECREF (item); ++ } ++ ++ if (item == NULL && PyErr_Occurred ()) ++ goto error; ++ ++ done: ++ do_cleanups (cleanups); ++ return success; ++ ++ error: ++ gdbpy_print_stack (); ++ do_cleanups (cleanups); ++ return PY_BT_ERROR; ++} +Index: gdb-7.6/gdb/python/py-objfile.c +=================================================================== +--- gdb-7.6.orig/gdb/python/py-objfile.c 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/python/py-objfile.c 2013-05-20 22:25:52.112165767 +0200 +@@ -33,6 +33,8 @@ typedef struct + /* The pretty-printer list of functions. */ + PyObject *printers; + ++ /* The frame filter list of functions. */ ++ PyObject *frame_filters; + /* The type-printer list. */ + PyObject *type_printers; + } objfile_object; +@@ -61,6 +63,7 @@ objfpy_dealloc (PyObject *o) + objfile_object *self = (objfile_object *) o; + + Py_XDECREF (self->printers); ++ Py_XDECREF (self->frame_filters); + Py_XDECREF (self->type_printers); + Py_TYPE (self)->tp_free (self); + } +@@ -81,6 +84,13 @@ objfpy_new (PyTypeObject *type, PyObject + return NULL; + } + ++ self->frame_filters = PyDict_New (); ++ if (!self->frame_filters) ++ { ++ Py_DECREF (self); ++ return NULL; ++ } ++ + self->type_printers = PyList_New (0); + if (!self->type_printers) + { +@@ -129,6 +139,47 @@ objfpy_set_printers (PyObject *o, PyObje + return 0; + } + ++/* Return the Python dictionary attribute containing frame filters for ++ this object file. */ ++PyObject * ++objfpy_get_frame_filters (PyObject *o, void *ignore) ++{ ++ objfile_object *self = (objfile_object *) o; ++ ++ Py_INCREF (self->frame_filters); ++ return self->frame_filters; ++} ++ ++/* Set this object file's frame filters dictionary to FILTERS. */ ++static int ++objfpy_set_frame_filters (PyObject *o, PyObject *filters, void *ignore) ++{ ++ PyObject *tmp; ++ objfile_object *self = (objfile_object *) o; ++ ++ if (! filters) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ _("Cannot delete the frame filters attribute.")); ++ return -1; ++ } ++ ++ if (! PyDict_Check (filters)) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ _("The frame_filters attribute must be a dictionary.")); ++ return -1; ++ } ++ ++ /* Take care in case the LHS and RHS are related somehow. */ ++ tmp = self->frame_filters; ++ Py_INCREF (filters); ++ self->frame_filters = filters; ++ Py_XDECREF (tmp); ++ ++ return 0; ++} ++ + /* Get the 'type_printers' attribute. */ + + static PyObject * +@@ -225,6 +276,13 @@ objfile_to_objfile_object (struct objfil + return NULL; + } + ++ object->frame_filters = PyDict_New (); ++ if (!object->frame_filters) ++ { ++ Py_DECREF (object); ++ return NULL; ++ } ++ + object->type_printers = PyList_New (0); + if (!object->type_printers) + { +@@ -270,6 +328,8 @@ static PyGetSetDef objfile_getset[] = + "The objfile's filename, or None.", NULL }, + { "pretty_printers", objfpy_get_printers, objfpy_set_printers, + "Pretty printers.", NULL }, ++ { "frame_filters", objfpy_get_frame_filters, ++ objfpy_set_frame_filters, "Frame Filters.", NULL }, + { "type_printers", objfpy_get_type_printers, objfpy_set_type_printers, + "Type printers.", NULL }, + { NULL } +Index: gdb-7.6/gdb/python/py-progspace.c +=================================================================== +--- gdb-7.6.orig/gdb/python/py-progspace.c 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/python/py-progspace.c 2013-05-20 22:25:52.112165767 +0200 +@@ -35,6 +35,8 @@ typedef struct + /* The pretty-printer list of functions. */ + PyObject *printers; + ++ /* The frame filter list of functions. */ ++ PyObject *frame_filters; + /* The type-printer list. */ + PyObject *type_printers; + } pspace_object; +@@ -69,6 +71,7 @@ pspy_dealloc (PyObject *self) + pspace_object *ps_self = (pspace_object *) self; + + Py_XDECREF (ps_self->printers); ++ Py_XDECREF (ps_self->frame_filters); + Py_XDECREF (ps_self->type_printers); + Py_TYPE (self)->tp_free (self); + } +@@ -89,6 +92,13 @@ pspy_new (PyTypeObject *type, PyObject * + return NULL; + } + ++ self->frame_filters = PyDict_New (); ++ if (!self->frame_filters) ++ { ++ Py_DECREF (self); ++ return NULL; ++ } ++ + self->type_printers = PyList_New (0); + if (!self->type_printers) + { +@@ -137,6 +147,47 @@ pspy_set_printers (PyObject *o, PyObject + return 0; + } + ++/* Return the Python dictionary attribute containing frame filters for ++ this program space. */ ++PyObject * ++pspy_get_frame_filters (PyObject *o, void *ignore) ++{ ++ pspace_object *self = (pspace_object *) o; ++ ++ Py_INCREF (self->frame_filters); ++ return self->frame_filters; ++} ++ ++/* Set this object file's frame filters dictionary to FILTERS. */ ++static int ++pspy_set_frame_filters (PyObject *o, PyObject *frame, void *ignore) ++{ ++ PyObject *tmp; ++ pspace_object *self = (pspace_object *) o; ++ ++ if (! frame) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "cannot delete the frame filter attribute"); ++ return -1; ++ } ++ ++ if (! PyDict_Check (frame)) ++ { ++ PyErr_SetString (PyExc_TypeError, ++ "the frame filter attribute must be a dictionary"); ++ return -1; ++ } ++ ++ /* Take care in case the LHS and RHS are related somehow. */ ++ tmp = self->frame_filters; ++ Py_INCREF (frame); ++ self->frame_filters = frame; ++ Py_XDECREF (tmp); ++ ++ return 0; ++} ++ + /* Get the 'type_printers' attribute. */ + + static PyObject * +@@ -221,6 +272,13 @@ pspace_to_pspace_object (struct program_ + return NULL; + } + ++ object->frame_filters = PyDict_New (); ++ if (!object->frame_filters) ++ { ++ Py_DECREF (object); ++ return NULL; ++ } ++ + object->type_printers = PyList_New (0); + if (!object->type_printers) + { +@@ -257,6 +315,8 @@ static PyGetSetDef pspace_getset[] = + "The progspace's main filename, or None.", NULL }, + { "pretty_printers", pspy_get_printers, pspy_set_printers, + "Pretty printers.", NULL }, ++ { "frame_filters", pspy_get_frame_filters, pspy_set_frame_filters, ++ "Frame filters.", NULL }, + { "type_printers", pspy_get_type_printers, pspy_set_type_printers, + "Type printers.", NULL }, + { NULL } +Index: gdb-7.6/gdb/python/py-utils.c +=================================================================== +--- gdb-7.6.orig/gdb/python/py-utils.c 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/python/py-utils.c 2013-05-20 22:25:52.113165766 +0200 +@@ -48,6 +48,28 @@ make_cleanup_py_decref (PyObject *py) + return make_cleanup (py_decref, (void *) py); + } + ++/* This is a cleanup function which decrements the refcount on a ++ Python object. This function accounts appropriately for NULL ++ references. */ ++ ++static void ++py_xdecref (void *p) ++{ ++ PyObject *py = p; ++ ++ Py_XDECREF (py); ++} ++ ++/* Return a new cleanup which will decrement the Python object's ++ refcount when run. Account for and operate on NULL references ++ correctly. */ ++ ++struct cleanup * ++make_cleanup_py_xdecref (PyObject *py) ++{ ++ return make_cleanup (py_xdecref, py); ++} ++ + /* Converts a Python 8-bit string to a unicode string object. Assumes the + 8-bit string is in the host charset. If an error occurs during conversion, + returns NULL with a python exception set. +Index: gdb-7.6/gdb/python/python-internal.h +=================================================================== +--- gdb-7.6.orig/gdb/python/python-internal.h 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/python/python-internal.h 2013-05-20 22:25:52.113165766 +0200 +@@ -251,9 +251,11 @@ PyObject *frame_info_to_frame_object (st + + PyObject *pspace_to_pspace_object (struct program_space *); + PyObject *pspy_get_printers (PyObject *, void *); ++PyObject *pspy_get_frame_filters (PyObject *, void *); + + PyObject *objfile_to_objfile_object (struct objfile *); + PyObject *objfpy_get_printers (PyObject *, void *); ++PyObject *objfpy_get_frame_filters (PyObject *, void *); + + PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch); + +@@ -304,6 +306,7 @@ void gdbpy_initialize_new_objfile_event + void gdbpy_initialize_arch (void); + + struct cleanup *make_cleanup_py_decref (PyObject *py); ++struct cleanup *make_cleanup_py_xdecref (PyObject *py); + + struct cleanup *ensure_python_env (struct gdbarch *gdbarch, + const struct language_defn *language); +Index: gdb-7.6/gdb/python/python.c +=================================================================== +--- gdb-7.6.orig/gdb/python/python.c 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/python/python.c 2013-05-20 22:25:52.113165766 +0200 +@@ -1442,6 +1442,15 @@ free_type_printers (void *arg) + { + } + ++enum py_bt_status ++apply_frame_filter (struct frame_info *frame, int flags, ++ enum py_frame_args args_type, ++ struct ui_out *out, int frame_low, ++ int frame_high) ++{ ++ return PY_BT_NO_FILTERS; ++} ++ + #endif /* HAVE_PYTHON */ + + +Index: gdb-7.6/gdb/python/python.h +=================================================================== +--- gdb-7.6.orig/gdb/python/python.h 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/python/python.h 2013-05-20 22:25:52.113165766 +0200 +@@ -21,6 +21,7 @@ + #define GDB_PYTHON_H + + #include "value.h" ++#include "mi/mi-cmds.h" + + struct breakpoint_object; + +@@ -28,6 +29,66 @@ struct breakpoint_object; + E.g. When the program loads libfoo.so, look for libfoo-gdb.py. */ + #define GDBPY_AUTO_FILE_NAME "-gdb.py" + ++/* Python frame-filter status return values. */ ++enum py_bt_status ++ { ++ /* Return when an error has occurred in processing frame filters, ++ or when printing the stack. */ ++ PY_BT_ERROR = -1, ++ ++ /* Return from internal routines to indicate that the function ++ succeeded. */ ++ PY_BT_OK = 1, ++ ++ /* Return when the frame filter process is complete, and all ++ operations have succeeded. */ ++ PY_BT_COMPLETED = 2, ++ ++ /* Return when the frame filter process is complete, but there ++ were no filter registered and enabled to process. */ ++ PY_BT_NO_FILTERS = 3 ++ }; ++ ++/* Flags to pass to apply_frame_filter. */ ++ ++enum frame_filter_flags ++ { ++ /* Set this flag if frame level is to be printed. */ ++ PRINT_LEVEL = 1, ++ ++ /* Set this flag if frame information is to be printed. */ ++ PRINT_FRAME_INFO = 2, ++ ++ /* Set this flag if frame arguments are to be printed. */ ++ PRINT_ARGS = 4, ++ ++ /* Set this flag if frame locals are to be printed. */ ++ PRINT_LOCALS = 8, ++ }; ++ ++/* A choice of the different frame argument printing strategies that ++ can occur in different cases of frame filter instantiation. */ ++typedef enum py_frame_args ++{ ++ /* Print no values for arguments when invoked from the MI. */ ++ NO_VALUES = PRINT_NO_VALUES, ++ ++ MI_PRINT_ALL_VALUES = PRINT_ALL_VALUES, ++ ++ /* Print only simple values (what MI defines as "simple") for ++ arguments when invoked from the MI. */ ++ MI_PRINT_SIMPLE_VALUES = PRINT_SIMPLE_VALUES, ++ ++ ++ /* Print only scalar values for arguments when invoked from the ++ CLI. */ ++ CLI_SCALAR_VALUES, ++ ++ /* Print all values for arguments when invoked from the ++ CLI. */ ++ CLI_ALL_VALUES ++} py_frame_args; ++ + extern void finish_python_initialization (void); + + void eval_python_from_control_command (struct command_line *); +@@ -43,6 +104,11 @@ int apply_val_pretty_printer (struct typ + const struct value_print_options *options, + const struct language_defn *language); + ++enum py_bt_status apply_frame_filter (struct frame_info *frame, int flags, ++ enum py_frame_args args_type, ++ struct ui_out *out, int frame_low, ++ int frame_high); ++ + void preserve_python_values (struct objfile *objfile, htab_t copied_types); + + void gdbpy_load_auto_scripts_for_objfile (struct objfile *objfile); +Index: gdb-7.6/gdb/python/lib/gdb/FrameDecorator.py +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/python/lib/gdb/FrameDecorator.py 2013-05-20 22:25:52.113165766 +0200 +@@ -0,0 +1,285 @@ ++# Copyright (C) 2013 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 ++ ++class FrameDecorator(object): ++ """Basic implementation of a Frame Decorator""" ++ ++ """ This base frame decorator decorates a frame or another frame ++ decorator, and provides convenience methods. If this object is ++ wrapping a frame decorator, defer to that wrapped object's method ++ if it has one. This allows for frame decorators that have ++ sub-classed FrameDecorator object, but also wrap other frame ++ decorators on the same frame to correctly execute. ++ ++ E.g ++ ++ If the result of frame filters running means we have one gdb.Frame ++ wrapped by multiple frame decorators, all sub-classed from ++ FrameDecorator, the resulting hierarchy will be: ++ ++ Decorator1 ++ -- (wraps) Decorator2 ++ -- (wraps) FrameDecorator ++ -- (wraps) gdb.Frame ++ ++ In this case we have two frame decorators, both of which are ++ sub-classed from FrameDecorator. If Decorator1 just overrides the ++ 'function' method, then all of the other methods are carried out ++ by the super-class FrameDecorator. But Decorator2 may have ++ overriden other methods, so FrameDecorator will look at the ++ 'base' parameter and defer to that class's methods. And so on, ++ down the chain.""" ++ ++ # 'base' can refer to a gdb.Frame or another frame decorator. In ++ # the latter case, the child class will have called the super ++ # method and _base will be an object conforming to the Frame Filter ++ # class. ++ def __init__(self, base): ++ self._base = base ++ ++ @staticmethod ++ def _is_limited_frame(frame): ++ """Internal utility to determine if the frame is special or ++ limited.""" ++ sal = frame.find_sal() ++ ++ if (not sal.symtab or not sal.symtab.filename ++ or frame.type() == gdb.DUMMY_FRAME ++ or frame.type() == gdb.SIGTRAMP_FRAME): ++ ++ return True ++ ++ return False ++ ++ def elided(self): ++ """Return any elided frames that this class might be ++ wrapping, or None.""" ++ if hasattr(self._base, "elided"): ++ return self._base.elided() ++ ++ return None ++ ++ def function(self): ++ """ Return the name of the frame's function or an address of ++ the function of the frame. First determine if this is a ++ special frame. If not, try to determine filename from GDB's ++ frame internal function API. Finally, if a name cannot be ++ determined return the address. If this function returns an ++ address, GDB will attempt to determine the function name from ++ its internal minimal symbols store (for example, for inferiors ++ without debug-info).""" ++ ++ # Both gdb.Frame, and FrameDecorator have a method called ++ # "function", so determine which object this is. ++ if not isinstance(self._base, gdb.Frame): ++ if hasattr(self._base, "function"): ++ # If it is not a gdb.Frame, and there is already a ++ # "function" method, use that. ++ return self._base.function() ++ ++ frame = self.inferior_frame() ++ ++ if frame.type() == gdb.DUMMY_FRAME: ++ return "" ++ elif frame.type() == gdb.SIGTRAMP_FRAME: ++ return "" ++ ++ func = frame.function() ++ ++ # If we cannot determine the function name, return the ++ # address. If GDB detects an integer value from this function ++ # it will attempt to find the function name from minimal ++ # symbols via its own internal functions. ++ if func == None: ++ pc = frame.pc() ++ return pc ++ ++ return str(func) ++ ++ def address(self): ++ """ Return the address of the frame's pc""" ++ ++ if hasattr(self._base, "address"): ++ return self._base.address() ++ ++ frame = self.inferior_frame() ++ return frame.pc() ++ ++ def filename(self): ++ """ Return the filename associated with this frame, detecting ++ and returning the appropriate library name is this is a shared ++ library.""" ++ ++ if hasattr(self._base, "filename"): ++ return self._base.filename() ++ ++ frame = self.inferior_frame() ++ sal = frame.find_sal() ++ if not sal.symtab or not sal.symtab.filename: ++ pc = frame.pc() ++ return gdb.solib_name(pc) ++ else: ++ return sal.symtab.filename ++ ++ def frame_args(self): ++ """ Return an iterable of frame arguments for this frame, if ++ any. The iterable object contains objects conforming with the ++ Symbol/Value interface. If there are no frame arguments, or ++ if this frame is deemed to be a special case, return None.""" ++ ++ if hasattr(self._base, "frame_args"): ++ return self._base.frame_args() ++ ++ frame = self.inferior_frame() ++ if self._is_limited_frame(frame): ++ return None ++ ++ args = FrameVars(frame) ++ return args.fetch_frame_args() ++ ++ def frame_locals(self): ++ """ Return an iterable of local variables for this frame, if ++ any. The iterable object contains objects conforming with the ++ Symbol/Value interface. If there are no frame locals, or if ++ this frame is deemed to be a special case, return None.""" ++ ++ if hasattr(self._base, "frame_locals"): ++ return self._base.frame_locals() ++ ++ frame = self.inferior_frame() ++ if self._is_limited_frame(frame): ++ return None ++ ++ args = FrameVars(frame) ++ return args.fetch_frame_locals() ++ ++ def line(self): ++ """ Return line number information associated with the frame's ++ pc. If symbol table/line information does not exist, or if ++ this frame is deemed to be a special case, return None""" ++ ++ if hasattr(self._base, "line"): ++ return self._base.line() ++ ++ frame = self.inferior_frame() ++ if self._is_limited_frame(frame): ++ return None ++ ++ sal = frame.find_sal() ++ if (sal): ++ return sal.line ++ else: ++ return None ++ ++ def inferior_frame(self): ++ """ Return the gdb.Frame underpinning this frame decorator.""" ++ ++ # If 'base' is a frame decorator, we want to call its inferior ++ # frame method. If '_base' is a gdb.Frame, just return that. ++ if hasattr(self._base, "inferior_frame"): ++ return self._base.inferior_frame() ++ return self._base ++ ++class SymValueWrapper(object): ++ """A container class conforming to the Symbol/Value interface ++ which holds frame locals or frame arguments.""" ++ def __init__(self, symbol, value): ++ self.sym = symbol ++ self.val = value ++ ++ def value(self): ++ """ Return the value associated with this symbol, or None""" ++ return self.val ++ ++ def symbol(self): ++ """ Return the symbol, or Python text, associated with this ++ symbol, or None""" ++ return self.sym ++ ++class FrameVars(object): ++ ++ """Utility class to fetch and store frame local variables, or ++ frame arguments.""" ++ ++ def __init__(self, frame): ++ self.frame = frame ++ self.symbol_class = { ++ gdb.SYMBOL_LOC_STATIC: True, ++ gdb.SYMBOL_LOC_REGISTER: True, ++ gdb.SYMBOL_LOC_ARG: True, ++ gdb.SYMBOL_LOC_REF_ARG: True, ++ gdb.SYMBOL_LOC_LOCAL: True, ++ gdb.SYMBOL_LOC_REGPARM_ADDR: True, ++ gdb.SYMBOL_LOC_COMPUTED: True ++ } ++ ++ def fetch_b(self, sym): ++ """ Local utility method to determine if according to Symbol ++ type whether it should be included in the iterator. Not all ++ symbols are fetched, and only symbols that return ++ True from this method should be fetched.""" ++ ++ # SYM may be a string instead of a symbol in the case of ++ # synthetic local arguments or locals. If that is the case, ++ # always fetch. ++ if isinstance(sym, basestring): ++ return True ++ ++ sym_type = sym.addr_class ++ ++ return self.symbol_class.get(sym_type, False) ++ ++ def fetch_frame_locals(self): ++ """Public utility method to fetch frame local variables for ++ the stored frame. Frame arguments are not fetched. If there ++ are no frame local variables, return an empty list.""" ++ lvars = [] ++ ++ block = self.frame.block() ++ ++ while block != None: ++ if block.is_global or block.is_static: ++ break ++ for sym in block: ++ if sym.is_argument: ++ continue; ++ if self.fetch_b(sym): ++ lvars.append(SymValueWrapper(sym, None)) ++ ++ block = block.superblock ++ ++ return lvars ++ ++ def fetch_frame_args(self): ++ """Public utility method to fetch frame arguments for the ++ stored frame. Frame arguments are the only type fetched. If ++ there are no frame argument variables, return an empty list.""" ++ ++ args = [] ++ block = self.frame.block() ++ while block != None: ++ if block.function != None: ++ break ++ block = block.superblock ++ ++ if block != None: ++ for sym in block: ++ if not sym.is_argument: ++ continue; ++ args.append(SymValueWrapper(sym, None)) ++ ++ return args +Index: gdb-7.6/gdb/python/lib/gdb/FrameIterator.py +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/python/lib/gdb/FrameIterator.py 2013-05-20 22:25:52.114165766 +0200 +@@ -0,0 +1,45 @@ ++# Copyright (C) 2013 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 itertools ++ ++class FrameIterator(object): ++ """A gdb.Frame iterator. Iterates over gdb.Frames or objects that ++ conform to that interface.""" ++ ++ def __init__(self, frame_obj): ++ """Initialize a FrameIterator. ++ ++ Arguments: ++ frame_obj the starting frame.""" ++ ++ super(FrameIterator, self).__init__() ++ self.frame = frame_obj ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ """next implementation. ++ ++ Returns: ++ The next oldest frame.""" ++ ++ result = self.frame ++ if result is None: ++ raise StopIteration ++ self.frame = result.older() ++ return result +Index: gdb-7.6/gdb/python/lib/gdb/frames.py +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/python/lib/gdb/frames.py 2013-05-20 22:25:52.114165766 +0200 +@@ -0,0 +1,229 @@ ++# Frame-filter commands. ++# Copyright (C) 2013 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 . ++ ++"""Internal functions for working with frame-filters.""" ++ ++import gdb ++from gdb.FrameIterator import FrameIterator ++from gdb.FrameDecorator import FrameDecorator ++import itertools ++import collections ++ ++def get_priority(filter_item): ++ """ Internal worker function to return the frame-filter's priority ++ from a frame filter object. This is a fail free function as it is ++ used in sorting and filtering. If a badly implemented frame ++ filter does not implement the priority attribute, return zero ++ (otherwise sorting/filtering will fail and prevent other frame ++ filters from executing). ++ ++ Arguments: ++ filter_item: An object conforming to the frame filter ++ interface. ++ ++ Returns: ++ The priority of the frame filter from the "priority" ++ attribute, or zero. ++ """ ++ # Do not fail here, as the sort will fail. If a filter has not ++ # (incorrectly) set a priority, set it to zero. ++ return getattr(filter_item, "priority", 0) ++ ++def set_priority(filter_item, priority): ++ """ Internal worker function to set the frame-filter's priority. ++ ++ Arguments: ++ filter_item: An object conforming to the frame filter ++ interface. ++ priority: The priority to assign as an integer. ++ """ ++ ++ filter_item.priority = priority ++ ++def get_enabled(filter_item): ++ """ Internal worker function to return a filter's enabled state ++ from a frame filter object. This is a fail free function as it is ++ used in sorting and filtering. If a badly implemented frame ++ filter does not implement the enabled attribute, return False ++ (otherwise sorting/filtering will fail and prevent other frame ++ filters from executing). ++ ++ Arguments: ++ filter_item: An object conforming to the frame filter ++ interface. ++ ++ Returns: ++ The enabled state of the frame filter from the "enabled" ++ attribute, or False. ++ """ ++ ++ # If the filter class is badly implemented when called from the ++ # Python filter command, do not cease filter operations, just set ++ # enabled to False. ++ return getattr(filter_item, "enabled", False) ++ ++def set_enabled(filter_item, state): ++ """ Internal Worker function to set the frame-filter's enabled ++ state. ++ ++ Arguments: ++ filter_item: An object conforming to the frame filter ++ interface. ++ state: True or False, depending on desired state. ++ """ ++ ++ filter_item.enabled = state ++ ++def return_list(name): ++ """ Internal Worker function to return the frame filter ++ dictionary, depending on the name supplied as an argument. If the ++ name is not "all", "global" or "progspace", it is assumed to name ++ an object-file. ++ ++ Arguments: ++ name: The name of the list, as specified by GDB user commands. ++ ++ Returns: ++ A dictionary object for a single specified dictionary, or a ++ list containing all the items for "all" ++ ++ Raises: ++ gdb.GdbError: A dictionary of that name cannot be found. ++ """ ++ ++ # If all dictionaries are wanted in the case of "all" we ++ # cannot return a combined dictionary as keys() may clash in ++ # between different dictionaries. As we just want all the frame ++ # filters to enable/disable them all, just return the combined ++ # items() as a list. ++ if name == "all": ++ all_dicts = gdb.frame_filters.values() ++ all_dicts = all_dicts + gdb.current_progspace().frame_filters.values() ++ for objfile in gdb.objfiles(): ++ all_dicts = all_dicts + objfile.frame_filters.values() ++ return all_dicts ++ ++ if name == "global": ++ return gdb.frame_filters ++ else: ++ if name == "progspace": ++ cp = gdb.current_progspace() ++ return cp.frame_filters ++ else: ++ for objfile in gdb.objfiles(): ++ if name == objfile.filename: ++ return objfile.frame_filters ++ ++ msg = "Cannot find frame-filter dictionary for '" + name + "'" ++ raise gdb.GdbError(msg) ++ ++def _sort_list(): ++ """ Internal Worker function to merge all known frame-filter ++ lists, prune any filters with the state set to "disabled", and ++ sort the list on the frame-filter's "priority" attribute. ++ ++ Returns: ++ sorted_list: A sorted, pruned list of frame filters to ++ execute. ++ """ ++ ++ all_filters = [] ++ for objfile in gdb.objfiles(): ++ all_filters = all_filters + objfile.frame_filters.values() ++ cp = gdb.current_progspace() ++ ++ all_filters = all_filters + cp.frame_filters.values() ++ all_filters = all_filters + gdb.frame_filters.values() ++ ++ sorted_frame_filters = sorted(all_filters, key = get_priority, ++ reverse = True) ++ ++ sorted_frame_filters = filter(get_enabled, ++ sorted_frame_filters) ++ ++ return sorted_frame_filters ++ ++def execute_frame_filters(frame, frame_low, frame_high): ++ """ Internal function called from GDB that will execute the chain ++ of frame filters. Each filter is executed in priority order. ++ After the execution completes, slice the iterator to frame_low - ++ frame_high range. ++ ++ Arguments: ++ frame: The initial frame. ++ ++ frame_low: The low range of the slice. If this is a negative ++ integer then it indicates a backward slice (ie bt -4) which ++ counts backward from the last frame in the backtrace. ++ ++ frame_high: The high range of the slice. If this is -1 then ++ it indicates all frames until the end of the stack from ++ frame_low. ++ ++ Returns: ++ frame_iterator: The sliced iterator after all frame ++ filters have had a change to execute, or None if no frame ++ filters are registered. ++ """ ++ ++ # Get a sorted list of frame filters. ++ sorted_list = _sort_list() ++ ++ # Check to see if there are any frame-filters. If not, just ++ # return None and let default backtrace printing occur. ++ if len(sorted_list) == 0: ++ return None ++ ++ frame_iterator = FrameIterator(frame) ++ ++ # Apply a basic frame decorator to all gdb.Frames. This unifies the ++ # interface. ++ frame_iterator = itertools.imap(FrameDecorator, frame_iterator) ++ ++ for ff in sorted_list: ++ frame_iterator = ff.filter(frame_iterator) ++ ++ # Slicing ++ ++ # Is this a slice from the end of the backtrace, ie bt -2? ++ if frame_low < 0: ++ count = 0 ++ slice_length = abs(frame_low) ++ # We cannot use MAXLEN argument for deque as it is 2.6 onwards ++ # and some GDB versions might be < 2.6. ++ sliced = collections.deque() ++ ++ for frame_item in frame_iterator: ++ if count >= slice_length: ++ sliced.popleft(); ++ count = count + 1 ++ sliced.append(frame_item) ++ ++ return iter(sliced) ++ ++ # -1 for frame_high means until the end of the backtrace. Set to ++ # None if that is the case, to indicate to itertools.islice to ++ # slice to the end of the iterator. ++ if frame_high == -1: ++ frame_high = None ++ else: ++ # As frames start from 0, add one to frame_high so islice ++ # correctly finds the end ++ frame_high = frame_high + 1; ++ ++ sliced = itertools.islice(frame_iterator, frame_low, frame_high) ++ ++ return sliced +Index: gdb-7.6/gdb/python/lib/gdb/__init__.py +=================================================================== +--- gdb-7.6.orig/gdb/python/lib/gdb/__init__.py 2013-05-20 22:23:36.748215146 +0200 ++++ gdb-7.6/gdb/python/lib/gdb/__init__.py 2013-05-20 22:25:52.114165766 +0200 +@@ -67,6 +67,8 @@ pretty_printers = [] + + # Initial type printers. + type_printers = [] ++# Initial frame filters. ++frame_filters = {} + + # Convenience variable to GDB's python directory + PYTHONDIR = os.path.dirname(os.path.dirname(__file__)) +Index: gdb-7.6/gdb/python/lib/gdb/command/frame_filters.py +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/python/lib/gdb/command/frame_filters.py 2013-05-20 22:25:52.114165766 +0200 +@@ -0,0 +1,461 @@ ++# Frame-filter commands. ++# Copyright (C) 2013 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 . ++ ++"""GDB commands for working with frame-filters.""" ++ ++import gdb ++import copy ++from gdb.FrameIterator import FrameIterator ++from gdb.FrameDecorator import FrameDecorator ++import gdb.frames ++import itertools ++ ++# GDB Commands. ++class SetFilterPrefixCmd(gdb.Command): ++ """Prefix command for 'set' frame-filter related operations.""" ++ ++ def __init__(self): ++ super(SetFilterPrefixCmd, self).__init__("set frame-filter", ++ gdb.COMMAND_OBSCURE, ++ gdb.COMPLETE_NONE, True) ++ ++class ShowFilterPrefixCmd(gdb.Command): ++ """Prefix command for 'show' frame-filter related operations.""" ++ def __init__(self): ++ super(ShowFilterPrefixCmd, self).__init__("show frame-filter", ++ gdb.COMMAND_OBSCURE, ++ gdb.COMPLETE_NONE, True) ++class InfoFrameFilter(gdb.Command): ++ """List all registered Python frame-filters. ++ ++ Usage: info frame-filters ++ """ ++ ++ def __init__(self): ++ super(InfoFrameFilter, self).__init__("info frame-filter", ++ gdb.COMMAND_DATA) ++ @staticmethod ++ def enabled_string(state): ++ """Return "Yes" if filter is enabled, otherwise "No".""" ++ if state: ++ return "Yes" ++ else: ++ return "No" ++ ++ def list_frame_filters(self, frame_filters): ++ """ Internal worker function to list and print frame filters ++ in a dictionary. ++ ++ Arguments: ++ frame_filters: The name of the dictionary, as ++ specified by GDB user commands. ++ """ ++ ++ sorted_frame_filters = sorted(frame_filters.items(), ++ key=lambda i: gdb.frames.get_priority(i[1]), ++ reverse=True) ++ ++ if len(sorted_frame_filters) == 0: ++ print(" No frame filters registered.") ++ else: ++ print(" Priority Enabled Name") ++ for frame_filter in sorted_frame_filters: ++ name = frame_filter[0] ++ try: ++ priority = '{:<8}'.format( ++ str(gdb.frames.get_priority(frame_filter[1]))) ++ enabled = '{:<7}'.format( ++ self.enabled_string(gdb.frames.get_enabled(frame_filter[1]))) ++ except Exception as e: ++ print(" Error printing filter '"+name+"': "+str(e)) ++ else: ++ print(" %s %s %s" % (priority, enabled, name)) ++ ++ def print_list(self, title, filter_list, blank_line): ++ print(title) ++ self.list_frame_filters(filter_list) ++ if blank_line: ++ print("") ++ ++ def invoke(self, arg, from_tty): ++ self.print_list("global frame-filters:", gdb.frame_filters, True) ++ ++ cp = gdb.current_progspace() ++ self.print_list("progspace %s frame-filters:" % cp.filename, ++ cp.frame_filters, True) ++ ++ for objfile in gdb.objfiles(): ++ self.print_list("objfile %s frame-filters:" % objfile.filename, ++ objfile.frame_filters, False) ++ ++# Internal enable/disable functions. ++ ++def _enable_parse_arg(cmd_name, arg): ++ """ Internal worker function to take an argument from ++ enable/disable and return a tuple of arguments. ++ ++ Arguments: ++ cmd_name: Name of the command invoking this function. ++ args: The argument as a string. ++ ++ Returns: ++ A tuple containing the dictionary, and the argument, or just ++ the dictionary in the case of "all". ++ """ ++ ++ argv = gdb.string_to_argv(arg); ++ argc = len(argv) ++ if argv[0] == "all" and argc > 1: ++ raise gdb.GdbError(cmd_name + ": with 'all' " \ ++ "you may not specify a filter.") ++ else: ++ if argv[0] != "all" and argc != 2: ++ raise gdb.GdbError(cmd_name + " takes exactly two arguments.") ++ ++ return argv ++ ++def _do_enable_frame_filter(command_tuple, flag): ++ """Worker for enabling/disabling frame_filters. ++ ++ Arguments: ++ command_type: A tuple with the first element being the ++ frame filter dictionary, and the second being ++ the frame filter name. ++ flag: True for Enable, False for Disable. ++ """ ++ ++ list_op = command_tuple[0] ++ op_list = gdb.frames.return_list(list_op) ++ ++ if list_op == "all": ++ for item in op_list: ++ gdb.frames.set_enabled(item, flag) ++ else: ++ frame_filter = command_tuple[1] ++ try: ++ ff = op_list[frame_filter] ++ except KeyError: ++ msg = "frame-filter '" + str(name) + "' not found." ++ raise gdb.GdbError(msg) ++ ++ gdb.frames.set_enabled(ff, flag) ++ ++def _complete_frame_filter_list(text, word, all_flag): ++ """Worker for frame filter dictionary name completion. ++ ++ Arguments: ++ text: The full text of the command line. ++ word: The most recent word of the command line. ++ all_flag: Whether to include the word "all" in completion. ++ ++ Returns: ++ A list of suggested frame filter dictionary name completions ++ from text/word analysis. This list can be empty when there ++ are no suggestions for completion. ++ """ ++ if all_flag == True: ++ filter_locations = ["all", "global", "progspace"] ++ else: ++ filter_locations = ["global", "progspace"] ++ for objfile in gdb.objfiles(): ++ filter_locations.append(objfile.filename) ++ ++ # If the user just asked for completions with no completion ++ # hints, just return all the frame filter dictionaries we know ++ # about. ++ if (text == ""): ++ return filter_locations ++ ++ # Otherwise filter on what we know. ++ flist = filter(lambda x,y=text:x.startswith(y), filter_locations) ++ ++ # If we only have one completion, complete it and return it. ++ if len(flist) == 1: ++ flist[0] = flist[0][len(text)-len(word):] ++ ++ # Otherwise, return an empty list, or a list of frame filter ++ # dictionaries that the previous filter operation returned. ++ return flist ++ ++def _complete_frame_filter_name(word, printer_dict): ++ """Worker for frame filter name completion. ++ ++ Arguments: ++ ++ word: The most recent word of the command line. ++ ++ printer_dict: The frame filter dictionary to search for frame ++ filter name completions. ++ ++ Returns: A list of suggested frame filter name completions ++ from word analysis of the frame filter dictionary. This list ++ can be empty when there are no suggestions for completion. ++ """ ++ ++ printer_keys = printer_dict.keys() ++ if (word == ""): ++ return printer_keys ++ ++ flist = filter(lambda x,y=word:x.startswith(y), printer_keys) ++ return flist ++ ++class EnableFrameFilter(gdb.Command): ++ """GDB command to disable the specified frame-filter. ++ ++ Usage: enable frame-filter enable DICTIONARY [NAME] ++ ++ DICTIONARY is the name of the frame filter dictionary on which to ++ operate. If dictionary is set to "all", perform operations on all ++ dictionaries. Named dictionaries are: "global" for the global ++ frame filter dictionary, "progspace" for the program space's frame ++ filter dictionary. If either all, or the two named dictionaries ++ are not specified, the dictionary name is assumed to be the name ++ of the object-file name. ++ ++ NAME matches the name of the frame-filter to operate on. If ++ DICTIONARY is "all", NAME is ignored. ++ """ ++ def __init__(self): ++ super(EnableFrameFilter, self).__init__("enable frame-filter", ++ gdb.COMMAND_DATA) ++ def complete(self, text, word): ++ """Completion function for both frame filter dictionary, and ++ frame filter name.""" ++ if text.count(" ") == 0: ++ return _complete_frame_filter_list(text, word, True) ++ else: ++ printer_list = gdb.frames.return_list(text.split()[0].rstrip()) ++ return _complete_frame_filter_name(word, printer_list) ++ ++ def invoke(self, arg, from_tty): ++ command_tuple = _enable_parse_arg("enable frame-filter", arg) ++ _do_enable_frame_filter(command_tuple, True) ++ ++ ++class DisableFrameFilter(gdb.Command): ++ """GDB command to disable the specified frame-filter. ++ ++ Usage: disable frame-filter disable DICTIONARY [NAME] ++ ++ DICTIONARY is the name of the frame filter dictionary on which to ++ operate. If dictionary is set to "all", perform operations on all ++ dictionaries. Named dictionaries are: "global" for the global ++ frame filter dictionary, "progspace" for the program space's frame ++ filter dictionary. If either all, or the two named dictionaries ++ are not specified, the dictionary name is assumed to be the name ++ of the object-file name. ++ ++ NAME matches the name of the frame-filter to operate on. If ++ DICTIONARY is "all", NAME is ignored. ++ """ ++ def __init__(self): ++ super(DisableFrameFilter, self).__init__("disable frame-filter", ++ gdb.COMMAND_DATA) ++ ++ def complete(self, text, word): ++ """Completion function for both frame filter dictionary, and ++ frame filter name.""" ++ if text.count(" ") == 0: ++ return _complete_frame_filter_list(text, word, True) ++ else: ++ printer_list = gdb.frames.return_list(text.split()[0].rstrip()) ++ return _complete_frame_filter_name(word, printer_list) ++ ++ def invoke(self, arg, from_tty): ++ command_tuple = _enable_parse_arg("disable frame-filter", arg) ++ _do_enable_frame_filter(command_tuple, False) ++ ++class SetFrameFilterPriority(gdb.Command): ++ """GDB command to set the priority of the specified frame-filter. ++ ++ Usage: set frame-filter priority DICTIONARY NAME PRIORITY ++ ++ DICTIONARY is the name of the frame filter dictionary on which to ++ operate. Named dictionaries are: "global" for the global frame ++ filter dictionary, "progspace" for the program space's framefilter ++ dictionary. If either of these two are not specified, the ++ dictionary name is assumed to be the name of the object-file name. ++ ++ NAME matches the name of the frame filter to operate on. ++ ++ PRIORITY is the an integer to assign the new priority to the frame ++ filter. ++ """ ++ ++ def __init__(self): ++ super(SetFrameFilterPriority, self).__init__("set frame-filter " \ ++ "priority", ++ gdb.COMMAND_DATA) ++ ++ def _parse_pri_arg(self, arg): ++ """Internal worker to parse a priority from a tuple. ++ ++ Arguments: ++ arg: Tuple which contains the arguments from the command. ++ ++ Returns: ++ A tuple containing the dictionary, name and priority from ++ the arguments. ++ ++ Raises: ++ gdb.GdbError: An error parsing the arguments. ++ """ ++ ++ argv = gdb.string_to_argv(arg); ++ argc = len(argv) ++ if argc != 3: ++ print("set frame-filter priority " \ ++ "takes exactly three arguments.") ++ return None ++ ++ return argv ++ ++ def _set_filter_priority(self, command_tuple): ++ """Internal worker for setting priority of frame-filters, by ++ parsing a tuple and calling _set_priority with the parsed ++ tuple. ++ ++ Arguments: ++ command_tuple: Tuple which contains the arguments from the ++ command. ++ """ ++ ++ list_op = command_tuple[0] ++ frame_filter = command_tuple[1] ++ priority = command_tuple[2] ++ ++ op_list = gdb.frames.return_list(list_op) ++ ++ try: ++ ff = op_list[frame_filter] ++ except KeyError: ++ msg = "frame-filter '" + str(name) + "' not found." ++ raise gdb.GdbError(msg) ++ ++ gdb.frames.set_priority(ff, priority) ++ ++ def complete(self, text, word): ++ """Completion function for both frame filter dictionary, and ++ frame filter name.""" ++ if text.count(" ") == 0: ++ return _complete_frame_filter_list(text, word, False) ++ else: ++ printer_list = gdb.frames.return_list(text.split()[0].rstrip()) ++ return _complete_frame_filter_name(word, printer_list) ++ ++ def invoke(self, arg, from_tty): ++ command_tuple = self._parse_pri_arg(arg) ++ if command_tuple != None: ++ self._set_filter_priority(command_tuple) ++ ++class ShowFrameFilterPriority(gdb.Command): ++ """GDB command to show the priority of the specified frame-filter. ++ ++ Usage: show frame-filter priority DICTIONARY NAME ++ ++ DICTIONARY is the name of the frame filter dictionary on which to ++ operate. Named dictionaries are: "global" for the global frame ++ filter dictionary, "progspace" for the program space's framefilter ++ dictionary. If either of these two are not specified, the ++ dictionary name is assumed to be the name of the object-file name. ++ ++ NAME matches the name of the frame-filter to operate on. ++ """ ++ ++ def __init__(self): ++ super(ShowFrameFilterPriority, self).__init__("show frame-filter " \ ++ "priority", ++ gdb.COMMAND_DATA) ++ ++ def _parse_pri_arg(self, arg): ++ """Internal worker to parse a dictionary and name from a ++ tuple. ++ ++ Arguments: ++ arg: Tuple which contains the arguments from the command. ++ ++ Returns: ++ A tuple containing the dictionary, and frame filter name. ++ ++ Raises: ++ gdb.GdbError: An error parsing the arguments. ++ """ ++ ++ argv = gdb.string_to_argv(arg); ++ argc = len(argv) ++ if argc != 2: ++ print("show frame-filter priority " \ ++ "takes exactly two arguments.") ++ return None ++ ++ return argv ++ ++ def get_filter_priority(self, frame_filters, name): ++ """Worker for retrieving the priority of frame_filters. ++ ++ Arguments: ++ frame_filters: Name of frame filter dictionary. ++ name: object to select printers. ++ ++ Returns: ++ The priority of the frame filter. ++ ++ Raises: ++ gdb.GdbError: A frame filter cannot be found. ++ """ ++ ++ op_list = gdb.frames.return_list(frame_filters) ++ ++ try: ++ ff = op_list[name] ++ except KeyError: ++ msg = "frame-filter '" + str(name) + "' not found." ++ raise gdb.GdbError(msg) ++ ++ return gdb.frames.get_priority(ff) ++ ++ def complete(self, text, word): ++ """Completion function for both frame filter dictionary, and ++ frame filter name.""" ++ ++ if text.count(" ") == 0: ++ return _complete_frame_filter_list(text, word, False) ++ else: ++ printer_list = frame._return_list(text.split()[0].rstrip()) ++ return _complete_frame_filter_name(word, printer_list) ++ ++ def invoke(self, arg, from_tty): ++ command_tuple = self._parse_pri_arg(arg) ++ if command_tuple == None: ++ return ++ filter_name = command_tuple[1] ++ list_name = command_tuple[0] ++ try: ++ priority = self.get_filter_priority(list_name, filter_name); ++ except Exception as e: ++ print("Error printing filter priority for '"+name+"':"+str(e)) ++ else: ++ print("Priority of filter '" + filter_name + "' in list '" \ ++ + list_name + "' is: " + str(priority)) ++ ++# Register commands ++SetFilterPrefixCmd() ++ShowFilterPrefixCmd() ++InfoFrameFilter() ++EnableFrameFilter() ++DisableFrameFilter() ++SetFrameFilterPriority() ++ShowFrameFilterPriority() +Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-gdb.py.in +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-gdb.py.in 2013-05-20 22:25:52.114165766 +0200 +@@ -0,0 +1,48 @@ ++# Copyright (C) 2013 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 . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# frame-filters. ++import gdb ++import itertools ++from gdb.FrameDecorator import FrameDecorator ++ ++ ++class FrameObjFile (): ++ ++ def __init__ (self): ++ self.name = "Filter1" ++ self.priority = 1 ++ self.enabled = False ++ gdb.current_progspace().frame_filters ["Progspace" + self.name] = self ++ gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self ++ ++ def filter (self, frame_iter): ++ return frame_iter ++ ++class FrameObjFile2 (): ++ ++ def __init__ (self): ++ self.name = "Filter2" ++ self.priority = 100 ++ self.enabled = True ++ gdb.current_progspace().frame_filters ["Progspace" + self.name] = self ++ gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self ++ ++ def filter (self, frame_iter): ++ return frame_iter ++ ++FrameObjFile() ++FrameObjFile2() +Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.c 2013-05-20 22:25:52.114165766 +0200 +@@ -0,0 +1,138 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2013 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 . */ ++ ++#include ++ ++void funca(void); ++int count = 0; ++ ++typedef struct ++{ ++ char *nothing; ++ int f; ++ short s; ++} foobar; ++ ++void end_func (int foo, char *bar, foobar *fb, foobar bf) ++{ ++ const char *str = "The End"; ++ const char *st2 = "Is Near"; ++ int b = 12; ++ short c = 5; ++ { ++ int d = 15; ++ int e = 14; ++ const char *foo = "Inside block"; ++ { ++ int f = 42; ++ int g = 19; ++ const char *bar = "Inside block x2"; ++ { ++ short h = 9; ++ h = h +1; /* Inner test breakpoint */ ++ } ++ } ++ } ++ ++ return; /* Backtrace end breakpoint */ ++} ++ ++void funcb(int j) ++{ ++ struct foo ++ { ++ int a; ++ int b; ++ }; ++ ++ struct foo bar; ++ ++ bar.a = 42; ++ bar.b = 84; ++ ++ funca(); ++ return; ++} ++ ++void funca(void) ++{ ++ foobar fb; ++ foobar *bf; ++ ++ if (count < 10) ++ { ++ count++; ++ funcb(count); ++ } ++ ++ fb.nothing = "Foo Bar"; ++ fb.f = 42; ++ fb.s = 19; ++ ++ bf = malloc (sizeof (foobar)); ++ bf->nothing = malloc (128); ++ bf->nothing = "Bar Foo"; ++ bf->f = 24; ++ bf->s = 91; ++ ++ end_func(21, "Param", bf, fb); ++ free (bf->nothing); ++ free (bf); ++ return; ++} ++ ++ ++void func1(void) ++{ ++ funca(); ++ return; ++} ++ ++int func2(void) ++{ ++ func1(); ++ return 1; ++} ++ ++void func3(int i) ++{ ++ func2(); ++ ++ return; ++} ++ ++int func4(int j) ++{ ++ func3(j); ++ ++ return 2; ++} ++ ++int func5(int f, int d) ++{ ++ int i = 0; ++ char *random = "random"; ++ i=i+f; ++ ++ func4(i); ++ return i; ++} ++ ++main() ++{ ++ func5(3,5); ++} +Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.exp 2013-05-20 22:25:52.115165766 +0200 +@@ -0,0 +1,179 @@ ++# Copyright (C) 2013 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 . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# frame-filters. ++load_lib mi-support.exp ++load_lib gdb-python.exp ++ ++set MIFLAGS "-i=mi2" ++ ++gdb_exit ++if [mi_gdb_start] { ++ continue ++} ++ ++standard_testfile py-framefilter-mi.c ++set pyfile py-framefilter.py ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } { ++ untested ${testfile}.exp ++ return -1 ++} ++ ++mi_delete_breakpoints ++mi_gdb_reinitialize_dir $srcdir/$subdir ++mi_gdb_load ${binfile} ++ ++if {[lsearch -exact [mi_get_features] python] < 0} { ++ unsupported "python support is disabled" ++ return -1 ++} ++ ++mi_runto main ++ ++set remote_python_file [remote_download host ${srcdir}/${subdir}/${pyfile}] ++ ++mi_gdb_test "python execfile ('${remote_python_file}')" ".*\\^done." \ ++ "Load python file" ++ ++# Multiple blocks test ++mi_continue_to_line [gdb_get_line_number {Inner test breakpoint} ${srcfile}] \ ++ "step to breakpoint" ++ ++mi_gdb_test "-stack-list-locals --all-values" \ ++ "\\^done,locals=\\\[{name=\"h\",value=\"9\"},{name=\"f\",value=\"42\"},{name=\"g\",value=\"19\"},{name=\"bar\",value=\"$hex \\\\\"Inside block x2\\\\\"\"},{name=\"d\",value=\"15\"},{name=\"e\",value=\"14\"},{name=\"foo\",value=\"$hex \\\\\"Inside block\\\\\"\"},{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ ++ "stack-list-locals --all-values" ++ ++mi_gdb_test "-enable-frame-filters" ".*\\^done." "enable frame filters" ++mi_gdb_test "-stack-list-locals --all-values" \ ++ "\\^done,locals=\\\[{name=\"h\",value=\"9\"},{name=\"f\",value=\"42\"},{name=\"g\",value=\"19\"},{name=\"bar\",value=\"$hex \\\\\"Inside block x2\\\\\"\"},{name=\"d\",value=\"15\"},{name=\"e\",value=\"14\"},{name=\"foo\",value=\"$hex \\\\\"Inside block\\\\\"\"},{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ ++ "stack-list-locals --all-values frame filters enabled" ++ ++mi_continue_to_line [gdb_get_line_number {Backtrace end breakpoint} ${srcfile}] \ ++ "step to breakpoint" ++ ++mi_gdb_test "-stack-list-frames" \ ++ "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*},frame={level=\"27\",addr=\"$hex\",func=\"niam\".*}\\\].*" \ ++ "filtered stack listing" ++mi_gdb_test "-stack-list-frames 0 3" \ ++ "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*}\\\]" \ ++ "filtered stack list 0 3" ++mi_gdb_test "-stack-list-frames 22 24" \ ++ "\\^done,stack=\\\[frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*}\\\]" \ ++ "filtered stack list 22 24" ++ ++#stack list arguments ++ ++ ++mi_gdb_test "-stack-list-arguments 0" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 0" ++ ++mi_gdb_test "-stack-list-arguments --no-frame-filters 0" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},.*frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments --no-frame-filters 0" ++ ++mi_gdb_test "-stack-list-arguments 0 0 3" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 0 0 3" ++ ++mi_gdb_test "-stack-list-arguments 0 22 27" \ ++ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 0 22 27" ++ ++mi_gdb_test "-stack-list-arguments 1" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 1" ++ ++mi_gdb_test "-stack-list-arguments --no-frame-filters 1" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments --no-frame-filters 1" ++ ++ ++mi_gdb_test "-stack-list-arguments 1 0 3" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 1 0 3" ++ ++mi_gdb_test "-stack-list-arguments 1 22 27" \ ++ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 1 22 27" ++ ++mi_gdb_test "-stack-list-arguments 2" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"\}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 2" ++ ++mi_gdb_test "-stack-list-arguments --no-frame-filters 2" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments --no-frame-filters 2" ++ ++ ++mi_gdb_test "-stack-list-arguments 2 0 3" \ ++ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 2 0 3" ++ ++mi_gdb_test "-stack-list-arguments 2 22 27" \ ++ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments 2 22 27" ++ ++mi_gdb_test "-stack-list-arguments --no-frame-filters 2 22 27" \ ++ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ ++ "stack-list-arguments --no-frame-filters 2 22 27" ++ ++#stack-list-locals ++mi_gdb_test "-stack-list-locals --no-frame-filters 0" \ ++ "\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \ ++ "stack-list-locals --no-frame-filters 0" ++ ++mi_gdb_test "-stack-list-locals --no-frame-filters 1" \ ++ "\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ ++ "stack-list-locals --no-frame-filters 1" ++ ++mi_gdb_test "-stack-list-locals --no-frame-filters 2" \ ++ "\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \ ++ "stack-list-locals --no-frame-filters 2" ++ ++mi_gdb_test "-stack-list-locals --no-frame-filters --no-values" \ ++ "\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \ ++ "stack-list-locals --no-frame-filters --no-values" ++ ++mi_gdb_test "-stack-list-locals --no-frame-filters --all-values" \ ++ "\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ ++ "stack-list-locals --no-frame-filters --all-values" ++ ++mi_gdb_test "-stack-list-locals --no-frame-filters --simple-values" \ ++ "\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \ ++ "stack-list-locals --no-frame-filters --simple-values" ++ ++mi_gdb_test "-stack-list-locals 0" \ ++ "\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \ ++ "stack-list-locals 0" ++ ++mi_gdb_test "-stack-list-locals 1" \ ++ "\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ ++ "stack-list-locals 1" ++ ++mi_gdb_test "-stack-list-locals 2" \ ++ "\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \ ++ "stack-list-locals 2" ++ ++# stack-list-variables ++mi_gdb_test "-stack-list-variables --no-frame-filters 0" \ ++ "\\^done,variables=\\\[{name=\"foo\",arg=\"1\"},{name=\"bar\",arg=\"1\"},{name=\"fb\",arg=\"1\"},{name=\"bf\",arg=\"1\"},{name=\"str\"},{name=\"st2\"},{name=\"b\"},{name=\"c\"}\\\]" \ ++ "stack-list-variables --no-frame-filters 0" ++ ++mi_gdb_test "-stack-list-variables 0" \ ++ "\\^done,variables=\\\[{name=\"foo\",arg=\"1\"},{name=\"bar\",arg=\"1\"},{name=\"fb\",arg=\"1\"},{name=\"bf\",arg=\"1\"},{name=\"str\"},{name=\"st2\"},{name=\"b\"},{name=\"c\"}\\\]" \ ++ "stack-list-variables 0" +Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.c 2013-05-20 22:25:52.115165766 +0200 +@@ -0,0 +1,155 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2013 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 . */ ++ ++#include ++ ++void funca(void); ++int count = 0; ++ ++typedef struct ++{ ++ char *nothing; ++ int f; ++ short s; ++} foobar; ++ ++void end_func (int foo, char *bar, foobar *fb, foobar bf) ++{ ++ const char *str = "The End"; ++ const char *st2 = "Is Near"; ++ int b = 12; ++ short c = 5; ++ ++ { ++ int d = 15; ++ int e = 14; ++ const char *foo = "Inside block"; ++ { ++ int f = 42; ++ int g = 19; ++ const char *bar = "Inside block x2"; ++ { ++ short h = 9; ++ h = h +1; /* Inner test breakpoint */ ++ } ++ } ++ } ++ ++ return; /* Backtrace end breakpoint */ ++} ++ ++void funcb(int j) ++{ ++ struct foo ++ { ++ int a; ++ int b; ++ }; ++ ++ struct foo bar; ++ ++ bar.a = 42; ++ bar.b = 84; ++ ++ funca(); ++ return; ++} ++ ++void funca(void) ++{ ++ foobar fb; ++ foobar *bf = NULL; ++ ++ if (count < 10) ++ { ++ count++; ++ funcb(count); ++ } ++ ++ fb.nothing = "Foo Bar"; ++ fb.f = 42; ++ fb.s = 19; ++ ++ bf = alloca (sizeof (foobar)); ++ bf->nothing = alloca (128); ++ bf->nothing = "Bar Foo"; ++ bf->f = 24; ++ bf->s = 91; ++ ++ end_func(21, "Param", bf, fb); ++ return; ++} ++ ++ ++void func1(void) ++{ ++ funca(); ++ return; ++} ++ ++int func2(int f) ++{ ++ int c; ++ const char *elided = "Elided frame"; ++ foobar fb; ++ foobar *bf = NULL; ++ ++ fb.nothing = "Elided Foo Bar"; ++ fb.f = 84; ++ fb.s = 38; ++ ++ bf = alloca (sizeof (foobar)); ++ bf->nothing = alloca (128); ++ bf->nothing = "Elided Bar Foo"; ++ bf->f = 48; ++ bf->s = 182; ++ ++ func1(); ++ return 1; ++} ++ ++void func3(int i) ++{ ++ func2(i); ++ ++ return; ++} ++ ++int func4(int j) ++{ ++ func3(j); ++ ++ return 2; ++} ++ ++int func5(int f, int d) ++{ ++ int i = 0; ++ char *random = "random"; ++ i=i+f; ++ ++ func4(i); ++ return i; ++} ++ ++main() ++{ ++ int z = 32; ++ int y = 44; ++ const char *foo1 = "Test"; ++ func5(3,5); ++} +Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.exp 2013-05-20 22:25:52.115165766 +0200 +@@ -0,0 +1,239 @@ ++# Copyright (C) 2013 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 . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# frame-filters. ++ ++load_lib gdb-python.exp ++ ++standard_testfile ++ ++# We cannot use prepare_for_testing as we have to set the safe-patch ++# to check objfile and progspace printers. ++if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} { ++ return -1 ++} ++ ++# Start with a fresh gdb. ++gdb_exit ++gdb_start ++ ++# Skip all tests if Python scripting is not enabled. ++if { [skip_python_tests] } { continue } ++ ++# Make the -gdb.py script available to gdb, it is automagically loaded by gdb. ++# Care is taken to put it in the same directory as the binary so that ++# gdb will find it. ++set remote_obj_python_file \ ++ [remote_download \ ++ host ${srcdir}/${subdir}/${testfile}-gdb.py.in \ ++ ${subdir}/${testfile}-gdb.py] ++ ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_test_no_output "set auto-load safe-path ${remote_obj_python_file}" \ ++ "set auto-load safe-path" ++gdb_load ${binfile} ++# Verify gdb loaded the script. ++gdb_test "info auto-load python-scripts" "Yes.*/${testfile}-gdb.py.*" \ ++ "Test auto-load had loaded python scripts" ++ ++if ![runto_main] then { ++ perror "couldn't run to breakpoint" ++ return ++} ++gdb_test_no_output "set python print-stack full" \ ++ "Set python print-stack to full" ++ ++# Load global frame-filters ++set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py] ++gdb_test_no_output "python execfile ('${remote_python_file}')" \ ++ "Load python file" ++ ++gdb_breakpoint [gdb_get_line_number "Backtrace end breakpoint"] ++gdb_breakpoint [gdb_get_line_number "Inner test breakpoint"] ++gdb_continue_to_breakpoint "Inner test breakpoint" ++ ++# Test multiple local blocks. ++gdb_test "bt full no-filters" \ ++ ".*#0.*end_func.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \ ++ "bt full no-filters" ++gdb_test "bt full" \ ++ ".*#0.*cnuf_dne.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \ ++ "bt full with filters" ++ ++gdb_continue_to_breakpoint "Backtrace end breakpoint" ++ ++# Test set/show ++gdb_test "info frame-filter" \ ++ ".*900.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ ++ "info frame filter before setting priority" ++gdb_test "show frame-filter priority global Elider" \ ++ "Priority of filter 'Elider' in list 'global' is: 900" \ ++ "show frame-filter priority global Elider before setting" ++gdb_test_no_output "set frame-filter priority global Elider 1000" \ ++ "set frame-filter priotiy global Elider 1000" ++gdb_test "show frame-filter priority global Elider" \ ++ "Priority of filter 'Elider' in list 'global' is: 1000" \ ++ "show frame-filter priority global Elider after setting" ++gdb_test "info frame-filter" \ ++ ".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ ++ "info frame filter after setting priority" ++ ++# Test enable/disable ++gdb_test "info frame-filter" \ ++ ".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ ++ "info frame filter before disable frame filter" ++gdb_test_no_output "disable frame-filter global Elider" \ ++ "disable frame-filter global Elider" ++gdb_test "info frame-filter" \ ++ ".*1000.*No.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ ++ "info frame filter after disable frame filter" ++gdb_test_no_output "enable frame-filter global Elider" \ ++ "enable frame-filter global Elider" ++gdb_test "info frame-filter" \ ++ ".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ ++ "info frame filter after reenabling frame filter" ++ ++# Test no-filters ++gdb_test "bt no-filters" \ ++ ".*#0.*end_func.*#22.*in func1.*#27.*in main \\(\\).*" \ ++ "bt no-filters" ++ ++# Test reverse ++gdb_test "bt" \ ++ ".*#0.*cnuf_dne.*#22.*in 1cnuf.*#27.*in niam \\(\\).*" \ ++ "bt with frame filters" ++ ++# Disable Reverse ++gdb_test_no_output "disable frame-filter global Reverse" \ ++ "disable frame-filter global Reverse" ++gdb_test "bt" \ ++ ".*#0.*end_func.*#22.*in func1.*#27.*in main \\(\\).*" \ ++ "bt with frame-filter Reverse disabled" ++gdb_test "bt -2" \ ++ ".*#26.*func5.*#27.*in main \\(\\).*" \ ++ "bt -2 with frame-filter Reverse disabled" ++gdb_test "bt 3" \ ++ ".*#0.*end_func.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*" \ ++ "bt 3 with frame-filter Reverse disabled" ++gdb_test "bt no-filter full" \ ++ ".*#0.*end_func.*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*bar = \{a = 42, b = 84\}.*" \ ++ "bt no-filters full with Reverse disabled" ++gdb_test "bt full" \ ++ ".*#0.*end_func.*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*bar = \{a = 42, b = 84\}.*#22.*in func1 \\(\\).*#23.*in func2 \\(f=3\\).*elided = $hex \"Elided frame\".*fb = \{nothing = $hex \"Elided Foo Bar\", f = 84, s = 38\}.*bf = $hex.*" \ ++ "bt full with Reverse disabled" ++ ++# Test set print frame-arguments ++# none ++gdb_test_no_output "set print frame-arguments none" \ ++ "turn off frame arguments" ++gdb_test "bt no-filter 1" \ ++ "#0.*end_func \\(foo=\.\.\., bar=\.\.\., fb=\.\.\., bf=\.\.\.\\) at .*py-framefilter.c.*" \ ++ "bt no-filter 1 no args" ++gdb_test "bt 1" \ ++ "#0.*end_func \\(foo=\.\.\., bar=\.\.\., fb=\.\.\., bf=\.\.\.\\) at .*py-framefilter.c.*" \ ++ "bt 1 no args" ++ ++# scalars ++gdb_test_no_output "set print frame-arguments scalars" \ ++ "turn frame arguments to scalars only" ++gdb_test "bt no-filter 1" \ ++ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\.\.\.\\) at .*py-framefilter.c.*" \ ++ "bt no-filter 1 scalars" ++gdb_test "bt 1" \ ++ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\.\.\.\\) at .*py-framefilter.c.*" \ ++ "bt 1 scalars" ++ ++# all ++gdb_test_no_output "set print frame-arguments all" \ ++ "turn on frame arguments" ++gdb_test "bt no-filter 1" \ ++ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\{nothing = $hex \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ ++ "bt no-filter 1 all args" ++gdb_test "bt 1" \ ++ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\{nothing = $hex \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ ++ "bt 1 all args" ++ ++# set print address off ++gdb_test_no_output "set print address off" \ ++ "Turn off address printing" ++gdb_test "bt no-filter 1" \ ++ "#0 end_func \\(foo=21, bar=\"Param\", fb=, bf=\{nothing = \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ ++ "bt no-filter 1 no address" ++gdb_test "bt 1" \ ++ "#0 end_func \\(foo=21, bar=\"Param\", fb=, bf=\{nothing = \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ ++ "bt 1 no addresss" ++ ++remote_file host delete ${remote_python_file} ++ ++# Test with no debuginfo ++ ++# We cannot use prepare_for_testing as we have to set the safe-patch ++# to check objfile and progspace printers. ++if {[build_executable $testfile.exp $testfile $srcfile {nodebug}] == -1} { ++ return -1 ++} ++ ++# Start with a fresh gdb. ++gdb_exit ++gdb_start ++ ++# Skip all tests if Python scripting is not enabled. ++if { [skip_python_tests] } { continue } ++ ++# Make the -gdb.py script available to gdb, it is automagically loaded by gdb. ++# Care is taken to put it in the same directory as the binary so that ++# gdb will find it. ++set remote_obj_python_file \ ++ [remote_download \ ++ host ${srcdir}/${subdir}/${testfile}-gdb.py.in \ ++ ${subdir}/${testfile}-gdb.py] ++ ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_test_no_output "set auto-load safe-path ${remote_obj_python_file}" \ ++ "set auto-load safe-path for no debug info" ++gdb_load ${binfile} ++ ++# Verify gdb loaded the script. ++gdb_test "info auto-load python-scripts" "Yes.*/${testfile}-gdb.py.*" \ ++ "Set autoload path for no debug info tests" ++if ![runto_main] then { ++ perror "couldn't run to breakpoint" ++ return ++} ++ ++gdb_test_no_output "set python print-stack full" \ ++ "set python print-stack full for no debuginfo tests" ++ ++# Load global frame-filters ++set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py] ++gdb_test_no_output "python execfile ('${remote_python_file}')" \ ++ "Load python file for no debuginfo tests" ++ ++# Disable Reverse ++gdb_test_no_output "disable frame-filter global Reverse" \ ++ "disable frame-filter gloval Reverse for no debuginfo" ++gdb_test "bt" \ ++ ".*#0..*in main \\(\\).*" \ ++ "bt for no debuginfo" ++gdb_test "bt full" \ ++ ".*#0..*in main \\(\\).*" \ ++ "bt full for no debuginfo" ++gdb_test "bt no-filters" \ ++ ".*#0..*in main \\(\\).*" \ ++ "bt no filters for no debuginfo" ++gdb_test "bt no-filters full" \ ++ ".*#0..*in main \\(\\).*" \ ++ "bt no-filters full no debuginfo" +Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.py +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.py 2013-05-20 22:25:52.115165766 +0200 +@@ -0,0 +1,117 @@ ++# Copyright (C) 2013 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 . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# frame-filters. ++import gdb ++import itertools ++from gdb.FrameDecorator import FrameDecorator ++import copy ++ ++class Reverse_Function (FrameDecorator): ++ ++ def __init__(self, fobj): ++ super(Reverse_Function, self).__init__(fobj) ++ self.fobj = fobj ++ ++ def function (self): ++ fname = str (self.fobj.function()) ++ if (fname == None or fname == ""): ++ return None ++ else: ++ fname = fname[::-1] ++ return fname ++ ++class Dummy (FrameDecorator): ++ ++ def __init__(self, fobj): ++ super(Dummy, self).__init__(fobj) ++ self.fobj = fobj ++ ++ def function (self): ++ return "Dummy function" ++ ++ def address (self): ++ return 0x123 ++ ++ def filename (self): ++ return "Dummy filename" ++ ++ def frame_args (self): ++ return [("Foo",gdb.Value(12)),("Bar","Stuff"), ("FooBar",42)] ++ ++ def frame_locals (self): ++ return [] ++ ++ def line (self): ++ return 0 ++ ++ def elided (self): ++ return None ++ ++class FrameFilter (): ++ ++ def __init__ (self): ++ self.name = "Reverse" ++ self.priority = 100 ++ self.enabled = True ++ gdb.frame_filters [self.name] = self ++ ++ def filter (self, frame_iter): ++ frame_iter = itertools.imap (Reverse_Function, ++ frame_iter) ++ return frame_iter ++ ++class ElidingFrameDecorator(FrameDecorator): ++ ++ def __init__(self, frame, elided_frames): ++ super(ElidingFrameDecorator, self).__init__(frame) ++ self.elided_frames = elided_frames ++ ++ def elided(self): ++ return iter(self.elided_frames) ++ ++class ElidingIterator: ++ def __init__(self, ii): ++ self.input_iterator = ii ++ ++ def __iter__(self): ++ return self ++ ++ def next(self): ++ frame = next(self.input_iterator) ++ if str(frame.function()) != 'func1': ++ return frame ++ ++ # Suppose we want to return the 'func1' frame but elide the ++ # next frame. E.g., if call in our interpreter language takes ++ # two C frames to implement, and the first one we see is the ++ # "sentinel". ++ elided = next(self.input_iterator) ++ return ElidingFrameDecorator(frame, [elided]) ++ ++class FrameElider (): ++ ++ def __init__ (self): ++ self.name = "Elider" ++ self.priority = 900 ++ self.enabled = True ++ gdb.frame_filters [self.name] = self ++ ++ def filter (self, frame_iter): ++ return ElidingIterator (frame_iter) ++ ++FrameFilter() ++FrameElider() diff --git a/gdb-upstream-framefilters-2of2.patch b/gdb-upstream-framefilters-2of2.patch new file mode 100644 index 0000000..0446ef6 --- /dev/null +++ b/gdb-upstream-framefilters-2of2.patch @@ -0,0 +1,175 @@ +http://sourceware.org/ml/gdb-cvs/2013-05/msg00141.html + +### src/gdb/ChangeLog 2013/05/17 06:58:33 1.15565 +### src/gdb/ChangeLog 2013/05/17 08:34:18 1.15566 +## -1,3 +1,18 @@ ++2013-05-17 Phil Muldoon ++ ++ * frame.c (frame_stash): Convert to htab. ++ (frame_addr_hash): New function. ++ (frame_addr_hash_eq): New function. ++ (frame_stash_create): Convert function to create ++ a hash table. ++ (frame_stash_add): Convert function to add an entry to a hash ++ table. ++ (frame_stash_find): Convert function to search the hash table. ++ (frame_stash_invalidate): Convert function to empty the hash ++ table. ++ (get_frame_id): Only add to stash if a frame_id is created. ++ (_initialize_frame): Call frame_stash_create. ++ + 2013-05-16 Yue Lu (tiny change) + + * configure.ac: Ensure MIG is available when building for GNU Hurd +--- src/gdb/frame.c 2013/04/10 15:11:11 1.317 ++++ src/gdb/frame.c 2013/05/17 08:34:18 1.318 +@@ -43,6 +43,7 @@ + #include "block.h" + #include "inline-frame.h" + #include "tracepoint.h" ++#include "hashtab.h" + + static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame); + static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame); +@@ -128,38 +129,107 @@ + enum unwind_stop_reason stop_reason; + }; + +-/* A frame stash used to speed up frame lookups. */ ++/* A frame stash used to speed up frame lookups. Create a hash table ++ to stash frames previously accessed from the frame cache for ++ quicker subsequent retrieval. The hash table is emptied whenever ++ the frame cache is invalidated. */ ++ ++static htab_t frame_stash; ++ ++/* Internal function to calculate a hash from the frame_id addresses, ++ using as many valid addresses as possible. Frames below level 0 ++ are not stored in the hash table. */ ++ ++static hashval_t ++frame_addr_hash (const void *ap) ++{ ++ const struct frame_info *frame = ap; ++ const struct frame_id f_id = frame->this_id.value; ++ hashval_t hash = 0; ++ ++ gdb_assert (f_id.stack_addr_p || f_id.code_addr_p ++ || f_id.special_addr_p); ++ ++ if (f_id.stack_addr_p) ++ hash = iterative_hash (&f_id.stack_addr, ++ sizeof (f_id.stack_addr), hash); ++ if (f_id.code_addr_p) ++ hash = iterative_hash (&f_id.code_addr, ++ sizeof (f_id.code_addr), hash); ++ if (f_id.special_addr_p) ++ hash = iterative_hash (&f_id.special_addr, ++ sizeof (f_id.special_addr), hash); + +-/* We currently only stash one frame at a time, as this seems to be +- sufficient for now. */ +-static struct frame_info *frame_stash = NULL; ++ return hash; ++} ++ ++/* Internal equality function for the hash table. This function ++ defers equality operations to frame_id_eq. */ ++ ++static int ++frame_addr_hash_eq (const void *a, const void *b) ++{ ++ const struct frame_info *f_entry = a; ++ const struct frame_info *f_element = b; + +-/* Add the following FRAME to the frame stash. */ ++ return frame_id_eq (f_entry->this_id.value, ++ f_element->this_id.value); ++} ++ ++/* Internal function to create the frame_stash hash table. 100 seems ++ to be a good compromise to start the hash table at. */ ++ ++static void ++frame_stash_create (void) ++{ ++ frame_stash = htab_create (100, ++ frame_addr_hash, ++ frame_addr_hash_eq, ++ NULL); ++} ++ ++/* Internal function to add a frame to the frame_stash hash table. Do ++ not store frames below 0 as they may not have any addresses to ++ calculate a hash. */ + + static void + frame_stash_add (struct frame_info *frame) + { +- frame_stash = frame; ++ /* Do not stash frames below level 0. */ ++ if (frame->level >= 0) ++ { ++ struct frame_info **slot; ++ ++ slot = (struct frame_info **) htab_find_slot (frame_stash, ++ frame, ++ INSERT); ++ *slot = frame; ++ } + } + +-/* Search the frame stash for an entry with the given frame ID. +- If found, return that frame. Otherwise return NULL. */ ++/* Internal function to search the frame stash for an entry with the ++ given frame ID. If found, return that frame. Otherwise return ++ NULL. */ + + static struct frame_info * + frame_stash_find (struct frame_id id) + { +- if (frame_stash && frame_id_eq (frame_stash->this_id.value, id)) +- return frame_stash; ++ struct frame_info dummy; ++ struct frame_info *frame; + +- return NULL; ++ dummy.this_id.value = id; ++ frame = htab_find (frame_stash, &dummy); ++ return frame; + } + +-/* Invalidate the frame stash by removing all entries in it. */ ++/* Internal function to invalidate the frame stash by removing all ++ entries in it. This only occurs when the frame cache is ++ invalidated. */ + + static void + frame_stash_invalidate (void) + { +- frame_stash = NULL; ++ htab_empty (frame_stash); + } + + /* Flag to control debugging. */ +@@ -345,10 +415,9 @@ + fprint_frame_id (gdb_stdlog, fi->this_id.value); + fprintf_unfiltered (gdb_stdlog, " }\n"); + } ++ frame_stash_add (fi); + } + +- frame_stash_add (fi); +- + return fi->this_id.value; + } + +@@ -2451,6 +2520,8 @@ + { + obstack_init (&frame_cache_obstack); + ++ frame_stash_create (); ++ + observer_attach_target_changed (frame_observer_target_changed); + + add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\ diff --git a/gdb-upstream.patch b/gdb-upstream.patch index bcc5667..3240ab2 100644 --- a/gdb-upstream.patch +++ b/gdb-upstream.patch @@ -1199,3 +1199,97 @@ http://sourceware.org/ml/gdb-cvs/2013-04/msg00070.html -($(POD2MAN5) gdbinit.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \ mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1) rm -f gdbinit.pod + + + +http://sourceware.org/bugzilla/show_bug.cgi?id=15413 +http://sourceware.org/ml/gdb-cvs/2013-05/msg00063.html + +### src/gdb/ChangeLog 2013/04/26 14:13:13 1.15260.2.50 +### src/gdb/ChangeLog 2013/05/07 17:04:56 1.15260.2.51 +## -1,3 +1,10 @@ ++2013-05-07 Sergio Durigan Junior ++ ++ PR breakpoints/15413: ++ * breakpoint.c (condition_completer): Simplify the code to ++ disconsider multiple locations of breakpoints when completing the ++ "condition" command. ++ + 2013-04-26 Joel Brobecker + + * version.in: Set version to 7.6.0.20130426-cvs. +--- src/gdb/breakpoint.c 2013/04/25 08:15:34 1.745.2.5 ++++ src/gdb/breakpoint.c 2013/05/07 17:04:57 1.745.2.6 +@@ -1015,27 +1015,14 @@ + len = strlen (text); + + ALL_BREAKPOINTS (b) +- { +- int single = b->loc->next == NULL; +- struct bp_location *loc; +- int count = 1; +- +- for (loc = b->loc; loc; loc = loc->next) +- { +- char location[50]; +- +- if (single) +- xsnprintf (location, sizeof (location), "%d", b->number); +- else +- xsnprintf (location, sizeof (location), "%d.%d", b->number, +- count); ++ { ++ char number[50]; + +- if (strncmp (location, text, len) == 0) +- VEC_safe_push (char_ptr, result, xstrdup (location)); ++ xsnprintf (number, sizeof (number), "%d", b->number); + +- ++count; +- } +- } ++ if (strncmp (number, text, len) == 0) ++ VEC_safe_push (char_ptr, result, xstrdup (number)); ++ } + + return result; + } +### src/gdb/testsuite/ChangeLog 2013/05/03 16:26:32 1.3580.2.20 +### src/gdb/testsuite/ChangeLog 2013/05/07 17:04:57 1.3580.2.21 +## -1,3 +1,11 @@ ++2013-05-07 Sergio Durigan Junior ++ ++ PR breakpoints/15413: ++ * gdb.base/pending.exp: Add test for completion of the "condition" ++ command for pending breakpoints. ++ * gdb.linespec/linespec.ex: Add test for completion of the ++ "condition" command when dealing with multiple locations. ++ + 2013-05-03 Hafiz Abid Qadeer + + * status-stop.exp (test_tstart_tstart): Check for error +--- src/gdb/testsuite/gdb.base/pending.exp 2013/01/01 06:33:26 1.27 ++++ src/gdb/testsuite/gdb.base/pending.exp 2013/05/07 17:04:57 1.27.2.1 +@@ -55,6 +55,9 @@ + } + } + ++# Complete the condition (PR 15413). ++gdb_test "complete condition " "condition 1" ++ + gdb_test "info break" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* + \[0-9\]+\[\t \]+breakpoint keep y.*PENDING.*pendfunc1.*" \ +--- src/gdb/testsuite/gdb.linespec/linespec.exp 2013/01/01 06:41:24 1.6 ++++ src/gdb/testsuite/gdb.linespec/linespec.exp 2013/05/07 17:04:57 1.6.2.1 +@@ -63,6 +63,10 @@ + "Breakpoint $decimal at $hex: dupname:label. \[(\]2 locations\[)\]" \ + "multi-location break using duplicate function name and label" + ++# Testing if the "condition" command completes only the breakpoints, ++# not the locations. ++gdb_test "complete condition " "condition $decimal\r\ncondition $decimal\r\ncondition $decimal" ++ + gdb_test_no_output "set breakpoint pending off" \ + "disable pending breakpoints for linespec tests" + diff --git a/gdb.spec b/gdb.spec index 16bc3f0..8aada04 100644 --- a/gdb.spec +++ b/gdb.spec @@ -36,7 +36,7 @@ Version: 7.6 # The release always contains a leading reserved number, start it at 1. # `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing. -Release: 29%{?dist} +Release: 30%{?dist} License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and BSD and Public Domain Group: Development/Debuggers @@ -266,6 +266,9 @@ Patch231: gdb-6.3-bz202689-exec-from-pthread-test.patch Patch232: gdb-upstream.patch Patch828: gdb-upstream-man-gcore-1of2.patch Patch829: gdb-upstream-man-gcore-2of2.patch +# Backported Python frame filters (Phil Muldoon). +Patch836: gdb-upstream-framefilters-1of2.patch +Patch837: gdb-upstream-framefilters-2of2.patch # Testcase for PPC Power6/DFP instructions disassembly (BZ 230000). #=fedoratest+ppc @@ -780,6 +783,8 @@ find -name "*.info*"|xargs rm -f %patch232 -p1 %patch828 -p1 %patch829 -p1 +%patch836 -p1 +%patch837 -p1 %patch1 -p1 %patch3 -p1 @@ -1397,8 +1402,12 @@ fi %endif # 0%{!?el5:1} || "%{_target_cpu}" == "noarch" %changelog +* Tue May 21 2013 Jan Kratochvil - 7.6-30.fc19 +- Backported Python frame filters (Phil Muldoon). +- Backported breakpoint conditions crash fix (Sergio Durigan Junior). + * Sun May 19 2013 Jan Kratochvil - 7.6-29.fc19 -- Fix performance regression when inferior opens many libraries (Gary Benson). +- Fix performance regression opening many libraries (Gary Benson, BZ 965106). * Thu May 9 2013 Jan Kratochvil - 7.6-28.fc19 - Fix needless expansion of non-gdbindex symtabs (Doug Evans).