public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* Events when inferior is modified
@ 2013-06-28 17:07 Nick Bull
  2013-07-30 21:04 ` Tom Tromey
  0 siblings, 1 reply; 12+ messages in thread
From: Nick Bull @ 2013-06-28 17:07 UTC (permalink / raw)
  To: gdb-patches

Hi,

This patch adds new observers, and corresponding Python events, for
various actions on an inferior: calling a function (by hand),
modifying registers or modifying memory.

A use case for these events is that by flagging these occurrences, it
can be noticed that the execution of the program is potentially
'dirty'.  (Hence why the notification doesn't carry information about
what was modified; for my purposes it's enough to know that /a/
change has happened.)

This is my first patch submission, so (a) apologies for things I've
got wrong and (b) I believe I may need to do some paperwork for
copyright assignment.

Thanks for your thoughts.

Nick

2013-06-28  Nick Bull  <nicholaspbull@gmail.com>

	* doc/observer.texi (inferior_call_pre, inferior_call_post,
	register_change, memory_change): New observers.
	* infcall.c (call_function_by_hand): Notify observer before and
	after inferior call.
	* Makefile.in: add py-infcallevent.c / py-infcallevent.o.
	* python/py-event.h (inferior_altered_kind): New enum.
	(emit_inferior_altered_event): New prototype.
	* python/py-events.h (events_object): New inferior_altered registry.
	* python/py-evts.c (gdbpy_initialize_py_events): Add the
	inferior_altered registry.
	* python/py-infcallevent.c: New.
	* python/py-inferior.c (python_on_inferior_call_pre,
	python_on_inferior_call_post, python_on_register_change,
	python_on_memory_change): New.
	(gdbpy_initialize_inferior): Attach python handler to new
	observers.
	* python/python.c (_initialize_python): Initialize new events.
	* python/python-internal.h: (gdbpy_initialize_inferior_call_pre_event,
	gdbpy_initialize_inferior_call_post_event,
	gdbpy_initialize_register_change_event,
	gdbpy_initialize_memory_change_event): New prototypes.
	* target.c (memory_xfer_partial_1, target_xfer_partial):
	Notify memory change observer.
	(target_store_registers): Notify register change observer.



diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c27c03a..f21a6be 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -292,6 +292,7 @@ SUBDIR_PYTHON_OBS = \
  	py-function.o \
  	py-gdb-readline.o \
  	py-inferior.o \
+	py-infcallevent.o \
  	py-infthread.o \
  	py-lazy-string.o \
  	py-newobjfileevent.o \
@@ -327,6 +328,7 @@ SUBDIR_PYTHON_SRCS = \
  	python/py-function.c \
  	python/py-gdb-readline.c \
  	python/py-inferior.c \
+	python/py-infcallevent.c \
  	python/py-infthread.c \
  	python/py-lazy-string.c \
  	python/py-newobjfileevent.c \
@@ -2162,6 +2164,10 @@ py-inferior.o: $(srcdir)/python/py-inferior.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c
  	$(POSTCOMPILE)
  
+py-infcallevent.o: $(srcdir)/python/py-infcallevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infcallevent.c
+	$(POSTCOMPILE)
+
  py-infthread.o: $(srcdir)/python/py-infthread.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infthread.c
  	$(POSTCOMPILE)
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index adb7085..d64de98 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -249,6 +249,22 @@ The trace state variable @var{tsv} is deleted.  If @var{tsv} is
  The trace state value @var{tsv} is modified.
  @end deftypefun
  
+@deftypefun void inferior_call_pre (void)
+An inferior function is about to be called.
+@end deftypefun
+
+@deftypefun void inferior_call_post (void)
+An inferior function has just been called.
+@end deftypefun
+
+@deftypefun void register_change (void)
+One or more registers in the inferior have been modified.
+@end deftypefun
+
+@deftypefun void memory_change (void)
+Memory in the inferior has been modified.
+@end deftypefun
+
  @deftypefun void test_notification (int @var{somearg})
  This observer is used for internal testing.  Do not use.
  See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 19af044..07dbbe3 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -36,6 +36,7 @@
  #include "ada-lang.h"
  #include "gdbthread.h"
  #include "exceptions.h"
+#include "observer.h"
  
  /* If we can't find a function's name from its address,
     we print this instead.  */
@@ -611,6 +612,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
        target_values_type = values_type;
      }
  
+  observer_notify_inferior_call_pre ();
+
    /* Determine the location of the breakpoint (and possibly other
       stuff) that the called function will return to.  The SPARC, for a
       function returning a structure or union, needs to make space for
@@ -844,6 +847,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
      e = run_inferior_call (tp, real_pc);
    }
  
+  observer_notify_inferior_call_post ();
+
    /* Rethrow an error if we got one trying to run the inferior.  */
  
    if (e.reason < 0)
diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h
index f0ff629..b4d391f 100644
--- a/gdb/python/py-event.h
+++ b/gdb/python/py-event.h
@@ -105,6 +105,14 @@ typedef struct
  extern int emit_continue_event (ptid_t ptid);
  extern int emit_exited_event (const LONGEST *exit_code, struct inferior *inf);
  
+typedef enum {
+  inferior_altered_pre_call,
+  inferior_altered_post_call,
+  inferior_altered_register_change,
+  inferior_altered_memory_change
+} inferior_altered_kind;
+
+extern int emit_inferior_altered_event (inferior_altered_kind kind);
  extern int evpy_emit_event (PyObject *event,
                              eventregistry_object *registry)
    CPYCHECKER_STEALS_REFERENCE_TO_ARG (1);
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
index 4ec3832..2f035c7 100644
--- a/gdb/python/py-events.h
+++ b/gdb/python/py-events.h
@@ -46,6 +46,7 @@ typedef struct
    eventregistry_object *cont;
    eventregistry_object *exited;
    eventregistry_object *new_objfile;
+  eventregistry_object *inferior_altered;
  
    PyObject *module;
  
diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c
index 971c520..f20974e 100644
--- a/gdb/python/py-evts.c
+++ b/gdb/python/py-evts.c
@@ -73,6 +73,10 @@ gdbpy_initialize_py_events (void)
    if (add_new_registry (&gdb_py_events.exited, "exited") < 0)
      return -1;
  
+  if (add_new_registry (&gdb_py_events.inferior_altered,
+			"inferior_altered") < 0)
+    return -1;
+
    if (add_new_registry (&gdb_py_events.new_objfile, "new_objfile") < 0)
      return -1;
  
diff --git a/gdb/python/py-infcallevent.c b/gdb/python/py-infcallevent.c
new file mode 100644
index 0000000..19e74e5
--- /dev/null
+++ b/gdb/python/py-infcallevent.c
@@ -0,0 +1,98 @@
+/* Python interface to inferior function events.
+
+   Copyright (C) 2009-2013 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-event.h"
+
+static PyTypeObject inferior_call_pre_event_object_type;
+static PyTypeObject inferior_call_post_event_object_type;
+static PyTypeObject register_change_event_object_type;
+static PyTypeObject memory_change_event_object_type;
+
+static PyObject *
+create_inferior_call_event_object (int flag)
+{
+  PyObject * event;
+
+  switch (flag)
+    {
+    case inferior_altered_pre_call:
+      event = create_event_object (&inferior_call_pre_event_object_type);
+      break;
+    case inferior_altered_post_call:
+      event = create_event_object (&inferior_call_post_event_object_type);
+      break;
+    case inferior_altered_register_change:
+      event = create_event_object (&register_change_event_object_type);
+      break;
+    case inferior_altered_memory_change:
+      event = create_event_object (&memory_change_event_object_type);
+      break;
+    default:
+      return NULL;
+    }
+
+  return event;
+}
+
+/* Callback function which notifies observers when an inferior altered event occurs.
+   This function will create a new Python continue event object.
+   Return -1 if emit fails.  */
+
+int
+emit_inferior_altered_event (inferior_altered_kind kind)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.inferior_altered))
+    return 0;
+
+  event = create_inferior_call_event_object (kind);
+  if (event)
+    return evpy_emit_event (event, gdb_py_events.inferior_altered);
+  return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_pre,
+                      "gdb.InferiorCallPreEvent",
+                      "InferiorCallPreEvent",
+                      "GDB inferior function pre-call event object",
+                      event_object_type,
+                      static);
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_post,
+                      "gdb.InferiorCallPostEvent",
+                      "InferiorCallPostEvent",
+                      "GDB inferior function post-call event object",
+                      event_object_type,
+                      static);
+
+GDBPY_NEW_EVENT_TYPE (register_change,
+                      "gdb.RegisterChangeEvent",
+                      "RegisterChangeEvent",
+                      "GDB register change event object",
+                      event_object_type,
+                      static);
+
+GDBPY_NEW_EVENT_TYPE (memory_change,
+                      "gdb.MemoryChangeEvent",
+                      "MemoryChangeEvent",
+                      "GDB memory change event object",
+                      event_object_type,
+                      static);
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 26ee004..9c30eef 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -118,6 +118,70 @@ python_on_resume (ptid_t ptid)
  }
  
  static void
+python_on_inferior_call_pre (void)
+{
+  struct cleanup *cleanup;
+
+  if (!gdb_python_initialized)
+    return;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_pre_call) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_inferior_call_post (void)
+{
+  struct cleanup *cleanup;
+
+  if (!gdb_python_initialized)
+    return;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_post_call) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_register_change (void)
+{
+  struct cleanup *cleanup;
+
+  if (!gdb_python_initialized)
+    return;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_register_change) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_memory_change (void)
+{
+  struct cleanup *cleanup;
+
+  if (!gdb_python_initialized)
+    return;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_memory_change) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
  python_inferior_exit (struct inferior *inf)
  {
    struct cleanup *cleanup;
@@ -793,6 +857,10 @@ gdbpy_initialize_inferior (void)
    observer_attach_thread_exit (delete_thread_object);
    observer_attach_normal_stop (python_on_normal_stop);
    observer_attach_target_resumed (python_on_resume);
+  observer_attach_inferior_call_pre (python_on_inferior_call_pre);
+  observer_attach_inferior_call_post (python_on_inferior_call_post);
+  observer_attach_register_change (python_on_register_change);
+  observer_attach_memory_change (python_on_memory_change);
    observer_attach_inferior_exit (python_inferior_exit);
    observer_attach_new_objfile (python_new_objfile);
  
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index d947be6..519b680 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -391,6 +391,14 @@ int gdbpy_initialize_breakpoint_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_continue_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_pre_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_post_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_register_change_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_memory_change_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_exited_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_thread_event (void)
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 00092c7..bc9bde3 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1683,6 +1683,10 @@ message == an error message without a stack will be printed."),
        || gdbpy_initialize_signal_event () < 0
        || gdbpy_initialize_breakpoint_event () < 0
        || gdbpy_initialize_continue_event () < 0
+      || gdbpy_initialize_inferior_call_pre_event () < 0
+      || gdbpy_initialize_inferior_call_post_event () < 0
+      || gdbpy_initialize_register_change_event () < 0
+      || gdbpy_initialize_memory_change_event () < 0
        || gdbpy_initialize_exited_event () < 0
        || gdbpy_initialize_thread_event () < 0
        || gdbpy_initialize_new_objfile_event ()  < 0
diff --git a/gdb/target.c b/gdb/target.c
index 920f916..1e85bdd 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -43,6 +43,7 @@
  #include "tracepoint.h"
  #include "gdb/fileio.h"
  #include "agent.h"
+#include "observer.h"
  
  static void target_info (char *, int);
  
@@ -1611,6 +1612,8 @@ memory_xfer_partial_1 (struct target_ops *ops, enum target_object object,
  
    do
      {
+      if (writebuf)
+	observer_notify_memory_change ();
        res = ops->to_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL,
  				  readbuf, writebuf, memaddr, reg_len);
        if (res > 0)
@@ -1733,6 +1736,8 @@ target_xfer_partial (struct target_ops *ops,
        if (raw_object == TARGET_OBJECT_RAW_MEMORY)
  	raw_object = TARGET_OBJECT_MEMORY;
  
+      if (writebuf)
+	observer_notify_memory_change ();
        retval = ops->to_xfer_partial (ops, raw_object, annex, readbuf,
  				     writebuf, offset, len);
      }
@@ -4021,6 +4026,7 @@ target_store_registers (struct regcache *regcache, int regno)
      {
        if (t->to_store_registers != NULL)
  	{
+	  observer_notify_register_change ();
  	  t->to_store_registers (t, regcache, regno);
  	  if (targetdebug)
  	    {


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Events when inferior is modified
  2013-06-28 17:07 Events when inferior is modified Nick Bull
@ 2013-07-30 21:04 ` Tom Tromey
  2013-08-01 15:47   ` Pedro Alves
  2013-08-07 14:41   ` Nick Bull
  0 siblings, 2 replies; 12+ messages in thread
