This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
[python] implement "upto" (Was: feature idea: upto)
- From: Tom Tromey <tromey at redhat dot com>
- To: Roland McGrath <roland at redhat dot com>
- Cc: Project Archer <archer at sourceware dot org>
- Date: Tue, 07 Jul 2009 10:18:11 -0600
- Subject: [python] implement "upto" (Was: feature idea: upto)
- References: <20090702223351.64F00404FD@magilla.sf.frob.com>
- Reply-to: Tom Tromey <tromey at redhat dot com>
Roland> upto "a frame with source"
Roland> upto source foobar.c
Roland> upto source */myapp/*
Roland> upto shlib foo.so*
Roland> upto exec # not shlib
Roland> upto func
Roland> upto funcpfx_*
Roland> upto cl::func(over,load)
Roland> upto cl:: # any method/func with this ns/class prefix
Roland> upto foo.c:27 where arg==17 # skip frames where !expr
Roland> upto where arg==23 # also skip frames where expr not resolvable
Roland> upto where $r13 == 27 # cond can apply to any context
For fun I wrote a simple implementation of this.
It isn't perfect, and doesn't do quite everything above, but it does a
lot of it.
I think this exposes some oddities in the gdb.Frame API. We don't
have a nice way to print a frame in a gdb-like way. And, all the
FrameWrapper code seems like something that should just go away.
Arguably the base command here should just be named "up".
Patch appended. I'll commit shortly.
Tom
gdb
* python/python-symtab.c (stpy_get_objfile): New function.
(symtab_object_getset): Add "objfile".
* python/python-frame.c (frapy_select): New function.
(frame_object_methods): Add "select".
* python/lib/gdb/command/upto.py: New file.
* python/lib/gdb/command/backtrace.py: Move code to
FrameWrapper.py.
* python/lib/gdb/FrameWrapper.py: New file.
* Makefile.in (PY_FILES): Add new files.
gdb/doc
* gdb.texinfo (Frames In Python): Document Frame.select.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0d8c3ed..947bcd5 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1957,9 +1957,9 @@ python-value.o: $(srcdir)/python/python-value.c
# All python library files, with the "python/lib" stripped off.
# Note that we should only install files in the "gdb" module.
-PY_FILES = gdb/FrameIterator.py gdb/command/alias.py \
+PY_FILES = gdb/FrameIterator.py gdb/FrameWrapper.py gdb/command/alias.py \
gdb/command/backtrace.py gdb/command/require.py \
- gdb/command/pahole.py gdb/command/__init__.py \
+ gdb/command/pahole.py gdb/command/upto.py gdb/command/__init__.py \
gdb/command/ignore_errors.py gdb/command/save_breakpoints.py \
gdb/function/caller_is.py gdb/function/in_scope.py \
gdb/function/__init__.py gdb/backtrace.py gdb/__init__.py
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 234397e..7ac503f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -20262,6 +20262,10 @@ Return the frame's symtab and line object. @c (@pxref{Symtab_and_line,, Symtab a
Return the value of the given variable in this frame. @var{variable} must
be a string.
@end defmethod
+
+@defmethod Frame select
+Set this frame to be the user's selected frame.
+@end defmethod
@end table
@node Interpreters
diff --git a/gdb/python/lib/gdb/FrameWrapper.py b/gdb/python/lib/gdb/FrameWrapper.py
new file mode 100644
index 0000000..39f8246
--- /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 <http://www.gnu.org/licenses/>.
+
+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.frame.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.frame.type () == gdb.DUMMY_FRAME:
+ stream.write (" <function called from gdb>\n")
+ elif self.frame.type () == gdb.SIGTRAMP_FRAME:
+ stream.write (" <signal handler called>\n")
+ else:
+ sal = self.frame.find_sal ()
+ pc = self.frame.pc ()
+ name = self.frame.name ()
+ if not name:
+ name = "??"
+ if pc != sal.pc or not sal.symtab:
+ stream.write (" 0x%08x in" % pc)
+ stream.write (" " + name + " (")
+
+ func = self.frame.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.frame.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/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py
index c49fd55..ec9a527 100644
--- a/gdb/python/lib/gdb/command/backtrace.py
+++ b/gdb/python/lib/gdb/command/backtrace.py
@@ -19,101 +19,9 @@ import gdb
import gdb.backtrace
import itertools
from gdb.FrameIterator import FrameIterator
+from gdb.FrameWrapper import FrameWrapper
import sys
-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.frame.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.frame.type () == gdb.DUMMY_FRAME:
- stream.write (" <function called from gdb>\n")
- elif self.frame.type () == gdb.SIGTRAMP_FRAME:
- stream.write (" <signal handler called>\n")
- else:
- sal = self.frame.find_sal ()
- pc = self.frame.pc ()
- name = self.frame.name ()
- if not name:
- name = "??"
- if pc != sal.pc or not sal.symtab:
- stream.write (" 0x%08x in" % pc)
- stream.write (" " + name + " (")
-
- func = self.frame.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.frame.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)
-
class ReverseBacktraceParameter (gdb.Parameter):
"""The new-backtrace command can show backtraces in 'reverse' order.
This means that the innermost frame will be printed last.
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 <http://www.gnu.org/licenses/>.
+
+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/python-frame.c b/gdb/python/python-frame.c
index 229ba30..3d2f61f 100644
--- a/gdb/python/python-frame.c
+++ b/gdb/python/python-frame.c
@@ -440,6 +440,25 @@ frapy_read_var (PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
+/* Select this frame. */
+
+static PyObject *
+frapy_select (PyObject *self, PyObject *args)
+{
+ struct frame_info *fi;
+ frame_object *frame = (frame_object *) self;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID (frame, fi);
+ select_frame (fi);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ Py_RETURN_NONE;
+}
+
/* Implementation of gdb.selected_frame () -> gdb.Frame.
Returns the selected frame object. */
@@ -577,6 +596,8 @@ Return the frame's symtab and line." },
{ "read_var", frapy_read_var, METH_VARARGS,
"read_var (variable) -> gdb.Value.\n\
Return the value of the variable in this frame." },
+ { "select", frapy_select, METH_NOARGS,
+ "Select this frame as the user's current frame." },
{NULL} /* Sentinel */
};
diff --git a/gdb/python/python-symtab.c b/gdb/python/python-symtab.c
index a48c38c..830e586 100644
--- a/gdb/python/python-symtab.c
+++ b/gdb/python/python-symtab.c
@@ -1,6 +1,6 @@
/* Python interface to symbol tables.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
@@ -78,6 +78,15 @@ stpy_get_filename (PyObject *self, void *closure)
}
static PyObject *
+stpy_get_objfile (PyObject *self, void *closure)
+{
+ symtab_object *self_symtab = (symtab_object *) self;
+ PyObject *result = objfile_to_objfile_object (self_symtab->symtab->objfile);
+ Py_INCREF (result);
+ return result;
+}
+
+static PyObject *
stpy_fullname (PyObject *self, PyObject *args)
{
char *fullname;
@@ -225,6 +234,8 @@ gdbpy_initialize_symtabs (void)
static PyGetSetDef symtab_object_getset[] = {
{ "filename", stpy_get_filename, NULL,
"The symbol table's source filename.", NULL },
+ { "objfile", stpy_get_objfile, NULL, "The symtab's objfile.",
+ NULL },
{NULL} /* Sentinel */
};