Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* Add a python event registry for selected frame changes
@ 2013-04-26 21:07 Maxime Coste
  2013-04-26 21:09 ` [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame Maxime Coste
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Maxime Coste @ 2013-04-26 21:07 UTC (permalink / raw)
  To: gdb-patches

Hello,

Here is a patch serie which permits python scripts to watch for selected
frame changes, ignoring changes which are triggered by implementation detail
(like executing a call command).

I know the real solution to select_frame would be for most function to take
a frame rather than relying on the current selected frame, however I am not
familiar enough with gdb internals to fix that.

Regards,

Maxime Coste.



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

* [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame
  2013-04-26 21:07 Add a python event registry for selected frame changes Maxime Coste
@ 2013-04-26 21:09 ` Maxime Coste
  2013-04-30 11:05   ` Tom Tromey
  2013-04-26 21:10 ` [PATCH 2/3] Add a frame_changed observer Maxime Coste
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 14+ messages in thread
From: Maxime Coste @ 2013-04-26 21:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Maxime Coste

select_frame calls specify if the frame is selected due to
a breakpoint/signal (REASON_STOP), a user command (REASON_USER)
or just as an implementation detail (REASON_IMPL_DETAIL) which
should restore the previous frame once finished.
---
 gdb/ada-lang.c        |  4 ++--
 gdb/breakpoint.c      | 10 +++++-----
 gdb/frame.c           |  6 +++---
 gdb/frame.h           | 16 +++++++++++++++-
 gdb/infrun.c          |  8 ++++----
 gdb/mi/mi-main.c      |  2 +-
 gdb/python/py-frame.c |  2 +-
 gdb/stack.c           |  9 +++++----
 gdb/thread.c          |  8 ++++----
 gdb/valops.c          |  2 +-
 gdb/varobj.c          |  6 +++---
 11 files changed, 44 insertions(+), 29 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index fdfc0b4..d45731b 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -11167,7 +11167,7 @@ ada_find_printable_frame (struct frame_info *fi)
     {
       if (!is_known_support_routine (fi))
         {
-          select_frame (fi);
+          select_frame (fi, REASON_STOP);
           break;
         }
     }
@@ -11222,7 +11222,7 @@ ada_unhandled_exception_name_addr_from_raise (void)
   if (fi == NULL)
     return 0;
 
-  select_frame (fi);
+  select_frame (fi, REASON_STOP);
   return parse_and_eval_address ("id.full_name");
 }
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 35ada7a..843a4d1 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1761,7 +1761,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
       fi = frame_find_by_id (b->watchpoint_frame);
       within_current_scope = (fi != NULL);
       if (within_current_scope)
-	select_frame (fi);
+	select_frame (fi, REASON_IMPL_DETAIL);
     }
 
   /* We don't free locations.  They are stored in the bp_location array
@@ -1996,7 +1996,7 @@ in which its expression is valid.\n"),
 
   /* Restore the selected frame.  */
   if (frame_saved)
-    select_frame (frame_find_by_id (saved_frame_id));
+    select_frame (frame_find_by_id (saved_frame_id), REASON_IMPL_DETAIL);
 }
 
 
@@ -4765,7 +4765,7 @@ watchpoint_check (void *p)
 	/* If we end up stopping, the current frame will get selected
 	   in normal_stop.  So this call to select_frame won't affect
 	   the user.  */
-	select_frame (fr);
+	select_frame (fr, REASON_IMPL_DETAIL);
     }
 
   if (within_current_scope)
@@ -5091,7 +5091,7 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
 	     of the inlined function; the current frame will be the
 	     call site.  */
 	  if (w == NULL || w->cond_exp_valid_block == NULL)
-	    select_frame (get_current_frame ());
+	    select_frame (get_current_frame (), REASON_IMPL_DETAIL);
 	  else
 	    {
 	      struct frame_info *frame;
@@ -5112,7 +5112,7 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
 		 intuitive.  */
 	      frame = block_innermost_frame (w->cond_exp_valid_block);
 	      if (frame != NULL)
-		select_frame (frame);
+		select_frame (frame, REASON_IMPL_DETAIL);
 	      else
 		within_current_scope = 0;
 	    }
