Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.
@ 2014-09-01 23:07 Doug Evans
  2014-09-02  1:34 ` Sergio Durigan Junior
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Doug Evans @ 2014-09-01 23:07 UTC (permalink / raw)
  To: gdb-patches, jan.kratochvil, eliz

Hi.

Redhat has $caller_is and $caller_matches in their tree.
I've had a use for them from time to time, and I've finally gone ahead
and finished the patch so that it can be submitted.

I've also had a use for $_any_caller_is/$_any_caller_matches so I've
added those too.

Redhat names these functions $caller_is and $caller_matches
but convention in the FSF tree is to prepend the name with "_"
so I've done that to be consistent.

Jan: I'm happy to add a Redhat person to the ChangeLog entry,
but I'm not sure who wrote this.  Was it you or Tom or ...?

2014-09-01  Doug Evans  <xdje42@gmail.com>
	    ??? <???@redhat.com>

        PR 15276
	* NEWS: Mention $_caller_is, $_caller_matches, $_any_caller_is,
	$_any_caller_matches.
	* data-directory/Makefile.in (PYTHON_FILE_LIST): Add caller_is.py.
	* python/lib/gdb/function/caller_is.py: New file.

	testsuite/
	* gdb.python/py-caller-is.c: New file.
	* gdb.python/py-caller-is.exp: New file.

	doc/
	* gdb.texinfo (Convenience Funs): Document $_caller_is,
	$_caller_matches, $_any_caller_is, $_any_caller_matches.

diff --git a/gdb/NEWS b/gdb/NEWS
index d603cf7..f57eccd 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,13 @@
 
 *** Changes since GDB 7.8
 
+* New Python-based convenience functions:
+
+  ** $_caller_is(name [, number_of_frames])
+  ** $_caller_matches(regexp [, number_of_frames])
+  ** $_any_caller_is(name [, number_of_frames])
+  ** $_any_caller_matches(regexp [, number_of_frames])
+
 * On resume, GDB now always passes the signal the program had stopped
   for to the thread the signal was sent to, even if the user changed
   threads before resuming.  Previously GDB would often (but not
diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index 509f888..1e8cd4b 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -73,6 +73,7 @@ PYTHON_FILE_LIST = \
 	gdb/command/prompt.py \
 	gdb/command/explore.py \
 	gdb/function/__init__.py \
+	gdb/function/caller_is.py \
 	gdb/function/strfns.py
 
 @HAVE_PYTHON_TRUE@PYTHON_FILES = $(PYTHON_FILE_LIST)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8d9148c..facbd16 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10098,6 +10098,70 @@ Otherwise it returns zero.
 @findex $_strlen@r{, convenience function}
 Returns the length of string @var{str}.
 
+@item $_caller_is(@var{name}@r{[}, @var{number_of_frames}@r{]})
+@findex $_caller_is@r{, convenience function}
+Returns one if the calling function's name is equal to @var{name}.
+Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+Example:
+
+@smallexample
+(gdb) backtrace
+#0  bottom_func ()
+    at testsuite/gdb.python/py-caller-is.c:21
+#1  0x00000000004005a0 in middle_func ()
+    at testsuite/gdb.python/py-caller-is.c:27
+#2  0x00000000004005ab in top_func ()
+    at testsuite/gdb.python/py-caller-is.c:33
+#3  0x00000000004005b6 in main ()
+    at testsuite/gdb.python/py-caller-is.c:39
+(gdb) print $_caller_is ("middle_func")
+$1 = 1
+(gdb) print $_caller_is ("top_func", 2)
+$1 = 1
+@end smallexample
+
+@item $_caller_matches(@var{regexp}@r{[}, @var{number_of_frames}@r{]})
+@findex $_caller_matches@r{, convenience function}
+Returns one if the calling function's name matches the regular expression
+@var{regexp}.  Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+@item $_any_caller_is(@var{name}@r{[}, @var{number_of_frames}@r{]})
+@findex $_any_caller_is@r{, convenience function}
+Returns one if any calling function's name is equal to @var{name}.
+Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+This function differs from @code{$_caller_is} in that this function
+checks all stack frames from the immediate caller to the frame specified
+by @var{number_of_frames}, whereas @code{$_caller_is} only checks the
+frame specified by @var{number_of_frames}.
+
+@item $_any_caller_matches(@var{regexp}@r{[}, @var{number_of_frames}@r{]})
+@findex $_any_caller_matches@r{, convenience function}
+Returns one if any calling function's name matches the regular expression
+@var{regexp}.  Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+This function differs from @code{$_caller_matches} in that this function
+checks all stack frames from the immediate caller to the frame specified
+by @var{number_of_frames}, whereas @code{$_caller_matches} only checks the
+frame specified by @var{number_of_frames}.
+
 @end table
 
 @value{GDBN} provides the ability to list and get help on
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..58257df
--- /dev/null
+++ b/gdb/python/lib/gdb/function/caller_is.py
@@ -0,0 +1,156 @@
+# Caller-is functions.
+# Copyright (C) 2008, 2014 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
+
+class CallerIs (gdb.Function):
+    """Check the calling function's name.
+
+Usage:
+  $_caller_is(name [, number_of_frames])
+
+Arguments:
+
+  name: The name of the function to search for.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if the function's name at the specified frame is equal to name.
+"""
+
+    def __init__ (self):
+        super (CallerIs, self).__init__ ("_caller_is")
+
+    def invoke (self, name, nframes = 1):
+        assert nframes > 0
+        frame = gdb.selected_frame ()
+        while nframes > 0:
+            frame = frame.older ()
+            if frame is None:
+                return False
+            nframes = nframes - 1
+        return frame.name () == name.string ()
+
+class CallerMatches (gdb.Function):
+    """Compare the calling function's name with a regexp.
+
+Usage:
+  $_caller_matches(regex [, number_of_frames])
+
+Arguments:
+
+  regex: The regular expression to compare the function's name with.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if the function's name at the specified frame matches regex.
+"""
+
+    def __init__ (self):
+        super (CallerMatches, self).__init__ ("_caller_matches")
+
+    def invoke (self, name, nframes = 1):
+        assert nframes > 0
+        frame = gdb.selected_frame ()
+        while nframes > 0:
+            frame = frame.older ()
+            if frame is None:
+                return False
+            nframes = nframes - 1
+        return re.match (name.string (), frame.name ()) is not None
+
+class AnyCallerIs (gdb.Function):
+    """Check all calling function's names.
+
+Usage:
+  $_any_caller_is(name [, number_of_frames])
+
+Arguments:
+
+  name: The name of the function to search for.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if any function's name is equal to name.
+"""
+
+    def __init__ (self):
+        super (AnyCallerIs, self).__init__ ("_any_caller_is")
+
+    def invoke (self, name, nframes = 1):
+        assert nframes > 0
+        frame = gdb.selected_frame ()
+        while nframes > 0:
+            frame = frame.older ()
+            if frame is None:
+                return False
+            if frame.name () == name.string ():
+                return True 
+            nframes = nframes - 1
+        return False
+
+class AnyCallerMatches (gdb.Function):
+    """Compare all calling function's names with a regexp.
+
+Usage:
+  $_any_caller_matches(regex [, number_of_frames])
+
+Arguments:
+
+  regex: The regular expression to compare the function's name with.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if any function's name matches regex.
+"""
+
+    def __init__ (self):
+        super (AnyCallerMatches, self).__init__ ("_any_caller_matches")
+
+    def invoke (self, name, nframes = 1):
+        assert nframes > 0
+        frame = gdb.selected_frame ()
+        name_re = re.compile (name.string ())
+        while nframes > 0:
+            frame = frame.older ()
+            if frame is None:
+                return False
+            if name_re.match (frame.name ()) is not None:
+                return True
+            nframes = nframes - 1
+        return False
+
+CallerIs()
+CallerMatches()
+AnyCallerIs()
+AnyCallerMatches()
diff --git a/gdb/testsuite/gdb.python/py-caller-is.c b/gdb/testsuite/gdb.python/py-caller-is.c
new file mode 100644
index 0000000..2c86388
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-caller-is.c
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2014 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/>.  */
+
+static void
+bottom_func (void)
+{
+  return; /* Break bottom_func here.  */
+}
+
+static void
+middle_func (void)
+{
+  bottom_func ();
+}
+
+static void
+top_func (void)
+{
+  middle_func ();
+}
+
+int
+main ()
+{
+  top_func ();
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.python/py-caller-is.exp b/gdb/testsuite/gdb.python/py-caller-is.exp
new file mode 100644
index 0000000..bed158b
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-caller-is.exp
@@ -0,0 +1,65 @@
+# Copyright (C) 2012-2014 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/>.
+
+# This file is part of the GDB testsuite.  It tests the convenience
+# functions in caller_is.py.
+
+load_lib gdb-python.exp
+
+standard_testfile
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return 0
+}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+gdb_breakpoint "bottom_func"
+gdb_continue_to_breakpoint "bottom_func"
+
+proc test_all_caller_is_fns { } {
+    gdb_test "p \$_caller_is (\"middle_func\")" " = 1"
+    gdb_test "p \$_caller_is (\"top_func\")" " = 0"
+    gdb_test "p \$_caller_is (\"middle_func\", 2)" " = 0"
+    gdb_test "p \$_caller_is (\"top_func\", 2)" " = 1"
+    gdb_test "p \$_caller_is (\"foo\", 100)" " = 0"
+
+    gdb_test "p \$_caller_matches (\"^middle_\")" " = 1"
+    gdb_test "p \$_caller_matches (\"^top_\")" " = 0"
+    gdb_test "p \$_caller_matches (\"^middle_\", 2)" " = 0"
+    gdb_test "p \$_caller_matches (\"^top_f\", 2)" " = 1"
+    gdb_test "p \$_caller_matches (\"foo\", 100)" " = 0"
+
+    gdb_test "p \$_any_caller_is (\"middle_func\")" " = 1"
+    gdb_test "p \$_any_caller_is (\"top_func\")" " = 0"
+    gdb_test "p \$_any_caller_is (\"middle_func\", 2)" " = 1"
+    gdb_test "p \$_any_caller_is (\"top_func\", 2)" " = 1"
+    gdb_test "p \$_any_caller_is (\"main\", 100)" " = 1"
+    gdb_test "p \$_any_caller_is (\"foo\", 100)" " = 0"
+
+    gdb_test "p \$_any_caller_matches (\"^middle_\")" " = 1"
+    gdb_test "p \$_any_caller_matches (\"^top_\")" " = 0"
+    gdb_test "p \$_any_caller_matches (\"^middle_\", 2)" " = 1"
+    gdb_test "p \$_any_caller_matches (\"^top_f\", 2)" " = 1"
+    gdb_test "p \$_any_caller_matches (\"^main\", 100)" " = 1"
+    gdb_test "p \$_any_caller_matches (\"foo\", 100)" " = 0"
+}
+
+test_all_caller_is_fns


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.
  2014-09-01 23:07 [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al Doug Evans
@ 2014-09-02  1:34 ` Sergio Durigan Junior
  2014-09-02  7:43 ` Jan Kratochvil
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Sergio Durigan Junior @ 2014-09-02  1:34 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, jan.kratochvil, eliz

On Monday, September 01 2014, Doug Evans wrote:

> Jan: I'm happy to add a Redhat person to the ChangeLog entry,
> but I'm not sure who wrote this.  Was it you or Tom or ...?

Hello Doug,

According to 5bbc9e9236e752b546f99749a2ebc758c5fb7fcf on archer.git, the
author was Tom.

-- 
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.
  2014-09-01 23:07 [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al Doug Evans
  2014-09-02  1:34 ` Sergio Durigan Junior
