Add Python rbreak command.
gdb/Changelog 2017-11-16 Phil Muldoon <pmuldoon@redhat.com> * python/python.c (gdbpy_rbreak): New function. * NEWS: Document Python rbreak feature. testsuite/Changelog 2017-11-16 Phil Muldoon <pmuldoon@redhat.com> * gdb.python/py-rbreak.exp: New file. * gdb.python/py-rbreak.c: New file. * gdb.python/py-rbreak-func2.c: New file. doc/Changelog 2017-11-16 Phil Muldoon <pmuldoon@redhat.com> * python.texi (Basic Python): Add rbreak documentation.
This commit is contained in:
parent
38b28f7088
commit
d8ae99a7b0
@ -1,3 +1,8 @@
|
||||
2017-11-16 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* python/python.c (gdbpy_rbreak): New function.
|
||||
* NEWS: Document Python rbreak feature.
|
||||
|
||||
2017-11-16 Yao Qi <yao.qi@linaro.org>
|
||||
|
||||
* features/tic6x-c62x.xml: Remove.
|
||||
|
4
gdb/NEWS
4
gdb/NEWS
@ -24,6 +24,10 @@
|
||||
gdb.new_thread are emitted. See the manual for further
|
||||
description of these.
|
||||
|
||||
** A new command, "rbreak" has been added to the Python API. This
|
||||
command allows the setting of a large number of breakpoints via a
|
||||
regex pattern in Python. See the manual for further details.
|
||||
|
||||
* New features in the GDB remote stub, GDBserver
|
||||
|
||||
** GDBserver is now able to start inferior processes with a
|
||||
|
@ -1,3 +1,7 @@
|
||||
2017-11-16 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* python.texi (Basic Python): Add rbreak documentation.
|
||||
|
||||
2017-11-07 Xavier Roirand <roirand@adacore.com>
|
||||
Pedro Alves <palves@redhat.com>
|
||||
|
||||
|
@ -243,6 +243,23 @@ were no breakpoints. This peculiarity was subsequently fixed, and now
|
||||
@code{gdb.breakpoints} returns an empty sequence in this case.
|
||||
@end defun
|
||||
|
||||
@defun gdb.rbreak (regex @r{[}, minsyms @r{[}, throttle, @r{[}, symtabs @r{]]]})
|
||||
Return a Python list holding a collection of newly set
|
||||
@code{gdb.Breakpoint} objects matching function names defined by the
|
||||
@var{regex} pattern. If the @var{minsyms} keyword is @code{True}, all
|
||||
system functions (those not explicitly defined in the inferior) will
|
||||
also be included in the match. The @var{throttle} keyword takes an
|
||||
integer that defines the maximum number of pattern matches for
|
||||
functions matched by the @var{regex} pattern. If the number of
|
||||
matches exceeds the integer value of @var{throttle}, a
|
||||
@code{RuntimeError} will be raised and no breakpoints will be created.
|
||||
If @var{throttle} is not defined then there is no imposed limit on the
|
||||
maximum number of matches and breakpoints to be created. The
|
||||
@var{symtabs} keyword takes a Python iterable that yields a collection
|
||||
of @code{gdb.Symtab} objects and will restrict the search to those
|
||||
functions only contained within the @code{gdb.Symtab} objects.
|
||||
@end defun
|
||||
|
||||
@findex gdb.parameter
|
||||
@defun gdb.parameter (parameter)
|
||||
Return the value of a @value{GDBN} @var{parameter} given by its name,
|
||||
|
@ -640,6 +640,190 @@ gdbpy_solib_name (PyObject *self, PyObject *args)
|
||||
return str_obj;
|
||||
}
|
||||
|
||||
/* Implementation of Python rbreak command. Take a REGEX and
|
||||
optionally a MINSYMS, THROTTLE and SYMTABS keyword and return a
|
||||
Python list that contains newly set breakpoints that match that
|
||||
criteria. REGEX refers to a GDB format standard regex pattern of
|
||||
symbols names to search; MINSYMS is an optional boolean (default
|
||||
False) that indicates if the function should search GDB's minimal
|
||||
symbols; THROTTLE is an optional integer (default unlimited) that
|
||||
indicates the maximum amount of breakpoints allowable before the
|
||||
function exits (note, if the throttle bound is passed, no
|
||||
breakpoints will be set and a runtime error returned); SYMTABS is
|
||||
an optional Python iterable that contains a set of gdb.Symtabs to
|
||||
constrain the search within. */
|
||||
|
||||
static PyObject *
|
||||
gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
/* A simple type to ensure clean up of a vector of allocated strings
|
||||
when a C interface demands a const char *array[] type
|
||||
interface. */
|
||||
struct symtab_list_type
|
||||
{
|
||||
~symtab_list_type ()
|
||||
{
|
||||
for (const char *elem: vec)
|
||||
xfree ((void *) elem);
|
||||
}
|
||||
std::vector<const char *> vec;
|
||||
};
|
||||
|
||||
char *regex = NULL;
|
||||
std::vector<symbol_search> symbols;
|
||||
unsigned long count = 0;
|
||||
PyObject *symtab_list = NULL;
|
||||
PyObject *minsyms_p_obj = NULL;
|
||||
int minsyms_p = 0;
|
||||
unsigned int throttle = 0;
|
||||
static const char *keywords[] = {"regex","minsyms", "throttle",
|
||||
"symtabs", NULL};
|
||||
symtab_list_type symtab_paths;
|
||||
|
||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!IO", keywords,
|
||||
®ex, &PyBool_Type,
|
||||
&minsyms_p_obj, &throttle,
|
||||
&symtab_list))
|
||||
return NULL;
|
||||
|
||||
/* Parse minsyms keyword. */
|
||||
if (minsyms_p_obj != NULL)
|
||||
{
|
||||
int cmp = PyObject_IsTrue (minsyms_p_obj);
|
||||
if (cmp < 0)
|
||||
return NULL;
|
||||
minsyms_p = cmp;
|
||||
}
|
||||
|
||||
/* The "symtabs" keyword is any Python iterable object that returns
|
||||
a gdb.Symtab on each iteration. If specified, iterate through
|
||||
the provided gdb.Symtabs and extract their full path. As
|
||||
python_string_to_target_string returns a
|
||||
gdb::unique_xmalloc_ptr<char> and a vector containing these types
|
||||
cannot be coerced to a const char **p[] via the vector.data call,
|
||||
release the value from the unique_xmalloc_ptr and place it in a
|
||||
simple type symtab_list_type (which holds the vector and a
|
||||
destructor that frees the contents of the allocated strings. */
|
||||
if (symtab_list != NULL)
|
||||
{
|
||||
gdbpy_ref<> iter (PyObject_GetIter (symtab_list));
|
||||
|
||||
if (iter == NULL)
|
||||
return NULL;
|
||||
|
||||
while (true)
|
||||
{
|
||||
gdbpy_ref<> next (PyIter_Next (iter.get ()));
|
||||
|
||||
if (next == NULL)
|
||||
{
|
||||
if (PyErr_Occurred ())
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
gdbpy_ref<> obj_name (PyObject_GetAttrString (next.get (),
|
||||
"filename"));
|
||||
|
||||
if (obj_name == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Is the object file still valid? */
|
||||
if (obj_name == Py_None)
|
||||
continue;
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> filename =
|
||||
python_string_to_target_string (obj_name.get ());
|
||||
|
||||
if (filename == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Make sure there is a definite place to store the value of
|
||||
filename before it is released. */
|
||||
symtab_paths.vec.push_back (nullptr);
|
||||
symtab_paths.vec.back () = filename.release ();
|
||||
}
|
||||
}
|
||||
|
||||
if (symtab_list)
|
||||
{
|
||||
const char **files = symtab_paths.vec.data ();
|
||||
|
||||
symbols = search_symbols (regex, FUNCTIONS_DOMAIN,
|
||||
symtab_paths.vec.size (), files);
|
||||
}
|
||||
else
|
||||
symbols = search_symbols (regex, FUNCTIONS_DOMAIN, 0, NULL);
|
||||
|
||||
/* Count the number of symbols (both symbols and optionally minimal
|
||||
symbols) so we can correctly check the throttle limit. */
|
||||
for (const symbol_search &p : symbols)
|
||||
{
|
||||
/* Minimal symbols included? */
|
||||
if (minsyms_p)
|
||||
{
|
||||
if (p.msymbol.minsym != NULL)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (p.symbol != NULL)
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Check throttle bounds and exit if in excess. */
|
||||
if (throttle != 0 && count > throttle)
|
||||
{
|
||||
PyErr_SetString (PyExc_RuntimeError,
|
||||
_("Number of breakpoints exceeds throttled maximum."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gdbpy_ref<> return_list (PyList_New (0));
|
||||
|
||||
if (return_list == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Construct full path names for symbols and call the Python
|
||||
breakpoint constructor on the resulting names. Be tolerant of
|
||||
individual breakpoint failures. */
|
||||
for (const symbol_search &p : symbols)
|
||||
{
|
||||
std::string symbol_name;
|
||||
|
||||
/* Skipping minimal symbols? */
|
||||
if (minsyms_p == 0)
|
||||
if (p.msymbol.minsym != NULL)
|
||||
continue;
|
||||
|
||||
if (p.msymbol.minsym == NULL)
|
||||
{
|
||||
struct symtab *symtab = symbol_symtab (p.symbol);
|
||||
const char *fullname = symtab_to_fullname (symtab);
|
||||
|
||||
symbol_name = fullname;
|
||||
symbol_name += ":";
|
||||
symbol_name += SYMBOL_LINKAGE_NAME (p.symbol);
|
||||
}
|
||||
else
|
||||
symbol_name = MSYMBOL_LINKAGE_NAME (p.msymbol.minsym);
|
||||
|
||||
gdbpy_ref<> argList (Py_BuildValue("(s)", symbol_name.c_str ()));
|
||||
gdbpy_ref<> obj (PyObject_CallObject ((PyObject *)
|
||||
&breakpoint_object_type,
|
||||
argList.get ()));
|
||||
|
||||
/* Tolerate individual breakpoint failures. */
|
||||
if (obj == NULL)
|
||||
gdbpy_print_stack ();
|
||||
else
|
||||
{
|
||||
if (PyList_Append (return_list.get (), obj.get ()) == -1)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return return_list.release ();
|
||||
}
|
||||
|
||||
/* A Python function which is a wrapper for decode_line_1. */
|
||||
|
||||
static PyObject *
|
||||
@ -1910,7 +2094,9 @@ Return the name of the current target charset." },
|
||||
{ "target_wide_charset", gdbpy_target_wide_charset, METH_NOARGS,
|
||||
"target_wide_charset () -> string.\n\
|
||||
Return the name of the current target wide charset." },
|
||||
|
||||
{ "rbreak", (PyCFunction) gdbpy_rbreak, METH_VARARGS | METH_KEYWORDS,
|
||||
"rbreak (Regex) -> List.\n\
|
||||
Return a Tuple containing gdb.Breakpoint objects that match the given Regex." },
|
||||
{ "string_to_argv", gdbpy_string_to_argv, METH_VARARGS,
|
||||
"string_to_argv (String) -> Array.\n\
|
||||
Parse String and return an argv-like array.\n\
|
||||
|
@ -1,3 +1,9 @@
|
||||
2017-11-16 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* gdb.python/py-rbreak.exp: New file.
|
||||
* gdb.python/py-rbreak.c: New file.
|
||||
* gdb.python/py-rbreak-func2.c: New file.
|
||||
|
||||
2017-11-16 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdb.base/starti.exp ("continue" test): Remove ".*"s from
|
||||
|
34
gdb/testsuite/gdb.python/py-rbreak-func2.c
Normal file
34
gdb/testsuite/gdb.python/py-rbreak-func2.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2017 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/>. */
|
||||
|
||||
int
|
||||
efunc1 ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
efunc2 ()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
int
|
||||
efunc3 ()
|
||||
{
|
||||
return 3;
|
||||
}
|
70
gdb/testsuite/gdb.python/py-rbreak.c
Normal file
70
gdb/testsuite/gdb.python/py-rbreak.c
Normal file
@ -0,0 +1,70 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2013-2017 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/>. */
|
||||
|
||||
int
|
||||
func1 ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
func2 ()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
int
|
||||
func3 ()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
int
|
||||
func4 ()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
int
|
||||
func5 ()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
void
|
||||
func6 ()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
outside_scope ()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
func1 (); /* Break func1. */
|
||||
func2 ();
|
||||
func3 ();
|
||||
func4 ();
|
||||
func5 ();
|
||||
func6 ();
|
||||
outside_scope ();
|
||||
}
|
61
gdb/testsuite/gdb.python/py-rbreak.exp
Normal file
61
gdb/testsuite/gdb.python/py-rbreak.exp
Normal file
@ -0,0 +1,61 @@
|
||||
# Copyright (C) 2017 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 mechanism
|
||||
# exposing values to Python.
|
||||
|
||||
load_lib gdb-python.exp
|
||||
|
||||
standard_testfile py-rbreak.c py-rbreak-func2.c
|
||||
|
||||
if {[prepare_for_testing "failed to prepare" ${testfile} [list $srcfile $srcfile2]] } {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Skip all tests if Python scripting is not enabled.
|
||||
if { [skip_python_tests] } { continue }
|
||||
|
||||
if ![runto_main] then {
|
||||
fail "can't run to main"
|
||||
return 0
|
||||
}
|
||||
|
||||
gdb_py_test_silent_cmd "py sl = gdb.rbreak(\"\",minsyms=False)" \
|
||||
"get all function breakpoints" 0
|
||||
gdb_test "py print(len(sl))" "11" \
|
||||
"check number of returned breakpoints is 11"
|
||||
gdb_py_test_silent_cmd "py sl = gdb.rbreak(\"main\.\*\",minsyms=False)" \
|
||||
"get main function breakpoint" 0
|
||||
gdb_test "py print(len(sl))" "1" \
|
||||
"check number of returned breakpoints is 1"
|
||||
gdb_py_test_silent_cmd "py sl = gdb.rbreak(\"func\.\*\",minsyms=False,throttle=10)" \
|
||||
"get functions matching func.*" 0
|
||||
gdb_test "py print(len(sl))" "9" \
|
||||
"check number of returned breakpoints is 9"
|
||||
gdb_test "py gdb.rbreak(\"func\.\*\",minsyms=False,throttle=5)" \
|
||||
"Number of breakpoints exceeds throttled maximum.*" \
|
||||
"check throttle errors on too many breakpoints"
|
||||
gdb_py_test_silent_cmd "py sl = gdb.rbreak(\"func1\",minsyms=True)" \
|
||||
"including minimal symbols, get functions matching func.*" 0
|
||||
gdb_test "py print(len(sl))" "2" \
|
||||
"check number of returned breakpoints is 2"
|
||||
gdb_py_test_silent_cmd "python sym = gdb.lookup_symbol(\"efunc1\")" \
|
||||
"find a symbol in objfile" 1
|
||||
gdb_py_test_silent_cmd "python symtab = sym\[0\].symtab" \
|
||||
"get backing symbol table" 1
|
||||
gdb_py_test_silent_cmd "py sl = gdb.rbreak(\"func\.\*\",minsyms=False,throttle=10,symtabs=\[symtab\])" \
|
||||
"get functions matching func.* in one symtab only" 0
|
||||
gdb_test "py print(len(sl))" "3" \
|
||||
"check number of returned breakpoints is 3"
|
Loading…
x
Reference in New Issue
Block a user