diff --git a/gdb/frame.c b/gdb/frame.c
index 8d4e2c8..0a0acda 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1382,7 +1382,7 @@ get_selected_frame (const char *message)
       /* Hey!  Don't trust this.  It should really be re-finding the
 	 last selected frame of the currently selected thread.  This,
 	 though, is better than nothing.  */
-      select_frame (get_current_frame ());
+      select_frame (get_current_frame (), REASON_IMPL_DETAIL);
     }
   /* There is always a frame.  */
   gdb_assert (selected_frame != NULL);
@@ -1412,7 +1412,7 @@ deprecated_safe_get_selected_frame (void)
 /* Select frame FI (or NULL - to invalidate the current frame).  */
 
 void
-select_frame (struct frame_info *fi)
+select_frame (struct frame_info *fi, enum select_frame_reason reason)
 {
   selected_frame = fi;
   /* NOTE: cagney/2002-05-04: FI can be NULL.  This occurs when the
@@ -1548,7 +1548,7 @@ reinit_frame_cache (void)
     annotate_frames_invalid ();
 
   current_frame = NULL;		/* Invalidate cache */
-  select_frame (NULL);
+  select_frame (NULL, REASON_IMPL_DETAIL);
   frame_stash_invalidate ();
   if (frame_debug)
     fprintf_unfiltered (gdb_stdlog, "{ reinit_frame_cache () }\n");
diff --git a/gdb/frame.h b/gdb/frame.h
index 31b9cb7..34115b4 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -219,6 +219,20 @@ enum frame_type
   SENTINEL_FRAME
 };
 
+/* Reason why a frame is being selected, so that select_frame is aware
+   of why it is being called */
+
+enum select_frame_reason
+{
+  /* Selected for as an implementation detail, user selected
+     frame should be restored */
+  REASON_IMPL_DETAIL,
+  /* Selecting this frame was a user request. */
+  REASON_USER,
+  /* A the inferior was stopped due to breakpoint/signal... */
+  REASON_STOP,
+};
+
 /* For every stopped thread, GDB tracks two frames: current and
    selected.  Current frame is the inner most frame of the selected
    thread.  Selected frame is the one being examined by the GDB
@@ -268,7 +282,7 @@ extern struct frame_info *get_selected_frame_if_set (void);
 
 /* Select a specific frame.  NULL, apparently implies re-select the
    inner most frame.  */
-extern void select_frame (struct frame_info *);
+extern void select_frame (struct frame_info *, enum select_frame_reason);
 
 /* Given a FRAME, return the next (more inner, younger) or previous
    (more outer, older) frame.  */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 5d6a9af..9d0e9e7 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6029,7 +6029,7 @@ normal_stop (void)
 
   if (!stop_stack_dummy)
     {
-      select_frame (get_current_frame ());
+      select_frame (get_current_frame (), REASON_STOP);
 
       /* Print current location without a level number, if
          we have changed functions or hit a breakpoint.
@@ -6124,7 +6124,7 @@ normal_stop (void)
 	 stopped (e.g. the dummy call previously hit a breakpoint).
 	 We can't know which case we have so just always re-establish
 	 a selected frame here.  */
-      select_frame (get_current_frame ());
+      select_frame (get_current_frame (), REASON_IMPL_DETAIL);
     }
 
 done:
@@ -6925,7 +6925,7 @@ restore_selected_frame (void *args)
       return 0;
     }
 
-  select_frame (frame);
+  select_frame (frame, REASON_IMPL_DETAIL);
 
   return (1);
 }
@@ -6967,7 +6967,7 @@ restore_infcall_control_state (struct infcall_control_state *inf_status)
 	   RETURN_MASK_ERROR) == 0)
 	/* Error in restoring the selected frame.  Select the innermost
 	   frame.  */
-	select_frame (get_current_frame ());
+	select_frame (get_current_frame (), REASON_IMPL_DETAIL);
     }
 
   xfree (inf_status);
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 94fda8f..0f0f3f5 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -2116,7 +2116,7 @@ mi_cmd_execute (struct mi_parse *parse)
       fid = find_relative_frame (get_current_frame (), &frame);
       if (frame == 0)
 	/* find_relative_frame was successful */
-	select_frame (fid);
+	select_frame (fid, REASON_USER);
       else
 	error (_("Invalid frame id: %d"), frame);
     }
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index e2eb9c5..d5926b0 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -511,7 +511,7 @@ frapy_select (PyObject *self, PyObject *args)
     {
       FRAPY_REQUIRE_VALID (self, fi);
 
-      select_frame (fi);
+      select_frame (fi, REASON_USER);
     }
   GDB_PY_HANDLE_EXCEPTION (except);
 
diff --git a/gdb/stack.c b/gdb/stack.c
index c072a2e..e4aaab6 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2116,7 +2116,7 @@ args_plus_locals_info (char *ignore, int from_tty)
 static void
 select_and_print_frame (struct frame_info *frame)
 {
-  select_frame (frame);
+  select_frame (frame, REASON_USER);
   if (frame)
     print_stack_frame (frame, 1, SRC_AND_LOC);
 }
@@ -2185,7 +2185,8 @@ find_relative_frame (struct frame_info *frame, int *level_offset_ptr)
 void
 select_frame_command (char *level_exp, int from_tty)
 {
-  select_frame (parse_frame_specification_1 (level_exp, "No stack.", NULL));
+  select_frame (parse_frame_specification_1 (level_exp, "No stack.", NULL),
+                REASON_USER);
 }
 
 /* The "frame" command.  With no argument, print the selected frame
@@ -2222,7 +2223,7 @@ up_silently_base (char *count_exp)
   frame = find_relative_frame (get_selected_frame ("No stack."), &count);
   if (count != 0 && count_exp == NULL)
     error (_("Initial frame selected; you cannot go up."));
-  select_frame (frame);
+  select_frame (frame, REASON_USER);
 }
 
 static void
@@ -2261,7 +2262,7 @@ down_silently_base (char *count_exp)
       error (_("Bottom (innermost) frame selected; you cannot go down."));
     }
 
-  select_frame (frame);
+  select_frame (frame, REASON_USER);
 }
 
 static void
diff --git a/gdb/thread.c b/gdb/thread.c
index 2a1d723..0a11ce9 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1016,7 +1016,7 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
   /* This means there was no selected frame.  */
   if (frame_level == -1)
     {
-      select_frame (NULL);
+      select_frame (NULL, REASON_IMPL_DETAIL);
       return;
     }
 
@@ -1037,7 +1037,7 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
       && frame_id_eq (get_frame_id (frame), a_frame_id))
     {
       /* Cool, all is fine.  */
-      select_frame (frame);
+      select_frame (frame, REASON_IMPL_DETAIL);
       return;
     }
 
@@ -1045,13 +1045,13 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
   if (frame != NULL)
     {
       /* Cool, refound it.  */
-      select_frame (frame);
+      select_frame (frame, REASON_IMPL_DETAIL);
       return;
     }
 
   /* Nothing else to do, the frame layout really changed.  Select the
      innermost stack frame.  */
-  select_frame (get_current_frame ());
+  select_frame (get_current_frame (), REASON_IMPL_DETAIL);
 
   /* Warn the user.  */
   if (frame_level > 0 && !ui_out_is_mi_like_p (current_uiout))
diff --git a/gdb/valops.c b/gdb/valops.c
index 93c09d8..d801809 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1419,7 +1419,7 @@ value_assign (struct value *toval, struct value *fromval)
 	struct frame_info *fi = frame_find_by_id (old_frame);
 
 	if (fi != NULL)
-	  select_frame (fi);
+	  select_frame (fi, REASON_IMPL_DETAIL);
       }
 
       break;
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 467e59a..c158d69 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -707,7 +707,7 @@ varobj_create (char *objname,
 	  var->root->frame = get_frame_id (fi);
 	  var->root->thread_id = pid_to_thread_id (inferior_ptid);
 	  old_id = get_frame_id (get_selected_frame (NULL));
-	  select_frame (fi);	 
+	  select_frame (fi, REASON_IMPL_DETAIL);
 	}
 
       /* We definitely need to catch errors here.
@@ -746,7 +746,7 @@ varobj_create (char *objname,
 
       /* Reset the selected frame.  */
       if (frame_id_p (old_id))
-	select_frame (frame_find_by_id (old_id));
+	select_frame (frame_find_by_id (old_id), REASON_IMPL_DETAIL);
     }
 
   /* If the variable object name is null, that means this
@@ -3405,7 +3405,7 @@ check_scope (struct varobj *var)
 	  pc >= BLOCK_END (var->root->valid_block))
 	scope = 0;
       else
-	select_frame (fi);
+	select_frame (fi, REASON_IMPL_DETAIL);
     }
   return scope;
 }
-- 
1.8.2.1



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

* [PATCH 2/3] Add a frame_changed observer
  2013-04-26 21:07 Add a python event registry for selected frame changes Maxime Coste
  2013-04-26 21:09 ` [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame Maxime Coste
@ 2013-04-26 21:10 ` Maxime Coste
  2013-04-30 10:51   ` Tom Tromey
  2013-04-27  7:55 ` [PATCH 3/3] Add a gdb.events.frame_change event registry Maxime Coste
  2013-04-30 10:53 ` Add a python event registry for selected frame changes Tom Tromey
  3 siblings, 1 reply; 14+ messages in thread
From: Maxime Coste @ 2013-04-26 21:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: Maxime Coste

---
 gdb/doc/observer.texi | 4 ++++
 gdb/frame.c           | 6 ++++++
 2 files changed, 10 insertions(+)

diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index adb7085..9653d6b 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -105,6 +105,10 @@ been modified since being loaded by the debugger (by being recompiled,
 for instance).
 @end deftypefun
 
+@deftypefun void frame_changed (struct frame_info *@var{frame})
+the selected frame has changed;
+@end deftypefun
+
 @deftypefun void inferior_created (struct target_ops *@var{objfile}, int @var{from_tty})
 @value{GDBN} has just connected to an inferior.  For @samp{run},
 @value{GDBN} calls this observer while the inferior is still stopped
diff --git a/gdb/frame.c b/gdb/frame.c
index 0a0acda..0e21e33 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1414,6 +1414,9 @@ deprecated_safe_get_selected_frame (void)
 void
 select_frame (struct frame_info *fi, enum select_frame_reason reason)
 {
+  int changed = (reason == REASON_USER || reason == REASON_STOP)
+                && (fi != selected_frame);
+
   selected_frame = fi;
   /* NOTE: cagney/2002-05-04: FI can be NULL.  This occurs when the
      frame is being invalidated.  */
@@ -1453,6 +1456,9 @@ select_frame (struct frame_info *fi, enum select_frame_reason reason)
 	    set_language (s->language);
 	}
     }
+
+    if (changed)
+      observer_notify_frame_changed (fi);
 }
 
 /* Create an arbitrary (i.e. address specified by user) or innermost frame.
-- 
1.8.2.1



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

* [PATCH 3/3] Add a gdb.events.frame_change event registry
  2013-04-26 21:07 Add a python event registry for selected frame changes Maxime Coste
  2013-04-26 21:09 ` [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame Maxime Coste
  2013-04-26 21:10 ` [PATCH 2/3] Add a frame_changed observer Maxime Coste
@ 2013-04-27  7:55 ` Maxime Coste
  2013-04-30 11:07   ` Tom Tromey
  2013-04-30 10:53 ` Add a python event registry for selected frame changes Tom Tromey
  3 siblings, 1 reply; 14+ messages in thread
From: Maxime Coste @ 2013-04-27  7:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Maxime Coste

---
 gdb/Makefile.in                  |  6 ++++
 gdb/python/py-events.h           |  1 +
 gdb/python/py-evts.c             |  3 ++
 gdb/python/py-framechangeevent.c | 76 ++++++++++++++++++++++++++++++++++++++++
 gdb/python/py-framechangeevent.h | 29 +++++++++++++++
 gdb/python/python-internal.h     |  1 +
 gdb/python/python.c              | 18 ++++++++++
 7 files changed, 134 insertions(+)
 create mode 100644 gdb/python/py-framechangeevent.c
 create mode 100644 gdb/python/py-framechangeevent.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c891c83..748d0ca 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -288,6 +288,7 @@ SUBDIR_PYTHON_OBS = \
 	py-exitedevent.o \
 	py-finishbreakpoint.o \
 	py-frame.o \
+	py-framechangeevent.o \
 	py-function.o \
 	py-gdb-readline.o \
 	py-inferior.o \
@@ -322,6 +323,7 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-exitedevent.c \
 	python/py-finishbreakpoint.c \
 	python/py-frame.c \
+	python/py-framechangeevent.c \
 	python/py-function.c \
 	python/py-gdb-readline.c \
 	python/py-inferior.c \
@@ -2141,6 +2143,10 @@ py-frame.o: $(srcdir)/python/py-frame.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c
 	$(POSTCOMPILE)
 
+py-framechangeevent.o: $(srcdir)/python/py-framechangeevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-framechangeevent.c
+	$(POSTCOMPILE)
+
 py-function.o: $(srcdir)/python/py-function.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c
 	$(POSTCOMPILE)
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
index 537bcc9..a61858c 100644
--- a/gdb/python/py-events.h
+++ b/gdb/python/py-events.h
@@ -45,6 +45,7 @@ typedef struct
   eventregistry_object *cont;
   eventregistry_object *exited;
   eventregistry_object *new_objfile;
+  eventregistry_object *frame_change;
 
   PyObject *module;
 
diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c
index 4c079e2..f4d1fbf 100644
--- a/gdb/python/py-evts.c
+++ b/gdb/python/py-evts.c
@@ -81,6 +81,9 @@ gdbpy_initialize_py_events (void)
   if (add_new_registry (&gdb_py_events.new_objfile, "new_objfile") < 0)
     goto fail;
 
+  if (add_new_registry (&gdb_py_events.frame_change, "frame_change") < 0)
+    goto fail;
+
 #ifndef IS_PY3K
   Py_INCREF (gdb_py_events.module);
 #endif
diff --git a/gdb/python/py-framechangeevent.c b/gdb/python/py-framechangeevent.c
new file mode 100644
index 0000000..f18ef39
--- /dev/null
+++ b/gdb/python/py-framechangeevent.c
@@ -0,0 +1,76 @@
+/* Python interface to inferior frame 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-framechangeevent.h"
+
+static PyTypeObject frame_change_event_object_type;
+
+static PyObject *
+create_frame_change_event_object (struct frame_info *frame)
+{
+  PyObject *frame_change_event;
+  PyObject *py_frame;
+
+  frame_change_event = create_event_object (&frame_change_event_object_type);
+  if (!frame_change_event)
+    goto fail;
+
+  /* Note that frame_to_frame_object returns a borrowed reference,
+     so we don't need a decref here.  */
+  py_frame = frame ? frame_info_to_frame_object (frame) : Py_None;
+  if (!py_frame || evpy_add_attribute (frame_change_event,
+                                         "frame",
+                                         py_frame) < 0)
+    goto fail;
+
+  return frame_change_event;
+
+ fail:
+  Py_XDECREF (frame_change_event);
+  return NULL;
+}
+
+/* Callback observers when a frame event occurs.  This function will create a
+   new Python frame event object.  If only a specific thread is frameped the
+   thread object of the event will be set to that thread.  Otherwise, if all
+   threads are frameped thread object will be set to None.
+   return 0 if the event was created and emitted successfully otherwise
+   returns -1.  */
+
+int
+emit_frame_change_event (struct frame_info* frame)
+{
+  PyObject *frame_change_event_obj = NULL;
+
+  if (evregpy_no_listeners_p (gdb_py_events.frame_change))
+    return 0;
+
+  frame_change_event_obj = create_frame_change_event_object(frame);
+  if (frame_change_event_obj)
+    return evpy_emit_event (frame_change_event_obj, gdb_py_events.frame_change);
+  return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (frame_change,
+                      "gdb.FrameChangeEvent",
+                      "FrameChangeEvent",
+                      "GDB frame event object",
+                      event_object_type,
+                      static);
diff --git a/gdb/python/py-framechangeevent.h b/gdb/python/py-framechangeevent.h
new file mode 100644
index 0000000..e7564b0
--- /dev/null
+++ b/gdb/python/py-framechangeevent.h
@@ -0,0 +1,29 @@
+/* Python interface to inferior 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/>.  */
+
+#ifndef GDB_PY_FRAMECHANGEEVENT_H
+#define GDB_PY_FRAMECHANGEEVENT_H
+
+#include "py-event.h"
+
+extern void frame_change_evpy_dealloc (PyObject *self);
+
+extern int emit_frame_change_event (struct frame_info* frame);
+
+#endif /* GDB_PY_FRAMECHANGEEVENT_H */
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index ea97226..676096d 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -301,6 +301,7 @@ void gdbpy_initialize_continue_event (void);
 void gdbpy_initialize_exited_event (void);
 void gdbpy_initialize_thread_event (void);
 void gdbpy_initialize_new_objfile_event (void);
+void gdbpy_initialize_frame_change_event (void);
 void gdbpy_initialize_arch (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 67d06e5..ded99c7 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -72,6 +72,7 @@ static const char *gdbpy_should_print_stack = python_excp_message;
 #include "observer.h"
 #include "interps.h"
 #include "event-top.h"
+#include "py-framechangeevent.h"
 
 static PyMethodDef GdbMethods[];
 
@@ -881,6 +882,21 @@ gdbpy_initialize_events (void)
     }
 }
 
+
+static void
+python_frame_changed (struct frame_info *frame)
+{
+  struct cleanup *cleanup;
+  struct gdbarch *arch = frame ? get_frame_arch(frame) : target_gdbarch();
+
+  cleanup = ensure_python_env (arch, current_language);
+
+  if (emit_frame_change_event (frame) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
 \f
 
 static void
@@ -1630,9 +1646,11 @@ message == an error message without a stack will be printed."),
   gdbpy_initialize_exited_event ();
   gdbpy_initialize_thread_event ();
   gdbpy_initialize_new_objfile_event () ;
+  gdbpy_initialize_frame_change_event () ;
   gdbpy_initialize_arch ();
 
   observer_attach_before_prompt (before_prompt_hook);
+  observer_attach_frame_changed (python_frame_changed);
 
   gdbpy_to_string_cst = PyString_FromString ("to_string");
   gdbpy_children_cst = PyString_FromString ("children");
-- 
1.8.2.1



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

* Re: [PATCH 2/3] Add a frame_changed observer
  2013-04-26 21:10 ` [PATCH 2/3] Add a frame_changed observer Maxime Coste
@ 2013-04-30 10:51   ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2013-04-30 10:51 UTC (permalink / raw)
  To: Maxime Coste; +Cc: gdb-patches

>>>>> "Maxime" == Maxime Coste <frrrwww@gmail.com> writes:

Maxime> +@deftypefun void frame_changed (struct frame_info *@var{frame})
Maxime> +the selected frame has changed;
Maxime> +@end deftypefun

I think this needs more text and should probably be a full sentence.
Like

    The selected frame has changed in a user-visible way.  @var{frame}
    is the new frame.

Tom


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

* Re: Add a python event registry for selected frame changes
  2013-04-26 21:07 Add a python event registry for selected frame changes Maxime Coste
                   ` (2 preceding siblings ...)
  2013-04-27  7:55 ` [PATCH 3/3] Add a gdb.events.frame_change event registry Maxime Coste
@ 2013-04-30 10:53 ` Tom Tromey
  2013-04-30 23:29   ` Maxime Coste
  3 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2013-04-30 10:53 UTC (permalink / raw)
  To: Maxime Coste; +Cc: gdb-patches

>>>>> "Maxime" == Maxime Coste <frrrwww@gmail.com> writes:

Maxime> Here is a patch serie which permits python scripts to watch for
Maxime> selected frame changes, ignoring changes which are triggered by
Maxime> implementation detail (like executing a call command).

Thanks.

I think this series needs 3 things --

1. ChangeLog entries.  See the GNU Coding Standards for details.
2. Test cases.
3. Copyright assignment paperwork on file.

I can get you started with #3 if you contact me off-list.

Tom


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

* Re: [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame
  2013-04-26 21:09 ` [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame Maxime Coste
@ 2013-04-30 11:05   ` Tom Tromey
  2013-04-30 11:53     ` Joel Brobecker
  2013-05-06 16:54     ` Pedro Alves
  0 siblings, 2 replies; 14+ messages in thread
From: Tom Tromey @ 2013-04-30 11:05 UTC (permalink / raw)
  To: Maxime Coste; +Cc: gdb-patches

>>>>> "Maxime" == Maxime Coste <frrrwww@gmail.com> writes:

Maxime> select_frame calls specify if the frame is selected due to
Maxime> a breakpoint/signal (REASON_STOP), a user command (REASON_USER)
Maxime> or just as an implementation detail (REASON_IMPL_DETAIL) which
Maxime> should restore the previous frame once finished.

I don't mind this approach but I would like to hear from other
maintainers.

Tom


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

* Re: [PATCH 3/3] Add a gdb.events.frame_change event registry
  2013-04-27  7:55 ` [PATCH 3/3] Add a gdb.events.frame_change event registry Maxime Coste
@ 2013-04-30 11:07   ` Tom Tromey
  2013-04-30 11:09     ` Tom Tromey
  0 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2013-04-30 11:07 UTC (permalink / raw)
  To: Maxime Coste; +Cc: gdb-patches

>>>>> "Maxime" == Maxime Coste <frrrwww@gmail.com> writes:

Maxime> +  /* Note that frame_to_frame_object returns a borrowed reference,
Maxime> +     so we don't need a decref here.  */
Maxime> +  py_frame = frame ? frame_info_to_frame_object (frame) : Py_None;

I don't think that comment is true.
Also we recently agreed in gdb to do explicit checks against NULL, so
"frame != NULL" here.

Maxime> +  if (!py_frame || evpy_add_attribute (frame_change_event,

Likewise for py_frame.

Maxime> +emit_frame_change_event (struct frame_info* frame)

Space before the "*", not after.

Maxime> +
Maxime> +static void
Maxime> +python_frame_changed (struct frame_info *frame)

Every new function needs an introductory comment.

Maxime> +  struct gdbarch *arch = frame ? get_frame_arch(frame) : target_gdbarch();

Space before open paren.

This patch needs a documentation change for the new Python API.

Tom


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

* Re: [PATCH 3/3] Add a gdb.events.frame_change event registry
  2013-04-30 11:07   ` Tom Tromey
@ 2013-04-30 11:09     ` Tom Tromey
  0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2013-04-30 11:09 UTC (permalink / raw)
  To: Maxime Coste; +Cc: gdb-patches

Tom> This patch needs a documentation change for the new Python API.

... oh, and a NEWS entry as well.

Tom


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

* Re: [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame
  2013-04-30 11:05   ` Tom Tromey
@ 2013-04-30 11:53     ` Joel Brobecker
  2013-05-06 16:54     ` Pedro Alves
  1 sibling, 0 replies; 14+ messages in thread
From: Joel Brobecker @ 2013-04-30 11:53 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Maxime Coste, gdb-patches

> Maxime> select_frame calls specify if the frame is selected due to
> Maxime> a breakpoint/signal (REASON_STOP), a user command (REASON_USER)
> Maxime> or just as an implementation detail (REASON_IMPL_DETAIL) which
> Maxime> should restore the previous frame once finished.
> 
> I don't mind this approach but I would like to hear from other
> maintainers.

I wasn't super fond when I saw this yesterday, TBH, particuarly
after seeing how it's used in the patch. But I haven't really had
time to think this over to see if I can propose something else.
So do not block the patch on my account.

-- 
Joel


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

* Re: Add a python event registry for selected frame changes
  2013-04-30 10:53 ` Add a python event registry for selected frame changes Tom Tromey
@ 2013-04-30 23:29   ` Maxime Coste
  0 siblings, 0 replies; 14+ messages in thread
From: Maxime Coste @ 2013-04-30 23:29 UTC (permalink / raw)
  To: gdb-patches

Hello,

Here are the corrected patches.

Maxime.



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

* Re: [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame
  2013-04-30 11:05   ` Tom Tromey
  2013-04-30 11:53     ` Joel Brobecker
@ 2013-05-06 16:54     ` Pedro Alves
  2013-05-10 19:50       ` Tom Tromey
  2013-05-14 13:23       ` Maxime Coste
  1 sibling, 2 replies; 14+ messages in thread
From: Pedro Alves @ 2013-05-06 16:54 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Maxime Coste, gdb-patches

On 04/29/2013 09:27 PM, Tom Tromey wrote:
>>>>>> "Maxime" == Maxime Coste <frrrwww@gmail.com> writes:
> 
> Maxime> select_frame calls specify if the frame is selected due to
> Maxime> a breakpoint/signal (REASON_STOP), a user command (REASON_USER)
> Maxime> or just as an implementation detail (REASON_IMPL_DETAIL) which
> Maxime> should restore the previous frame once finished.
> 
> I don't mind this approach but I would like to hear from other
> maintainers.

I'm not sure I like the approach.

I couldn't find any use for the REASON_STOP/REASON_USER
distinction in the series.  If there's a rationale for it,
it'd be good to hear it, otherwise it just looks like over engineering.

The (fi != selected_frame) check in the REASON_STOP
looks suspicious.  Was the intent to prevent a notification
if the program stopped in the same function it was stopped
before it was resumed?

IMO, it'd be better to leave select_frame unaware of why it's being
called, and just add a wrapper for user visible frame selection.
It feels like different conceptual levels to me.  IOW, something like:

void
select_user_frame (struct frame_info *fi)
{
  int changed = (fi != selected_frame);

  select_frame (fi);

  if (changed)
   observer_notify_frame_changed (fi);
}

But,
note that in non-stop mode, e.g., thread #2 may be running while
you inspect thread #1.  If thread #2 stops for any reason, say, a breakpoint,
GDB switches temporarily to thread #2 to handle the event, and then that ends
up calling normal_stop and select_frame.  The patch makes that a
user visible frame change.  But, what happens is that GDB immediately
afterwards changes back to thread #1 (and its frame), using a cleanup, giving
the illusion that thread #1 was selected the whole time.  This frame restore
is an IMPL_DETAIL select_frame in this approach, so I think the frame
change observer (python, in this case) ends up confused.

Another problematic case I can think of off hand, is around
errors.  Say, the target is running, and while handling an
event, we error out, and normal_stop isn't reached.

I'm wondering whether we really need to call the frame change
observers for stops.  We have stop notifications/observers in
both Python and MI, so it seems to be a script/frontend can
already get the info it needs from those.

If we limit frame change notifications to user frame changes
(CLI up/down/frame and MI equivalents), then these issues
with stops would be non-issues by design...

-- 
Pedro Alves


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

* Re: [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame
  2013-05-06 16:54     ` Pedro Alves
@ 2013-05-10 19:50       ` Tom Tromey
  2013-05-14 13:23       ` Maxime Coste
  1 sibling, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2013-05-10 19:50 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Maxime Coste, gdb-patches

>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> If we limit frame change notifications to user frame changes
Pedro> (CLI up/down/frame and MI equivalents), then these issues
Pedro> with stops would be non-issues by design...

That sounds like a reasonable plan to me.

Tom


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

* Re: [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame
  2013-05-06 16:54     ` Pedro Alves
  2013-05-10 19:50       ` Tom Tromey
@ 2013-05-14 13:23       ` Maxime Coste
  1 sibling, 0 replies; 14+ messages in thread
From: Maxime Coste @ 2013-05-14 13:23 UTC (permalink / raw)
  To: Pedro Alves, Tom Tromey; +Cc: gdb-patches

Hello

On Mon, 06 May 2013 17:54:01 +0100, Pedro Alves <palves@redhat.com> wrote:
> IMO, it'd be better to leave select_frame unaware of why it's being
> called, and just add a wrapper for user visible frame selection.
> It feels like different conceptual levels to me.  IOW, something like:
> 
> void
> select_user_frame (struct frame_info *fi)
> [...]

That seems better to me too, I went the other way because at first I tried
to add checks for frame restoration (there were IMPL_DETAIL_{PUSH,POP}
with a counter checking that only IMPL_DETAIL_* were nested...

I'll prepare a patch using this approach.

> If we limit frame change notifications to user frame changes
> (CLI up/down/frame and MI equivalents), then these issues
> with stops would be non-issues by design...

Yes, this seems more reasonable as well.

Thanks for the review.

Maxime.


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

end of thread, other threads:[~2013-05-14 13:23 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-26 21:07 Add a python event registry for selected frame changes Maxime Coste
2013-04-26 21:09 ` [PATCH 1/3] Add a select_frame_reason enum parameter to select_frame Maxime Coste
2013-04-30 11:05   ` Tom Tromey
2013-04-30 11:53     ` Joel Brobecker
2013-05-06 16:54     ` Pedro Alves
2013-05-10 19:50       ` Tom Tromey
2013-05-14 13:23       ` Maxime Coste
2013-04-26 21:10 ` [PATCH 2/3] Add a frame_changed observer Maxime Coste
2013-04-30 10:51   ` Tom Tromey
2013-04-27  7:55 ` [PATCH 3/3] Add a gdb.events.frame_change event registry Maxime Coste
2013-04-30 11:07   ` Tom Tromey
2013-04-30 11:09     ` Tom Tromey
2013-04-30 10:53 ` Add a python event registry for selected frame changes Tom Tromey
2013-04-30 23:29   ` Maxime Coste

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox