This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PING^3] [PATCH] Expose signal and syscall catchpoints to Python


Alessandro Di Federico writes:
 > This patch exposes syscall and signal catchpoints to Python. This means
 > that `gdb.breakpoints()` also returns syscall and signal catchpoints, and
 > it is possible to create them through `gdb.Breakpoint`.
 >
 > The patch also implements `gdb.SyscallEvent`, which allows to catch
 > syscalls through `gdb.events.stop.connect`, and the
 > `gdb.get_{syscall,signal}_{name,number}` support functions.
 >
 > Finally, the testsuite has been extended to cover the new features.

Hi.
First, thanks for the patch and especially the patience!

Lots of style nits, easily fixed.

This will need doc additions too of course, but before you
spend time on that there is a high level issue that we
(the community) should decide on:
Is it time to start subclassing breakpoints instead of
continually extending the one uber-breakpoint class?
IOW, should catchpoints be a subclass of breakpoints?

Subclassing is clearly a better way to go,
so I'm kinda thinking now's the time.

 >
 > 2015-06-01  Alessandro Di Federico  <ale+gdb@clearmind.me>
 >
 > gdb/
 >
 > 	* Makefile.in: add python/py-syscallevent.c.
 > 	* break-catch-sig.c (gdb_signal_type): Move definition in
 > 	breakpoint.h.
 > 	(signal_catchpoint_p): New function.
 > 	(iterate_over_signals): New function.
 > 	(signal_is_catch_all): New function.
 > 	(create_signal_catchpoint): Change linkage to external.
 > 	* break-catch-syscall.c (syscall_catchpoint_p): Change linkage to
 > 	external.
 > 	(iterate_over_syscalls): New function.
 > 	(create_syscall_event_catchpoint): Change linkage to external and
 > 	remove useless parameter.
 > 	* breakpoint.h (gdb_signal_type): Move from break-catch-sig.c.
 > 	(syscall_catchpoint_p, iterate_over_syscalls, signal_catchpoint_p,
 > 	iterate_over_signals, signal_is_catch_all,
 > 	create_syscall_event_catchpoint,
 > 	create_signal_catchpoint): Declare functions.
 >
 > gdb/common/
 >
 > 	* break-common.h (catchpoint_type): New enumeration.
 >
 > gdb/python/
 >
 > 	* py-breakpoint.c (pybp_codes): Introduce BP_CATCHPOINT breakpoint
 > 	type.
 > 	(pybp_catchpoint_types): New structure for catchpoint types.
 > 	(bppy_get_last_syscall): New function.
 > 	(bppy_get_last_signal): New function.
 > 	(bppy_get_internal_signals): New function.
 > 	(bppy_get_catchpoint_type): New function.
 > 	(add_syscall_to_list): New function.
 > 	(add_signal_to_list): New function.
 > 	(bppy_get_filter): New function.
 > 	(bppy_init): Extend to support creation of signal and syscall
 > 	catchpoints.
 > 	(gdbpy_initialize_breakpoints): Add initialization of gdb.CT_*
 > 	constants.
 > 	(breakpoint_object_getset): Add properties to support signal and
 > 	syscall catchpoints.
 > 	* py-stopevent.c (emit_stop_event): Implement handling of the
 > 	syscall case.
 > 	* py-stopevent.h (create_syscall_event_object): New declaration.
 > 	* python-internal.h (gdbpy_initialize_syscall_event): New declaration.
 > 	(VEC_py_list_to_vec): Template-like function to convert a Python
 > 	list to a VEC.
 > 	* python.c (gdbpy_get_syscall_name): New function.
 > 	(gdbpy_get_syscall_number): New function.
 > 	(gdbpy_get_signal_name): New function.
 > 	(gdbpy_get_signal_number): New function.
 > 	(_initialize_python): Add initialization of SyscallEvent.
 > 	(python_GdbMethods): Add get_{syscall,signal}_{name,number}
 > 	* py-syscallevent.c: New.
 >
 > gdb/testsuite/gdb.python/
 >
 > 	* py-breakpoint.exp (test_catchpoints): New test.
 > 	(test_syscall_catchpoint): New test.
 > 	(test_signal_catchpoint): New test.
 > 	* py-events.py: Merge all the handlers of `gdb.events.stop` in a
 > 	single one handling SignalEvent, SyscallEvent and BreakpointEvent.
 > 	* py-evsignal.exp: Fix expectations accordingly to the changes in
 > 	py-events.py.
 > 	* py-evthreads.exp: Likewise.
 > 	* py-evsyscall.exp: New test.
 > ---
 >  gdb/Makefile.in                            |   6 +
 >  gdb/break-catch-sig.c                      |  49 +++++-
 >  gdb/break-catch-syscall.c                  |  39 ++++-
 >  gdb/breakpoint.h                           |  18 +++
 >  gdb/common/break-common.h                  |  10 ++
> gdb/python/py-breakpoint.c | 229 ++++++++++++++++++++++++++++-
 >  gdb/python/py-stopevent.c                  |  15 ++
 >  gdb/python/py-stopevent.h                  |   3 +
 >  gdb/python/py-syscallevent.c               |  61 ++++++++
 >  gdb/python/python-internal.h               |  47 ++++++
 >  gdb/python/python.c                        | 122 +++++++++++++++
 >  gdb/testsuite/gdb.python/py-breakpoint.exp | 134 +++++++++++++++++
 >  gdb/testsuite/gdb.python/py-events.py      |  15 +-
 >  gdb/testsuite/gdb.python/py-evsignal.exp   |   2 +-
 >  gdb/testsuite/gdb.python/py-evsyscall.exp  |  41 ++++++
 >  gdb/testsuite/gdb.python/py-evthreads.exp  |   2 +-
 >  16 files changed, 764 insertions(+), 29 deletions(-)
 >  create mode 100644 gdb/python/py-syscallevent.c
 >  create mode 100644 gdb/testsuite/gdb.python/py-evsyscall.exp
 >
 > diff --git a/gdb/Makefile.in b/gdb/Makefile.in
 > index 3eadbbc..729d494 100644
 > --- a/gdb/Makefile.in
 > +++ b/gdb/Makefile.in
 > @@ -409,6 +409,7 @@ SUBDIR_PYTHON_OBS = \
 >  	py-stopevent.o \
 >  	py-symbol.o \
 >  	py-symtab.o \
 > +	py-syscallevent.o \
 >  	py-threadevent.o \
 >  	py-type.o \
 >  	py-unwind.o \
 > @@ -449,6 +450,7 @@ SUBDIR_PYTHON_SRCS = \
 >  	python/py-stopevent.c \
 >  	python/py-symbol.c \
 >  	python/py-symtab.c \
 > +	python/py-syscallevent.c \
 >  	python/py-threadevent.c \
 >  	python/py-type.c \
 >  	python/py-unwind.c \
 > @@ -2671,6 +2673,10 @@ py-symtab.o: $(srcdir)/python/py-symtab.c
 >  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
 >  	$(POSTCOMPILE)
 >
 > +py-syscallevent.o: $(srcdir)/python/py-syscallevent.c
 > +	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-syscallevent.c
 > +	$(POSTCOMPILE)
 > +
 >  py-threadevent.o: $(srcdir)/python/py-threadevent.c
 >  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-threadevent.c
 >  	$(POSTCOMPILE)
 > diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
 > index 158ce03..9b3d027 100644
 > --- a/gdb/break-catch-sig.c
 > +++ b/gdb/break-catch-sig.c
 > @@ -32,10 +32,6 @@
 >
> #define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT)
 >
 > -typedef enum gdb_signal gdb_signal_type;
 > -
 > -DEF_VEC_I (gdb_signal_type);
 > -
 >  /* An instance of this type is used to represent a signal catchpoint.
 >     It includes a "struct breakpoint" as a kind of base class; users
 >     downcast to "struct breakpoint *" when needed.  A breakpoint is
 > @@ -66,6 +62,49 @@ struct signal_catchpoint
 >
 >  static struct breakpoint_ops signal_catchpoint_ops;
 >
 > +/* Returns non-zero if 'b' is a signal catchpoint.  */
 > +
 > +int
 > +signal_catchpoint_p (struct breakpoint *b)
 > +{
 > +  return (b->ops == &signal_catchpoint_ops);

remove the parens.

[I realize syscall_catchpoint_p has them,
but the convention is no parens in this case.]

 > +}
 > +
> +/* Iterates over the signals catched by the catchpoint calling callback */

- period at end of sentences, plus two spaces after that
- need to document how to interpret the return value

 > +
 > +int
 > +iterate_over_signals (struct breakpoint *b,
 > +		       int (*callback) (int, void *),
 > +		       void *data)
 > +{
 > +  struct signal_catchpoint *cp = (struct signal_catchpoint *) b;
 > +  int i = 0, result = 0;
 > +  gdb_signal_type iter = 0;
 > +
 > +  if (cp->signals_to_be_caught == NULL)
 > +    return -1;
 > +
 > +  for (i = 0;
 > +       VEC_iterate (gdb_signal_type, cp->signals_to_be_caught, i, iter);
 > +       i++)
 > +    {
 > +      result = (*callback) (iter, data);
 > +      if (result)
 > +	return result;
 > +    }
 > +
 > +  return result;
 > +}
 > +
> +/* Returns non-zero if the signal catchpoint catches also internal signals */
 > +
 > +int
 > +signal_is_catch_all (struct breakpoint *b)
 > +{
 > +  struct signal_catchpoint *cp = (struct signal_catchpoint *) b;

blank line here

 > +  return cp->catch_all;
 > +}
 > +
 >  /* Count of each signal.  */
 >
 >  static unsigned int *signal_catch_counts;
> @@ -366,7 +405,7 @@ signal_catchpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig)
 >     valid if FILTER is NULL.  If FILTER is NULL and CATCH_ALL is zero,
 >     then internal signals like SIGTRAP are not caught.  */
 >
 > -static void
 > +void
 >  create_signal_catchpoint (int tempflag, VEC (gdb_signal_type) *filter,
 >  			  int catch_all)
 >  {
 > diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
 > index 7ae115f..23d11d5 100644
 > --- a/gdb/break-catch-syscall.c
 > +++ b/gdb/break-catch-syscall.c
> @@ -419,21 +419,47 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops;
 >
 >  /* Returns non-zero if 'b' is a syscall catchpoint.  */
 >
 > -static int
 > +int
 >  syscall_catchpoint_p (struct breakpoint *b)
 >  {
 >    return (b->ops == &catch_syscall_breakpoint_ops);
 >  }
 >
 > -static void
 > -create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
 > -                                 const struct breakpoint_ops *ops)
> +/* Iterates over the syscalls catched by the catchpoint calling callback */
 > +
 > +int
 > +iterate_over_syscalls (struct breakpoint *b,
 > +		       int (*callback) (int, void *),
 > +		       void *data)
 > +{
 > +  struct syscall_catchpoint *cp = (struct syscall_catchpoint *) b;
 > +  int i = 0, iter = 0, result = 0;
 > +
 > +  if (cp->syscalls_to_be_caught == NULL)
 > +    return -1;
 > +
 > +  for (i = 0;
 > +       VEC_iterate (int, cp->syscalls_to_be_caught, i, iter);
 > +       i++)
 > +    {
 > +      result = (*callback) (iter, data);
 > +      if (result)
 > +	return result;
 > +    }
 > +
 > +  return result;
 > +}
 > +
 > +/* Creates a syscall catchpoint */
 > +
 > +void
 > +create_syscall_event_catchpoint (int tempflag, VEC(int) *filter)
 >  {
 >    struct syscall_catchpoint *c;
 >    struct gdbarch *gdbarch = get_current_arch ();
 >
 >    c = XNEW (struct syscall_catchpoint);
 > -  init_catchpoint (&c->base, gdbarch, tempflag, NULL, ops);
> + init_catchpoint (&c->base, gdbarch, tempflag, NULL, &catch_syscall_breakpoint_ops);
 >    c->syscalls_to_be_caught = filter;
 >
 >    install_breakpoint (0, &c->base, 1);
 > @@ -525,8 +551,7 @@ this architecture yet."));
 >    else
 >      filter = NULL;
 >
 > -  create_syscall_event_catchpoint (tempflag, filter,
 > -				   &catch_syscall_breakpoint_ops);
 > +  create_syscall_event_catchpoint (tempflag, filter);
 >  }
 >
 >
 > diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
 > index 7079b75..1c64e6e 100644
 > --- a/gdb/breakpoint.h
 > +++ b/gdb/breakpoint.h
 > @@ -1252,6 +1252,18 @@ extern struct breakpoint_ops bkpt_breakpoint_ops;
 >  extern struct breakpoint_ops tracepoint_breakpoint_ops;
 >  extern struct breakpoint_ops dprintf_breakpoint_ops;
 >
 > +extern int syscall_catchpoint_p (struct breakpoint *);
 > +extern int iterate_over_syscalls (struct breakpoint *,
 > +				  int (*) (int, void *), void *);
 > +extern int signal_catchpoint_p (struct breakpoint *);
> +extern int iterate_over_signals (struct breakpoint *, int (*) (int, void *),
 > +				 void *);
 > +extern int signal_is_catch_all (struct breakpoint *b);
 > +
 > +
 > +typedef enum gdb_signal gdb_signal_type;
 > +DEF_VEC_I (gdb_signal_type);
 > +
 >  extern void initialize_breakpoint_ops (void);
 >
 >  /* Arguments to pass as context to some catch command handlers.  */
> @@ -1337,6 +1349,12 @@ extern int create_breakpoint (struct gdbarch *gdbarch,
 >  			      int enabled,
 >  			      int internal, unsigned flags);
 >
> +extern void create_syscall_event_catchpoint (int tempflag, VEC(int) *filter);
 > +extern void create_signal_catchpoint (int tempflag,
 > +				      VEC (gdb_signal_type) *filter,
 > +				      int catch_all);
 > +
 > +
 >  extern void insert_breakpoints (void);
 >
 >  extern int remove_breakpoints (void);
 > diff --git a/gdb/common/break-common.h b/gdb/common/break-common.h
 > index e5b55b4..9e2cb11 100644
 > --- a/gdb/common/break-common.h
 > +++ b/gdb/common/break-common.h
 > @@ -19,6 +19,8 @@
 >  #ifndef BREAK_COMMON_H
 >  #define BREAK_COMMON_H 1
 >
 > +/* Possible types for hardware breakpoints */

period at end of sentences, plus two spaces after that

 > +
 >  enum target_hw_bp_type
 >    {
 >      hw_write   = 0, 		/* Common  HW watchpoint */
 > @@ -27,4 +29,12 @@ enum target_hw_bp_type
 >      hw_execute = 3		/* Execute HW breakpoint */
 >    };
 >
 > +/* Enumeration for the different types of catchpoints */

period at end of sentences, plus two spaces after that

 > +
 > +enum catchpoint_type
 > +  {
 > +    ct_syscall = 0,             /* Syscall catchpoint */
 > +    ct_signal  = 1              /* Signal catchpoint  */
 > +  };
 > +
 >  #endif
 > diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
 > index 9c0b0e4..4be5ec3 100644
 > --- a/gdb/python/py-breakpoint.c
 > +++ b/gdb/python/py-breakpoint.c
 > @@ -31,6 +31,10 @@
 >  #include "arch-utils.h"
 >  #include "language.h"
 >  #include "location.h"
 > +#include "common/gdb_signals.h"
 > +
 > +DEF_VEC_PY_OP(gdb_signal_type);
 > +DEF_VEC_PY_OP(int);

space before paren

 >
 >  /* Number of live breakpoints.  */
 >  static int bppy_live;
 > @@ -60,6 +64,7 @@ static struct pybp_code pybp_codes[] =
 >    { "BP_HARDWARE_WATCHPOINT", bp_hardware_watchpoint},
 >    { "BP_READ_WATCHPOINT", bp_read_watchpoint},
 >    { "BP_ACCESS_WATCHPOINT", bp_access_watchpoint},
 > +  { "BP_CATCHPOINT", bp_catchpoint},
 >    {NULL} /* Sentinel.  */
 >  };
 >
 > @@ -72,6 +77,14 @@ static struct pybp_code pybp_watch_types[] =
 >    {NULL} /* Sentinel.  */
 >  };
 >
 > +/* Entries related to catchpoint types. */
 > +static struct pybp_code pybp_catchpoint_types[] =
 > +{
 > +  { "CT_SYSCALL", ct_syscall},
 > +  { "CT_SIGNAL", ct_signal},

I'm reading "CT_SYSCALL" in the patch to the testsuite and wondering
"What does CT_ stand for?"
Then I come back here and find it and wonder if this is something
others are going to ask or whether CT_ is something I (and users in
general) can remember.

I like CP_SYSCALL,CP_SIGNAL.
It looks like BP_FOO and I know what BP stands for.
And it appeals to my Consistency Is Good mantra. :-)

 > +  {NULL} /* Sentinel.  */
 > +};
 > +
 >  /* Python function which checks the validity of a breakpoint object.  */
 >  static PyObject *
 >  bppy_is_valid (PyObject *self, PyObject *args)
 > @@ -546,6 +559,149 @@ bppy_get_visibility (PyObject *self, void *closure)
 >    Py_RETURN_TRUE;
 >  }
 >
 > +/* Python function to get the number of the last catched syscall */
 > +
 > +static PyObject *
 > +bppy_get_last_syscall (PyObject *self, void *closure)
 > +{
 > +  gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
 > +  struct target_waitstatus last;
 > +  ptid_t ptid;
 > +
 > +  BPPY_REQUIRE_VALID (self_bp);
 > +
> + if (self_bp->bp->type == bp_catchpoint && syscall_catchpoint_p (self_bp->bp))
 > +    {
 > +      get_last_target_status (&ptid, &last);
 > +      return PyInt_FromLong (last.value.syscall_number);
 > +    }
 > +
 > +  Py_RETURN_NONE;
 > +}
 > +
 > +/* Python function to get the number of the last catched signal */
 > +
 > +static PyObject *
 > +bppy_get_last_signal (PyObject *self, void *closure)
 > +{
 > +  gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
 > +  struct target_waitstatus last;
 > +  ptid_t ptid;
 > +
 > +  BPPY_REQUIRE_VALID (self_bp);
 > +
> + if (self_bp->bp->type == bp_catchpoint && signal_catchpoint_p (self_bp->bp))
 > +    {
 > +      get_last_target_status (&ptid, &last);
 > +      return PyInt_FromLong (last.value.sig);
 > +    }
 > +
 > +  Py_RETURN_NONE;
 > +}
 > +
> +/* Python function to get the whether the current catchpoint catches internal
 > +   signals too */

period at end of sentences, plus two spaces after that

I'm a little bit leary about exporting something that says "internal"
into the python API.
What's the use-case for this?
[Plus the name doesn't feel right, but let's establish
a use-case first.]

 > +
 > +static PyObject *
 > +bppy_get_internal_signals (PyObject *self, void *closure)
 > +{
 > +  gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
 > +  struct target_waitstatus last;
 > +  ptid_t ptid;
 > +
 > +  BPPY_REQUIRE_VALID (self_bp);
 > +
> + if (self_bp->bp->type == bp_catchpoint && signal_catchpoint_p (self_bp->bp))
 > +    {
 > +      if (signal_is_catch_all (self_bp->bp))
 > +	Py_RETURN_TRUE;
 > +      else
 > +	Py_RETURN_FALSE;
 > +    }
 > +
 > +  Py_RETURN_NONE;
 > +}
 > +
 > +/* Python function to obtain the type of the current catchpoint
 > +   (e.g. syscall or signal catchpoint) */

period at end of sentences, plus two spaces after that

 > +
 > +static PyObject *
 > +bppy_get_catchpoint_type (PyObject *self, void *closure)
 > +{
 > +  gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
 > +
 > +  BPPY_REQUIRE_VALID (self_bp);
 > +
 > +  if (self_bp->bp->type == bp_catchpoint)
 > +    {
 > +      if (signal_catchpoint_p (self_bp->bp))
 > +	return PyInt_FromLong (ct_signal);
 > +      else if (syscall_catchpoint_p (self_bp->bp))
 > +	return PyInt_FromLong (ct_syscall);
 > +      else
 > +	Py_RETURN_NONE;
 > +    }
 > +
 > +  Py_RETURN_NONE;
 > +}
 > +
 > +/* A simple function to append integers to a Python list */

