Implement explicit locations for Python breakpoints.
This introduces several new keywords to the bppy_init constructor. The spec parameter is now optional but mutually exclusive to the explicit keywords source, label, function and line. gdb/ChangeLog 2017-12-07 Phil Muldoon <pmuldoon@redhat.com> * python/py-breakpoint.c (bppy_init): Use string_to_event_location over basic location code. Implement explicit location keywords. (bppy_init_validate_args): New function. * NEWS: Document Python explicit breakpoint locations. doc/ChangeLog 2017-12-07 Phil Muldoon <pmuldoon@redhat.com> * python.texi (Breakpoints In Python): Add text relating to allowed explicit locations and keywords in gdb.Breakpoints. testsuite/ChangeLog 2017-12-07 Phil Muldoon <pmuldoon@redhat.com> * gdb.python/py-breakpoint.exp (test_bkpt_explicit_loc): Add new tests for explicit locations.
This commit is contained in:
parent
9c226a8689
commit
824cc835aa
@ -1,3 +1,10 @@
|
||||
2017-12-07 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* python/py-breakpoint.c (bppy_init): Use string_to_event_location
|
||||
over basic location code. Implement explicit location keywords.
|
||||
(bppy_init_validate_args): New function.
|
||||
* NEWS: Document Python explicit breakpoint locations.
|
||||
|
||||
2017-12-07 Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
* MAINTAINERS: Restore target entries for m68hc11-elf,
|
||||
|
4
gdb/NEWS
4
gdb/NEWS
@ -115,6 +115,10 @@
|
||||
command allows the setting of a large number of breakpoints via a
|
||||
regex pattern in Python. See the manual for further details.
|
||||
|
||||
** Python breakpoints can now accept explicit locations. See the
|
||||
manual for a further description of this feature.
|
||||
|
||||
|
||||
* New features in the GDB remote stub, GDBserver
|
||||
|
||||
** GDBserver is now able to start inferior processes with a
|
||||
|
@ -1,3 +1,8 @@
|
||||
2017-12-07 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* python.texi (Breakpoints In Python): Add text relating
|
||||
to allowed explicit locations and keywords in gdb.Breakpoints.
|
||||
|
||||
2017-12-04 Tom Tromey <tom@tromey.com>
|
||||
|
||||
* gdb.texinfo (Rust): Update trait object status
|
||||
|
@ -4878,27 +4878,30 @@ represented as Python @code{Long} values.
|
||||
Python code can manipulate breakpoints via the @code{gdb.Breakpoint}
|
||||
class.
|
||||
|
||||
@defun Breakpoint.__init__ (spec @r{[}, type @r{[}, wp_class @r{[},internal @r{[},temporary@r{]]]]})
|
||||
@defun Breakpoint.__init__ (spec @r{[}, type @r{[}, wp_class @r{[}, internal @r{[}, temporary @r{]}, source @r{]}, function @r{]}, label @r{]}, line @r{]]]]]]]]})
|
||||
Create a new breakpoint according to @var{spec}, which is a string
|
||||
naming the location of the breakpoint, or an expression that defines a
|
||||
watchpoint. The contents can be any location recognized by the
|
||||
@code{break} command, or in the case of a watchpoint, by the
|
||||
@code{watch} command. The optional @var{type} denotes the breakpoint
|
||||
to create from the types defined later in this chapter. This argument
|
||||
can be either @code{gdb.BP_BREAKPOINT} or @code{gdb.BP_WATCHPOINT}; it
|
||||
defaults to @code{gdb.BP_BREAKPOINT}. The optional @var{internal}
|
||||
argument allows the breakpoint to become invisible to the user. The
|
||||
breakpoint will neither be reported when created, nor will it be
|
||||
listed in the output from @code{info breakpoints} (but will be listed
|
||||
with the @code{maint info breakpoints} command). The optional
|
||||
@var{temporary} argument makes the breakpoint a temporary breakpoint.
|
||||
Temporary breakpoints are deleted after they have been hit. Any
|
||||
further access to the Python breakpoint after it has been hit will
|
||||
result in a runtime error (as that breakpoint has now been
|
||||
automatically deleted). The optional @var{wp_class} argument defines
|
||||
the class of watchpoint to create, if @var{type} is
|
||||
@code{gdb.BP_WATCHPOINT}. If a watchpoint class is not provided, it
|
||||
is assumed to be a @code{gdb.WP_WRITE} class.
|
||||
watchpoint. The contents can be any location recognized by the
|
||||
@code{break} command or, in the case of a watchpoint, by the
|
||||
@code{watch} command. Alternatively, create a new a explicit location
|
||||
breakpoint (@pxref{Explicit Locations}) according to the
|
||||
specifications contained in the key words @var{source},
|
||||
@var{function}, @var{label} and @var{line}. The optional @var{type}
|
||||
denotes the breakpoint to create from the types defined later in this
|
||||
chapter. This argument can be either @code{gdb.BP_BREAKPOINT} or
|
||||
@code{gdb.BP_WATCHPOINT}; it defaults to @code{gdb.BP_BREAKPOINT}.
|
||||
The optional @var{internal} argument allows the breakpoint to become
|
||||
invisible to the user. The breakpoint will neither be reported when
|
||||
created, nor will it be listed in the output from @code{info
|
||||
breakpoints} (but will be listed with the @code{maint info
|
||||
breakpoints} command). The optional @var{temporary} argument makes
|
||||
the breakpoint a temporary breakpoint. Temporary breakpoints are
|
||||
deleted after they have been hit. Any further access to the Python
|
||||
breakpoint after it has been hit will result in a runtime error (as
|
||||
that breakpoint has now been automatically deleted). The optional
|
||||
@var{wp_class} argument defines the class of watchpoint to create, if
|
||||
@var{type} is @code{gdb.BP_WATCHPOINT}. If a watchpoint class is not
|
||||
provided, it is assumed to be a @code{gdb.WP_WRITE} class.
|
||||
@end defun
|
||||
|
||||
The available types are represented by constants defined in the @code{gdb}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "language.h"
|
||||
#include "location.h"
|
||||
#include "py-event.h"
|
||||
#include "linespec.h"
|
||||
|
||||
/* Number of live breakpoints. */
|
||||
static int bppy_live;
|
||||
@ -631,25 +632,104 @@ bppy_get_ignore_count (PyObject *self, void *closure)
|
||||
return PyInt_FromLong (self_bp->bp->ignore_count);
|
||||
}
|
||||
|
||||
/* Internal function to validate the Python parameters/keywords
|
||||
provided to bppy_init. */
|
||||
|
||||
static int
|
||||
bppy_init_validate_args (const char *spec, char *source,
|
||||
char *function, char *label,
|
||||
char *line, enum bptype type)
|
||||
{
|
||||
/* If spec is defined, ensure that none of the explicit location
|
||||
keywords are also defined. */
|
||||
if (spec != NULL)
|
||||
{
|
||||
if (source != NULL || function != NULL || label != NULL || line != NULL)
|
||||
{
|
||||
PyErr_SetString (PyExc_RuntimeError,
|
||||
_("Breakpoints specified with spec cannot "
|
||||
"have source, function, label or line defined."));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If spec isn't defined, ensure that the user is not trying to
|
||||
define a watchpoint with an explicit location. */
|
||||
if (type == bp_watchpoint)
|
||||
{
|
||||
PyErr_SetString (PyExc_RuntimeError,
|
||||
_("Watchpoints cannot be set by explicit "
|
||||
"location parameters."));
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, ensure some explicit locations are defined. */
|
||||
if (source == NULL && function == NULL && label == NULL
|
||||
&& line == NULL)
|
||||
{
|
||||
PyErr_SetString (PyExc_RuntimeError,
|
||||
_("Neither spec nor explicit location set."));
|
||||
return -1;
|
||||
}
|
||||
/* Finally, if source is specified, ensure that line, label
|
||||
or function are specified too. */
|
||||
if (source != NULL && function == NULL && label == NULL
|
||||
&& line == NULL)
|
||||
{
|
||||
PyErr_SetString (PyExc_RuntimeError,
|
||||
_("Specifying a source must also include a "
|
||||
"line, label or function."));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Python function to create a new breakpoint. */
|
||||
static int
|
||||
bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static const char *keywords[] = { "spec", "type", "wp_class", "internal",
|
||||
"temporary", NULL };
|
||||
const char *spec;
|
||||
int type = bp_breakpoint;
|
||||
"temporary","source", "function",
|
||||
"label", "line", NULL };
|
||||
const char *spec = NULL;
|
||||
enum bptype type = bp_breakpoint;
|
||||
int access_type = hw_write;
|
||||
PyObject *internal = NULL;
|
||||
PyObject *temporary = NULL;
|
||||
PyObject *lineobj = NULL;;
|
||||
int internal_bp = 0;
|
||||
int temporary_bp = 0;
|
||||
gdb::unique_xmalloc_ptr<char> line;
|
||||
char *label = NULL;
|
||||
char *source = NULL;
|
||||
char *function = NULL;
|
||||
|
||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiOO", keywords,
|
||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|siiOOsssO", keywords,
|
||||
&spec, &type, &access_type,
|
||||
&internal, &temporary))
|
||||
&internal,
|
||||
&temporary, &source,
|
||||
&function, &label, &lineobj))
|
||||
return -1;
|
||||
|
||||
|
||||
if (lineobj != NULL)
|
||||
{
|
||||
if (PyInt_Check (lineobj))
|
||||
line.reset (xstrprintf ("%ld", PyInt_AsLong (lineobj)));
|
||||
else if (PyString_Check (lineobj))
|
||||
line = python_string_to_host_string (lineobj);
|
||||
else
|
||||
{
|
||||
PyErr_SetString (PyExc_RuntimeError,
|
||||
_("Line keyword should be an integer or a string. "));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (internal)
|
||||
{
|
||||
internal_bp = PyObject_IsTrue (internal);
|
||||
@ -664,23 +744,47 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bppy_init_validate_args (spec, source, function, label, line.get (),
|
||||
type) == -1)
|
||||
return -1;
|
||||
|
||||
bppy_pending_object = (gdbpy_breakpoint_object *) self;
|
||||
bppy_pending_object->number = -1;
|
||||
bppy_pending_object->bp = NULL;
|
||||
|
||||
TRY
|
||||
{
|
||||
gdb::unique_xmalloc_ptr<char>
|
||||
copy_holder (xstrdup (skip_spaces (spec)));
|
||||
const char *copy = copy_holder.get ();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case bp_breakpoint:
|
||||
{
|
||||
event_location_up location
|
||||
= string_to_event_location_basic (©, current_language,
|
||||
symbol_name_match_type::WILD);
|
||||
event_location_up location;
|
||||
|
||||
if (spec != NULL)
|
||||
{
|
||||
gdb::unique_xmalloc_ptr<char>
|
||||
copy_holder (xstrdup (skip_spaces (spec)));
|
||||
const char *copy = copy_holder.get ();
|
||||
|
||||
location = string_to_event_location (©,
|
||||
current_language);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct explicit_location explicit_loc;
|
||||
|
||||
initialize_explicit_location (&explicit_loc);
|
||||
explicit_loc.source_filename = source;
|
||||
explicit_loc.function_name = function;
|
||||
explicit_loc.label_name = label;
|
||||
|
||||
if (line != NULL)
|
||||
explicit_loc.line_offset =
|
||||
linespec_parse_line_offset (line.get ());
|
||||
|
||||
location = new_explicit_location (&explicit_loc);
|
||||
}
|
||||
|
||||
create_breakpoint (python_gdbarch,
|
||||
location.get (), NULL, -1, NULL,
|
||||
0,
|
||||
@ -691,8 +795,12 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
0, 1, internal_bp, 0);
|
||||
break;
|
||||
}
|
||||
case bp_watchpoint:
|
||||
case bp_watchpoint:
|
||||
{
|
||||
gdb::unique_xmalloc_ptr<char>
|
||||
copy_holder (xstrdup (skip_spaces (spec)));
|
||||
char *copy = copy_holder.get ();
|
||||
|
||||
if (access_type == hw_write)
|
||||
watch_command_wrapper (copy, 0, internal_bp);
|
||||
else if (access_type == hw_access)
|
||||
|
@ -1,3 +1,8 @@
|
||||
2017-12-07 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* gdb.python/py-breakpoint.exp (test_bkpt_explicit_loc): Add new
|
||||
tests for explicit locations.
|
||||
|
||||
2017-12-06 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdb.arch/i386-avx.exp: If testing with a RSP target, check
|
||||
|
@ -24,7 +24,7 @@ int multiply (int i)
|
||||
|
||||
int add (int i)
|
||||
{
|
||||
return i + i;
|
||||
return i + i; /* Break at function add. */
|
||||
}
|
||||
|
||||
|
||||
|
@ -531,6 +531,85 @@ proc_with_prefix test_bkpt_events {} {
|
||||
check_last_event breakpoint_deleted
|
||||
}
|
||||
|
||||
proc test_bkpt_explicit_loc {} {
|
||||
global srcfile testfile
|
||||
|
||||
with_test_prefix test_bkpt_invisible {
|
||||
# Start with a fresh gdb.
|
||||
clean_restart ${testfile}
|
||||
|
||||
if ![runto_main] then {
|
||||
fail "cannot run to main."
|
||||
return 0
|
||||
}
|
||||
|
||||
delete_breakpoints
|
||||
|
||||
set bp_location1 [gdb_get_line_number "Break at multiply."]
|
||||
set bp_location2 [gdb_get_line_number "Break at add."]
|
||||
|
||||
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (line=$bp_location1)" \
|
||||
"set explicit breakpoint by line" 0
|
||||
gdb_continue_to_breakpoint "break at multiply for explicit line" \
|
||||
".*Break at multiply.*"
|
||||
|
||||
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (line=\"+1\")" \
|
||||
"set explicit breakpoint by relative line" 0
|
||||
gdb_continue_to_breakpoint "break at add for relative line" \
|
||||
".*Break at add.*"
|
||||
|
||||
delete_breakpoints
|
||||
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (line=\"-1\")" \
|
||||
"set explicit breakpoint by relative negative line" 0
|
||||
gdb_continue_to_breakpoint "break at multiply for negative line" \
|
||||
".*Break at multiply.*"
|
||||
|
||||
delete_breakpoints
|
||||
gdb_test "python bp1 = gdb.Breakpoint (line=bp1)" \
|
||||
"RuntimeError: Line keyword should be an integer or a string.*" \
|
||||
"set explicit breakpoint by invalid line type"
|
||||
|
||||
delete_breakpoints
|
||||
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (function=\"add\")" \
|
||||
"set explicit breakpoint by function" 0
|
||||
gdb_continue_to_breakpoint "break at function add for function" \
|
||||
".*Break at function add.*"
|
||||
|
||||
delete_breakpoints
|
||||
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (source=\"$srcfile\", function=\"add\")" \
|
||||
"set explicit breakpoint by source file and function" 0
|
||||
gdb_continue_to_breakpoint "break at function add for source and function" \
|
||||
".*Break at function add.*"
|
||||
|
||||
delete_breakpoints
|
||||
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (source=\"$srcfile\", line=\"$bp_location2\")" \
|
||||
"set explicit breakpoint by source file and line number" 0
|
||||
gdb_continue_to_breakpoint "break at add for source and line" \
|
||||
".*Break at add.*"
|
||||
|
||||
delete_breakpoints
|
||||
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (\"-source $srcfile -line $bp_location2\")" \
|
||||
"set explicit breakpoint by source file and line number in spec" 0
|
||||
gdb_continue_to_breakpoint "break at add for source and line in spec" \
|
||||
".*Break at add.*"
|
||||
|
||||
delete_breakpoints
|
||||
gdb_test "python bp1 = gdb.Breakpoint (source=\"$srcfile\")" \
|
||||
"RuntimeError: Specifying a source must also include a line, label or function.*" \
|
||||
"set invalid explicit breakpoint by source only"
|
||||
|
||||
gdb_test "python bp1 = gdb.Breakpoint (source=\"foo.c\", line=\"5\")" \
|
||||
"No source file named foo.*" \
|
||||
"set invalid explicit breakpoint by missing source and line"
|
||||
gdb_test "python bp1 = gdb.Breakpoint (source=\"$srcfile\", line=\"900\")" \
|
||||
"No line 900 in file \"$srcfile\".*" \
|
||||
"set invalid explicit breakpoint by source and invalid line"
|
||||
gdb_test "python bp1 = gdb.Breakpoint (function=\"blah\")" \
|
||||
"Function \"blah\" not defined.*" \
|
||||
"set invalid explicit breakpoint by missing function"
|
||||
}
|
||||
}
|
||||
|
||||
test_bkpt_basic
|
||||
test_bkpt_deletion
|
||||
test_bkpt_cond_and_cmds
|
||||
@ -542,3 +621,4 @@ test_bkpt_temporary
|
||||
test_bkpt_address
|
||||
test_bkpt_pending
|
||||
test_bkpt_events
|
||||
test_bkpt_explicit_loc
|
||||
|
Loading…
Reference in New Issue
Block a user