@ 2014-09-02  7:43 ` Jan Kratochvil
  2014-09-02 15:28 ` Eli Zaretskii
  2014-09-06 16:28 ` Doug Evans
  3 siblings, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2014-09-02  7:43 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, eliz

On Tue, 02 Sep 2014 01:07:01 +0200, Doug Evans wrote:
> Jan: I'm happy to add a Redhat person to the ChangeLog entry,
> but I'm not sure who wrote this.  Was it you or Tom or ...?

Tom:
	https://sourceware.org/git/?p=archer.git;a=blame;f=gdb/python/lib/gdb/function/caller_is.py;h=2b9c5c74a83569b60923431943aa834e97c5d7f9;hb=refs/heads/tromey/python

BTW s/Redhat/Red Hat/.


Jan


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.
  2014-09-01 23:07 [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al Doug Evans
  2014-09-02  1:34 ` Sergio Durigan Junior
  2014-09-02  7:43 ` Jan Kratochvil
@ 2014-09-02 15:28 ` Eli Zaretskii
  2014-09-06 16:28 ` Doug Evans
  3 siblings, 0 replies; 7+ messages in thread
From: Eli Zaretskii @ 2014-09-02 15:28 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, jan.kratochvil

> From: Doug Evans <xdje42@gmail.com>
> Date: Mon, 01 Sep 2014 16:07:01 -0700
> 
> Redhat has $caller_is and $caller_matches in their tree.
> I've had a use for them from time to time, and I've finally gone ahead
> and finished the patch so that it can be submitted.
> 
> I've also had a use for $_any_caller_is/$_any_caller_matches so I've
> added those too.

OK for the documentation parts.

Thanks.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.
  2014-09-01 23:07 [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al Doug Evans
                   ` (2 preceding siblings ...)
  2014-09-02 15:28 ` Eli Zaretskii
@ 2014-09-06 16:28 ` Doug Evans
  2014-09-07 11:59   ` Regression for gdb.base/default.exp [Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.] Jan Kratochvil
  3 siblings, 1 reply; 7+ messages in thread
From: Doug Evans @ 2014-09-06 16:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: jan.kratochvil, eliz

Doug Evans <xdje42@gmail.com> writes:
> Hi.
>
> Redhat has $caller_is and $caller_matches in their tree.
> I've had a use for them from time to time, and I've finally gone ahead
> and finished the patch so that it can be submitted.
>
> I've also had a use for $_any_caller_is/$_any_caller_matches so I've
> added those too.

Hi.

Here is what I pushed.
It's slightly different from the original post:
- better exception is generated for nframes < 0
- handles nframes == 0
- more tests

2014-09-02  Doug Evans  <xdje42@gmail.com>
	    Tom Tromey  <tromey@redhat.com>

	PR 15276
	* NEWS: Mention $_caller_is, $_caller_matches, $_any_caller_is,
	$_any_caller_matches.
	* data-directory/Makefile.in (PYTHON_FILE_LIST): Add caller_is.py.
	* python/lib/gdb/function/caller_is.py: New file.

	testsuite/
	* gdb.python/py-caller-is.c: New file.
	* gdb.python/py-caller-is.exp: New file.

	doc/
	* gdb.texinfo (Convenience Funs): Document $_caller_is,
	$_caller_matches, $_any_caller_is, $_any_caller_matches.

diff --git a/gdb/NEWS b/gdb/NEWS
index 46c6a87..3bb1c74 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -6,6 +6,13 @@
 * Python Scripting
   You can now access frame registers from Python scripts.
 
+* New Python-based convenience functions:
+
+  ** $_caller_is(name [, number_of_frames])
+  ** $_caller_matches(regexp [, number_of_frames])
+  ** $_any_caller_is(name [, number_of_frames])
+  ** $_any_caller_matches(regexp [, number_of_frames])
+
 * On resume, GDB now always passes the signal the program had stopped
   for to the thread the signal was sent to, even if the user changed
   threads before resuming.  Previously GDB would often (but not
diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index 509f888..1e8cd4b 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -73,6 +73,7 @@ PYTHON_FILE_LIST = \
 	gdb/command/prompt.py \
 	gdb/command/explore.py \
 	gdb/function/__init__.py \
+	gdb/function/caller_is.py \
 	gdb/function/strfns.py
 
 @HAVE_PYTHON_TRUE@PYTHON_FILES = $(PYTHON_FILE_LIST)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8d9148c..facbd16 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10098,6 +10098,70 @@ Otherwise it returns zero.
 @findex $_strlen@r{, convenience function}
 Returns the length of string @var{str}.
 
+@item $_caller_is(@var{name}@r{[}, @var{number_of_frames}@r{]})
+@findex $_caller_is@r{, convenience function}
+Returns one if the calling function's name is equal to @var{name}.
+Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+Example:
+
+@smallexample
+(gdb) backtrace
+#0  bottom_func ()
+    at testsuite/gdb.python/py-caller-is.c:21
+#1  0x00000000004005a0 in middle_func ()
+    at testsuite/gdb.python/py-caller-is.c:27
+#2  0x00000000004005ab in top_func ()
+    at testsuite/gdb.python/py-caller-is.c:33
+#3  0x00000000004005b6 in main ()
+    at testsuite/gdb.python/py-caller-is.c:39
+(gdb) print $_caller_is ("middle_func")
+$1 = 1
+(gdb) print $_caller_is ("top_func", 2)
+$1 = 1
+@end smallexample
+
+@item $_caller_matches(@var{regexp}@r{[}, @var{number_of_frames}@r{]})
+@findex $_caller_matches@r{, convenience function}
+Returns one if the calling function's name matches the regular expression
+@var{regexp}.  Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+@item $_any_caller_is(@var{name}@r{[}, @var{number_of_frames}@r{]})
+@findex $_any_caller_is@r{, convenience function}
+Returns one if any calling function's name is equal to @var{name}.
+Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+This function differs from @code{$_caller_is} in that this function
+checks all stack frames from the immediate caller to the frame specified
+by @var{number_of_frames}, whereas @code{$_caller_is} only checks the
+frame specified by @var{number_of_frames}.
+
+@item $_any_caller_matches(@var{regexp}@r{[}, @var{number_of_frames}@r{]})
+@findex $_any_caller_matches@r{, convenience function}
+Returns one if any calling function's name matches the regular expression
+@var{regexp}.  Otherwise it returns zero.
+
+If the optional argument @var{number_of_frames} is provided,
+it is the number of frames up in the stack to look.
+The default is 1.
+
+This function differs from @code{$_caller_matches} in that this function
+checks all stack frames from the immediate caller to the frame specified
+by @var{number_of_frames}, whereas @code{$_caller_matches} only checks the
+frame specified by @var{number_of_frames}.
+
 @end table
 
 @value{GDBN} provides the ability to list and get help on
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..f5b0a58
--- /dev/null
+++ b/gdb/python/lib/gdb/function/caller_is.py
@@ -0,0 +1,160 @@
+# Caller-is functions.
+# Copyright (C) 2008, 2014 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
+
+class CallerIs(gdb.Function):
+    """Check the calling function's name.
+
+Usage:
+  $_caller_is(name [, number_of_frames])
+
+Arguments:
+
+  name: The name of the function to search for.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if the function's name at the specified frame is equal to name.
+"""
+
+    def __init__(self):
+        super(CallerIs, self).__init__("_caller_is")
+
+    def invoke(self, name, nframes = 1):
+        if nframes < 0:
+            raise ValueError("nframes must be >= 0")
+        frame = gdb.selected_frame()
+        while nframes > 0:
+            frame = frame.older()
+            if frame is None:
+                return False
+            nframes = nframes - 1
+        return frame.name() == name.string()
+
+class CallerMatches(gdb.Function):
+    """Compare the calling function's name with a regexp.
+
+Usage:
+  $_caller_matches(regex [, number_of_frames])
+
+Arguments:
+
+  regex: The regular expression to compare the function's name with.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if the function's name at the specified frame matches regex.
+"""
+
+    def __init__(self):
+        super(CallerMatches, self).__init__("_caller_matches")
+
+    def invoke(self, name, nframes = 1):
+        if nframes < 0:
+            raise ValueError("nframes must be >= 0")
+        frame = gdb.selected_frame()
+        while nframes > 0:
+            frame = frame.older()
+            if frame is None:
+                return False
+            nframes = nframes - 1
+        return re.match(name.string(), frame.name()) is not None
+
+class AnyCallerIs(gdb.Function):
+    """Check all calling function's names.
+
+Usage:
+  $_any_caller_is(name [, number_of_frames])
+
+Arguments:
+
+  name: The name of the function to search for.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if any function's name is equal to name.
+"""
+
+    def __init__(self):
+        super(AnyCallerIs, self).__init__("_any_caller_is")
+
+    def invoke(self, name, nframes = 1):
+        if nframes < 0:
+            raise ValueError("nframes must be >= 0")
+        frame = gdb.selected_frame()
+        while nframes >= 0:
+            if frame.name() == name.string():
+                return True 
+            frame = frame.older()
+            if frame is None:
+                return False
+            nframes = nframes - 1
+        return False
+
+class AnyCallerMatches(gdb.Function):
+    """Compare all calling function's names with a regexp.
+
+Usage:
+  $_any_caller_matches(regex [, number_of_frames])
+
+Arguments:
+
+  regex: The regular expression to compare the function's name with.
+
+  number_of_frames: How many stack frames to traverse back from the currently
+    selected frame to compare with.  If the value is greater than the depth of
+    the stack from that point then the result is False.
+    The default is 1.
+
+Returns:
+  True if any function's name matches regex.
+"""
+
+    def __init__(self):
+        super(AnyCallerMatches, self).__init__("_any_caller_matches")
+
+    def invoke(self, name, nframes = 1):
+        if nframes < 0:
+            raise ValueError("nframes must be >= 0")
+        frame = gdb.selected_frame()
+        name_re = re.compile(name.string())
+        while nframes >= 0:
+            if name_re.match(frame.name()) is not None:
+                return True
+            frame = frame.older()
+            if frame is None:
+                return False
+            nframes = nframes - 1
+        return False
+
+CallerIs()
+CallerMatches()
+AnyCallerIs()
+AnyCallerMatches()
diff --git a/gdb/testsuite/gdb.python/py-caller-is.c b/gdb/testsuite/gdb.python/py-caller-is.c
new file mode 100644
index 0000000..2c86388
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-caller-is.c
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2014 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/>.  */
+
+static void
+bottom_func (void)
+{
+  return; /* Break bottom_func here.  */
+}
+
+static void
+middle_func (void)
+{
+  bottom_func ();
+}
+
+static void
+top_func (void)
+{
+  middle_func ();
+}
+
+int
+main ()
+{
+  top_func ();
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.python/py-caller-is.exp b/gdb/testsuite/gdb.python/py-caller-is.exp
new file mode 100644
index 0000000..23c58ea
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-caller-is.exp
@@ -0,0 +1,73 @@
+# Copyright (C) 2012-2014 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/>.
+
+# This file is part of the GDB testsuite.  It tests the convenience
+# functions in caller_is.py.
+
+load_lib gdb-python.exp
+
+standard_testfile
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return 0
+}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+gdb_breakpoint "bottom_func"
+gdb_continue_to_breakpoint "bottom_func"
+
+proc test_all_caller_is_fns { } {
+    gdb_test "p \$_caller_is (\"bottom_func\", 0)" " = 1"
+    gdb_test "p \$_caller_is (\"middle_func\")" " = 1"
+    gdb_test "p \$_caller_is (\"top_func\")" " = 0"
+    gdb_test "p \$_caller_is (\"middle_func\", 2)" " = 0"
+    gdb_test "p \$_caller_is (\"top_func\", 2)" " = 1"
+    gdb_test "p \$_caller_is (\"foo\", 100)" " = 0"
+    gdb_test "p \$_caller_is (\"foo\", -1)" "nframes must be >= 0"
+
+    gdb_test "p \$_caller_matches (\"^bottom\", 0)" " = 1"
+    gdb_test "p \$_caller_matches (\"^middle_\")" " = 1"
+    gdb_test "p \$_caller_matches (\"^top_\")" " = 0"
+    gdb_test "p \$_caller_matches (\"^middle_\", 2)" " = 0"
+    gdb_test "p \$_caller_matches (\"^top_f\", 2)" " = 1"
+    gdb_test "p \$_caller_matches (\"foo\", 100)" " = 0"
+    gdb_test "p \$_caller_matches (\"foo\", -1)" "nframes must be >= 0"
+
+    gdb_test "p \$_any_caller_is (\"bottom_func\", 0)" " = 1"
+    gdb_test "p \$_any_caller_is (\"middle_func\")" " = 1"
+    gdb_test "p \$_any_caller_is (\"top_func\")" " = 0"
+    gdb_test "p \$_any_caller_is (\"middle_func\", 2)" " = 1"
+    gdb_test "p \$_any_caller_is (\"top_func\", 2)" " = 1"
+    gdb_test "p \$_any_caller_is (\"main\", 100)" " = 1"
+    gdb_test "p \$_any_caller_is (\"foo\", 100)" " = 0"
+    gdb_test "p \$_any_caller_is (\"foo\", -1)" "nframes must be >= 0"
+
+    gdb_test "p \$_any_caller_matches (\"^bottom\", 0)" " = 1"
+    gdb_test "p \$_any_caller_matches (\"^middle_\")" " = 1"
+    gdb_test "p \$_any_caller_matches (\"^top_\")" " = 0"
+    gdb_test "p \$_any_caller_matches (\"^middle_\", 2)" " = 1"
+    gdb_test "p \$_any_caller_matches (\"^top_f\", 2)" " = 1"
+    gdb_test "p \$_any_caller_matches (\"^main\", 100)" " = 1"
+    gdb_test "p \$_any_caller_matches (\"foo\", 100)" " = 0"
+    gdb_test "p \$_any_caller_matches (\"foo\", -1)" "nframes must be >= 0"
+}
+
+test_all_caller_is_fns


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Regression for gdb.base/default.exp  [Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.]
  2014-09-06 16:28 ` Doug Evans