From: Tom Tromey @ 2013-07-30 21:04 UTC (permalink / raw)
  To: Nick Bull; +Cc: gdb-patches

>>>>> "Nick" == Nick Bull <nicholaspbull@gmail.com> writes:

Nick> This patch adds new observers, and corresponding Python events, for
Nick> various actions on an inferior: calling a function (by hand),
Nick> modifying registers or modifying memory.

Thanks.

Nick> This is my first patch submission, so (a) apologies for things I've
Nick> got wrong and (b) I believe I may need to do some paperwork for
Nick> copyright assignment.

I don't remember if I got you started on the paperwork or not.
I will send you email off-list.

Don't worry about (a).  This review is mostly little nits.

Nick>  +@deftypefun void inferior_call_pre (void)
Nick> +An inferior function is about to be called.
Nick> +@end deftypefun
Nick> +
Nick> +@deftypefun void inferior_call_post (void)
Nick> +An inferior function has just been called.
Nick> +@end deftypefun

I'm curious to know why you wanted pre- and post-observers for inferior
calls, but not anything else.

Also, the patch got a little mangled (see the space before the "+" on
the first quoted line here).  This happened in a few spots.

Nick>  extern int emit_exited_event (const LONGEST *exit_code, struct inferior *inf);
Nick>  +typedef enum {

Blank line between the previous declaration and this one.
The brace should go on its own line.

Nick> +
Nick> +static PyObject *
Nick> +create_inferior_call_event_object (int flag)
Nick> +{

Needs an intro comment.  It can be short.

I think it would be better if the "int" were instead
"inferior_altered_kind".

Nick> +  PyObject * event;

No space after "*".

Nick> +    default:
Nick> +      return NULL;

I think gdb_assert_not_reached is more correct here.
However if you want to return NULL then you have to set the Python
exception.

Nick> +int
Nick> +emit_inferior_altered_event (inferior_altered_kind kind)
Nick> +{

I think it would be fine to make this static and put all the observers
into this file.

Nick> diff --git a/gdb/target.c b/gdb/target.c
Nick> index 920f916..1e85bdd 100644
Nick> --- a/gdb/target.c
Nick> +++ b/gdb/target.c
Nick> @@ -43,6 +43,7 @@
Nick>  #include "tracepoint.h"
Nick>  #include "gdb/fileio.h"
Nick>  #include "agent.h"
Nick> +#include "observer.h"
Nick>  static void target_info (char *, int);
Nick>  @@ -1611,6 +1612,8 @@ memory_xfer_partial_1 (struct target_ops *ops,
Nick> enum target_object object,
Nick>   do
Nick>      {
Nick> +      if (writebuf)
Nick> +	observer_notify_memory_change ();

I think "if (writebuf != NULL)", here and elsewhere.


It seem to me that this may just be an approximation of "dirty" in the
remote case.  E.g., gdbserver may write a breakpoint and otherwise
modify things without notifying gdb.

On the other hand, maybe you want to rule out breakpoints from being
considered "dirty".  But then the change has to be more complicated in
another way.

Tom

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Events when inferior is modified
  2013-07-30 21:04 ` Tom Tromey
@ 2013-08-01 15:47   ` Pedro Alves
  2013-08-07 14:41   ` Nick Bull
  1 sibling, 0 replies; 12+ messages in thread
From: Pedro Alves @ 2013-08-01 15:47 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Nick Bull, gdb-patches

On 07/30/2013 10:04 PM, Tom Tromey wrote:
>>>>>> >>>>> "Nick" == Nick Bull <nicholaspbull@gmail.com> writes:
> Nick> This patch adds new observers, and corresponding Python events, for
> Nick> various actions on an inferior: calling a function (by hand),
> Nick> modifying registers or modifying memory.
> 
> Thanks.
> 
> Nick> This is my first patch submission, so (a) apologies for things I've
> Nick> got wrong and (b) I believe I may need to do some paperwork for
> Nick> copyright assignment.
> 
> I don't remember if I got you started on the paperwork or not.
> I will send you email off-list.
> 
> Don't worry about (a).  This review is mostly little nits.
> 
> Nick>  +@deftypefun void inferior_call_pre (void)
> Nick> +An inferior function is about to be called.
> Nick> +@end deftypefun
> Nick> +
> Nick> +@deftypefun void inferior_call_post (void)
> Nick> +An inferior function has just been called.
> Nick> +@end deftypefun
> 
> I'm curious to know why you wanted pre- and post-observers for inferior
> calls, but not anything else.
> 
> Also, the patch got a little mangled (see the space before the "+" on
> the first quoted line here).  This happened in a few spots.
> 
> Nick>  extern int emit_exited_event (const LONGEST *exit_code, struct inferior *inf);
> Nick>  +typedef enum {
> 
> Blank line between the previous declaration and this one.
> The brace should go on its own line.
> 
> Nick> +
> Nick> +static PyObject *
> Nick> +create_inferior_call_event_object (int flag)
> Nick> +{
> 
> Needs an intro comment.  It can be short.
> 
> I think it would be better if the "int" were instead
> "inferior_altered_kind".
> 
> Nick> +  PyObject * event;
> 
> No space after "*".
> 
> Nick> +    default:
> Nick> +      return NULL;
> 
> I think gdb_assert_not_reached is more correct here.
> However if you want to return NULL then you have to set the Python
> exception.
> 
> Nick> +int
> Nick> +emit_inferior_altered_event (inferior_altered_kind kind)
> Nick> +{
> 
> I think it would be fine to make this static and put all the observers
> into this file.
> 
> Nick> diff --git a/gdb/target.c b/gdb/target.c
> Nick> index 920f916..1e85bdd 100644
> Nick> --- a/gdb/target.c
> Nick> +++ b/gdb/target.c
> Nick> @@ -43,6 +43,7 @@
> Nick>  #include "tracepoint.h"
> Nick>  #include "gdb/fileio.h"
> Nick>  #include "agent.h"
> Nick> +#include "observer.h"
> Nick>  static void target_info (char *, int);
> Nick>  @@ -1611,6 +1612,8 @@ memory_xfer_partial_1 (struct target_ops *ops,
> Nick> enum target_object object,
> Nick>   do
> Nick>      {
> Nick> +      if (writebuf)
> Nick> +	observer_notify_memory_change ();
> 
> I think "if (writebuf != NULL)", here and elsewhere.
> 
> 
> It seem to me that this may just be an approximation of "dirty" in the
> remote case.  E.g., gdbserver may write a breakpoint and otherwise
> modify things without notifying gdb.
> 
> On the other hand, maybe you want to rule out breakpoints from being
> considered "dirty".  But then the change has to be more complicated in
> another way.

Yeah.  Also, on several targets, including x86, GDB adjusts the PC
register whenever a breakpoint is hit (as it points at the
instruction after the trap, not at the trap address itself).

Also, we've discussed the limitations of memory/registers changed
events before:

  http://sourceware.org/ml/gdb-patches/2012-11/msg00156.html
  http://sourceware.org/ml/gdb-patches/2012-11/msg00127.html

There are other things that can be changed and "dirty"
the execution.  Say, clobbering $_siginfo.

The use case here is just "dirty".  I wonder whether the
all-encompassing "target_changed" event from

 http://sourceware.org/bugzilla/show_bug.cgi?id=7574

wouldn't be more prudent.

Whatever the case, the use case, and conditions these events
trigger should be very well document, or we risk using them
for other use cases going forward, and breaking the original
intentions.

> @@ -1733,6 +1736,8 @@ target_xfer_partial (struct target_ops *ops,
>         if (raw_object == TARGET_OBJECT_RAW_MEMORY)
>   	raw_object = TARGET_OBJECT_MEMORY;
>
> +      if (writebuf)
> +	observer_notify_memory_change ();
>         retval = ops->to_xfer_partial (ops, raw_object, annex, readbuf,
>   				     writebuf, offset, len);

Note this path handles other objects, not just memory.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Events when inferior is modified
  2013-07-30 21:04 ` Tom Tromey
  2013-08-01 15:47   ` Pedro Alves
@ 2013-08-07 14:41   ` Nick Bull
  2013-11-18 12:51     ` [PATCH v2] " Nick Bull
  1 sibling, 1 reply; 12+ messages in thread
From: Nick Bull @ 2013-08-07 14:41 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

Tom,

Thanks for your comments: I'll modify and resubmit.

On 30 July 2013 22:04, Tom Tromey <tromey@redhat.com> wrote:
>
> I'm curious to know why you wanted pre- and post-observers for inferior
> calls, but not anything else.
[...]
>
> It seem to me that this may just be an approximation of "dirty" in the
> remote case.  E.g., gdbserver may write a breakpoint and otherwise
> modify things without notifying gdb.
>
> On the other hand, maybe you want to rule out breakpoints from being
> considered "dirty".  But then the change has to be more complicated in
> another way.

The sense of "dirty" that I'm using is "the user has interfered with
program state", and not for example "gdb has some cached data which is
now stale".

For context, I'm using this patch in a system with a lot of Python
scripting around gdb to support the user in various ways. I'm also
only concerned with the remote gdbserver case, should that be
relevant.

The motivation behind this work is that the user, sitting at the gdb
command line trying to debug their program, has the ability to modify
the program's state under its feet and hence change its future
behaviour. Which is potentially useful in exploring fixes without
recompiling, but carries the risk that you leave a change in and carry
on, forgetting that you're not debugging the real system any more. I
don't want to totally prevent that kind of modification, but I do want
to know that it has happened. Various UI options are possible at that
point, such as emitting warnings, changing the prompt etc, but those
choices can all be made in the scripting layer.

Breakpoints aren't a modification for these purposes, as they don't
cause the debugged program to generate different results. Well, I hope
not.

Inferior function calls are useful in conditional breakpoints and for
interrogating data structures, but sometimes they perturb the program
state and sometimes they don't. Ignoring the synthesized stack frame
on which they were called, of course. By receiving observer events
before and after the call, we can work behind the user's back to check
for differences. Again, what we do about that---issuing a warning, or
maybe even reverting the changes---can be decided at a higher level.

Picking up changes to registers and memory is a bonus feature for me,
rather than essential, as it's an explicit choice to change state
whereas a fn call may just read state. And per Pedro's comment, other
ways to modify program state are possible, but haven't tripped me up
yet; so in that respect the itch is sufficiently scratched for now.

Nick

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2] Events when inferior is modified
  2013-08-07 14:41   ` Nick Bull
@ 2013-11-18 12:51     ` Nick Bull
  2013-11-18 15:15       ` Eli Zaretskii
  2013-11-25 11:50       ` Phil Muldoon
  0 siblings, 2 replies; 12+ messages in thread
From: Nick Bull @ 2013-11-18 12:51 UTC (permalink / raw)
  To: gdb-patches

[ Apologies for taking a long time to resubmit this.  The patch is
   essentially the same as before, but with fixes to address review
   comments, and made consistent with upstream changes in the
   meantime. ]

Hi,

This patch adds new observers, and corresponding Python events, for
various actions on an inferior: calling a function (by hand),
modifying registers or modifying memory.

A use case for these events is that by flagging these occurrences, it
can be noticed that the execution of the program is potentially
'dirty'.  (Hence why the notification doesn't carry information about
what was modified; for my purposes it's enough to know that /a/
change has happened.)

Nick


2013-11-18  Nick Bull  <nicholaspbull@gmail.com>

	* doc/observer.texi (inferior_call_pre, inferior_call_post
	register_change, memory_change): New observers.
	* infcall.c (call_function_by_hand): Notify observer before and
	after inferior call.
	* Makefile.in: add py-infcallevent.c / py-infcallevent.o.
	* python/py-event.h (inferior_altered_kind): New enum.
	(emit_inferior_altered_event): New prototype.
	* python/py-events.h (events_object): New inferior_altered
	registry.
	* python/py-evts.c (gdbpy_initialize_py_events): Add the
	inferior_altered registry.
	* python/py-infcallevent.c: New.
	* python/py-inferior.c (python_on_inferior_call_pre)
	(python_on_inferior_call_post, python_on_register_change)
	(python_on_memory_change): New functions.
	(gdbpy_initialize_inferior): Attach python handler to new
	observers.
	* python/python.c (_initialize_python): Initialize new events.
	* python/python-internal.h:
	(gdbpy_initialize_inferior_call_pre_event)
	(gdbpy_initialize_inferior_call_post_event)
	(gdbpy_initialize_register_change_event)
	(gdbpy_initialize_memory_change_event): New prototypes.
	* target.c (memory_xfer_partial_1, target_xfer_partial):
	Notify memory change observer.
	(target_store_registers): Notify register change observer.


diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 975edbf..7775bde 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -297,6 +297,7 @@ SUBDIR_PYTHON_OBS = \
  	py-function.o \
  	py-gdb-readline.o \
  	py-inferior.o \
+	py-infcallevent.o \
  	py-infthread.o \
  	py-lazy-string.o \
  	py-linetable.o \
@@ -333,6 +334,7 @@ SUBDIR_PYTHON_SRCS = \
  	python/py-function.c \
  	python/py-gdb-readline.c \
  	python/py-inferior.c \
+	python/py-infcallevent.c \
  	python/py-infthread.c \
  	python/py-lazy-string.c \
  	python/py-linetable.c \
@@ -2221,6 +2223,10 @@ py-inferior.o: $(srcdir)/python/py-inferior.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c
  	$(POSTCOMPILE)

+py-infcallevent.o: $(srcdir)/python/py-infcallevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infcallevent.c
+	$(POSTCOMPILE)
+
  py-infthread.o: $(srcdir)/python/py-infthread.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infthread.c
  	$(POSTCOMPILE)
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index f753965..ab15725 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -253,6 +253,22 @@ The trace state variable @var{tsv} is deleted.  If 
@var{tsv} is
  The trace state value @var{tsv} is modified.
  @end deftypefun

+@deftypefun void inferior_call_pre (void)
+An inferior function is about to be called.
+@end deftypefun
+
+@deftypefun void inferior_call_post (void)
+An inferior function has just been called.
+@end deftypefun
+
+@deftypefun void register_change (void)
+One or more registers in the inferior have been modified.
+@end deftypefun
+
+@deftypefun void memory_change (void)
+Memory in the inferior has been modified.
+@end deftypefun
+
  @deftypefun void test_notification (int @var{somearg})
  This observer is used for internal testing.  Do not use.
  See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 19af044..07dbbe3 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -36,6 +36,7 @@
  #include "ada-lang.h"
  #include "gdbthread.h"
  #include "exceptions.h"
+#include "observer.h"

  /* If we can't find a function's name from its address,
     we print this instead.  */
@@ -611,6 +612,8 @@ call_function_by_hand (struct value *function, int 
nargs, struct value **args)
        target_values_type = values_type;
      }

+  observer_notify_inferior_call_pre ();
+
    /* Determine the location of the breakpoint (and possibly other
       stuff) that the called function will return to.  The SPARC, for a
       function returning a structure or union, needs to make space for
@@ -844,6 +847,8 @@ call_function_by_hand (struct value *function, int 
nargs, struct value **args)
      e = run_inferior_call (tp, real_pc);
    }

+  observer_notify_inferior_call_post ();
+
    /* Rethrow an error if we got one trying to run the inferior.  */

    if (e.reason < 0)
diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h
index f0ff629..2f2da90 100644
--- a/gdb/python/py-event.h
+++ b/gdb/python/py-event.h
@@ -105,6 +105,15 @@ typedef struct
  extern int emit_continue_event (ptid_t ptid);
  extern int emit_exited_event (const LONGEST *exit_code, struct 
inferior *inf);

+typedef enum
+{
+  inferior_altered_pre_call,
+  inferior_altered_post_call,
+  inferior_altered_register_change,
+  inferior_altered_memory_change
+} inferior_altered_kind;
+
+extern int emit_inferior_altered_event (inferior_altered_kind kind);
  extern int evpy_emit_event (PyObject *event,
                              eventregistry_object *registry)
    CPYCHECKER_STEALS_REFERENCE_TO_ARG (1);
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
index 4ec3832..2f035c7 100644
--- a/gdb/python/py-events.h
+++ b/gdb/python/py-events.h
@@ -46,6 +46,7 @@ typedef struct
    eventregistry_object *cont;
    eventregistry_object *exited;
    eventregistry_object *new_objfile;
+  eventregistry_object *inferior_altered;

    PyObject *module;

diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c
index 971c520..f20974e 100644
--- a/gdb/python/py-evts.c
+++ b/gdb/python/py-evts.c
@@ -73,6 +73,10 @@ gdbpy_initialize_py_events (void)
    if (add_new_registry (&gdb_py_events.exited, "exited") < 0)
      return -1;

+  if (add_new_registry (&gdb_py_events.inferior_altered,
+			"inferior_altered") < 0)
+    return -1;
+
    if (add_new_registry (&gdb_py_events.new_objfile, "new_objfile") < 0)
      return -1;

diff --git a/gdb/python/py-infcallevent.c b/gdb/python/py-infcallevent.c
new file mode 100644
index 0000000..68e70f1
--- /dev/null
+++ b/gdb/python/py-infcallevent.c
@@ -0,0 +1,98 @@
+/* Python interface to inferior function events.
+
+   Copyright (C) 2009-2013 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-event.h"
+
+static PyTypeObject inferior_call_pre_event_object_type;
+static PyTypeObject inferior_call_post_event_object_type;
+static PyTypeObject register_change_event_object_type;
+static PyTypeObject memory_change_event_object_type;
+
+static PyObject *
+create_inferior_call_event_object (int flag)
+{
+  PyObject * event;
+
+  switch (flag)
+    {
+    case inferior_altered_pre_call:
+      event = create_event_object (&inferior_call_pre_event_object_type);
+      break;
+    case inferior_altered_post_call:
+      event = create_event_object (&inferior_call_post_event_object_type);
+      break;
+    case inferior_altered_register_change:
+      event = create_event_object (&register_change_event_object_type);
+      break;
+    case inferior_altered_memory_change:
+      event = create_event_object (&memory_change_event_object_type);
+      break;
+    default:
+      return NULL;
+    }
+
+  return event;
+}
+
+/* Callback function which notifies observers when a continue event occurs.
+   This function will create a new Python continue event object.
+   Return -1 if emit fails.  */
+
+int
+emit_inferior_altered_event (inferior_altered_kind flag)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.inferior_altered))
+    return 0;
+
+  event = create_inferior_call_event_object (flag);
+  if (event != NULL)
+    return evpy_emit_event (event, gdb_py_events.inferior_altered);
+  return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_pre,
+                      "gdb.InferiorCallPreEvent",
+                      "InferiorCallPreEvent",
+                      "GDB inferior function pre-call event object",
+                      event_object_type,
+                      static);
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_post,
+                      "gdb.InferiorCallPostEvent",
+                      "InferiorCallPostEvent",
+                      "GDB inferior function post-call event object",
+                      event_object_type,
+                      static);
+
+GDBPY_NEW_EVENT_TYPE (register_change,
+                      "gdb.RegisterChangeEvent",
+                      "RegisterChangeEvent",
+                      "GDB register change event object",
+                      event_object_type,
+                      static);
+
+GDBPY_NEW_EVENT_TYPE (memory_change,
+                      "gdb.MemoryChangeEvent",
+                      "MemoryChangeEvent",
+                      "GDB memory change event object",
+                      event_object_type,
+                      static);
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index ed49290..4386f83 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -118,6 +118,58 @@ python_on_resume (ptid_t ptid)
  }

  static void
+python_on_inferior_call_pre (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_pre_call) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_inferior_call_post (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_post_call) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_register_change (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_register_change) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_memory_change (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_altered_event (inferior_altered_memory_change) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
  python_inferior_exit (struct inferior *inf)
  {
    struct cleanup *cleanup;
@@ -794,6 +846,10 @@ gdbpy_initialize_inferior (void)
    observer_attach_thread_exit (delete_thread_object);
    observer_attach_normal_stop (python_on_normal_stop);
    observer_attach_target_resumed (python_on_resume);
+  observer_attach_inferior_call_pre (python_on_inferior_call_pre);
+  observer_attach_inferior_call_post (python_on_inferior_call_post);
+  observer_attach_register_change (python_on_register_change);
+  observer_attach_memory_change (python_on_memory_change);
    observer_attach_inferior_exit (python_inferior_exit);
    observer_attach_new_objfile (python_new_objfile);

diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 7d8c4ad..6c800a3 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -393,6 +393,14 @@ int gdbpy_initialize_breakpoint_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_continue_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_pre_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_post_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_register_change_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_memory_change_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_exited_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_thread_event (void)
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 7cdf8a7..4942414 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1684,6 +1684,10 @@ message == an error message without a stack will 
be printed."),
        || gdbpy_initialize_signal_event () < 0
        || gdbpy_initialize_breakpoint_event () < 0
        || gdbpy_initialize_continue_event () < 0
+      || gdbpy_initialize_inferior_call_pre_event () < 0
+      || gdbpy_initialize_inferior_call_post_event () < 0
+      || gdbpy_initialize_register_change_event () < 0
+      || gdbpy_initialize_memory_change_event () < 0
        || gdbpy_initialize_exited_event () < 0
        || gdbpy_initialize_thread_event () < 0
        || gdbpy_initialize_new_objfile_event ()  < 0
diff --git a/gdb/target.c b/gdb/target.c
index 86a5572..3768a61 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -43,6 +43,7 @@
  #include "tracepoint.h"
  #include "gdb/fileio.h"
  #include "agent.h"
+#include "observer.h"

  static void target_info (char *, int);

@@ -1616,6 +1617,8 @@ memory_xfer_partial_1 (struct target_ops *ops, 
enum target_object object,

    do
      {
+      if (writebuf != NULL)
+	observer_notify_memory_change ();
        res = ops->to_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL,
  				  readbuf, writebuf, memaddr, reg_len);
        if (res > 0)
@@ -1745,6 +1748,8 @@ target_xfer_partial (struct target_ops *ops,
        if (raw_object == TARGET_OBJECT_RAW_MEMORY)
  	raw_object = TARGET_OBJECT_MEMORY;

+      if (writebuf != NULL)
+	observer_notify_memory_change ();
        retval = ops->to_xfer_partial (ops, raw_object, annex, readbuf,
  				     writebuf, offset, len);
      }
@@ -3992,6 +3997,7 @@ target_store_registers (struct regcache *regcache, 
int regno)
      {
        if (t->to_store_registers != NULL)
  	{
+	  observer_notify_register_change ();
  	  t->to_store_registers (t, regcache, regno);
  	  if (targetdebug)
  	    {

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Events when inferior is modified
  2013-11-18 12:51     ` [PATCH v2] " Nick Bull
@ 2013-11-18 15:15       ` Eli Zaretskii
  2013-11-25 11:50       ` Phil Muldoon
  1 sibling, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2013-11-18 15:15 UTC (permalink / raw)
  To: Nick Bull; +Cc: gdb-patches

> Date: Mon, 18 Nov 2013 12:39:31 +0000
> From: Nick Bull <nicholaspbull@gmail.com>
> 
> This patch adds new observers, and corresponding Python events, for
> various actions on an inferior: calling a function (by hand),
> modifying registers or modifying memory.
> 
> A use case for these events is that by flagging these occurrences, it
> can be noticed that the execution of the program is potentially
> 'dirty'.  (Hence why the notification doesn't carry information about
> what was modified; for my purposes it's enough to know that /a/
> change has happened.)
> 
> Nick
> 
> 
> 2013-11-18  Nick Bull  <nicholaspbull@gmail.com>
> 
> 	* doc/observer.texi (inferior_call_pre, inferior_call_post
> 	register_change, memory_change): New observers.

The observer.texi part is OK.

Thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Events when inferior is modified
  2013-11-18 12:51     ` [PATCH v2] " Nick Bull
  2013-11-18 15:15       ` Eli Zaretskii
@ 2013-11-25 11:50       ` Phil Muldoon
  2013-12-01 15:23         ` Nick Bull
  1 sibling, 1 reply; 12+ messages in thread
From: Phil Muldoon @ 2013-11-25 11:50 UTC (permalink / raw)
  To: Nick Bull, gdb-patches

On 18/11/13 12:39, Nick Bull wrote:

> This patch adds new observers, and corresponding Python events, for
> various actions on an inferior: calling a function (by hand),
> modifying registers or modifying memory.

Thanks just a few nits and some questions. I did not see tests for
these, and also, documentation?  In any case, both are needed.

Cheers,

Phil


> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 975edbf..7775bde 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -297,6 +297,7 @@ SUBDIR_PYTHON_OBS = \
>      py-function.o \
>      py-gdb-readline.o \
>      py-inferior.o \
> +    py-infcallevent.o \

I'd appreciate if you kept the alphabetical ordering here.

>      py-infthread.o \
>      py-lazy-string.o \
>      py-linetable.o \
> @@ -333,6 +334,7 @@ SUBDIR_PYTHON_SRCS = \
>      python/py-function.c \
>      python/py-gdb-readline.c \
>      python/py-inferior.c \
> +    python/py-infcallevent.c \

And here.

> +py-infcallevent.o: $(srcdir)/python/py-infcallevent.c
> +    $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infcallevent.c
> +    $(POSTCOMPILE)
> +
>  py-infthread.o: $(srcdir)/python/py-infthread.c
>      $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infthread.c
>      $(POSTCOMPILE)

Ditto.

> diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
> index f753965..ab15725 100644
> --- a/gdb/doc/observer.texi
> +++ b/gdb/doc/observer.texi
> @@ -253,6 +253,22 @@ The trace state variable @var{tsv} is deleted.  If @var{tsv} is

> diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h
> index f0ff629..2f2da90 100644
> --- a/gdb/python/py-event.h
> +++ b/gdb/python/py-event.h
> @@ -105,6 +105,15 @@ typedef struct
>  extern int emit_continue_event (ptid_t ptid);
>  extern int emit_exited_event (const LONGEST *exit_code, struct inferior *inf);
> 
> +typedef enum
> +{
> +  inferior_altered_pre_call,
> +  inferior_altered_post_call,
> +  inferior_altered_register_change,
> +  inferior_altered_memory_change
> +} inferior_altered_kind;
> +

I'm kind of on the fence about the inferior_altered naming.  A lot of
things can alter an inferior which would make this a very broad event
category. Like single stepping I would consider altering the inferior.

With your memory changed event, would it fire on a breakpoint
insertion? GDB does a lot of installing/uninstalling of breakpoints
behind the scene in the inferior.

Also, it would be super if we could split up the register
and memory events with read/write events.  What do you think?


> diff --git a/gdb/python/py-infcallevent.c b/gdb/python/py-infcallevent.c
> new file mode 100644
> index 0000000..68e70f1
> --- /dev/null
> +++ b/gdb/python/py-infcallevent.c
> @@ -0,0 +1,98 @@
> +/* Python interface to inferior function events.
> +
> +   Copyright (C) 2009-2013 Free Software Foundation, Inc.
> +

If this is a new file, probably just 2013.


> +/* Callback function which notifies observers when a continue event occurs.
> +   This function will create a new Python continue event object.
> +   Return -1 if emit fails.  */
> +

This comment attached to the function below  looks pasted from another function?

> +int
> +emit_inferior_altered_event (inferior_altered_kind flag)
> +{
> +  PyObject *event;
> +
> +  if (evregpy_no_listeners_p (gdb_py_events.inferior_altered))
> +    return 0;
> +
> +  event = create_inferior_call_event_object (flag);
> +  if (event != NULL)
> +    return evpy_emit_event (event, gdb_py_events.inferior_altered);
> +  return -1;
> +}
> +


Cheers,

Phil

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Events when inferior is modified
  2013-11-25 11:50       ` Phil Muldoon
@ 2013-12-01 15:23         ` Nick Bull
  2013-12-09 17:48           ` Nick Bull
  0 siblings, 1 reply; 12+ messages in thread
From: Nick Bull @ 2013-12-01 15:23 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gdb-patches

On 25 November 2013 09:48, Phil Muldoon <pmuldoon@redhat.com> wrote:
> On 18/11/13 12:39, Nick Bull wrote:
>
>> This patch adds new observers, and corresponding Python events, for
>> various actions on an inferior: calling a function (by hand),
>> modifying registers or modifying memory.
>
> Thanks just a few nits and some questions. I did not see tests for
> these, and also, documentation?  In any case, both are needed.

Phil,

Thanks for looking at this. All the nits make sense, and I'll fix them and
add tests.

> I'm kind of on the fence about the inferior_altered naming.  A lot of
> things can alter an inferior which would make this a very broad event
> category. Like single stepping I would consider altering the inferior.
>
> With your memory changed event, would it fire on a breakpoint
> insertion? GDB does a lot of installing/uninstalling of breakpoints
> behind the scene in the inferior.
>
> Also, it would be super if we could split up the register
> and memory events with read/write events.  What do you think?

I'm going to revise the memory change event to use the existing
memory_changed observer, which I had overlooked because it doesn't
have a Python event. It's closer to what I wanted anyway, which is
to track only modifications to the program that are made explicitly by
the GDB user.

Given this I would give it a separate MemoryChangedEvent type so
that the name matches the corresponding observer. Then the other
events would be RegisterChanged and InferiorCall.

I suppose we might want to somehow distinguish that these events are
about explicit changes to program state rather than the 'behind-the-scenes'
work that GDB does, in case we ever want to create events of the
latter type. But I don't have any great suggestions for names just now.

Nick

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Events when inferior is modified
  2013-12-01 15:23         ` Nick Bull
@ 2013-12-09 17:48           ` Nick Bull
  2013-12-10 11:04             ` Phil Muldoon
  0 siblings, 1 reply; 12+ messages in thread
From: Nick Bull @ 2013-12-09 17:48 UTC (permalink / raw)
  To: gdb-patches

On 25 November 2013 09:48, Phil Muldoon <pmuldoon@redhat.com> wrote:
 > On 18/11/13 12:39, Nick Bull wrote:
 >
 >> This patch adds new observers, and corresponding Python events, for
 >> various actions on an inferior: calling a function (by hand),
 >> modifying registers or modifying memory.
 >
 > Thanks just a few nits and some questions. I did not see tests for
 > these, and also, documentation?  In any case, both are needed.

Now with the nits addressed, rejigging to use the existing
memory_changed observer, some test coverage and documentation.
make check ran without regressions.

Nick

gdb/ChangeLog

2013-12-09  Nick Bull  <nicholaspbull@gmail.com>

         * Makefile.in: add py-infcallevent.c / py-infcallevent.o.
         * doc/observer.texi (inferior_call_pre, inferior_call_post
         register_changed): New observers.
         * infcall.c (call_function_by_hand): Notify observer before and
         after inferior call.
         * python/py-event.h (inferior_call_kind): New enum.
         (emit_inferior_call_event): New prototype.
         (emit_register_changed_event): New prototype.
         (emit_memory_changed_event): New prototype.
         * python/py-events.h (events_object): New registries
	inferior_call, memory_changed and register_changed.
         * python/py-evts.c (gdbpy_initialize_py_events): Add the
         inferior_call, memory_changed and register_changed registries.
         * python/py-infcallevent.c: New.
         * python/py-inferior.c (python_on_inferior_call_pre)
         (python_on_inferior_call_post, python_on_register_change)
         (python_on_memory_change): New functions.
         (gdbpy_initialize_inferior): Attach python handler to new
         observers.
         * python/python-internal.h:
         (gdbpy_initialize_inferior_call_pre_event)
         (gdbpy_initialize_inferior_call_post_event)
         (gdbpy_initialize_register_changed_event)
         (gdbpy_initialize_memory_changed_event): New prototypes.
         * python/python.c (_initialize_python): Initialize new events.
	* valops.c (value_assign): Notify register_changed observer.

gdb/testsuite/ChangeLog

2013-12-09  Nick Bull  <nicholaspbull@gmail.com>

	* gdb.python/py-events.py (inferior_fn_handler): New.
	(register_changed_handler, memory_changed_handler): New.
	(test_events.invoke): Register new handlers.
	* gdb.python/py-events.exp: Add tests for inferior call,
	memory_changed and register_changed events.


diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index be30dfd..40e9875 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -296,6 +296,7 @@ SUBDIR_PYTHON_OBS = \
  	py-framefilter.o \
  	py-function.o \
  	py-gdb-readline.o \
+	py-infcallevent.o \
  	py-inferior.o \
  	py-infthread.o \
  	py-lazy-string.o \
@@ -332,6 +333,7 @@ SUBDIR_PYTHON_SRCS = \
  	python/py-framefilter.c \
  	python/py-function.c \
  	python/py-gdb-readline.c \
+	python/py-infcallevent.c \
  	python/py-inferior.c \
  	python/py-infthread.c \
  	python/py-lazy-string.c \
@@ -2217,6 +2219,10 @@ py-gdb-readline.o: $(srcdir)/python/py-gdb-readline.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-gdb-readline.c
  	$(POSTCOMPILE)

+py-infcallevent.o: $(srcdir)/python/py-infcallevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infcallevent.c
+	$(POSTCOMPILE)
+
  py-inferior.o: $(srcdir)/python/py-inferior.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c
  	$(POSTCOMPILE)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 87d5145..f4adef1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -25808,6 +25808,30 @@ A reference to the object file 
(@code{gdb.Objfile}) which has been loaded.
  @xref{Objfiles In Python}, for details of the @code{gdb.Objfile} object.
  @end defvar

+@item inferior_call_pre
+Emits @code{gdb.InferiorCallPreEvent} which indicates that a function in
+the inferior is about to be called.
+
+@item inferior_call_post
+Emits @code{gdb.InferiorCallPostEvent} which indicates that a function in
+the inferior has returned.
+
+@item memory_changed
+Emits @code{gdb.MemoryChangedEvent} which indicates that the memory of the
+inferior has been modified by the GDB user, for instance via a command like
+@code{set *addr = value}.  The event has the following attributes:
+
+@defvar MemoryChangedEvent.address
+The start address of the changed region.
+@end defvar
+@defvar MemoryChangedEvent.length
+Length in bytes of the changed region.
+@end defvar
+
+@item register_changed
+Emits @code{gdb.RegisterChangedEvent} which indicates that a register 
in the
+inferior has been modified by the GDB user.
+
  @end table

  @node Threads In Python
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index f753965..c20fec5 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -253,6 +253,18 @@ The trace state variable @var{tsv} is deleted.  If 
@var{tsv} is
  The trace state value @var{tsv} is modified.
  @end deftypefun

+@deftypefun void inferior_call_pre (void)
+An inferior function is about to be called.
+@end deftypefun
+
+@deftypefun void inferior_call_post (void)
+An inferior function has just been called.
+@end deftypefun
+
+@deftypefun void register_changed (void)
+One or more registers in the inferior have been modified.
+@end deftypefun
+
  @deftypefun void test_notification (int @var{somearg})
  This observer is used for internal testing.  Do not use.
  See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 212997f..7c1a5ae 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -36,6 +36,7 @@
  #include "ada-lang.h"
  #include "gdbthread.h"
  #include "exceptions.h"
+#include "observer.h"

  /* If we can't find a function's name from its address,
     we print this instead.  */
@@ -611,6 +612,8 @@ call_function_by_hand (struct value *function, int 
nargs, struct value **args)
        target_values_type = values_type;
      }

+  observer_notify_inferior_call_pre ();
+
    /* Determine the location of the breakpoint (and possibly other
       stuff) that the called function will return to.  The SPARC, for a
       function returning a structure or union, needs to make space for
@@ -844,6 +847,8 @@ call_function_by_hand (struct value *function, int 
nargs, struct value **args)
      e = run_inferior_call (tp, real_pc);
    }

+  observer_notify_inferior_call_post ();
+
    /* Rethrow an error if we got one trying to run the inferior.  */

    if (e.reason < 0)
diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h
index f0ff629..c17079d 100644
--- a/gdb/python/py-event.h
+++ b/gdb/python/py-event.h
@@ -105,6 +105,15 @@ typedef struct
  extern int emit_continue_event (ptid_t ptid);
  extern int emit_exited_event (const LONGEST *exit_code, struct 
inferior *inf);

+typedef enum
+{
+  inferior_call_pre,
+  inferior_call_post,
+} inferior_call_kind;
+
+extern int emit_inferior_call_event (inferior_call_kind kind);
+extern int emit_register_changed_event (void);
+extern int emit_memory_changed_event (CORE_ADDR addr, ssize_t len);
  extern int evpy_emit_event (PyObject *event,
                              eventregistry_object *registry)
    CPYCHECKER_STEALS_REFERENCE_TO_ARG (1);
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
index 4ec3832..d158211 100644
--- a/gdb/python/py-events.h
+++ b/gdb/python/py-events.h
@@ -46,6 +46,9 @@ typedef struct
    eventregistry_object *cont;
    eventregistry_object *exited;
    eventregistry_object *new_objfile;
+  eventregistry_object *inferior_call;
+  eventregistry_object *memory_changed;
+  eventregistry_object *register_changed;

    PyObject *module;

diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c
index 1ff3022..76f923b 100644
--- a/gdb/python/py-evts.c
+++ b/gdb/python/py-evts.c
@@ -73,6 +73,18 @@ gdbpy_initialize_py_events (void)
    if (add_new_registry (&gdb_py_events.exited, "exited") < 0)
      return -1;

+  if (add_new_registry (&gdb_py_events.inferior_call,
+			"inferior_call") < 0)
+    return -1;
+
+  if (add_new_registry (&gdb_py_events.memory_changed,
+			"memory_changed") < 0)
+    return -1;
+
+  if (add_new_registry (&gdb_py_events.register_changed,
+			"register_changed") < 0)
+    return -1;
+
    if (add_new_registry (&gdb_py_events.new_objfile, "new_objfile") < 0)
      return -1;

diff --git a/gdb/python/py-infcallevent.c b/gdb/python/py-infcallevent.c
new file mode 100644
index 0000000..4c8505d
--- /dev/null
+++ b/gdb/python/py-infcallevent.c
@@ -0,0 +1,172 @@
+/* Python interface to inferior function events.
+
+   Copyright (C) 2013 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-event.h"
+
+static PyTypeObject inferior_call_pre_event_object_type;
+static PyTypeObject inferior_call_post_event_object_type;
+static PyTypeObject register_changed_event_object_type;
+static PyTypeObject memory_changed_event_object_type;
+
+static PyObject *
+create_inferior_call_event_object (int flag)
+{
+  PyObject * event;
+
+  switch (flag)
+    {
+    case inferior_call_pre:
+      event = create_event_object (&inferior_call_pre_event_object_type);
+      break;
+    case inferior_call_post:
+      event = create_event_object (&inferior_call_post_event_object_type);
+      break;
+    default:
+      return NULL;
+    }
+
+  return event;
+}
+
+static PyObject *
+create_register_changed_event_object (void)
+{
+  PyObject * event;
+
+  event = create_event_object (&register_changed_event_object_type);
+
+  return event;
+}
+
+static PyObject *
+create_memory_changed_event_object (CORE_ADDR addr, ssize_t len)
+{
+  PyObject * event;
+  PyObject *addr_obj = NULL;
+  PyObject *len_obj = NULL;
+  int failed;
+
+  event = create_event_object (&memory_changed_event_object_type);
+
+  if (!event)
+    goto fail;
+
+  addr_obj = PyLong_FromLongLong (addr);
+  if (addr_obj == NULL)
+    goto fail;
+
+  failed = evpy_add_attribute (event, "address", addr_obj) < 0;
+  Py_DECREF (addr_obj);
+  if (failed)
+    goto fail;
+
+  len_obj = PyLong_FromLong (len);
+  if (len_obj == NULL)
+    goto fail;
+
+  failed = evpy_add_attribute (event, "length", len_obj) < 0;
+  Py_DECREF (len_obj);
+  if (failed)
+    goto fail;
+
+  return event;
+
+ fail:
+  Py_XDECREF (addr_obj);
+  Py_XDECREF (event);
+
+  return NULL;
+}
+
+/* Callback function which notifies observers when an event occurs which
+   calls a function in the inferior.
+   This function will create a new Python inferior-call event object.
+   Return -1 if emit fails.  */
+
+int
+emit_inferior_call_event (inferior_call_kind flag)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.inferior_call))
+    return 0;
+
+  event = create_inferior_call_event_object (flag);
+  if (event != NULL)
+    return evpy_emit_event (event, gdb_py_events.inferior_call);
+  return -1;
+}
+
+int
+emit_memory_changed_event (CORE_ADDR addr, ssize_t len)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.memory_changed))
+    return 0;
+
+  event = create_memory_changed_event_object (addr, len);
+  if (event != NULL)
+    return evpy_emit_event (event, gdb_py_events.memory_changed);
+  return -1;
+}
+
+int
+emit_register_changed_event (void)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.register_changed))
+    return 0;
+
+  event = create_register_changed_event_object ();
+  if (event != NULL)
+    return evpy_emit_event (event, gdb_py_events.register_changed);
+  return -1;
+}
+
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_pre,
+		      "gdb.InferiorCallPreEvent",
+		      "InferiorCallPreEvent",
+		      "GDB inferior function pre-call event object",
+		      event_object_type,
+		      static);
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_post,
+		      "gdb.InferiorCallPostEvent",
+		      "InferiorCallPostEvent",
+		      "GDB inferior function post-call event object",
+		      event_object_type,
+		      static);
+
+GDBPY_NEW_EVENT_TYPE (register_changed,
+		      "gdb.RegisterChangedEvent",
+		      "RegisterChangedEvent",
+		      "GDB register change event object",
+		      event_object_type,
+		      static);
+
+GDBPY_NEW_EVENT_TYPE (memory_changed,
+		      "gdb.MemoryChangedEvent",
+		      "MemoryChangedEvent",
+		      "GDB memory change event object",
+		      event_object_type,
+		      static);
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 1a1b774..28f6f7d 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -118,6 +118,58 @@ python_on_resume (ptid_t ptid)
  }

  static void