period at end of sentences, plus two spaces after that

 > +
 > +static int
 > +add_syscall_to_list(int value, void *list) {
 > +  return PyList_Append(list, PyInt_FromLong (value));
 > +}
 > +
 > +/* A simple function to append integers to a Python list */

period at end of sentences, plus two spaces after that

 > +
 > +static int
 > +add_signal_to_list(int value, void *list) {

space before opening paren

 > +  int host_signal = gdb_signal_to_host (value);
 > +  return PyList_Append(list, PyInt_FromLong (host_signal));

space before opening paren

 > +}
 > +
 > +/* Python function that returns a list of integers representing the
 > +   syscalls/signals catched by this breakpoint. */

two spaces after a sentence
s/breakpoint/catchpoint/

Btw, there's a open debate on whether we should be subclassing
from some breakpoint baseclass. At some point we might do that.
Maybe now's a good time, I'm not sure.
What do you think?

 > +
 > +static PyObject *
 > +bppy_get_filter (PyObject *self, void *closure)
 > +{
 > +  gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
 > +  int i = 0, iter = 0, iserr = 0;
 > +  PyObject *list = NULL;
 > +
 > +  BPPY_REQUIRE_VALID (self_bp);
 > +
 > +  if (self_bp->bp->type == bp_catchpoint)
 > +    {
 > +      list = PyList_New(0);

space before opening paren

 > +
 > +      if (!list)

ref: https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#NULL_Is_Not_Zero

 > +	{
 > +	  PyErr_SetString (PyExc_RuntimeError,
 > +			   "Couldn't create a list object.");
 > +	  return NULL;
 > +	}
 > +
 > +      if (syscall_catchpoint_p (self_bp->bp))
 > +	iserr = iterate_over_syscalls(self_bp->bp, add_syscall_to_list, list);

space before opening paren

 > +      else if (signal_catchpoint_p (self_bp->bp))
 > +	iserr = iterate_over_signals(self_bp->bp, add_signal_to_list, list);

space before opening paren

 > +
 > +      if (iserr == -1)
 > +	{
 > +	  PyErr_SetString (PyExc_RuntimeError,
 > +			   "Error while inserting an element in the list.");
 > +	  Py_DECREF (list);
 > +	  return NULL;
 > +	}
 > +
 > +      return list;
 > +    }
 > +
 > +  Py_RETURN_NONE;
 > +}
 > +
 >  /* Python function to determine if the breakpoint is a temporary
 >     breakpoint.  */
 >
> @@ -628,19 +784,23 @@ bppy_get_ignore_count (PyObject *self, void *closure)
 >  static int
 >  bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 >  {
 > -  static char *keywords[] = { "spec", "type", "wp_class", "internal",
 > -			      "temporary", NULL };
> + static char *keywords[] = { "spec", "type", "wp_class", "ct_type", "internal",

s/ct_type/cp_type/

 > +			      "temporary", "filter", "internal_signals", NULL };

Given the number of keyword arguments now present I wonder if we've crossed a threshold for being time to start subclassing instead of having one class for
all the different kinds of "breakpoints".

 >    const char *spec;
 >    int type = bp_breakpoint;
 >    int access_type = hw_write;
 > +  int catchpoint_type = ct_syscall;
 >    PyObject *internal = NULL;
 >    PyObject *temporary = NULL;
 >    int internal_bp = 0;
 >    int temporary_bp = 0;
 > +  PyObject *filter = NULL;
 > +  int internal_signals = 0;
 >
 > -  if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiOO", keywords,
> + if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiiOOOi", keywords,
 >  				     &spec, &type, &access_type,
 > -				     &internal, &temporary))
 > +				     &catchpoint_type, &internal, &temporary,
 > +				     &filter, &internal_signals))
 >      return -1;
 >
 >    if (internal)
> @@ -696,6 +856,40 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 >  	      error(_("Cannot understand watchpoint access type."));
 >  	    break;
 >  	  }
 > +	case bp_catchpoint:
 > +	  {
 > +	    switch (catchpoint_type)
 > +	      {
 > +	      case ct_syscall:
 > +		{
 > +		  VEC (int) *syscall_filter = NULL;
 > +
 > +		  if (filter != NULL)
 > +		    syscall_filter = VEC_py_list_to_vec (int, filter, NULL);
 > +
 > +		  create_syscall_event_catchpoint (temporary_bp, syscall_filter);
 > +		  break;
 > +		}
 > +	      case ct_signal:
 > +		{
 > +		  VEC (gdb_signal_type) *signal_filter = NULL;
 > +
 > +		  if (filter != NULL)
 > +		    signal_filter = VEC_py_list_to_vec (gdb_signal_type,
 > +							filter,
 > +							gdb_signal_from_host);
 > +
 > +		  create_signal_catchpoint (temporary_bp, signal_filter,
 > +					    internal_signals);
 > +		  break;
 > +		}
 > +	      default:
 > +		{
 > +		  error (_("Catchpoint type not supported."));
 > +		}
 > +	      }
 > +	    break;
 > +	  }
 >  	default:
 >  	  error(_("Do not understand breakpoint type to set."));
 >  	}
> @@ -715,8 +909,6 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 >    return 0;
 >  }
 >
 > -
 > -
 >  static int
 >  build_bp_list (struct breakpoint *b, void *arg)
 >  {
 > @@ -868,7 +1060,8 @@ gdbpy_breakpoint_created (struct breakpoint *bp)
 >        && bp->type != bp_watchpoint
 >        && bp->type != bp_hardware_watchpoint
 >        && bp->type != bp_read_watchpoint
 > -      && bp->type != bp_access_watchpoint)
 > +      && bp->type != bp_access_watchpoint
 > +      && bp->type != bp_catchpoint)
 >      return;
 >
 >    state = PyGILState_Ensure ();
 > @@ -963,6 +1156,16 @@ gdbpy_initialize_breakpoints (void)
 >  	return -1;
 >      }
 >
 > +  /* Add catchpoint types constants.  */
 > +  for (i = 0; pybp_catchpoint_types[i].name; ++i)
 > +    {
 > +      if (PyModule_AddIntConstant (gdb_module,
 > +				   /* Cast needed for Python 2.4.  */
 > +				   (char *) pybp_catchpoint_types[i].name,
 > +				   pybp_catchpoint_types[i].code) < 0)
 > +	return -1;
 > +    }
 > +
 >    return 0;
 >  }
 >
 > @@ -1052,6 +1255,18 @@ or None if no condition set."},
 >      "Whether the breakpoint is visible to the user."},
 >    { "temporary", bppy_get_temporary, NULL,
 >      "Whether this breakpoint is a temporary breakpoint."},
 > +  { "filter", bppy_get_filter, NULL,
> + "List of catched syscalls/signals. If empty, all the syscalls/signals are\n\
 > +being catched."},
 > +  { "internal_signals", bppy_get_internal_signals, NULL,
> + "Boolean indicating whether the breakpoint catches internal signals too or\n\
 > +not."},
 > +  { "last_syscall", bppy_get_last_syscall, NULL,
 > +    "Last catched syscall."},
 > +  { "last_signal", bppy_get_last_signal, NULL,
 > +    "Last catched signal."},
 > +  { "ct_type", bppy_get_catchpoint_type, NULL,
 > +    "Get catchpoint type."},
 >    { NULL }  /* Sentinel.  */
 >  };
 >
 > diff --git a/gdb/python/py-stopevent.c b/gdb/python/py-stopevent.c
 > index 684edff..e6da332 100644
 > --- a/gdb/python/py-stopevent.c
 > +++ b/gdb/python/py-stopevent.c
 > @@ -19,6 +19,7 @@
 >
 >  #include "defs.h"
 >  #include "py-stopevent.h"
 > +#include "infrun.h"
 >
 >  PyObject *
 >  create_stop_event_object (PyTypeObject *py_type)
> @@ -49,6 +50,8 @@ emit_stop_event (struct bpstats *bs, enum gdb_signal stop_signal)
 >    PyObject *list = NULL;
 >    PyObject *first_bp = NULL;
 >    struct bpstats *current_bs;
 > +  ptid_t ptidp;
 > +  struct target_waitstatus status;
 >
 >    if (evregpy_no_listeners_p (gdb_py_events.stop))
 >      return 0;
> @@ -95,6 +98,18 @@ emit_stop_event (struct bpstats *bs, enum gdb_signal stop_signal)
 >  	goto fail;
 >      }
 >
 > +  if (stop_signal == GDB_SIGNAL_0)
 > +    {
 > +      get_last_target_status(&ptidp, &status);

space before paren

 > +      if (status.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
 > +	{
 > +	  stop_event_obj =
 > +	    create_syscall_event_object (status.value.syscall_number, bs);
 > +	  if (!stop_event_obj)

ref: https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#NULL_Is_Not_Zero
[I realize other code in this file gets this wrong.
In this case I'd go with what's right over being
consistently wrong.]

 > +	    goto fail;
 > +	}
 > +    }
 > +
 >    /* If all fails emit an unknown stop event.  All event types should
 >       be known and this should eventually be unused.  */
 >    if (!stop_event_obj)
 > diff --git a/gdb/python/py-stopevent.h b/gdb/python/py-stopevent.h
 > index f219070..663da7c 100644
 > --- a/gdb/python/py-stopevent.h
 > +++ b/gdb/python/py-stopevent.h
> @@ -33,4 +33,7 @@ extern PyObject *create_breakpoint_event_object (PyObject *breakpoint_list,
 >
> extern PyObject *create_signal_event_object (enum gdb_signal stop_signal);
 >
 > +extern PyObject *create_syscall_event_object (int syscall_number,
 > +					      struct bpstats *bs);
 > +
 >  #endif /* GDB_PY_STOPEVENT_H */
 > diff --git a/gdb/python/py-syscallevent.c b/gdb/python/py-syscallevent.c
 > new file mode 100644
 > index 0000000..c844be8
 > --- /dev/null
 > +++ b/gdb/python/py-syscallevent.c
 > @@ -0,0 +1,61 @@
 > +/* Python interface to inferior syscall events.
 > +
 > +   Copyright (C) 2009-2015 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 "py-stopevent.h"
 > +#include "xml-syscall.h"
 > +
 > +extern PyTypeObject syscall_event_object_type
 > +    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object");
 > +
 > +PyObject *
 > +create_syscall_event_object (int syscall_number, struct bpstats *bs)
 > +{
 > +  PyObject *syscall_number_obj = NULL;
 > +  PyObject *syscall_event_obj =
 > +    create_stop_event_object (&syscall_event_object_type);
 > +  struct syscall s;
 > +  struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
 > +
 > +  if (!syscall_event_obj)

ref: https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#NULL_Is_Not_Zero

 > +    goto fail;
 > +
 > +  get_syscall_by_number (gdbarch, syscall_number, &s);
 > +
 > +  syscall_number_obj = PyLong_FromLongLong (syscall_number);
 > +  if (syscall_number_obj == NULL)
 > +    goto fail;
 > +
 > +  if (evpy_add_attribute (syscall_event_obj,
 > +                          "stop_syscall",
 > +                          syscall_number_obj) < 0)
 > +    goto fail;
 > +
 > +  return syscall_event_obj;
 > +
 > + fail:
 > +  Py_XDECREF (syscall_event_obj);
 > +  return NULL;
 > +}
 > +
 > +GDBPY_NEW_EVENT_TYPE (syscall,
 > +                      "gdb.SyscallEvent",
 > +                      "SyscallEvent",
 > +                      "GDB syscall event object",
 > +                      stop_event_object_type);
 > diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
 > index ee949b7..667d074 100644
 > --- a/gdb/python/python-internal.h
 > +++ b/gdb/python/python-internal.h
 > @@ -472,6 +472,8 @@ int gdbpy_initialize_stop_event (void)
 >    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 >  int gdbpy_initialize_signal_event (void)
 >    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 > +int gdbpy_initialize_syscall_event (void)
 > +  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 >  int gdbpy_initialize_breakpoint_event (void)
 >    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 >  int gdbpy_initialize_continue_event (void)
 > @@ -594,4 +596,49 @@ struct varobj;
 >  struct varobj_iter *py_varobj_get_iterator (struct varobj *var,
 >  					    PyObject *printer);
 >
> +/* Define a "template" macro to create a Python list from a VEC of integer-like
 > +   values. See vec.h. */

two spaces after a period
Also, this does the opposite of what the comment says:
It converts a python list to a VEC of integer-like values.

 > +
> +#define VEC_py_list_to_vec(T,V,C) (VEC_OP(T,py_list_to_vec)((V), (C) VEC_ASSERT_INFO))

Need to document that a NULL result is insufficient to denote errors,
the caller must also check PyErr_Occurred.

 > +
 > +#define DEF_VEC_PY_OP(T)						\
 > +static inline VEC(T)*							\
> +VEC_OP(T, py_list_to_vec) (PyObject *list, T (*converter)(int) VEC_ASSERT_DECL) \

spacing: VEC_OP (

 > +{									\
 > +  VEC(T)* result = NULL;						\
 > +  struct cleanup *cleanup = make_cleanup (VEC_cleanup (T), &result);	\
 > +  Py_ssize_t i = 0;							\
 > +  									\
 > +  if (!PyList_Check (list))						\
 > +    {									\
 > +      PyErr_SetString (PyExc_RuntimeError,				\
 > +		       _("Input object not a list."));			\
 > +      return NULL;							\
 > +    }									\
 > +  									\
 > +  for (i = 0; i < PyList_Size(list); i++)				\

space before paren, here and elsewhere

 > +    {									\
 > +      long value;							\
 > +									\
 > +      if (!gdb_py_int_as_long(PyList_GetItem (list, i), &value))	\

space before paren

 > +	{								\
 > +	  PyErr_SetString (PyExc_RuntimeError,				\
 > +			   _("Couldn't convert list element to long.")); \

gdb_py_int_as_long will have already set the error condition

 > +	  do_cleanups (cleanup);					\
 > +	  return NULL;							\
 > +	}								\
 > +      									\
 > +      if (converter)							\
 > +	value = converter(value);					\
 > +      									\
 > +      VEC_safe_push (T, result, value);					\
 > +    }									\
 > +  									\
 > +  discard_cleanups (cleanup);						\
 > +  return result;							\
 > +  									\
 > +}									\
 > +struct vec_swallow_trailing_semi
 > +
 > +
 >  #endif /* GDB_PYTHON_INTERNAL_H */
 > diff --git a/gdb/python/python.c b/gdb/python/python.c
 > index 6cbe5f0..7923627 100644
 > --- a/gdb/python/python.c
 > +++ b/gdb/python/python.c
 > @@ -33,6 +33,8 @@
 >  #include "python.h"
 >  #include "extension-priv.h"
 >  #include "cli/cli-utils.h"
 > +#include "xml-syscall.h"
 > +#include "common/gdb_signals.h"
 >  #include <ctype.h>
 >  #include "location.h"
 >
 > @@ -716,6 +718,113 @@ gdbpy_solib_name (PyObject *self, PyObject *args)
 >    return str_obj;
 >  }
 >
 > +/* Python function to obtain the name of a syscall given its number */

period at end of sentences, plus two spaces after that

 > +
 > +static PyObject *
 > +gdbpy_get_syscall_name (PyObject *self, PyObject *arg)
 > +{
 > +  long syscall_number;
 > +  struct gdbarch *gdbarch = get_current_arch ();
 > +  struct syscall s;
 > +
 > +  if (PyInt_Check (arg) && gdb_py_int_as_long (arg, &syscall_number))
 > +    {
 > +      get_syscall_by_number (gdbarch, syscall_number, &s);
 > +
 > +      if (!s.name || strlen (s.name) == 0)

Don't use ! to check for null pointers, compare with NULL.
ref: https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#NULL_Is_Not_Zero

 > +	Py_RETURN_NONE;
 > +
> + return PyString_Decode (s.name, strlen (s.name), host_charset (), NULL);

Use host_string_to_python_string, it exists now.

 > +    }
 > +
 > +  PyErr_SetString (PyExc_RuntimeError, "Argument is not a number.");

PyExc_TypeError

Plus gdb_py_int_as_long will have already set the error condition,
so you don't want to clobber that here.

  if (!PyInt_Check (arg))
    {
      PyErr_SetString (PyExc_TypeError, "Argument is not an integer.");
      return NULL;
    }
  if (!gdb_py_int_as_long (arg, &syscall_number))
    return NULL

  ...

 > +  return NULL;
 > +}
 > +
 > +/* Python function to obtain the number of a syscall given its name */
 > +
 > +static PyObject *
 > +gdbpy_get_syscall_number (PyObject *self, PyObject *arg)
 > +{
 > +  const char *syscall_name = NULL;
 > +  struct gdbarch *gdbarch = get_current_arch ();
 > +  struct syscall s;
 > +
 > +  if (!PyString_Check (arg))
 > +    {
 > +      PyErr_SetString (PyExc_RuntimeError, "Argument is not a string.");

PyExc_TypeError

 > +      return NULL;
 > +    }
 > +
 > +  syscall_name = PyBytes_AsString (arg);

The rest of the code uses PyString_FromString.
I realize this is a python 2 vs 3 thing,
but Consistency Is Good, so let's go with
PyString_FromString.

 > +
 > +  if (syscall_name == NULL)
 > +    Py_RETURN_NONE;
 > +
 > +  get_syscall_by_name (gdbarch, syscall_name, &s);
 > +
 > +  if (s.number == UNKNOWN_SYSCALL)
 > +    Py_RETURN_NONE;
 > +
 > +  return PyInt_FromLong (s.number);
 > +

remove blank line

 > +}
 > +

remove extra blank line

 > +
 > +/* Python function to obtain the name of a signal given its number */
 > +
 > +static PyObject *
 > +gdbpy_get_signal_name (PyObject *self, PyObject *arg)
 > +{
 > +  long signal_number;
 > +  struct gdbarch *gdbarch = get_current_arch ();
 > +  const char *s = NULL;
 > +  enum gdb_signal signal = 0;
 > +
 > +  if (PyInt_Check (arg) && gdb_py_int_as_long (arg, &signal_number))

See above.

 > +    {
 > +      signal = gdb_signal_from_host (signal_number);
 > +      s = gdb_signal_to_name (signal);
 > +
 > +      if (!s || strlen (s) == 0)

ref: https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#NULL_Is_Not_Zero

 > +	Py_RETURN_NONE;
 > +
 > +      return PyString_Decode (s, strlen (s), host_charset (), NULL);

Use host_string_to_python_string, it exists now.

 > +    }
 > +
 > +  PyErr_SetString (PyExc_RuntimeError, "Argument is not a number.");
 > +  return NULL;
 > +}
 > +
 > +/* Python function to obtain the number of a signal given its name */
 > +
 > +static PyObject *
 > +gdbpy_get_signal_number (PyObject *self, PyObject *arg)
 > +{
 > +  const char *signal_name = NULL;
 > +  int signal_number = 0;
 > +  enum gdb_signal signal = 0;
 > +
 > +  if (!PyString_Check (arg))
 > +    {
 > +      PyErr_SetString (PyExc_RuntimeError, "Argument is not a string.");

PyExc_TypeError

 > +      return NULL;
 > +    }
 > +
 > +  signal_name = PyBytes_AsString (arg);

PyString_FromString

 > +
 > +  if (signal_name == NULL)
 > +    Py_RETURN_NONE;
 > +
 > +  signal = gdb_signal_from_name (signal_name);
 > +  signal_number = gdb_signal_to_host (signal);
 > +
 > +  if (signal_number == 0)
 > +    Py_RETURN_NONE;
 > +
 > +  return PyInt_FromLong (signal_number);
 > +}
 > +
 >  /* A Python function which is a wrapper for decode_line_1.  */
 >
 >  static PyObject *
> @@ -1819,6 +1928,7 @@ message == an error message without a stack will be printed."),
 >        || gdbpy_initialize_event () < 0
 >        || gdbpy_initialize_stop_event () < 0
 >        || gdbpy_initialize_signal_event () < 0
 > +      || gdbpy_initialize_syscall_event () < 0
 >        || gdbpy_initialize_breakpoint_event () < 0
 >        || gdbpy_initialize_continue_event () < 0
 >        || gdbpy_initialize_inferior_call_pre_event () < 0
 > @@ -2081,6 +2191,18 @@ Return the selected inferior object." },
 >    { "inferiors", gdbpy_inferiors, METH_NOARGS,
 >      "inferiors () -> (gdb.Inferior, ...).\n\
 >  Return a tuple containing all inferiors." },
 > +  { "get_syscall_name", gdbpy_get_syscall_name, METH_O,
 > +    "get_syscall_name (number) -> string.\n\
 > +Return the name of the syscall." },
 > +  { "get_syscall_number", gdbpy_get_syscall_number, METH_O,
 > +    "get_syscall_number (string) -> number.\n\
 > +Return the syscall number corresponding to the specified name." },
 > +  { "get_signal_name", gdbpy_get_signal_name, METH_O,
 > +    "get_signal_name (number) -> string.\n\
 > +Return the name of the signal." },
 > +  { "get_signal_number", gdbpy_get_signal_number, METH_O,
 > +    "get_signal_number (string) -> number.\n\
 > +Return the signal number corresponding to the specified name." },
 >    {NULL, NULL, 0, NULL}
 >  };
 >
> diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp
 > index 0dfc845..772c162 100644
 > --- a/gdb/testsuite/gdb.python/py-breakpoint.exp
 > +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp
 > @@ -462,6 +462,137 @@ proc test_bkpt_temporary { } {
 >      }
 >  }
 >
 > +proc test_catchpoints { } {
 > +    global testfile hex
 > +
 > +    with_test_prefix test_catchpoints {
 > +	# Start with a fresh gdb.
 > +	clean_restart ${testfile}
 > +
 > +	if ![runto_main] then {
 > +	    fail "Cannot run to main."
 > +	    return 0
 > +	}
 > +
 > +	# Check get_{signal,syscall}_{name,number} given sensible results
> + gdb_test "python print gdb.get_syscall_name(gdb.get_syscall_number(\"write\")) == \"write\"" \
 > +	    "True" "Round-trip check for syscall"
> + gdb_test "python print gdb.get_signal_name(gdb.get_signal_number(\"SIGUSR2\")) == \"SIGUSR2\"" \
 > +	    "True" "Round-trip check for signal"

Whether any particular system is going to have write or SIGUSR2
is probably debatable.
I don't have a strong opinion on what to do here, maybe others do.
I see py-evsignal.exp uses SIGUSR1 so maybe using SIGUSR2 here is ok.

 > +
 > +	# Create a catchpoint on the write syscall
 > +	gdb_test "catch syscall write" \
 > +	    "Catchpoint.*\(write\).*" "catch syscall write"
 > +
 > +	# Check that the catchpoint exists and has the expected properties
 > +	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\[1\])" \
 > +	    "<gdb.Breakpoint object at $hex>" "Check obj exist"
 > +	gdb_test "python print (blist\[1\].type == gdb.BP_CATCHPOINT)" \
 > +	    "True" "Check the breakpoint is a catchpoint"
 > +	gdb_test "python print (blist\[1\].ct_type == gdb.CT_SYSCALL)" \
 > +	    "True" "Check the breakpoint is a syscall catchpoint"
> + gdb_test "python print (map(gdb.get_syscall_name, blist\[1\].filter))" \
 > +	    "\\\['write'\\\]" "Check correctness of the filter"
 > +
 > +	# Create a catchpoint for the SIGUSR1 signal
> + gdb_test "catch signal SIGUSR1" "Catchpoint.*\(signal SIGUSR1\).*" "catch signal SIGUSR1"
 > +
 > +	# Check that the catchpoint exists and has the expected properties
 > +	gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" \
 > +	    "Get Breakpoint List" 0
 > +	gdb_test "python print (len(blist))" \
 > +	    "3" "Check for three breakpoints"
 > +	gdb_test "python print (blist\[2\])" \
 > +	    "<gdb.Breakpoint object at $hex>" "Check obj exist"
 > +	gdb_test "python print (blist\[2\].type == gdb.BP_CATCHPOINT)" \
 > +	    "True" "Check the breakpoint is a catchpoint"
 > +	gdb_test "python print (blist\[2\].ct_type == gdb.CT_SIGNAL)" \
 > +	    "True" "Check the breakpoint is a signal catchpoint"
 > +	gdb_test "python print (map(gdb.get_signal_name, blist\[2\].filter))" \
 > +	    "\\\['SIGUSR1'\\\]" "Check correctness of the filter"
 > +	gdb_test "python print (blist\[2\].internal_signals)" \
 > +	    "False" "Check correctness of internal_signals"
 > +
 > +	# Create a catchpoint for all the signals, internal ones included
> + gdb_test "catch signal all" "Catchpoint.*\(any signal\).*" "catch signal all"
 > +
 > +	# Check that the catchpoint exists and has the expected properties
 > +	gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" \
 > +	    "Get Breakpoint List" 0
 > +	gdb_test "python print (len(blist))" \
 > +	    "4" "Check for three breakpoints"
 > +	gdb_test "python print (blist\[3\])" \
 > +	    "<gdb.Breakpoint object at $hex>" "Check obj exist"
 > +	gdb_test "python print (blist\[3\].ct_type == gdb.CT_SIGNAL)" \
 > +	    "True" "Check the breakpoint is a signal catchpoint"
 > +	gdb_test "python print (blist\[3\].type == gdb.BP_CATCHPOINT)" \
 > +	    "True" "Check the breakpoint is a catchpoint"
 > +	gdb_test "python print (blist\[3\].internal_signals)" \
 > +	    "True" "Check correctness of internal_signals"
 > +    }
 > +}
 > +
 > +proc test_syscall_catchpoint { } {
 > +    global testfile decimal
 > +
 > +    with_test_prefix test_signal_catchpoint {
 > +	# Start with a fresh gdb.
 > +	clean_restart ${testfile}
 > +
 > +	if ![runto_main] then {
 > +	    fail "Cannot run to main."
 > +	    return 0
 > +	}
 > +
 > +	# Create a syscall catchpoint from Python for write
> + gdb_py_test_silent_cmd "python cp1 = gdb.Breakpoint(\"\", type=gdb.BP_CATCHPOINT, ct_type=gdb.CT_SYSCALL, filter=\[gdb.get_syscall_number(\"write\")\])" \
 > +	    "Create catchpoint for a specific signal" 0
 > +	gdb_test "python print (cp1 in gdb.breakpoints())" "True" \
 > +	    "Check the catchpoint has been inserted"
 > +	gdb_test "python print (cp1.ct_type == gdb.CT_SYSCALL)" \
 > +	    "True" "Check the breakpoint is a syscall catchpoint"
 > +	gdb_test "python print (map(gdb.get_syscall_name, cp1.filter))" \
 > +	    "\\\['write'\\\]" "Check correctness of the filter"
 > +    }
 > +}
 > +
 > +proc test_signal_catchpoint { } {
 > +    global testfile decimal
 > +
 > +    with_test_prefix test_signal_catchpoint {
 > +	# Start with a fresh gdb.
 > +	clean_restart ${testfile}
 > +
 > +	if ![runto_main] then {
 > +	    fail "Cannot run to main."
 > +	    return 0
 > +	}
 > +
 > +	# Create a signal catchpoint from Python for all signals (internal
 > +	# ones included)
> + gdb_py_test_silent_cmd "python cp1 = gdb.Breakpoint(\"\", type=gdb.BP_CATCHPOINT, ct_type=gdb.CT_SIGNAL, internal_signals=True)" \
 > +	    "Create catchpoint for all signals" 0
 > +	gdb_test "python print (cp1 in gdb.breakpoints())" "True" \
 > +	    "Check the catchpoint has been inserted"
 > +	gdb_test "python print cp1.internal_signals" "True" \
 > +	    "Check internal_signals value"
 > +
 > +	# Create a signal catchpoint from Python for SIGUSR1
> + gdb_py_test_silent_cmd "python cp2 = gdb.Breakpoint(\"\", type=gdb.BP_CATCHPOINT, ct_type=gdb.CT_SIGNAL, filter=\[gdb.get_signal_number(\"SIGUSR1\")\])" \
 > +	    "Create catchpoint for a specific signal" 0
 > +	gdb_test "python print (cp2 in gdb.breakpoints())" "True" \
 > +	    "Check the catchpoint has been inserted"
 > +	gdb_test "python print cp2.internal_signals" "False" \
 > +	    "Check internal_signals value"
 > +	gdb_test "python print (map(gdb.get_signal_name, cp2.filter))" \
 > +	    "\\\['SIGUSR1'\\\]" "Check correctness of the filter"
 > +    }
 > +}
 > +
 >  test_bkpt_basic
 >  test_bkpt_deletion
 >  test_bkpt_cond_and_cmds
 > @@ -470,3 +601,6 @@ test_watchpoints
 >  test_bkpt_internal
 >  test_bkpt_eval_funcs
 >  test_bkpt_temporary
 > +test_catchpoints
 > +test_syscall_catchpoint
 > +test_signal_catchpoint
> diff --git a/gdb/testsuite/gdb.python/py-events.py b/gdb/testsuite/gdb.python/py-events.py
 > index d7fefe0..c166d19 100644
 > --- a/gdb/testsuite/gdb.python/py-events.py
 > +++ b/gdb/testsuite/gdb.python/py-events.py
 > @@ -17,19 +17,19 @@
 >  # printers.
 >  import gdb
 >
 > -def signal_stop_handler (event):
 > +def stop_handler (event):
 >      if (isinstance (event, gdb.StopEvent)):
 >          print ("event type: stop")
 > +
 >      if (isinstance (event, gdb.SignalEvent)):
 >          print ("stop reason: signal")
 >          print ("stop signal: %s" % (event.stop_signal))
 >          if ( event.inferior_thread is not None) :
 >              print ("thread num: %s" % (event.inferior_thread.num))
 > -
 > -def breakpoint_stop_handler (event):
 > -    if (isinstance (event, gdb.StopEvent)):
 > -        print ("event type: stop")
 > -    if (isinstance (event, gdb.BreakpointEvent)):
 > +    elif (isinstance (event, gdb.SyscallEvent)):
 > +        print ("stop reason: syscall")
 > +        print ("stop syscall: %d" % (event.stop_syscall))
 > +    elif (isinstance (event, gdb.BreakpointEvent)):
 >          print ("stop reason: breakpoint")
> print ("first breakpoint number: %s" % (event.breakpoint.number))
 >          for bp in event.breakpoints:
 > @@ -93,8 +93,7 @@ class test_events (gdb.Command):
 >          gdb.Command.__init__ (self, "test-events", gdb.COMMAND_STACK)
 >
 >      def invoke (self, arg, from_tty):
 > -        gdb.events.stop.connect (signal_stop_handler)
 > -        gdb.events.stop.connect (breakpoint_stop_handler)
 > +        gdb.events.stop.connect (stop_handler)
 >          gdb.events.exited.connect (exit_handler)
 >          gdb.events.cont.connect (continue_handler)
 >          gdb.events.inferior_call.connect (inferior_call_handler)
> diff --git a/gdb/testsuite/gdb.python/py-evsignal.exp b/gdb/testsuite/gdb.python/py-evsignal.exp
 > index ea7b73b..d8571d3 100644
 > --- a/gdb/testsuite/gdb.python/py-evsignal.exp
 > +++ b/gdb/testsuite/gdb.python/py-evsignal.exp
 > @@ -38,7 +38,7 @@ gdb_test_no_output "set non-stop on"
 >
 >  gdb_run_cmd
 >  gdb_test_multiple "" "Signal Thread 3"  {
> - -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n.*$gdb_prompt $" { > + -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\n$gdb_prompt $" {
 >          pass "thread 3 was signaled"
 >      }
 >      -re "The target does not support running in non-stop mode"  {
> diff --git a/gdb/testsuite/gdb.python/py-evsyscall.exp b/gdb/testsuite/gdb.python/py-evsyscall.exp
 > new file mode 100644
 > index 0000000..5040089
 > --- /dev/null
 > +++ b/gdb/testsuite/gdb.python/py-evsyscall.exp
 > @@ -0,0 +1,41 @@
 > +# Copyright (C) 2010-2015 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/>.
 > +
 > +load_lib gdb-python.exp
 > +
 > +standard_testfile py-value.c
 > +set pyfile ${srcdir}/${subdir}/py-events.py
 > +
> +if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
 > +    return -1
 > +}
 > +clean_restart $testfile
 > +
 > +if { [skip_python_tests] } { continue }
 > +
 > +
> +gdb_test "catch syscall write" "Catchpoint.*\(write\).*" "catch syscall write"
 > +
 > +gdb_test_no_output "python exec (open ('${pyfile}').read ())" ""
 > +
 > +gdb_test "test-events" "Event testers registered."
 > +
 > +gdb_run_cmd
 > +
 > +gdb_test_multiple "" "write syscall"  {
> + -re "event type: stop\r\nstop reason: syscall\r\nstop syscall: 1\r\n$gdb_prompt $" {
 > +        pass "write syscall performed"
 > +    }
 > +}
> diff --git a/gdb/testsuite/gdb.python/py-evthreads.exp b/gdb/testsuite/gdb.python/py-evthreads.exp
 > index deefda5..fa344a9 100644
 > --- a/gdb/testsuite/gdb.python/py-evthreads.exp
 > +++ b/gdb/testsuite/gdb.python/py-evthreads.exp
 > @@ -75,7 +75,7 @@ gdb_test_multiple "continue&" $test {
 >
 >  set test "thread 3 was signaled"
 >  gdb_test_multiple "" $test {
> - -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n" { > + -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\n$" {
 >          pass $test
 >      }
 >  }
 > --
 > 2.6.3
 >

--
/dje

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]