public inbox for archer@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tromey@redhat.com>
To: Roland McGrath <roland@redhat.com>
Cc: Project Archer <archer@sourceware.org>
Subject: [python] implement "upto" (Was: feature idea: upto)
Date: Tue, 07 Jul 2009 16:18:00 -0000	[thread overview]
Message-ID: <m363e4qxfg.fsf@fleche.redhat.com> (raw)
In-Reply-To: <20090702223351.64F00404FD@magilla.sf.frob.com> (Roland McGrath's message of "Thu\,  2 Jul 2009 15\:33\:51 -0700 \(PDT\)")

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 */
 };
 

  reply	other threads:[~2009-07-07 16:18 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-07-02 22:34 feature idea: upto Roland McGrath
2009-07-07 16:18 ` Tom Tromey [this message]
2009-07-09  4:25   ` [python] implement "upto" (Was: feature idea: upto) Roland McGrath
2009-07-17 22:06     ` [python] implement "upto" Tom Tromey
2009-07-20  6:17       ` Roland McGrath
2009-07-23  7:00 ` feature idea: upto Jim Blandy
2009-07-23 18:15   ` Roland McGrath
2009-07-23 18:52     ` Tom Tromey
2009-07-23 19:08       ` Roland McGrath

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m363e4qxfg.fsf@fleche.redhat.com \
    --to=tromey@redhat.com \
    --cc=archer@sourceware.org \
    --cc=roland@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).