+python_on_inferior_call_pre (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_call_event (inferior_call_pre) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_inferior_call_post (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_call_event (inferior_call_post) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_memory_change (struct inferior *inferior, CORE_ADDR addr, 
ssize_t len, const bfd_byte *data)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_memory_changed_event (addr, len) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_register_change (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_register_changed_event () < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
  python_inferior_exit (struct inferior *inf)
  {
    struct cleanup *cleanup;
@@ -794,6 +846,10 @@ gdbpy_initialize_inferior (void)
    observer_attach_thread_exit (delete_thread_object);
    observer_attach_normal_stop (python_on_normal_stop);
    observer_attach_target_resumed (python_on_resume);
+  observer_attach_inferior_call_pre (python_on_inferior_call_pre);
+  observer_attach_inferior_call_post (python_on_inferior_call_post);
+  observer_attach_memory_changed (python_on_memory_change);
+  observer_attach_register_changed (python_on_register_change);
    observer_attach_inferior_exit (python_inferior_exit);
    observer_attach_new_objfile (python_new_objfile);

diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 125670e..8eba303 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -393,6 +393,14 @@ int gdbpy_initialize_breakpoint_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_continue_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_pre_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_post_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_register_changed_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_memory_changed_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_exited_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_thread_event (void)
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 1873936..85cbefa 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1684,6 +1684,10 @@ message == an error message without a stack will 
be printed."),
        || gdbpy_initialize_signal_event () < 0
        || gdbpy_initialize_breakpoint_event () < 0
        || gdbpy_initialize_continue_event () < 0
+      || gdbpy_initialize_inferior_call_pre_event () < 0
+      || gdbpy_initialize_inferior_call_post_event () < 0
+      || gdbpy_initialize_register_changed_event () < 0
+      || gdbpy_initialize_memory_changed_event () < 0
        || gdbpy_initialize_exited_event () < 0
        || gdbpy_initialize_thread_event () < 0
        || gdbpy_initialize_new_objfile_event ()  < 0
diff --git a/gdb/testsuite/gdb.python/py-events.exp 
b/gdb/testsuite/gdb.python/py-events.exp
index 390a2ba..1027866 100644
--- a/gdb/testsuite/gdb.python/py-events.exp
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -79,6 +79,26 @@ all threads stopped"

  delete_breakpoints

+# Test inferior call events
+gdb_test "call do_nothing()" ".*event type: pre-call.*
+.*event type: continue.*
+.*event type: post-call.*"
+
+# Test register changed event
+gdb_test_no_output {set $old_sp = $sp}
+gdb_test {set $sp = 0} ".*event type: register-changed.*"
+gdb_test {set $sp = 1} ".*event type: register-changed.*"
+gdb_test {set $sp = $old_sp} ".*event type: register-changed.*"
+
+# Test memory changed event
+gdb_test_no_output {set $saved = *(int*) $sp}
+gdb_test {set *(int*) $sp = 0} ".*event type: memory-changed.*
+.*address: .*
+.*length: .*"
+gdb_test {set *(int*) $sp = $saved} ".*event type: memory-changed.*
+.*address: .*
+.*length: .*"
+
  #test exited event.
  gdb_test "continue" ".*event type: continue.*
  .*event type: exit.*
diff --git a/gdb/testsuite/gdb.python/py-events.py 
b/gdb/testsuite/gdb.python/py-events.py
index 7601ca1..5586961 100644
--- a/gdb/testsuite/gdb.python/py-events.py
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -57,6 +57,25 @@ def new_objfile_handler (event):
      print ("event type: new_objfile")
      print ("new objfile name: %s" % (event.new_objfile.filename))

+def inferior_fn_handler (event):
+    if (isinstance (event, gdb.InferiorCallPreEvent)):
+        print ("event type: pre-call")
+    elif (isinstance (event, gdb.InferiorCallPostEvent)):
+        print ("event type: post-call")
+    else:
+        assert False
+
+def register_changed_handler (event):
+    assert (isinstance (event, gdb.RegisterChangedEvent))
+    print ("event type: register-changed")
+
+def memory_changed_handler (event):
+    assert (isinstance (event, gdb.MemoryChangedEvent))
+    print ("event type: memory-changed")
+    print ("address: %s" % (event.address))
+    print ("length: %s" % (event.length))
+
+
  class test_events (gdb.Command):
      """Test events."""

@@ -68,6 +87,9 @@ class test_events (gdb.Command):
          gdb.events.stop.connect (breakpoint_stop_handler)
          gdb.events.exited.connect (exit_handler)
          gdb.events.cont.connect (continue_handler)
+        gdb.events.inferior_call.connect(inferior_fn_handler)
+        gdb.events.memory_changed.connect(memory_changed_handler)
+        gdb.events.register_changed.connect(register_changed_handler)
          print ("Event testers registered.")

  test_events ()
diff --git a/gdb/valops.c b/gdb/valops.c
index d43c758..7c90b4e 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1210,6 +1210,7 @@ value_assign (struct value *toval, struct value 
*fromval)
  	      }
  	  }

+	observer_notify_register_changed ();
  	if (deprecated_register_changed_hook)
  	  deprecated_register_changed_hook (-1);
  	break;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Events when inferior is modified
  2013-12-09 17:48           ` Nick Bull
@ 2013-12-10 11:04             ` Phil Muldoon
  2013-12-12 17:12               ` Nick Bull
  0 siblings, 1 reply; 12+ messages in thread
From: Phil Muldoon @ 2013-12-10 11:04 UTC (permalink / raw)
  To: Nick Bull, gdb-patches

On 09/12/13 17:47, Nick Bull wrote:
> On 25 November 2013 09:48, Phil Muldoon <pmuldoon@redhat.com> wrote:
> 
> Now with the nits addressed, rejigging to use the existing
> memory_changed observer, some test coverage and documentation.
> make check ran without regressions.

Thanks.


>         (emit_memory_changed_event): New prototype.
>         * python/py-events.h (events_object): New registries
>     inferior_call, memory_changed and register_changed.

Might be a tab or space issue, or even a mailer issue, but indention
looks incorrect  here.

> +Emits @code{gdb.MemoryChangedEvent} which indicates that the memory of the
> +inferior has been modified by the GDB user, for instance via a command like
> +@code{set *addr = value}.  The event has the following attributes:
> +
> +@defvar MemoryChangedEvent.address
> +The start address of the changed region.
> +@end defvar
> +@defvar MemoryChangedEvent.length
> +Length in bytes of the changed region.
> +@end defvar
> +
> +@item register_changed
> +Emits @code{gdb.RegisterChangedEvent} which indicates that a register in the
> +inferior has been modified by the GDB user.

I apologize for not catching this initially, but is it possible to
have what registers changed? I suppose you could scan beforehand, and
scan after.  But it would be a better API if registers' names were
included as an attribute. If this requires major surgery though, we
can look again at the original API for inclusion. Also it is not clear
from the tests. but would this callback trigger on frame change (either
through execution or the user selecting a different frame)?  Registers
are swapped in and out as each frame changes.


> +  PyObject * event;
> +  PyObject *addr_obj = NULL;
> +  PyObject *len_obj = NULL;
> +  int failed;
> +
> +  event = create_event_object (&memory_changed_event_object_type);
> +
> +  if (!event)
> +    goto fail;

This is a fairly new rule, but for all new submissions any pointer
expression has to be explicitly written.  So, rewrite to:

if (event == NULL)

> +  addr_obj = PyLong_FromLongLong (addr);
> +  if (addr_obj == NULL)
> +    goto fail;
> +
> +  failed = evpy_add_attribute (event, "address", addr_obj) < 0;
> +  Py_DECREF (addr_obj);
> +  if (failed)
> +    goto fail;

I believe there is a problem here in the failed branch.  You have
already decremented the reference count of addr_obj once, and in the
fail goto you do it again.  In these cases of conditional cleanups I
find the make_cleanup/do_cleanup kind of logic easier to write. If you
believe you will be saved by the XDECREF call not working on NULL,
remember that Py_DECREF just decrements the reference count of the
object, and nothing else.  So if the Python GC collected that object,
any further writes to that address would result in a possible sigsegv.

> +  len_obj = PyLong_FromLong (len);
> +  if (len_obj == NULL)
> +    goto fail;

Same here with addr_obj being decremented twice,

> +  failed = evpy_add_attribute (event, "length", len_obj) < 0;
> +  Py_DECREF (len_obj);
> +  if (failed)
> +    goto fail;

Here too.


> +# Test register changed event
> +gdb_test_no_output {set $old_sp = $sp}
> +gdb_test {set $sp = 0} ".*event type: register-changed.*"
> +gdb_test {set $sp = 1} ".*event type: register-changed.*"
> +gdb_test {set $sp = $old_sp} ".*event type: register-changed.*"

We need some tests to see if register changes initiated by frame
selection or program execution trigger the event mechanism.

> +# Test memory changed event
> +gdb_test_no_output {set $saved = *(int*) $sp}
> +gdb_test {set *(int*) $sp = 0} ".*event type: memory-changed.*
> +.*address: .*
> +.*length: .*"
> +gdb_test {set *(int*) $sp = $saved} ".*event type: memory-changed.*
> +.*address: .*
> +.*length: .*"

We need some tests here to test whether breakpoint hit, creation and
deletion trigger these (I don't think they should, but let's
create a barrier test to prove it).

Looking very good in general. I look forward to the next revision!

Cheers,

Phil

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Events when inferior is modified
  2013-12-10 11:04             ` Phil Muldoon
@ 2013-12-12 17:12               ` Nick Bull
  2013-12-21 21:26                 ` Nick Bull
  0 siblings, 1 reply; 12+ messages in thread
From: Nick Bull @ 2013-12-12 17:12 UTC (permalink / raw)
  To: gdb-patches, Phil Muldoon

On 10/12/13 11:04, Phil Muldoon wrote:
>
> Might be a tab or space issue, or even a mailer issue, but indention
> looks incorrect  here.

Editor issue, in fact. Thanks for spotting.

> I apologize for not catching this initially, but is it possible to
> have what registers changed? I suppose you could scan beforehand, and
> scan after.  But it would be a better API if registers' names were
> included as an attribute. If this requires major surgery though, we
> can look again at the original API for inclusion. Also it is not clear
> from the tests. but would this callback trigger on frame change (either
> through execution or the user selecting a different frame)?  Registers
> are swapped in and out as each frame changes.

Added.

I've chosen to to pass through the register identity numerically rather
than by name, on the basis of not doing a conversion until it's known
to be needed. As far as I can see there's no precedent for a Python API
that passes register names or numbers. Arguably the gdb.Architecture
object is the right place to supply a list of register names, should
Python code want to convert register numbers into human-readable form.

The observer is intended to trigger only when the user chooses to
change the state of the debugged program, outside of normal execution.
So it won't trigger on frame change. This is equivalent to the
behaviour of the existing memory_changed observer, which doesn't
trigger due to setting breakpoints, for example.

> This is a fairly new rule, but for all new submissions any pointer
> expression has to be explicitly written.  So, rewrite to:
 >
 > if (event == NULL)

Done.

> I believe there is a problem here in the failed branch.  You have
> already decremented the reference count of addr_obj once, and in the
> fail goto you do it again.  In these cases of conditional cleanups I
> find the make_cleanup/do_cleanup kind of logic easier to write. If you
> believe you will be saved by the XDECREF call not working on NULL,
> remember that Py_DECREF just decrements the reference count of the
> object, and nothing else.  So if the Python GC collected that object,
> any further writes to that address would result in a possible sigsegv.

Rewritten using cleanups.

> We need some tests to see if register changes initiated by frame
> selection or program execution trigger the event mechanism.

Done (as per above, they don't).

> We need some tests here to test whether breakpoint hit, creation and
> deletion trigger these (I don't think they should, but let's
> create a barrier test to prove it).

Also done.

Nick

gdb/ChangeLog

2013-12-09  Nick Bull  <nicholaspbull@gmail.com>

	* Makefile.in: add py-infcallevent.c / py-infcallevent.o.
	* doc/observer.texi (inferior_call_pre, inferior_call_post)
	(memory_changed, register_changed): New observers.
	* infcall.c (call_function_by_hand): Notify observer before and
	after inferior call.
	* python/py-event.h (inferior_call_kind): New enum.
	(emit_inferior_call_event): New prototype.
	(emit_register_changed_event): New prototype.
	(emit_memory_changed_event): New prototype.
	* python/py-events.h (events_object): New registries
	inferior_call, memory_changed and register_changed.
	* python/py-evts.c (gdbpy_initialize_py_events): Add the
	inferior_call, memory_changed and register_changed registries.
	* python/py-infcallevent.c: New.
	* python/py-inferior.c (python_on_inferior_call_pre)
	(python_on_inferior_call_post, python_on_register_change)
	(python_on_memory_change): New functions.
	(gdbpy_initialize_inferior): Attach python handler to new
	observers.
	* python/python-internal.h:
	(gdbpy_initialize_inferior_call_pre_event)
	(gdbpy_initialize_inferior_call_post_event)
	(gdbpy_initialize_register_changed_event)
	(gdbpy_initialize_memory_changed_event): New prototypes.
	* python/python.c (_initialize_python): Initialize new events.
	* valops.c (value_assign): Notify register_changed observer.

gdb/testsuite/ChangeLog

2013-12-09  Nick Bull  <nicholaspbull@gmail.com>

	* gdb.python/py-events.py (inferior_fn_handler): New.
	(register_changed_handler, memory_changed_handler): New.
	(test_events.invoke): Register new handlers.
	* gdb.python/py-events.exp: Add tests for inferior call,
	memory_changed and register_changed events.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index be30dfd..40e9875 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -296,6 +296,7 @@ SUBDIR_PYTHON_OBS = \
  	py-framefilter.o \
  	py-function.o \
  	py-gdb-readline.o \
+	py-infcallevent.o \
  	py-inferior.o \
  	py-infthread.o \
  	py-lazy-string.o \
@@ -332,6 +333,7 @@ SUBDIR_PYTHON_SRCS = \
  	python/py-framefilter.c \
  	python/py-function.c \
  	python/py-gdb-readline.c \
+	python/py-infcallevent.c \
  	python/py-inferior.c \
  	python/py-infthread.c \
  	python/py-lazy-string.c \
@@ -2217,6 +2219,10 @@ py-gdb-readline.o: $(srcdir)/python/py-gdb-readline.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-gdb-readline.c
  	$(POSTCOMPILE)

+py-infcallevent.o: $(srcdir)/python/py-infcallevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infcallevent.c
+	$(POSTCOMPILE)
+
  py-inferior.o: $(srcdir)/python/py-inferior.c
  	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c
  	$(POSTCOMPILE)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 87d5145..1210ea7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -25808,6 +25808,37 @@ A reference to the object file 
(@code{gdb.Objfile}) which has been loaded.
  @xref{Objfiles In Python}, for details of the @code{gdb.Objfile} object.
  @end defvar

+@item inferior_call_pre
+Emits @code{gdb.InferiorCallPreEvent} which indicates that a function in
+the inferior is about to be called.
+
+@item inferior_call_post
+Emits @code{gdb.InferiorCallPostEvent} which indicates that a function in
+the inferior has returned.
+
+@item memory_changed
+Emits @code{gdb.MemoryChangedEvent} which indicates that the memory of the
+inferior has been modified by the GDB user, for instance via a command like
+@code{set *addr = value}.  The event has the following attributes:
+
+@defvar MemoryChangedEvent.address
+The start address of the changed region.
+@end defvar
+@defvar MemoryChangedEvent.length
+Length in bytes of the changed region.
+@end defvar
+
+@item register_changed
+Emits @code{gdb.RegisterChangedEvent} which indicates that a register 
in the
+inferior has been modified by the GDB user.
+
+@defvar RegisterChangedEvent.frame
+A gdb.Frame object representing the frame in which the register was 
modified.
+@end defvar
+@defvar RegisterChangedEvent.regnum
+Denotes which register was modified.
+@end defvar
+
  @end table

  @node Threads In Python
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index f753965..277b112 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -253,6 +253,18 @@ The trace state variable @var{tsv} is deleted.  If 
@var{tsv} is
  The trace state value @var{tsv} is modified.
  @end deftypefun

+@deftypefun void inferior_call_pre (void)
+An inferior function is about to be called.
+@end deftypefun
+
+@deftypefun void inferior_call_post (void)
+An inferior function has just been called.
+@end deftypefun
+
+@deftypefun void register_changed (struct frame_info *@var{frame}, 
short @var{regnum})
+A register in the inferior has been modified.
+@end deftypefun
+
  @deftypefun void test_notification (int @var{somearg})
  This observer is used for internal testing.  Do not use.
  See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 212997f..7c1a5ae 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -36,6 +36,7 @@
  #include "ada-lang.h"
  #include "gdbthread.h"
  #include "exceptions.h"
+#include "observer.h"

  /* If we can't find a function's name from its address,
     we print this instead.  */
@@ -611,6 +612,8 @@ call_function_by_hand (struct value *function, int 
nargs, struct value **args)
        target_values_type = values_type;
      }

+  observer_notify_inferior_call_pre ();
+
    /* Determine the location of the breakpoint (and possibly other
       stuff) that the called function will return to.  The SPARC, for a
       function returning a structure or union, needs to make space for
@@ -844,6 +847,8 @@ call_function_by_hand (struct value *function, int 
nargs, struct value **args)
      e = run_inferior_call (tp, real_pc);
    }

+  observer_notify_inferior_call_post ();
+
    /* Rethrow an error if we got one trying to run the inferior.  */

    if (e.reason < 0)
diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h
index f0ff629..7579e04 100644
--- a/gdb/python/py-event.h
+++ b/gdb/python/py-event.h
@@ -105,6 +105,16 @@ typedef struct
  extern int emit_continue_event (ptid_t ptid);
  extern int emit_exited_event (const LONGEST *exit_code, struct 
inferior *inf);

+typedef enum
+{
+  inferior_call_pre,
+  inferior_call_post,
+} inferior_call_kind;
+
+extern int emit_inferior_call_event (inferior_call_kind kind);
+extern int emit_register_changed_event (struct frame_info *frame,
+					short regnum);
+extern int emit_memory_changed_event (CORE_ADDR addr, ssize_t len);
  extern int evpy_emit_event (PyObject *event,
                              eventregistry_object *registry)
    CPYCHECKER_STEALS_REFERENCE_TO_ARG (1);
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
index 4ec3832..d158211 100644
--- a/gdb/python/py-events.h
+++ b/gdb/python/py-events.h
@@ -46,6 +46,9 @@ typedef struct
    eventregistry_object *cont;
    eventregistry_object *exited;
    eventregistry_object *new_objfile;
+  eventregistry_object *inferior_call;
+  eventregistry_object *memory_changed;
+  eventregistry_object *register_changed;

    PyObject *module;

diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c
index 1ff3022..76f923b 100644
--- a/gdb/python/py-evts.c
+++ b/gdb/python/py-evts.c
@@ -73,6 +73,18 @@ gdbpy_initialize_py_events (void)
    if (add_new_registry (&gdb_py_events.exited, "exited") < 0)
      return -1;

+  if (add_new_registry (&gdb_py_events.inferior_call,
+			"inferior_call") < 0)
+    return -1;
+
+  if (add_new_registry (&gdb_py_events.memory_changed,
+			"memory_changed") < 0)
+    return -1;
+
+  if (add_new_registry (&gdb_py_events.register_changed,
+			"register_changed") < 0)
+    return -1;
+
    if (add_new_registry (&gdb_py_events.new_objfile, "new_objfile") < 0)
      return -1;

diff --git a/gdb/python/py-infcallevent.c b/gdb/python/py-infcallevent.c
new file mode 100644
index 0000000..a651bcb
--- /dev/null
+++ b/gdb/python/py-infcallevent.c
@@ -0,0 +1,203 @@
+/* Python interface to inferior function events.
+
+   Copyright (C) 2013 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-event.h"
+
+static PyTypeObject inferior_call_pre_event_object_type;
+static PyTypeObject inferior_call_post_event_object_type;
+static PyTypeObject register_changed_event_object_type;
+static PyTypeObject memory_changed_event_object_type;
+
+static PyObject *
+create_inferior_call_event_object (int flag)
+{
+  PyObject * event;
+
+  switch (flag)
+    {
+    case inferior_call_pre:
+      event = create_event_object (&inferior_call_pre_event_object_type);
+      break;
+    case inferior_call_post:
+      event = create_event_object (&inferior_call_post_event_object_type);
+      break;
+    default:
+      return NULL;
+    }
+
+  return event;
+}
+
+static PyObject *
+create_register_changed_event_object (struct frame_info *frame,
+				      short regnum)
+{
+  PyObject * event;
+  PyObject *frame_obj = NULL;
+  PyObject *regnum_obj = NULL;
+  int failed;
+  struct cleanup *cleanups;
+
+  event = create_event_object (&register_changed_event_object_type);
+  if (event == NULL)
+    return NULL;
+
+  cleanups = make_cleanup_py_decref (event);
+
+  frame_obj = frame_info_to_frame_object (frame);
+  if (frame_obj == NULL)
+    goto fail;
+  make_cleanup_py_decref (frame_obj);
+
+  failed = evpy_add_attribute (event, "frame", frame_obj) < 0;
+  if (failed)
+    goto fail;
+
+  regnum_obj = PyLong_FromLongLong (regnum);
+  if (regnum_obj == NULL)
+    goto fail;
+  make_cleanup_py_decref (regnum_obj);
+
+  failed = evpy_add_attribute (event, "regnum", regnum_obj) < 0;
+  if (failed)
+    goto fail;
+
+  return event;
+
+ fail:
+  do_cleanups (cleanups);
+  return NULL;
+}
+
+static PyObject *
+create_memory_changed_event_object (CORE_ADDR addr, ssize_t len)
+{
+  PyObject * event;
+  PyObject *addr_obj = NULL;
+  PyObject *len_obj = NULL;
+  int failed;
+  struct cleanup *cleanups;
+
+  event = create_event_object (&memory_changed_event_object_type);
+
+  if (event == NULL)
+    return NULL;
+  cleanups = make_cleanup_py_decref (event);
+
+  addr_obj = PyLong_FromLongLong (addr);
+  if (addr_obj == NULL)
+    goto fail;
+  make_cleanup_py_decref (addr_obj);
+
+  failed = evpy_add_attribute (event, "address", addr_obj) < 0;
+  if (failed)
+    goto fail;
+
+  len_obj = PyLong_FromLong (len);
+  if (len_obj == NULL)
+    goto fail;
+  make_cleanup_py_decref (len_obj);
+
+  failed = evpy_add_attribute (event, "length", len_obj) < 0;
+  if (failed)
+    goto fail;
+
+  return event;
+
+ fail:
+  do_cleanups (cleanups);
+  return NULL;
+}
+
+/* Callback function which notifies observers when an event occurs which
+   calls a function in the inferior.
+   This function will create a new Python inferior-call event object.
+   Return -1 if emit fails.  */
+
+int
+emit_inferior_call_event (inferior_call_kind flag)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.inferior_call))
+    return 0;
+
+  event = create_inferior_call_event_object (flag);
+  if (event != NULL)
+    return evpy_emit_event (event, gdb_py_events.inferior_call);
+  return -1;
+}
+
+int
+emit_memory_changed_event (CORE_ADDR addr, ssize_t len)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.memory_changed))
+    return 0;
+
+  event = create_memory_changed_event_object (addr, len);
+  if (event != NULL)
+    return evpy_emit_event (event, gdb_py_events.memory_changed);
+  return -1;
+}
+
+int
+emit_register_changed_event (struct frame_info* frame, short regnum)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.register_changed))
+    return 0;
+
+  event = create_register_changed_event_object (frame, regnum);
+  if (event != NULL)
+    return evpy_emit_event (event, gdb_py_events.register_changed);
+  return -1;
+}
+
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_pre,
+		      "gdb.InferiorCallPreEvent",
+		      "InferiorCallPreEvent",
+		      "GDB inferior function pre-call event object",
+		      event_object_type,
+		      static);
+
+GDBPY_NEW_EVENT_TYPE (inferior_call_post,
+		      "gdb.InferiorCallPostEvent",
+		      "InferiorCallPostEvent",
+		      "GDB inferior function post-call event object",
+		      event_object_type,
+		      static);
+
+GDBPY_NEW_EVENT_TYPE (register_changed,
+		      "gdb.RegisterChangedEvent",
+		      "RegisterChangedEvent",
+		      "GDB register change event object",
+		      event_object_type,
+		      static);
+
+GDBPY_NEW_EVENT_TYPE (memory_changed,
+		      "gdb.MemoryChangedEvent",
+		      "MemoryChangedEvent",
+		      "GDB memory change event object",
+		      event_object_type,
+		      static);
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 1a1b774..89bff40 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -118,6 +118,58 @@ python_on_resume (ptid_t ptid)
  }

  static void
