PR 15276: Add $_caller_is, $_caller_matches, $_any_caller_is, $_any_caller_matches

gdb/ChangeLog:

	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.

gdb/testsuite/ChangeLog:

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

gdb/doc/ChangeLog:

	PR 15276
	* gdb.texinfo (Convenience Funs): Document $_caller_is,
	$_caller_matches, $_any_caller_is, $_any_caller_matches.
This commit is contained in:
Doug Evans 2014-09-06 09:15:44 -07:00
parent 0d41ba00c6
commit faa42425cb
9 changed files with 366 additions and 0 deletions

View file

@ -1,3 +1,11 @@
2014-09-06 Doug Evans <xdje42@gmail.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.
2014-09-06 Doug Evans <xdje42@gmail.com>
* infcmd.c (program_info): Fix typo.

View file

@ -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

View file

@ -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)

View file

@ -1,3 +1,9 @@
2014-09-06 Doug Evans <xdje42@gmail.com>
PR 15276
* gdb.texinfo (Convenience Funs): Document $_caller_is,
$_caller_matches, $_any_caller_is, $_any_caller_matches.
2014-09-03 Justin Lebar <jlebar@google.com>
* python.texi (Types In Python): Type.template_argument(n) returns a

View file

@ -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

View file

@ -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()

View file

@ -1,3 +1,9 @@
2014-09-06 Doug Evans <xdje42@gmail.com>
PR 15276
* gdb.python/py-caller-is.c: New file.
* gdb.python/py-caller-is.exp: New file.
2014-09-05 Sergio Durigan Junior <sergiodj@redhat.com>
PR gdb/17235

View file

@ -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;
}

View file

@ -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