@ 2014-09-07 11:59   ` Jan Kratochvil
  2014-09-09  6:04     ` Doug Evans
  0 siblings, 1 reply; 7+ messages in thread
From: Jan Kratochvil @ 2014-09-07 11:59 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, eliz

[-- Attachment #1: Type: text/plain, Size: 452 bytes --]

On Sat, 06 Sep 2014 18:27:41 +0200, Doug Evans wrote:
> Here is what I pushed.

-PASS: gdb.base/default.exp: show convenience
+FAIL: gdb.base/default.exp: show convenience ($_exception = <error: No frame selected> not found)

due to:

commit faa42425cb1f5cd279fc8c91d0b75d37853a128a
Author: Doug Evans <xdje42@gmail.com>
Date:   Sat Sep 6 09:15:44 2014 -0700
    PR 15276: Add $_caller_is, $_caller_matches, $_any_caller_is, $_any_caller_matches


Jan

[-- Attachment #2: 1 --]
[-- Type: text/plain, Size: 4166 bytes --]

 (gdb) PASS: gdb.base/default.exp: show confirm
 python print ('test')^M
 test^M
 (gdb) python print (sys.version_info[0])^M
 2^M
 (gdb) python print (sys.version_info[1])^M
 7^M
 (gdb) show convenience^M
+$_any_caller_matches = <internal function _any_caller_matches>^Mseen: $_any_caller_matches = <internal function _any_caller_matches>^M
+extracted: $_any_caller_matches = <internal function _any_caller_matches>
+
+$_any_caller_is = <internal function _any_caller_is>^Mseen: $_any_caller_is = <internal function _any_caller_is>^M
+extracted: $_any_caller_is = <internal function _any_caller_is>
+
+$_caller_matches = <internal function _caller_matches>^Mseen: $_caller_matches = <internal function _caller_matches>^M
+extracted: $_caller_matches = <internal function _caller_matches>
+
+$_caller_is = <internal function _caller_is>^Mseen: $_caller_is = <internal function _caller_is>^M
+extracted: $_caller_is = <internal function _caller_is>
+
 $_regex = <internal function _regex>^Mseen: $_regex = <internal function _regex>^M
 extracted: $_regex = <internal function _regex>
 
 $_streq = <internal function _streq>^Mseen: $_streq = <internal function _streq>^M
 extracted: $_streq = <internal function _streq>
 
 $_strlen = <internal function _strlen>^Mseen: $_strlen = <internal function _strlen>^M
 extracted: $_strlen = <internal function _strlen>
 
 $_memeq = <internal function _memeq>^Mseen: $_memeq = <internal function _memeq>^M
 extracted: $_memeq = <internal function _memeq>
 
 $_thread = 0^Mseen: $_thread = 0^M
 extracted: $_thread = 0
 
 $_siginfo = void^Mseen: $_siginfo = void^M
 extracted: $_siginfo = void
 
 $_isvoid = <internal function _isvoid>^Mseen: $_isvoid = <internal function _isvoid>^M
 extracted: $_isvoid = <internal function _isvoid>
 
 $_exception = <error: No frame selected>^Mseen: $_exception = <error: No frame selected>^M
 extracted: $_exception = <error: No frame selected>
 
 $_probe_arg11 = <error: No frame selected>^Mseen: $_probe_arg11 = <error: No frame selected>^M
 extracted: $_probe_arg11 = <error: No frame selected>
 
 $_probe_arg10 = <error: No frame selected>^Mseen: $_probe_arg10 = <error: No frame selected>^M
 extracted: $_probe_arg10 = <error: No frame selected>
 
 $_probe_arg9 = <error: No frame selected>^Mseen: $_probe_arg9 = <error: No frame selected>^M
 extracted: $_probe_arg9 = <error: No frame selected>
 
 $_probe_arg8 = <error: No frame selected>^Mseen: $_probe_arg8 = <error: No frame selected>^M
 extracted: $_probe_arg8 = <error: No frame selected>
 
 $_probe_arg7 = <error: No frame selected>^Mseen: $_probe_arg7 = <error: No frame selected>^M
 extracted: $_probe_arg7 = <error: No frame selected>
 
 $_probe_arg6 = <error: No frame selected>^Mseen: $_probe_arg6 = <error: No frame selected>^M
 extracted: $_probe_arg6 = <error: No frame selected>
 
 $_probe_arg5 = <error: No frame selected>^Mseen: $_probe_arg5 = <error: No frame selected>^M
 extracted: $_probe_arg5 = <error: No frame selected>
 
 $_probe_arg4 = <error: No frame selected>^Mseen: $_probe_arg4 = <error: No frame selected>^M
 extracted: $_probe_arg4 = <error: No frame selected>
 
 $_probe_arg3 = <error: No frame selected>^Mseen: $_probe_arg3 = <error: No frame selected>^M
 extracted: $_probe_arg3 = <error: No frame selected>
 
 $_probe_arg2 = <error: No frame selected>^Mseen: $_probe_arg2 = <error: No frame selected>^M
 extracted: $_probe_arg2 = <error: No frame selected>
 
 $_probe_arg1 = <error: No frame selected>^Mseen: $_probe_arg1 = <error: No frame selected>^M
 extracted: $_probe_arg1 = <error: No frame selected>
 
 $_probe_arg0 = <error: No frame selected>^Mseen: $_probe_arg0 = <error: No frame selected>^M
 extracted: $_probe_arg0 = <error: No frame selected>
 
 $_probe_argc = <error: No frame selected>^Mseen: $_probe_argc = <error: No frame selected>^M
 extracted: $_probe_argc = <error: No frame selected>
 
 $_sdata = void^Mseen: $_sdata = void^M
 extracted: $_sdata = void
 
 $_tlb = void^Mseen: $_tlb = void^M
 extracted: $_tlb = void
 
-(gdb) PASS: gdb.base/default.exp: show convenience
+(gdb) FAIL: gdb.base/default.exp: show convenience ($_exception = <error: No frame selected> not found)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Regression for gdb.base/default.exp  [Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.]
  2014-09-07 11:59   ` Regression for gdb.base/default.exp [Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.] Jan Kratochvil
@ 2014-09-09  6:04     ` Doug Evans
  0 siblings, 0 replies; 7+ messages in thread
From: Doug Evans @ 2014-09-09  6:04 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, eliz

Jan Kratochvil <jan.kratochvil@redhat.com> writes:

> On Sat, 06 Sep 2014 18:27:41 +0200, Doug Evans wrote:
>> Here is what I pushed.
>
> -PASS: gdb.base/default.exp: show convenience
> +FAIL: gdb.base/default.exp: show convenience ($_exception = <error: No frame selected> not found)
>
> due to:
>
> commit faa42425cb1f5cd279fc8c91d0b75d37853a128a
> Author: Doug Evans <xdje42@gmail.com>
> Date:   Sat Sep 6 09:15:44 2014 -0700
>     PR 15276: Add $_caller_is, $_caller_matches, $_any_caller_is, $_any_caller_matches

Thanks.

I committed the following.

2014-09-09  Doug Evans  <xdje42@gmail.com>

	* gdb.base/default.exp (show_conv_list): Add _caller_is,
	_caller_matches, _any_caller_is, _any_caller_matches.

diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index 6674df3..ab74bdb 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -630,6 +630,10 @@ if ![skip_python_tests] {
 	    {$_regex = <internal function _regex>} \
 	    {$_streq = <internal function _streq>} \
 	    {$_strlen = <internal function _strlen>} \
+	    {$_caller_is = <internal function _caller_is>} \
+	    {$_caller_matches = <internal function _caller_matches>} \
+	    {$_any_caller_is = <internal function _any_caller_is>} \
+	    {$_any_caller_matches = <internal function _any_caller_matches>} \
 	}
 }
 gdb_test_list_exact "show convenience" "show convenience" \


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-09-09  6:04 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-01 23:07 [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al Doug Evans
2014-09-02  1:34 ` Sergio Durigan Junior
2014-09-02  7:43 ` Jan Kratochvil
2014-09-02 15:28 ` Eli Zaretskii
2014-09-06 16:28 ` Doug Evans
2014-09-07 11:59   ` Regression for gdb.base/default.exp [Re: [PATCH, doc RFA][PR 15276] Add $_caller_is, et. al.] Jan Kratochvil
2014-09-09  6:04     ` Doug Evans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox