mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
2010-04-09 Phil Muldoon <pmuldoon@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com> Tom Tromey <tromey@redhat.com> * breakpoint.c (condition_command): Simplify. Move condition setting code to ... (set_breakpoint_condition): ... here. New function. * breakpoint.h (set_breakpoint_condition): Declare. * Makefile.in (SUBDIR_PYTHON_OBS): Add py-breakpoint. (SUBDIR_PYTHON_SRCS): Likewise. (py-breakpoint.o): New rule. * python/py-breakpoint.c: New file. * python/python-internal.h (gdbpy_breakpoints) (gdbpy_initialize_breakpoints): Declare. (GDB_PY_SET_HANDLE_EXCEPTION) Define. 2010-04-09 Phil Muldoon <pmuldoon@redhat.com> * gdb.python/py-breakpoint.exp: New File. * gdb.python/py-breakpoint.C: Ditto. 2010-04-09 Phil Muldoon <pmuldoon@redhat.com> Thiago Jung Bauermann <bauerman@br.ibm.com> Tom Tromey <tromey@redhat.com> * gdb.texinfo (Breakpoints In Python): New Node.
This commit is contained in:
parent
e760a81b79
commit
adc368187c
@ -1,3 +1,19 @@
|
|||||||
|
2010-04-09 Phil Muldoon <pmuldoon@redhat.com>
|
||||||
|
Thiago Jung Bauermann <bauerman@br.ibm.com>
|
||||||
|
Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
|
* breakpoint.c (condition_command): Simplify. Move condition
|
||||||
|
setting code to ...
|
||||||
|
(set_breakpoint_condition): ... here. New function.
|
||||||
|
* breakpoint.h (set_breakpoint_condition): Declare.
|
||||||
|
* Makefile.in (SUBDIR_PYTHON_OBS): Add py-breakpoint.
|
||||||
|
(SUBDIR_PYTHON_SRCS): Likewise.
|
||||||
|
(py-breakpoint.o): New rule.
|
||||||
|
* python/py-breakpoint.c: New file.
|
||||||
|
* python/python-internal.h (gdbpy_breakpoints)
|
||||||
|
(gdbpy_initialize_breakpoints): Declare.
|
||||||
|
(GDB_PY_SET_HANDLE_EXCEPTION) Define.
|
||||||
|
|
||||||
2010-04-09 Pedro Alves <pedro@codesourcery.com>
|
2010-04-09 Pedro Alves <pedro@codesourcery.com>
|
||||||
|
|
||||||
* regformats/regdat.sh: Include server.h. Don't include
|
* regformats/regdat.sh: Include server.h. Don't include
|
||||||
|
@ -268,6 +268,7 @@ SUBDIR_TUI_CFLAGS= \
|
|||||||
SUBDIR_PYTHON_OBS = \
|
SUBDIR_PYTHON_OBS = \
|
||||||
python.o \
|
python.o \
|
||||||
py-block.o \
|
py-block.o \
|
||||||
|
py-breakpoint.o \
|
||||||
py-cmd.o \
|
py-cmd.o \
|
||||||
py-frame.o \
|
py-frame.o \
|
||||||
py-function.o \
|
py-function.o \
|
||||||
@ -282,6 +283,7 @@ SUBDIR_PYTHON_OBS = \
|
|||||||
SUBDIR_PYTHON_SRCS = \
|
SUBDIR_PYTHON_SRCS = \
|
||||||
python/python.c \
|
python/python.c \
|
||||||
python/py-block.c \
|
python/py-block.c \
|
||||||
|
python/py-breakpoint.c \
|
||||||
python/py-cmd.c \
|
python/py-cmd.c \
|
||||||
python/py-frame.c \
|
python/py-frame.c \
|
||||||
python/py-function.c \
|
python/py-function.c \
|
||||||
@ -1986,6 +1988,10 @@ py-block.o: $(srcdir)/python/py-block.c
|
|||||||
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
|
||||||
$(POSTCOMPILE)
|
$(POSTCOMPILE)
|
||||||
|
|
||||||
|
py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
|
||||||
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
|
||||||
|
$(POSTCOMPILE)
|
||||||
|
|
||||||
py-cmd.o: $(srcdir)/python/py-cmd.c
|
py-cmd.o: $(srcdir)/python/py-cmd.c
|
||||||
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
|
||||||
$(POSTCOMPILE)
|
$(POSTCOMPILE)
|
||||||
|
4
gdb/NEWS
4
gdb/NEWS
@ -25,8 +25,8 @@
|
|||||||
|
|
||||||
* Python scripting
|
* Python scripting
|
||||||
|
|
||||||
** The GDB Python API now has access to symbols, symbol tables, and
|
** The GDB Python API now has access to breakpoints, symbols, symbol
|
||||||
frame's code blocks.
|
tables, and frame's code blocks.
|
||||||
|
|
||||||
** New methods gdb.target_charset and gdb.target_wide_charset.
|
** New methods gdb.target_charset and gdb.target_wide_charset.
|
||||||
|
|
||||||
|
103
gdb/breakpoint.c
103
gdb/breakpoint.c
@ -709,6 +709,61 @@ get_breakpoint (int num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
set_breakpoint_condition (struct breakpoint *b, char *exp,
|
||||||
|
int from_tty)
|
||||||
|
{
|
||||||
|
struct bp_location *loc = b->loc;
|
||||||
|
|
||||||
|
for (; loc; loc = loc->next)
|
||||||
|
{
|
||||||
|
xfree (loc->cond);
|
||||||
|
loc->cond = NULL;
|
||||||
|
}
|
||||||
|
xfree (b->cond_string);
|
||||||
|
b->cond_string = NULL;
|
||||||
|
xfree (b->cond_exp);
|
||||||
|
b->cond_exp = NULL;
|
||||||
|
|
||||||
|
if (*exp == 0)
|
||||||
|
{
|
||||||
|
if (from_tty)
|
||||||
|
printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *arg = exp;
|
||||||
|
/* I don't know if it matters whether this is the string the user
|
||||||
|
typed in or the decompiled expression. */
|
||||||
|
b->cond_string = xstrdup (arg);
|
||||||
|
b->condition_not_parsed = 0;
|
||||||
|
|
||||||
|
if (is_watchpoint (b))
|
||||||
|
{
|
||||||
|
innermost_block = NULL;
|
||||||
|
arg = exp;
|
||||||
|
b->cond_exp = parse_exp_1 (&arg, 0, 0);
|
||||||
|
if (*arg)
|
||||||
|
error (_("Junk at end of expression"));
|
||||||
|
b->cond_exp_valid_block = innermost_block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (loc = b->loc; loc; loc = loc->next)
|
||||||
|
{
|
||||||
|
arg = exp;
|
||||||
|
loc->cond =
|
||||||
|
parse_exp_1 (&arg, block_for_pc (loc->address), 0);
|
||||||
|
if (*arg)
|
||||||
|
error (_("Junk at end of expression"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
breakpoints_changed ();
|
||||||
|
observer_notify_breakpoint_modified (b->number);
|
||||||
|
}
|
||||||
|
|
||||||
/* condition N EXP -- set break condition of breakpoint N to EXP. */
|
/* condition N EXP -- set break condition of breakpoint N to EXP. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -729,53 +784,7 @@ condition_command (char *arg, int from_tty)
|
|||||||
ALL_BREAKPOINTS (b)
|
ALL_BREAKPOINTS (b)
|
||||||
if (b->number == bnum)
|
if (b->number == bnum)
|
||||||
{
|
{
|
||||||
struct bp_location *loc = b->loc;
|
set_breakpoint_condition (b, arg, from_tty);
|
||||||
for (; loc; loc = loc->next)
|
|
||||||
{
|
|
||||||
xfree (loc->cond);
|
|
||||||
loc->cond = NULL;
|
|
||||||
}
|
|
||||||
xfree (b->cond_string);
|
|
||||||
b->cond_string = NULL;
|
|
||||||
xfree (b->cond_exp);
|
|
||||||
b->cond_exp = NULL;
|
|
||||||
|
|
||||||
if (*p == 0)
|
|
||||||
{
|
|
||||||
if (from_tty)
|
|
||||||
printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arg = p;
|
|
||||||
/* I don't know if it matters whether this is the string the user
|
|
||||||
typed in or the decompiled expression. */
|
|
||||||
b->cond_string = xstrdup (arg);
|
|
||||||
b->condition_not_parsed = 0;
|
|
||||||
|
|
||||||
if (is_watchpoint (b))
|
|
||||||
{
|
|
||||||
innermost_block = NULL;
|
|
||||||
arg = p;
|
|
||||||
b->cond_exp = parse_exp_1 (&arg, 0, 0);
|
|
||||||
if (*arg)
|
|
||||||
error (_("Junk at end of expression"));
|
|
||||||
b->cond_exp_valid_block = innermost_block;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (loc = b->loc; loc; loc = loc->next)
|
|
||||||
{
|
|
||||||
arg = p;
|
|
||||||
loc->cond =
|
|
||||||
parse_exp_1 (&arg, block_for_pc (loc->address), 0);
|
|
||||||
if (*arg)
|
|
||||||
error (_("Junk at end of expression"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
breakpoints_changed ();
|
|
||||||
observer_notify_breakpoint_modified (b->number);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,6 +1005,10 @@ extern int breakpoints_always_inserted_mode (void);
|
|||||||
in our opinion won't ever trigger. */
|
in our opinion won't ever trigger. */
|
||||||
extern void breakpoint_retire_moribund (void);
|
extern void breakpoint_retire_moribund (void);
|
||||||
|
|
||||||
|
/* Set break condition of breakpoint B to EXP. */
|
||||||
|
extern void set_breakpoint_condition (struct breakpoint *b, char *exp,
|
||||||
|
int from_tty);
|
||||||
|
|
||||||
/* Checks if we are catching syscalls or not.
|
/* Checks if we are catching syscalls or not.
|
||||||
Returns 0 if not, greater than 0 if we are. */
|
Returns 0 if not, greater than 0 if we are. */
|
||||||
extern int catch_syscall_enabled (void);
|
extern int catch_syscall_enabled (void);
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
2010-04-09 Phil Muldoon <pmuldoon@redhat.com>
|
||||||
|
Thiago Jung Bauermann <bauerman@br.ibm.com>
|
||||||
|
Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Breakpoints In Python): New Node.
|
||||||
|
|
||||||
2010-04-08 Stan Shebs <stan@codesourcery.com>
|
2010-04-08 Stan Shebs <stan@codesourcery.com>
|
||||||
|
|
||||||
* gdb.texinfo (Tracepoint Packets): Describe disconn and circular
|
* gdb.texinfo (Tracepoint Packets): Describe disconn and circular
|
||||||
|
@ -19714,6 +19714,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
|
|||||||
* Symbols In Python:: Python representation of symbols.
|
* Symbols In Python:: Python representation of symbols.
|
||||||
* Symbol Tables In Python:: Python representation of symbol tables.
|
* Symbol Tables In Python:: Python representation of symbol tables.
|
||||||
* Lazy Strings In Python:: Python representation of lazy strings.
|
* Lazy Strings In Python:: Python representation of lazy strings.
|
||||||
|
* Breakpoints In Python:: Manipulating breakpoints using Python.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Basic Python
|
@node Basic Python
|
||||||
@ -19739,6 +19740,12 @@ command as having originated from the user invoking it interactively.
|
|||||||
It must be a boolean value. If omitted, it defaults to @code{False}.
|
It must be a boolean value. If omitted, it defaults to @code{False}.
|
||||||
@end defun
|
@end defun
|
||||||
|
|
||||||
|
@findex gdb.breakpoints
|
||||||
|
@defun breakpoints
|
||||||
|
Return a sequence holding all of @value{GDBN}'s breakpoints.
|
||||||
|
@xref{Breakpoints In Python}, for more information.
|
||||||
|
@end defun
|
||||||
|
|
||||||
@findex gdb.parameter
|
@findex gdb.parameter
|
||||||
@defun parameter parameter
|
@defun parameter parameter
|
||||||
Return the value of a @value{GDBN} parameter. @var{parameter} is a
|
Return the value of a @value{GDBN} parameter. @var{parameter} is a
|
||||||
@ -21279,6 +21286,163 @@ Return the symbol table's source absolute file name.
|
|||||||
@end defmethod
|
@end defmethod
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@node Breakpoints In Python
|
||||||
|
@subsubsection Manipulating breakpoints using Python
|
||||||
|
|
||||||
|
@cindex breakpoints in python
|
||||||
|
@tindex gdb.Breakpoint
|
||||||
|
|
||||||
|
Python code can manipulate breakpoints via the @code{gdb.Breakpoint}
|
||||||
|
class.
|
||||||
|
|
||||||
|
@defmethod Breakpoint __init__ spec @r{[}type@r{]} @r{[}wp_class@r{]}
|
||||||
|
Create a new breakpoint. @var{spec} 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{BP_BREAKPOINT} or @code{BP_WATCHPOINT}. @var{type}
|
||||||
|
defaults to @code{BP_BREAKPOINT}. The optional @var{wp_class}
|
||||||
|
argument defines the class of watchpoint to create, if @var{type} is
|
||||||
|
defined as @code{BP_WATCHPOINT}. If a watchpoint class is not
|
||||||
|
provided, it is assumed to be a @var{WP_WRITE} class.
|
||||||
|
@end defmethod
|
||||||
|
|
||||||
|
The available watchpoint types represented by constants are defined in the
|
||||||
|
@code{gdb} module:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@findex WP_READ
|
||||||
|
@findex gdb.WP_READ
|
||||||
|
@item WP_READ
|
||||||
|
Read only watchpoint.
|
||||||
|
|
||||||
|
@findex WP_WRITE
|
||||||
|
@findex gdb.WP_WRITE
|
||||||
|
@item WP_WRITE
|
||||||
|
Write only watchpoint.
|
||||||
|
|
||||||
|
@findex WP_ACCESS
|
||||||
|
@findex gdb.WP_ACCESS
|
||||||
|
@item WP_ACCESS
|
||||||
|
Read/Write watchpoint.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@defmethod Breakpoint is_valid
|
||||||
|
Return @code{True} if this @code{Breakpoint} object is valid,
|
||||||
|
@code{False} otherwise. A @code{Breakpoint} object can become invalid
|
||||||
|
if the user deletes the breakpoint. In this case, the object still
|
||||||
|
exists, but the underlying breakpoint does not. In the cases of
|
||||||
|
watchpoint scope, the watchpoint remains valid even if execution of the
|
||||||
|
inferior leaves the scope of that watchpoint.
|
||||||
|
@end defmethod
|
||||||
|
|
||||||
|
@defivar Breakpoint enabled
|
||||||
|
This attribute is @code{True} if the breakpoint is enabled, and
|
||||||
|
@code{False} otherwise. This attribute is writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint silent
|
||||||
|
This attribute is @code{True} if the breakpoint is silent, and
|
||||||
|
@code{False} otherwise. This attribute is writable.
|
||||||
|
|
||||||
|
Note that a breakpoint can also be silent if it has commands and the
|
||||||
|
first command is @code{silent}. This is not reported by the
|
||||||
|
@code{silent} attribute.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint thread
|
||||||
|
If the breakpoint is thread-specific, this attribute holds the thread
|
||||||
|
id. If the breakpoint is not thread-specific, this attribute is
|
||||||
|
@code{None}. This attribute is writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint task
|
||||||
|
If the breakpoint is Ada task-specific, this attribute holds the Ada task
|
||||||
|
id. If the breakpoint is not task-specific (or the underlying
|
||||||
|
language is not Ada), this attribute is @code{None}. This attribute
|
||||||
|
is writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint ignore_count
|
||||||
|
This attribute holds the ignore count for the breakpoint, an integer.
|
||||||
|
This attribute is writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint number
|
||||||
|
This attribute holds the breakpoint's number --- the identifier used by
|
||||||
|
the user to manipulate the breakpoint. This attribute is not writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint type
|
||||||
|
This attribute holds the breakpoint's type --- the identifier used to
|
||||||
|
determine the actual breakpoint type or use-case. This attribute is not
|
||||||
|
writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
The available types are represented by constants defined in the @code{gdb}
|
||||||
|
module:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@findex BP_BREAKPOINT
|
||||||
|
@findex gdb.BP_BREAKPOINT
|
||||||
|
@item BP_BREAKPOINT
|
||||||
|
Normal code breakpoint.
|
||||||
|
|
||||||
|
@findex BP_WATCHPOINT
|
||||||
|
@findex gdb.BP_WATCHPOINT
|
||||||
|
@item BP_WATCHPOINT
|
||||||
|
Watchpoint breakpoint.
|
||||||
|
|
||||||
|
@findex BP_HARDWARE_WATCHPOINT
|
||||||
|
@findex gdb.BP_HARDWARE_WATCHPOINT
|
||||||
|
@item BP_HARDWARE_WATCHPOINT
|
||||||
|
Hardware assisted watchpoint.
|
||||||
|
|
||||||
|
@findex BP_READ_WATCHPOINT
|
||||||
|
@findex gdb.BP_READ_WATCHPOINT
|
||||||
|
@item BP_READ_WATCHPOINT
|
||||||
|
Hardware assisted read watchpoint.
|
||||||
|
|
||||||
|
@findex BP_ACCESS_WATCHPOINT
|
||||||
|
@findex gdb.BP_ACCESS_WATCHPOINT
|
||||||
|
@item BP_ACCESS_WATCHPOINT
|
||||||
|
Hardware assisted access watchpoint.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@defivar Breakpoint hit_count
|
||||||
|
This attribute holds the hit count for the breakpoint, an integer.
|
||||||
|
This attribute is writable, but currently it can only be set to zero.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint location
|
||||||
|
This attribute holds the location of the breakpoint, as specified by
|
||||||
|
the user. It is a string. If the breakpoint does not have a location
|
||||||
|
(that is, it is a watchpoint) the attribute's value is @code{None}. This
|
||||||
|
attribute is not writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint expression
|
||||||
|
This attribute holds a breakpoint expression, as specified by
|
||||||
|
the user. It is a string. If the breakpoint does not have an
|
||||||
|
expression (the breakpoint is not a watchpoint) the attribute's value
|
||||||
|
is @code{None}. This attribute is not writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint condition
|
||||||
|
This attribute holds the condition of the breakpoint, as specified by
|
||||||
|
the user. It is a string. If there is no condition, this attribute's
|
||||||
|
value is @code{None}. This attribute is writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
|
@defivar Breakpoint commands
|
||||||
|
This attribute holds the commands attached to the breakpoint. If
|
||||||
|
there are commands, this attribute's value is a string holding all the
|
||||||
|
commands, separated by newlines. If there are no commands, this
|
||||||
|
attribute is @code{None}. This attribute is not writable.
|
||||||
|
@end defivar
|
||||||
|
|
||||||
@node Lazy Strings In Python
|
@node Lazy Strings In Python
|
||||||
@subsubsection Python representation of lazy strings.
|
@subsubsection Python representation of lazy strings.
|
||||||
|
|
||||||
|
862
gdb/python/py-breakpoint.c
Normal file
862
gdb/python/py-breakpoint.c
Normal file
@ -0,0 +1,862 @@
|
|||||||
|
/* Python interface to breakpoints
|
||||||
|
|
||||||
|
Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
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/>. */
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "value.h"
|
||||||
|
#include "exceptions.h"
|
||||||
|
#include "python-internal.h"
|
||||||
|
#include "charset.h"
|
||||||
|
#include "breakpoint.h"
|
||||||
|
#include "gdbcmd.h"
|
||||||
|
#include "gdbthread.h"
|
||||||
|
#include "observer.h"
|
||||||
|
#include "cli/cli-script.h"
|
||||||
|
#include "ada-lang.h"
|
||||||
|
|
||||||
|
/* From breakpoint.c. */
|
||||||
|
typedef struct breakpoint_object breakpoint_object;
|
||||||
|
|
||||||
|
static PyTypeObject breakpoint_object_type;
|
||||||
|
|
||||||
|
/* A dynamically allocated vector of breakpoint objects. Each
|
||||||
|
breakpoint has a number. A breakpoint is valid if its slot in this
|
||||||
|
vector is non-null. When a breakpoint is deleted, we drop our
|
||||||
|
reference to it and zero its slot; this is how we let the Python
|
||||||
|
object have a lifetime which is independent from that of the gdb
|
||||||
|
breakpoint. */
|
||||||
|
static breakpoint_object **bppy_breakpoints;
|
||||||
|
|
||||||
|
/* Number of slots in bppy_breakpoints. */
|
||||||
|
static int bppy_slots;
|
||||||
|
|
||||||
|
/* Number of live breakpoints. */
|
||||||
|
static int bppy_live;
|
||||||
|
|
||||||
|
/* Variables used to pass information between the Breakpoint
|
||||||
|
constructor and the breakpoint-created hook function. */
|
||||||
|
static breakpoint_object *bppy_pending_object;
|
||||||
|
|
||||||
|
struct breakpoint_object
|
||||||
|
{
|
||||||
|
PyObject_HEAD
|
||||||
|
|
||||||
|
/* The breakpoint number according to gdb. */
|
||||||
|
int number;
|
||||||
|
|
||||||
|
/* The gdb breakpoint object, or NULL if the breakpoint has been
|
||||||
|
deleted. */
|
||||||
|
struct breakpoint *bp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
|
||||||
|
exception if it is invalid. */
|
||||||
|
#define BPPY_REQUIRE_VALID(Breakpoint) \
|
||||||
|
do { \
|
||||||
|
if (! bpnum_is_valid ((Breakpoint)->number)) \
|
||||||
|
return PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \
|
||||||
|
(Breakpoint)->number); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
|
||||||
|
exception if it is invalid. This macro is for use in setter functions. */
|
||||||
|
#define BPPY_SET_REQUIRE_VALID(Breakpoint) \
|
||||||
|
do { \
|
||||||
|
if (! bpnum_is_valid ((Breakpoint)->number)) \
|
||||||
|
{ \
|
||||||
|
PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \
|
||||||
|
(Breakpoint)->number); \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* This is used to initialize various gdb.bp_* constants. */
|
||||||
|
struct pybp_code
|
||||||
|
{
|
||||||
|
/* The name. */
|
||||||
|
const char *name;
|
||||||
|
/* The code. */
|
||||||
|
enum type_code code;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Entries related to the type of user set breakpoints. */
|
||||||
|
static struct pybp_code pybp_codes[] =
|
||||||
|
{
|
||||||
|
{ "BP_NONE", bp_none},
|
||||||
|
{ "BP_BREAKPOINT", bp_breakpoint},
|
||||||
|
{ "BP_WATCHPOINT", bp_watchpoint},
|
||||||
|
{ "BP_HARDWARE_WATCHPOINT", bp_hardware_watchpoint},
|
||||||
|
{ "BP_READ_WATCHPOINT", bp_read_watchpoint},
|
||||||
|
{ "BP_ACCESS_WATCHPOINT", bp_access_watchpoint},
|
||||||
|
{NULL} /* Sentinel. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Entries related to the type of watchpoint. */
|
||||||
|
static struct pybp_code pybp_watch_types[] =
|
||||||
|
{
|
||||||
|
{ "WP_READ", hw_read},
|
||||||
|
{ "WP_WRITE", hw_write},
|
||||||
|
{ "WP_ACCESS", hw_access},
|
||||||
|
{NULL} /* Sentinel. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */
|
||||||
|
static int
|
||||||
|
bpnum_is_valid (int num)
|
||||||
|
{
|
||||||
|
if (num >=0
|
||||||
|
&& num < bppy_slots
|
||||||
|
&& bppy_breakpoints[num] != NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function which checks the validity of a breakpoint object. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_is_valid (PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
if (self_bp->bp)
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to test whether or not the breakpoint is enabled. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_enabled (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
if (! self_bp->bp)
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
if (self_bp->bp->enable_state == bp_enabled)
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to test whether or not the breakpoint is silent. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_silent (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
if (self_bp->bp->silent)
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to set the enabled state of a breakpoint. */
|
||||||
|
static int
|
||||||
|
bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
BPPY_SET_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (newvalue == NULL)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("Cannot delete `enabled' attribute."));
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (! PyBool_Check (newvalue))
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("The value of `enabled' must be a boolean."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp = PyObject_IsTrue (newvalue);
|
||||||
|
if (cmp < 0)
|
||||||
|
return -1;
|
||||||
|
else if (cmp == 1)
|
||||||
|
enable_breakpoint (self_bp->bp);
|
||||||
|
else
|
||||||
|
disable_breakpoint (self_bp->bp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to set the 'silent' state of a breakpoint. */
|
||||||
|
static int
|
||||||
|
bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
BPPY_SET_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (newvalue == NULL)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("Cannot delete `silent' attribute."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (! PyBool_Check (newvalue))
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("The value of `silent' must be a boolean."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp = PyObject_IsTrue (newvalue);
|
||||||
|
if (cmp < 0)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
self_bp->bp->silent = cmp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to set the thread of a breakpoint. */
|
||||||
|
static int
|
||||||
|
bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
BPPY_SET_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (newvalue == NULL)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("Cannot delete `thread' attribute."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (PyInt_Check (newvalue))
|
||||||
|
{
|
||||||
|
id = (int) PyInt_AsLong (newvalue);
|
||||||
|
if (! valid_thread_id (id))
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_RuntimeError,
|
||||||
|
_("Invalid thread ID."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (newvalue == Py_None)
|
||||||
|
id = -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("The value of `thread' must be an integer or None."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self_bp->bp->thread = id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to set the (Ada) task of a breakpoint. */
|
||||||
|
static int
|
||||||
|
bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
BPPY_SET_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (newvalue == NULL)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("Cannot delete `task' attribute."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (PyInt_Check (newvalue))
|
||||||
|
{
|
||||||
|
id = (int) PyInt_AsLong (newvalue);
|
||||||
|
if (! valid_task_id (id))
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_RuntimeError,
|
||||||
|
_("Invalid task ID."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (newvalue == Py_None)
|
||||||
|
id = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("The value of `task' must be an integer or None."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self_bp->bp->task = id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Python function to set the ignore count of a breakpoint. */
|
||||||
|
static int
|
||||||
|
bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
long value;
|
||||||
|
|
||||||
|
BPPY_SET_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (newvalue == NULL)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("Cannot delete `ignore_count' attribute."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (! PyInt_Check (newvalue))
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("The value of `ignore_count' must be an integer."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = PyInt_AsLong (newvalue);
|
||||||
|
if (value < 0)
|
||||||
|
value = 0;
|
||||||
|
set_ignore_count (self_bp->number, (int) value, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to set the hit count of a breakpoint. */
|
||||||
|
static int
|
||||||
|
bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_SET_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (newvalue == NULL)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("Cannot delete `hit_count' attribute."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_AttributeError,
|
||||||
|
_("The value of `hit_count' must be zero."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self_bp->bp->hit_count = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the location of a breakpoint. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_location (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
breakpoint_object *obj = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (obj);
|
||||||
|
|
||||||
|
if (obj->bp->type != bp_breakpoint)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
str = obj->bp->addr_string;
|
||||||
|
|
||||||
|
if (! str)
|
||||||
|
str = "";
|
||||||
|
return PyString_Decode (str, strlen (str), host_charset (), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the breakpoint expression. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_expression (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
breakpoint_object *obj = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (obj);
|
||||||
|
|
||||||
|
if (obj->bp->type != bp_watchpoint
|
||||||
|
&& obj->bp->type != bp_hardware_watchpoint
|
||||||
|
&& obj->bp->type != bp_read_watchpoint
|
||||||
|
&& obj->bp->type != bp_access_watchpoint)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
str = obj->bp->exp_string;
|
||||||
|
if (! str)
|
||||||
|
str = "";
|
||||||
|
|
||||||
|
return PyString_Decode (str, strlen (str), host_charset (), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the condition expression of a breakpoint. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_condition (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
breakpoint_object *obj = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (obj);
|
||||||
|
|
||||||
|
str = obj->bp->cond_string;
|
||||||
|
if (! str)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
return PyString_Decode (str, strlen (str), host_charset (), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
|
||||||
|
{
|
||||||
|
char *exp;
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
volatile struct gdb_exception except;
|
||||||
|
|
||||||
|
BPPY_SET_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (newvalue == NULL)
|
||||||
|
{
|
||||||
|
PyErr_SetString (PyExc_TypeError,
|
||||||
|
_("Cannot delete `condition' attribute."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (newvalue == Py_None)
|
||||||
|
exp = "";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exp = python_string_to_host_string (newvalue);
|
||||||
|
if (exp == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_CATCH (except, RETURN_MASK_ALL)
|
||||||
|
{
|
||||||
|
set_breakpoint_condition (self_bp->bp, exp, 0);
|
||||||
|
}
|
||||||
|
GDB_PY_SET_HANDLE_EXCEPTION (except);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the commands attached to a breakpoint. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_commands (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
struct breakpoint *bp = self_bp->bp;
|
||||||
|
long length;
|
||||||
|
volatile struct gdb_exception except;
|
||||||
|
struct ui_file *string_file;
|
||||||
|
struct cleanup *chain;
|
||||||
|
PyObject *result;
|
||||||
|
char *cmdstr;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (! self_bp->bp->commands)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
string_file = mem_fileopen ();
|
||||||
|
chain = make_cleanup_ui_file_delete (string_file);
|
||||||
|
|
||||||
|
TRY_CATCH (except, RETURN_MASK_ALL)
|
||||||
|
{
|
||||||
|
ui_out_redirect (uiout, string_file);
|
||||||
|
print_command_lines (uiout, breakpoint_commands (bp), 0);
|
||||||
|
ui_out_redirect (uiout, NULL);
|
||||||
|
}
|
||||||
|
cmdstr = ui_file_xstrdup (string_file, &length);
|
||||||
|
GDB_PY_HANDLE_EXCEPTION (except);
|
||||||
|
|
||||||
|
result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL);
|
||||||
|
do_cleanups (chain);
|
||||||
|
xfree (cmdstr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the breakpoint type. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_type (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
return PyInt_FromLong (self_bp->bp->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the breakpoint's number. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_number (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
return PyInt_FromLong (self_bp->number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the breakpoint's thread ID. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_thread (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (self_bp->bp->thread == -1)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
return PyInt_FromLong (self_bp->bp->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the breakpoint's task ID (in Ada). */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_task (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
if (self_bp->bp->task == 0)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
return PyInt_FromLong (self_bp->bp->task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the breakpoint's hit count. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_hit_count (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
return PyInt_FromLong (self_bp->bp->hit_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to get the breakpoint's ignore count. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_get_ignore_count (PyObject *self, void *closure)
|
||||||
|
{
|
||||||
|
breakpoint_object *self_bp = (breakpoint_object *) self;
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID (self_bp);
|
||||||
|
|
||||||
|
return PyInt_FromLong (self_bp->bp->ignore_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Python function to create a new breakpoint. */
|
||||||
|
static PyObject *
|
||||||
|
bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
|
||||||
|
{
|
||||||
|
PyObject *result;
|
||||||
|
static char *keywords[] = { "spec", "type", "wp_class", NULL };
|
||||||
|
char *spec;
|
||||||
|
int type = bp_breakpoint;
|
||||||
|
int access_type = hw_write;
|
||||||
|
volatile struct gdb_exception except;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|ii", keywords,
|
||||||
|
&spec, &type, &access_type))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
result = subtype->tp_alloc (subtype, 0);
|
||||||
|
if (! result)
|
||||||
|
return NULL;
|
||||||
|
bppy_pending_object = (breakpoint_object *) result;
|
||||||
|
bppy_pending_object->number = -1;
|
||||||
|
bppy_pending_object->bp = NULL;
|
||||||
|
|
||||||
|
TRY_CATCH (except, RETURN_MASK_ALL)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case bp_breakpoint:
|
||||||
|
{
|
||||||
|
create_breakpoint (python_gdbarch,
|
||||||
|
spec, NULL, -1,
|
||||||
|
0,
|
||||||
|
0, 0, 0,
|
||||||
|
0,
|
||||||
|
AUTO_BOOLEAN_TRUE,
|
||||||
|
NULL, 0, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bp_watchpoint:
|
||||||
|
{
|
||||||
|
if (access_type == hw_write)
|
||||||
|
watch_command_wrapper (spec, 0);
|
||||||
|
else if (access_type == hw_access)
|
||||||
|
awatch_command_wrapper (spec, 0);
|
||||||
|
else if (access_type == hw_read)
|
||||||
|
rwatch_command_wrapper (spec, 0);
|
||||||
|
else
|
||||||
|
error(_("Cannot understand watchpoint access type."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
error(_("Do not understand breakpoint type to set."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (except.reason < 0)
|
||||||
|
{
|
||||||
|
subtype->tp_free (result);
|
||||||
|
return PyErr_Format (except.reason == RETURN_QUIT
|
||||||
|
? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
|
||||||
|
"%s", except.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPPY_REQUIRE_VALID ((breakpoint_object *) result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Static function to return a tuple holding all breakpoints. */
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
gdbpy_breakpoints (PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *result;
|
||||||
|
|
||||||
|
if (bppy_live == 0)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
result = PyTuple_New (bppy_live);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
int i, out = 0;
|
||||||
|
for (i = 0; out < bppy_live; ++i)
|
||||||
|
{
|
||||||
|
if (! bppy_breakpoints[i])
|
||||||
|
continue;
|
||||||
|
Py_INCREF (bppy_breakpoints[i]);
|
||||||
|
PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]);
|
||||||
|
++out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Event callback functions. */
|
||||||
|
|
||||||
|
/* Callback that is used when a breakpoint is created. This function
|
||||||
|
will create a new Python breakpoint object. */
|
||||||
|
static void
|
||||||
|
gdbpy_breakpoint_created (int num)
|
||||||
|
{
|
||||||
|
breakpoint_object *newbp;
|
||||||
|
struct breakpoint *bp = NULL;
|
||||||
|
PyGILState_STATE state;
|
||||||
|
|
||||||
|
if (num < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bp = get_breakpoint (num);
|
||||||
|
if (! bp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bp->type != bp_breakpoint
|
||||||
|
&& bp->type != bp_watchpoint
|
||||||
|
&& bp->type != bp_hardware_watchpoint
|
||||||
|
&& bp->type != bp_read_watchpoint
|
||||||
|
&& bp->type != bp_access_watchpoint)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (num >= bppy_slots)
|
||||||
|
{
|
||||||
|
int old = bppy_slots;
|
||||||
|
bppy_slots = bppy_slots * 2 + 10;
|
||||||
|
bppy_breakpoints
|
||||||
|
= (breakpoint_object **) xrealloc (bppy_breakpoints,
|
||||||
|
(bppy_slots
|
||||||
|
* sizeof (breakpoint_object *)));
|
||||||
|
memset (&bppy_breakpoints[old], 0,
|
||||||
|
(bppy_slots - old) * sizeof (PyObject *));
|
||||||
|
}
|
||||||
|
|
||||||
|
++bppy_live;
|
||||||
|
|
||||||
|
state = PyGILState_Ensure ();
|
||||||
|
|
||||||
|
if (bppy_pending_object)
|
||||||
|
{
|
||||||
|
newbp = bppy_pending_object;
|
||||||
|
bppy_pending_object = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
newbp = PyObject_New (breakpoint_object, &breakpoint_object_type);
|
||||||
|
if (newbp)
|
||||||
|
{
|
||||||
|
PyObject *hookfn;
|
||||||
|
|
||||||
|
newbp->number = num;
|
||||||
|
newbp->bp = bp;
|
||||||
|
bppy_breakpoints[num] = newbp;
|
||||||
|
Py_INCREF (newbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just ignore errors here. */
|
||||||
|
PyErr_Clear ();
|
||||||
|
|
||||||
|
PyGILState_Release (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback that is used when a breakpoint is deleted. This will
|
||||||
|
invalidate the corresponding Python object. */
|
||||||
|
static void
|
||||||
|
gdbpy_breakpoint_deleted (int num)
|
||||||
|
{
|
||||||
|
PyGILState_STATE state;
|
||||||
|
|
||||||
|
state = PyGILState_Ensure ();
|
||||||
|
if (bpnum_is_valid (num))
|
||||||
|
{
|
||||||
|
bppy_breakpoints[num]->bp = NULL;
|
||||||
|
Py_DECREF (bppy_breakpoints[num]);
|
||||||
|
bppy_breakpoints[num] = NULL;
|
||||||
|
--bppy_live;
|
||||||
|
}
|
||||||
|
PyGILState_Release (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize the Python breakpoint code. */
|
||||||
|
void
|
||||||
|
gdbpy_initialize_breakpoints (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
breakpoint_object_type.tp_new = bppy_new;
|
||||||
|
if (PyType_Ready (&breakpoint_object_type) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Py_INCREF (&breakpoint_object_type);
|
||||||
|
PyModule_AddObject (gdb_module, "Breakpoint",
|
||||||
|
(PyObject *) &breakpoint_object_type);
|
||||||
|
|
||||||
|
observer_attach_breakpoint_created (gdbpy_breakpoint_created);
|
||||||
|
observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted);
|
||||||
|
|
||||||
|
/* Add breakpoint types constants. */
|
||||||
|
for (i = 0; pybp_codes[i].name; ++i)
|
||||||
|
{
|
||||||
|
if (PyModule_AddIntConstant (gdb_module,
|
||||||
|
/* Cast needed for Python 2.4. */
|
||||||
|
(char *) pybp_codes[i].name,
|
||||||
|
pybp_codes[i].code) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add watchpoint types constants. */
|
||||||
|
for (i = 0; pybp_watch_types[i].name; ++i)
|
||||||
|
{
|
||||||
|
if (PyModule_AddIntConstant (gdb_module,
|
||||||
|
/* Cast needed for Python 2.4. */
|
||||||
|
(char *) pybp_watch_types[i].name,
|
||||||
|
pybp_watch_types[i].code) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static PyGetSetDef breakpoint_object_getset[] = {
|
||||||
|
{ "enabled", bppy_get_enabled, bppy_set_enabled,
|
||||||
|
"Boolean telling whether the breakpoint is enabled.", NULL },
|
||||||
|
{ "silent", bppy_get_silent, bppy_set_silent,
|
||||||
|
"Boolean telling whether the breakpoint is silent.", NULL },
|
||||||
|
{ "thread", bppy_get_thread, bppy_set_thread,
|
||||||
|
"Thread ID for the breakpoint.\n\
|
||||||
|
If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\
|
||||||
|
If the value is None, then this breakpoint is not thread-specific.\n\
|
||||||
|
No other type of value can be used.", NULL },
|
||||||
|
{ "task", bppy_get_task, bppy_set_task,
|
||||||
|
"Thread ID for the breakpoint.\n\
|
||||||
|
If the value is a task ID (integer), then this is an Ada task-specific breakpoint.\n\
|
||||||
|
If the value is None, then this breakpoint is not task-specific.\n\
|
||||||
|
No other type of value can be used.", NULL },
|
||||||
|
{ "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count,
|
||||||
|
"Number of times this breakpoint should be automatically continued.",
|
||||||
|
NULL },
|
||||||
|
{ "number", bppy_get_number, NULL,
|
||||||
|
"Breakpoint's number assigned by GDB.", NULL },
|
||||||
|
{ "hit_count", bppy_get_hit_count, bppy_set_hit_count,
|
||||||
|
"Number of times the breakpoint has been hit.\n\
|
||||||
|
Can be set to zero to clear the count. No other value is valid\n\
|
||||||
|
when setting this property.", NULL },
|
||||||
|
{ "location", bppy_get_location, NULL,
|
||||||
|
"Location of the breakpoint, as specified by the user.", NULL},
|
||||||
|
{ "expression", bppy_get_expression, NULL,
|
||||||
|
"Expression of the breakpoint, as specified by the user.", NULL},
|
||||||
|
{ "condition", bppy_get_condition, bppy_set_condition,
|
||||||
|
"Condition of the breakpoint, as specified by the user,\
|
||||||
|
or None if no condition set."},
|
||||||
|
{ "commands", bppy_get_commands, NULL,
|
||||||
|
"Commands of the breakpoint, as specified by the user."},
|
||||||
|
{ "type", bppy_get_type, NULL,
|
||||||
|
"Type of breakpoint."},
|
||||||
|
{ NULL } /* Sentinel. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyMethodDef breakpoint_object_methods[] =
|
||||||
|
{
|
||||||
|
{ "is_valid", bppy_is_valid, METH_NOARGS,
|
||||||
|
"Return true if this breakpoint is valid, false if not." },
|
||||||
|
{ NULL } /* Sentinel. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyTypeObject breakpoint_object_type =
|
||||||
|
{
|
||||||
|
PyObject_HEAD_INIT (NULL)
|
||||||
|
0, /*ob_size*/
|
||||||
|
"gdb.Breakpoint", /*tp_name*/
|
||||||
|
sizeof (breakpoint_object), /*tp_basicsize*/
|
||||||
|
0, /*tp_itemsize*/
|
||||||
|
0, /*tp_dealloc*/
|
||||||
|
0, /*tp_print*/
|
||||||
|
0, /*tp_getattr*/
|
||||||
|
0, /*tp_setattr*/
|
||||||
|
0, /*tp_compare*/
|
||||||
|
0, /*tp_repr*/
|
||||||
|
0, /*tp_as_number*/
|
||||||
|
0, /*tp_as_sequence*/
|
||||||
|
0, /*tp_as_mapping*/
|
||||||
|
0, /*tp_hash */
|
||||||
|
0, /*tp_call*/
|
||||||
|
0, /*tp_str*/
|
||||||
|
0, /*tp_getattro*/
|
||||||
|
0, /*tp_setattro*/
|
||||||
|
0, /*tp_as_buffer*/
|
||||||
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||||
|
"GDB breakpoint object", /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
breakpoint_object_methods, /* tp_methods */
|
||||||
|
0, /* tp_members */
|
||||||
|
breakpoint_object_getset /* tp_getset */
|
||||||
|
};
|
@ -75,6 +75,7 @@ extern PyTypeObject block_object_type;
|
|||||||
extern PyTypeObject symbol_object_type;
|
extern PyTypeObject symbol_object_type;
|
||||||
|
|
||||||
PyObject *gdbpy_history (PyObject *self, PyObject *args);
|
PyObject *gdbpy_history (PyObject *self, PyObject *args);
|
||||||
|
PyObject *gdbpy_breakpoints (PyObject *, PyObject *);
|
||||||
PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
|
PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
|
||||||
PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw);
|
PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw);
|
||||||
PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
|
PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
|
||||||
@ -82,6 +83,7 @@ PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args);
|
|||||||
PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
|
PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
|
||||||
PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
|
PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
|
||||||
const char *encoding, struct type *type);
|
const char *encoding, struct type *type);
|
||||||
|
PyObject *gdbpy_get_hook_function (const char *);
|
||||||
|
|
||||||
PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
|
PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
|
||||||
PyObject *symtab_to_symtab_object (struct symtab *symtab);
|
PyObject *symtab_to_symtab_object (struct symtab *symtab);
|
||||||
@ -111,6 +113,7 @@ void gdbpy_initialize_blocks (void);
|
|||||||
void gdbpy_initialize_types (void);
|
void gdbpy_initialize_types (void);
|
||||||
void gdbpy_initialize_functions (void);
|
void gdbpy_initialize_functions (void);
|
||||||
void gdbpy_initialize_objfile (void);
|
void gdbpy_initialize_objfile (void);
|
||||||
|
void gdbpy_initialize_breakpoints (void);
|
||||||
void gdbpy_initialize_lazy_string (void);
|
void gdbpy_initialize_lazy_string (void);
|
||||||
|
|
||||||
struct cleanup *make_cleanup_py_decref (PyObject *py);
|
struct cleanup *make_cleanup_py_decref (PyObject *py);
|
||||||
@ -131,6 +134,18 @@ extern const struct language_defn *python_language;
|
|||||||
"%s", Exception.message); \
|
"%s", Exception.message); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/* Use this after a TRY_EXCEPT to throw the appropriate Python
|
||||||
|
exception. This macro is for use inside setter functions. */
|
||||||
|
#define GDB_PY_SET_HANDLE_EXCEPTION(Exception) \
|
||||||
|
do { \
|
||||||
|
if (Exception.reason < 0) \
|
||||||
|
{ \
|
||||||
|
PyErr_Format (Exception.reason == RETURN_QUIT \
|
||||||
|
? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \
|
||||||
|
"%s", Exception.message); \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
void gdbpy_print_stack (void);
|
void gdbpy_print_stack (void);
|
||||||
|
|
||||||
|
@ -668,6 +668,7 @@ Enables or disables auto-loading of Python code when an object is opened."),
|
|||||||
gdbpy_initialize_functions ();
|
gdbpy_initialize_functions ();
|
||||||
gdbpy_initialize_types ();
|
gdbpy_initialize_types ();
|
||||||
gdbpy_initialize_objfile ();
|
gdbpy_initialize_objfile ();
|
||||||
|
gdbpy_initialize_breakpoints ();
|
||||||
gdbpy_initialize_lazy_string ();
|
gdbpy_initialize_lazy_string ();
|
||||||
|
|
||||||
PyRun_SimpleString ("import gdb");
|
PyRun_SimpleString ("import gdb");
|
||||||
@ -726,6 +727,9 @@ static PyMethodDef GdbMethods[] =
|
|||||||
{ "parameter", gdbpy_parameter, METH_VARARGS,
|
{ "parameter", gdbpy_parameter, METH_VARARGS,
|
||||||
"Return a gdb parameter's value" },
|
"Return a gdb parameter's value" },
|
||||||
|
|
||||||
|
{ "breakpoints", gdbpy_breakpoints, METH_NOARGS,
|
||||||
|
"Return a tuple of all breakpoint objects" },
|
||||||
|
|
||||||
{ "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
|
{ "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
|
||||||
"Find the default visualizer for a Value." },
|
"Find the default visualizer for a Value." },
|
||||||
|
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
2010-04-09 Phil Muldoon <pmuldoon@redhat.com>
|
||||||
|
|
||||||
|
* gdb.python/py-breakpoint.exp: New File.
|
||||||
|
* gdb.python/py-breakpoint.C: Ditto.
|
||||||
|
|
||||||
2010-04-08 Stan Shebs <stan@codesourcery.com>
|
2010-04-08 Stan Shebs <stan@codesourcery.com>
|
||||||
|
|
||||||
* gdb.trace/actions.exp: Clear default-collect.
|
* gdb.trace/actions.exp: Clear default-collect.
|
||||||
|
@ -2,7 +2,7 @@ VPATH = @srcdir@
|
|||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
|
|
||||||
EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
|
EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
|
||||||
py-symbol py-mi
|
py-symbol py-mi py-breakpoint
|
||||||
|
|
||||||
all info install-info dvi install uninstall installcheck check:
|
all info install-info dvi install uninstall installcheck check:
|
||||||
@echo "Nothing to be done for $@..."
|
@echo "Nothing to be done for $@..."
|
||||||
|
46
gdb/testsuite/gdb.python/py-breakpoint.c
Normal file
46
gdb/testsuite/gdb.python/py-breakpoint.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* This testcase is part of GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright 2010 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 multiply (int i)
|
||||||
|
{
|
||||||
|
return i * i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add (int i)
|
||||||
|
{
|
||||||
|
return i + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int foo = 5;
|
||||||
|
int bar = 42;
|
||||||
|
int result = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
result += multiply (foo); /* Break at multiply. */
|
||||||
|
result += add (bar); /* Break at add. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* Break at end. */
|
||||||
|
}
|
142
gdb/testsuite/gdb.python/py-breakpoint.exp
Normal file
142
gdb/testsuite/gdb.python/py-breakpoint.exp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
# Copyright (C) 2010 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.
|
||||||
|
|
||||||
|
if $tracelevel then {
|
||||||
|
strace $tracelevel
|
||||||
|
}
|
||||||
|
|
||||||
|
set testfile "py-breakpoint"
|
||||||
|
set srcfile ${testfile}.c
|
||||||
|
if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run a command in GDB, and report a failure if a Python exception is thrown.
|
||||||
|
# If report_pass is true, report a pass if no exception is thrown.
|
||||||
|
proc gdb_py_test_silent_cmd {cmd name report_pass} {
|
||||||
|
global gdb_prompt
|
||||||
|
|
||||||
|
gdb_test_multiple $cmd $name {
|
||||||
|
-re "Traceback.*$gdb_prompt $" { fail $name }
|
||||||
|
-re "$gdb_prompt $" { if $report_pass { pass $name } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start with a fresh gdb.
|
||||||
|
clean_restart ${testfile}
|
||||||
|
|
||||||
|
# Skip all tests if Python scripting is not enabled.
|
||||||
|
if { [skip_python_tests] } { continue }
|
||||||
|
|
||||||
|
if ![runto_main] then {
|
||||||
|
fail "Cannot run to main."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
global hex decimal
|
||||||
|
|
||||||
|
# Initially there should be one breakpoint: main.
|
||||||
|
|
||||||
|
gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
|
||||||
|
gdb_test "python print blist\[0\]" "<gdb.Breakpoint object at $hex>" "Check obj exists"
|
||||||
|
gdb_test "python print blist\[0\].location" "main." "Check breakpoint location"
|
||||||
|
|
||||||
|
gdb_breakpoint [gdb_get_line_number "Break at multiply."]
|
||||||
|
gdb_continue_to_breakpoint "Break at multiply."
|
||||||
|
|
||||||
|
# Check that the Python breakpoint code noted the addition of a
|
||||||
|
# breakpoint "behind the scenes".
|
||||||
|
gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
|
||||||
|
gdb_test "python print len(blist)" "2" "Check for two breakpoints"
|
||||||
|
gdb_test "python print blist\[0\]" "<gdb.Breakpoint object at $hex>" "Check obj exists"
|
||||||
|
gdb_test "python print blist\[0\].location" "main." "Check breakpoint location"
|
||||||
|
gdb_test "python print blist\[1\]" "<gdb.Breakpoint object at $hex>" "Check obj exists"
|
||||||
|
gdb_test "python print blist\[1\].location" "py-breakpoint\.c:41*" "Check breakpoint location"
|
||||||
|
|
||||||
|
# Check hit and ignore counts.
|
||||||
|
gdb_test "python print blist\[1\].hit_count" "1" "Check breakpoint hit count"
|
||||||
|
gdb_py_test_silent_cmd "python blist\[1\].ignore_count = 4" "Set breakpoint hit count" 0
|
||||||
|
gdb_continue_to_breakpoint "Break at multiply."
|
||||||
|
gdb_test "python print blist\[1\].hit_count" "6" "Check breakpoint hit count"
|
||||||
|
gdb_test "print result" "545" "Check expected variable result after 6 iterations"
|
||||||
|
|
||||||
|
# Test breakpoint is enabled and disabled correctly..
|
||||||
|
gdb_breakpoint [gdb_get_line_number "Break at add."]
|
||||||
|
gdb_continue_to_breakpoint "Break at add."
|
||||||
|
gdb_test "python print blist\[1\].enabled" "True" "Check breakpoint enabled."
|
||||||
|
gdb_py_test_silent_cmd "python blist\[1\].enabled = False" "Set breakpoint disabled." 0
|
||||||
|
gdb_continue_to_breakpoint "Break at add."
|
||||||
|
gdb_py_test_silent_cmd "python blist\[1\].enabled = True" "Set breakpoint enabled." 0
|
||||||
|
gdb_continue_to_breakpoint "Break at multiply."
|
||||||
|
|
||||||
|
# Test other getters and setters.
|
||||||
|
gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
|
||||||
|
gdb_test "python print blist\[1\].thread" "None" "Check breakpoint thread"
|
||||||
|
gdb_test "python print blist\[1\].type == gdb.BP_BREAKPOINT" "True" "Check breakpoint type"
|
||||||
|
gdb_test "python print blist\[0\].number" "1" "Check breakpoint number"
|
||||||
|
gdb_test "python print blist\[1\].number" "2" "Check breakpoint number"
|
||||||
|
gdb_test "python print blist\[2\].number" "3" "Check breakpoint number"
|
||||||
|
|
||||||
|
# Start with a fresh gdb.
|
||||||
|
clean_restart ${testfile}
|
||||||
|
|
||||||
|
if ![runto_main] then {
|
||||||
|
fail "Cannot run to main."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test conditional setting.
|
||||||
|
set bp_location1 [gdb_get_line_number "Break at multiply."]
|
||||||
|
gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (\"$bp_location1\")" "Set breakpoint" 0
|
||||||
|
gdb_continue_to_breakpoint "Break at multiply."
|
||||||
|
gdb_py_test_silent_cmd "python bp1.condition = \"i == 5\"" "Set breakpoint" 0
|
||||||
|
gdb_test "python print bp1.condition" "i == 5" "Test conditional has been set"
|
||||||
|
gdb_continue_to_breakpoint "Break at multiply."
|
||||||
|
gdb_test "print i" "5" "Test conditional breakpoint stopped after five iterations"
|
||||||
|
gdb_py_test_silent_cmd "python bp1.condition = None" "Clear condition" 0
|
||||||
|
gdb_test "python print bp1.condition" "None" "Test conditional read"
|
||||||
|
gdb_continue_to_breakpoint "Break at multiply."
|
||||||
|
gdb_test "print i" "6" "Test breakpoint stopped after six iterations"
|
||||||
|
|
||||||
|
# Test commands.
|
||||||
|
gdb_breakpoint [gdb_get_line_number "Break at add."]
|
||||||
|
set test {commands $bpnum}
|
||||||
|
gdb_test_multiple $test $test { -re "\r\n>$" { pass $test } }
|
||||||
|
set test {print "Command for breakpoint has been executed."}
|
||||||
|
gdb_test_multiple $test $test { -re "\r\n>$" { pass $test } }
|
||||||
|
set test {print result}
|
||||||
|
gdb_test_multiple $test $test { -re "\r\n>$" { pass $test } }
|
||||||
|
gdb_test "end"
|
||||||
|
|
||||||
|
gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
|
||||||
|
gdb_test "python print blist\[len(blist)-1\].commands" "print \"Command for breakpoint has been executed.\".*print result"
|
||||||
|
|
||||||
|
# Watchpoints
|
||||||
|
# Start with a fresh gdb.
|
||||||
|
clean_restart ${testfile}
|
||||||
|
|
||||||
|
if ![runto_main] then {
|
||||||
|
fail "Cannot run to main."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_py_test_silent_cmd "python wp1 = gdb.Breakpoint (\"result\", type=gdb.BP_WATCHPOINT, wp_class=gdb.WP_WRITE )" "Set watchpoint" 0
|
||||||
|
gdb_test "continue" ".*watchpoint.*result.*Old value = 0.*New value = 25.*main.*" "Test watchpoint write"
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user