+python_on_inferior_call_pre (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_call_event (inferior_call_pre) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_inferior_call_post (void)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_inferior_call_event (inferior_call_post) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_memory_change (struct inferior *inferior, CORE_ADDR addr, 
ssize_t len, const bfd_byte *data)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_memory_changed_event (addr, len) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_register_change (struct frame_info *frame, short regnum)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (target_gdbarch (), current_language);
+
+  if (emit_register_changed_event (frame, regnum) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
  python_inferior_exit (struct inferior *inf)
  {
    struct cleanup *cleanup;
@@ -794,6 +846,10 @@ gdbpy_initialize_inferior (void)
    observer_attach_thread_exit (delete_thread_object);
    observer_attach_normal_stop (python_on_normal_stop);
    observer_attach_target_resumed (python_on_resume);
+  observer_attach_inferior_call_pre (python_on_inferior_call_pre);
+  observer_attach_inferior_call_post (python_on_inferior_call_post);
+  observer_attach_memory_changed (python_on_memory_change);
+  observer_attach_register_changed (python_on_register_change);
    observer_attach_inferior_exit (python_inferior_exit);
    observer_attach_new_objfile (python_new_objfile);

diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 125670e..8eba303 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -393,6 +393,14 @@ int gdbpy_initialize_breakpoint_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_continue_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_pre_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_call_post_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_register_changed_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_memory_changed_event (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_exited_event (void)
    CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
  int gdbpy_initialize_thread_event (void)
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 1873936..85cbefa 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1684,6 +1684,10 @@ message == an error message without a stack will 
be printed."),
        || gdbpy_initialize_signal_event () < 0
        || gdbpy_initialize_breakpoint_event () < 0
        || gdbpy_initialize_continue_event () < 0
+      || gdbpy_initialize_inferior_call_pre_event () < 0
+      || gdbpy_initialize_inferior_call_post_event () < 0
+      || gdbpy_initialize_register_changed_event () < 0
+      || gdbpy_initialize_memory_changed_event () < 0
        || gdbpy_initialize_exited_event () < 0
        || gdbpy_initialize_thread_event () < 0
        || gdbpy_initialize_new_objfile_event ()  < 0
diff --git a/gdb/testsuite/gdb.python/py-events.exp 
b/gdb/testsuite/gdb.python/py-events.exp
index 390a2ba..ef90a1d 100644
--- a/gdb/testsuite/gdb.python/py-events.exp
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -79,6 +79,93 @@ all threads stopped"

  delete_breakpoints

+# Test inferior call events
+gdb_test "call do_nothing()" ".*event type: pre-call.*
+.*event type: continue.*
+.*event type: post-call.*"
+
+# Test register changed event
+gdb_test_no_output {set $old_sp = $sp}
+gdb_test {set $sp = 0} ".*event type: register-changed.*
+.*frame: .*
+.*num: .*"
+gdb_test {set $sp = 1} ".*event type: register-changed.*
+.*frame: .*
+.*num: .*"
+gdb_test {set $sp = $old_sp} ".*event type: register-changed.*
+.*frame: .*
+.*num: .*"
+
+# Test that no register_changed event is generated on "non-user"
+# modifications
+set test "up"
+gdb_test_multiple {up} $test {
+    -re "event type: register-changed" {
+	fail $test
+    }
+    -re "#1.*in first.*\r\n.*do_nothing.*\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
+
+set test "down"
+gdb_test_multiple {down} $test {
+    -re "event type: register-changed" {
+	fail $test
+    }
+    -re "#0.*do_nothing.*at.*\r\n.*void do_nothing.*\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
+
+set test "step"
+gdb_test_multiple {step} $test {
+    -re "event type: register-changed" {
+	fail $test
+    }
+    -re "first.*at.*\r\n.*28.*for.*\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
+
+
+# Test memory changed event
+gdb_test_no_output {set $saved = *(int*) $sp}
+gdb_test {set *(int*) $sp = 0} ".*event type: memory-changed.*
+.*address: .*
+.*length: .*"
+gdb_test {set *(int*) $sp = $saved} ".*event type: memory-changed.*
+.*address: .*
+.*length: .*"
+
+# Test that no memory_changed event is generated on breakpoint
+# activity
+set test "break second"
+gdb_test_multiple "break second" $test {
+     -re "event type: memory-changed" {
+	fail $test
+    }
+    -re "Breakpoint 5 at .*\r\n$gdb_prompt $" {
+	pass $test
+    }
+
+}
+
+set test "continue to breakpoint 5"
+gdb_test_multiple "continue" $test {
+     -re "event type: memory-changed" {
+	fail $test
+    }
+    -re ".*event type: continue.*
+.*event type: stop.*
+.*stop reason: breakpoint.*
+.*all threads stopped.*$gdb_prompt $" {
+	pass $test
+    }
+}
+
+gdb_test_no_output "delete 5"
+
  #test exited event.
  gdb_test "continue" ".*event type: continue.*
  .*event type: exit.*
diff --git a/gdb/testsuite/gdb.python/py-events.py 
b/gdb/testsuite/gdb.python/py-events.py
index 7601ca1..1ca701a 100644
--- a/gdb/testsuite/gdb.python/py-events.py
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -57,6 +57,28 @@ def new_objfile_handler (event):
      print ("event type: new_objfile")
      print ("new objfile name: %s" % (event.new_objfile.filename))

+def inferior_fn_handler (event):
+    if (isinstance (event, gdb.InferiorCallPreEvent)):
+        print ("event type: pre-call")
+    elif (isinstance (event, gdb.InferiorCallPostEvent)):
+        print ("event type: post-call")
+    else:
+        assert False
+
+def register_changed_handler (event):
+    assert (isinstance (event, gdb.RegisterChangedEvent))
+    print ("event type: register-changed")
+    assert (isinstance (event.frame, gdb.Frame))
+    print ("frame: %s" % (event.frame))
+    print ("num: %s" % (event.regnum))
+
+def memory_changed_handler (event):
+    assert (isinstance (event, gdb.MemoryChangedEvent))
+    print ("event type: memory-changed")
+    print ("address: %s" % (event.address))
+    print ("length: %s" % (event.length))
+
+
  class test_events (gdb.Command):
      """Test events."""

@@ -68,6 +90,9 @@ class test_events (gdb.Command):
          gdb.events.stop.connect (breakpoint_stop_handler)
          gdb.events.exited.connect (exit_handler)
          gdb.events.cont.connect (continue_handler)
+        gdb.events.inferior_call.connect(inferior_fn_handler)
+        gdb.events.memory_changed.connect(memory_changed_handler)
+        gdb.events.register_changed.connect(register_changed_handler)
          print ("Event testers registered.")

  test_events ()
diff --git a/gdb/valops.c b/gdb/valops.c
index d43c758..84c6661 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1210,6 +1210,7 @@ value_assign (struct value *toval, struct value 
*fromval)
  	      }
  	  }

+	observer_notify_register_changed (frame, value_reg);
  	if (deprecated_register_changed_hook)
  	  deprecated_register_changed_hook (-1);
  	break;


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] Events when inferior is modified
  2013-12-12 17:12               ` Nick Bull
@ 2013-12-21 21:26                 ` Nick Bull
  0 siblings, 0 replies; 12+ messages in thread
From: Nick Bull @ 2013-12-21 21:26 UTC (permalink / raw)
  To: gdb-patches, Phil Muldoon

On 12 December 2013 17:11, Nick Bull <nicholaspbull@gmail.com> wrote:
> On 10/12/13 11:04, Phil Muldoon wrote:
>>
>> [ issues ]

Ping? I think the updates to the patch address everything that's been
raised so far.

Nick

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2013-12-21 21:26 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-28 17:07 Events when inferior is modified Nick Bull
2013-07-30 21:04 ` Tom Tromey
2013-08-01 15:47   ` Pedro Alves
2013-08-07 14:41   ` Nick Bull
2013-11-18 12:51     ` [PATCH v2] " Nick Bull
2013-11-18 15:15       ` Eli Zaretskii
2013-11-25 11:50       ` Phil Muldoon
2013-12-01 15:23         ` Nick Bull
2013-12-09 17:48           ` Nick Bull
2013-12-10 11:04             ` Phil Muldoon
2013-12-12 17:12               ` Nick Bull
2013-12-21 21:26                 ` Nick Bull

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).