2011-05-26 Pedro Alves <pedro@codesourcery.com>
authorPedro Alves <palves@redhat.com>
Thu, 26 May 2011 18:11:33 +0000 (18:11 +0000)
committerPedro Alves <palves@redhat.com>
Thu, 26 May 2011 18:11:33 +0000 (18:11 +0000)
gdb/
* record.c: Include event-loop.h, inf-loop.h.
(record_beneath_to_async): New global.
(tmp_to_async): New global.
(record_async_inferior_event_token): New global.
(record_open_1): Don't error out if async is enabled.
(record_open): Handle to_async.  Create an async event source in
the event loop.
(record_close): Delete the async event source.
(record_resumed): New global.
(record_execution_dir): New global.
(record_resume, record_core_resume): Set them.  Register the
target on the event loop.
(record_wait): Rename to ...
(record_wait_1): ... this.  Add more debug output.  Handle
TARGET_WNOHANG, and the target beneath returning
TARGET_WAITKIND_IGNORE.
(record_wait): Reimplement on top of record_wait_1.
(record_async_mask_value): New global.
(record_async, record_async_mask, record_can_async_p)
(record_is_async_p, record_execution_direction): New functions.
(init_record_ops, init_record_core_ops): Install new methods.
* infrun.c (fetch_inferior_event): Temporarily switch the global
execution direction to the direction the target was going.
(execution_direction): Change type to int.
* target.c (default_execution_direction): New function.
(update_current_target): Inherit and de_fault
to_execution_direction.
* target.h (struct target_ops) <to_execution_direction>: New
field.
(target_execution_direction): New macro.
* inferior.h (execution_direction): Change type to int.

gdb/ChangeLog
gdb/inferior.h
gdb/infrun.c
gdb/record.c
gdb/target.c
gdb/target.h

index 2f6ae9793c8f9a084ac1385fbb73762ac541a3dc..31b34e5810ca47d6d035747fd4494de2507c6126 100644 (file)
@@ -1,3 +1,37 @@
+2011-05-26  Pedro Alves  <pedro@codesourcery.com>
+
+       * record.c: Include event-loop.h, inf-loop.h.
+       (record_beneath_to_async): New global.
+       (tmp_to_async): New global.
+       (record_async_inferior_event_token): New global.
+       (record_open_1): Don't error out if async is enabled.
+       (record_open): Handle to_async.  Create an async event source in
+       the event loop.
+       (record_close): Delete the async event source.
+       (record_resumed): New global.
+       (record_execution_dir): New global.
+       (record_resume, record_core_resume): Set them.  Register the
+       target on the event loop.
+       (record_wait): Rename to ...
+       (record_wait_1): ... this.  Add more debug output.  Handle
+       TARGET_WNOHANG, and the target beneath returning
+       TARGET_WAITKIND_IGNORE.
+       (record_wait): Reimplement on top of record_wait_1.
+       (record_async_mask_value): New global.
+       (record_async, record_async_mask, record_can_async_p)
+       (record_is_async_p, record_execution_direction): New functions.
+       (init_record_ops, init_record_core_ops): Install new methods.
+       * infrun.c (fetch_inferior_event): Temporarily switch the global
+       execution direction to the direction the target was going.
+       (execution_direction): Change type to int.
+       * target.c (default_execution_direction): New function.
+       (update_current_target): Inherit and de_fault
+       to_execution_direction.
+       * target.h (struct target_ops) <to_execution_direction>: New
+       field.
+       (target_execution_direction): New macro.
+       * inferior.h (execution_direction): Change type to int.
+
 2011-05-26  Pedro Alves  <pedro@codesourcery.com>
 
        * infcall.c (call_function_by_hand): Don't allow calling functions
index ae2363dac03bfbf06b30fea4c20414a5f75e2da5..9949136738ecd2d5758109c8f5bf9bf5674c2a15 100644 (file)
@@ -356,7 +356,10 @@ enum exec_direction_kind
     EXEC_ERROR
   };
 
-extern enum exec_direction_kind execution_direction;
+/* The current execution direction.  This should only be set to enum
+   exec_direction_kind values.  It is only an int to make it
+   compatible with make_cleanup_restore_integer.  */
+extern int execution_direction;
 
 /* Save register contents here when executing a "finish" command or are
    about to pop a stack dummy frame, if-and-only-if proceed_to_finish is set.
index 67acdc4fd051df7f1489a92f56427853ce95fffc..8502e69ee5881a627422fa7aa10e7f8e7940e3dc 100644 (file)
@@ -2742,6 +2742,9 @@ fetch_inferior_event (void *client_data)
   overlay_cache_invalid = 1;
   registers_changed ();
 
+  make_cleanup_restore_integer (&execution_direction);
+  execution_direction = target_execution_direction ();
+
   if (deprecated_target_wait_hook)
     ecs->ptid =
       deprecated_target_wait_hook (waiton_ptid, &ecs->ws, TARGET_WNOHANG);
@@ -6878,7 +6881,7 @@ save_inferior_ptid (void)
    Set exec-direction / show exec-direction commands
    (returns error unless target implements to_set_exec_direction method).  */
 
-enum exec_direction_kind execution_direction = EXEC_FORWARD;
+int execution_direction = EXEC_FORWARD;
 static const char exec_forward[] = "forward";
 static const char exec_reverse[] = "reverse";
 static const char *exec_direction = exec_forward;
index 65eaa111a7c4ae148e178d31245498a1ec886d7a..9a4fbba6287437c41b870182e5d1b61a7f8ee2f6 100644 (file)
@@ -30,6 +30,8 @@
 #include "record.h"
 #include "elf-bfd.h"
 #include "gcore.h"
+#include "event-loop.h"
+#include "inf-loop.h"
 
 #include <signal.h>
 
@@ -231,6 +233,7 @@ static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *,
 static int (*record_beneath_to_stopped_by_watchpoint) (void);
 static int (*record_beneath_to_stopped_data_address) (struct target_ops *,
                                                      CORE_ADDR *);
+static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *);
 
 /* Alloc and free functions for record_reg, record_mem, and record_end 
    entries.  */
@@ -806,9 +809,22 @@ static int (*tmp_to_remove_breakpoint) (struct gdbarch *,
                                        struct bp_target_info *);
 static int (*tmp_to_stopped_by_watchpoint) (void);
 static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
+static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
+static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *);
 
 static void record_restore (void);
 
+/* Asynchronous signal handle registered as event loop source for when
+   we have pending events ready to be passed to the core.  */
+
+static struct async_event_handler *record_async_inferior_event_token;
+
+static void
+record_async_inferior_event_handler (gdb_client_data data)
+{
+  inferior_event_handler (INF_REG_EVENT, NULL);
+}
+
 /* Open the process record target.  */
 
 static void
@@ -852,9 +868,6 @@ record_open_1 (char *name, int from_tty)
   if (non_stop)
     error (_("Process record target can't debug inferior in non-stop mode "
             "(non-stop)."));
-  if (target_async_permitted)
-    error (_("Process record target can't debug inferior in asynchronous "
-            "mode (target-async)."));
 
   if (!gdbarch_process_record_p (target_gdbarch))
     error (_("Process record: the current architecture doesn't support "
@@ -911,6 +924,7 @@ record_open (char *name, int from_tty)
   tmp_to_remove_breakpoint = NULL;
   tmp_to_stopped_by_watchpoint = NULL;
   tmp_to_stopped_data_address = NULL;
+  tmp_to_async = NULL;
 
   /* Set the beneath function pointers.  */
   for (t = current_target.beneath; t != NULL; t = t->beneath)
@@ -943,6 +957,8 @@ record_open (char *name, int from_tty)
        tmp_to_stopped_by_watchpoint = t->to_stopped_by_watchpoint;
       if (!tmp_to_stopped_data_address)
        tmp_to_stopped_data_address = t->to_stopped_data_address;
+      if (!tmp_to_async)
+       tmp_to_async = t->to_async;
     }
   if (!tmp_to_xfer_partial)
     error (_("Could not find 'to_xfer_partial' method on the target stack."));
@@ -966,11 +982,17 @@ record_open (char *name, int from_tty)
   record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
   record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
   record_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
+  record_beneath_to_async = tmp_to_async;
 
   if (core_bfd)
     record_core_open_1 (name, from_tty);
   else
     record_open_1 (name, from_tty);
+
+  /* Register extra event sources in the event loop.  */
+  record_async_inferior_event_token
+    = create_async_event_handler (record_async_inferior_event_handler,
+                                 NULL);
 }
 
 /* "to_close" target method.  Close the process record target.  */
@@ -1002,10 +1024,34 @@ record_close (int quitting)
        }
       record_core_buf_list = NULL;
     }
+
+  if (record_async_inferior_event_token)
+    delete_async_event_handler (&record_async_inferior_event_token);
 }
 
 static int record_resume_step = 0;
 
+/* True if we've been resumed, and so each record_wait call should
+   advance execution.  If this is false, record_wait will return a
+   TARGET_WAITKIND_IGNORE.  */
+static int record_resumed = 0;
+
+/* The execution direction of the last resume we got.  This is
+   necessary for async mode.  Vis (order is not strictly accurate):
+
+   1. user has the global execution direction set to forward
+   2. user does a reverse-step command
+   3. record_resume is called with global execution direction
+      temporarily switched to reverse
+   4. GDB's execution direction is reverted back to forward
+   5. target record notifies event loop there's an event to handle
+   6. infrun asks the target which direction was it going, and switches
+      the global execution direction accordingly (to reverse)
+   7. infrun polls an event out of the record target, and handles it
+   8. GDB goes back to the event loop, and goto #4.
+*/
+static enum exec_direction_kind record_execution_dir = EXEC_FORWARD;
+
 /* "to_resume" target method.  Resume the process record target.  */
 
 static void
@@ -1013,6 +1059,8 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step,
                enum target_signal signal)
 {
   record_resume_step = step;
+  record_resumed = 1;
+  record_execution_dir = execution_direction;
 
   if (!RECORD_IS_REPLAY)
     {
@@ -1054,6 +1102,16 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step,
       record_beneath_to_resume (record_beneath_to_resume_ops,
                                 ptid, step, signal);
     }
+
+  /* We are about to start executing the inferior (or simulate it),
+     let's register it with the event loop.  */
+  if (target_can_async_p ())
+    {
+      target_async (inferior_event_handler, 0);
+      /* Notify the event loop there's an event to wait for.  We do
+        most of the work in record_wait.  */
+      mark_async_event_handler (record_async_inferior_event_token);
+    }
 }
 
 static int record_get_sig = 0;
@@ -1100,17 +1158,27 @@ record_wait_cleanups (void *ignore)
    where to stop.  */
 
 static ptid_t
-record_wait (struct target_ops *ops,
-            ptid_t ptid, struct target_waitstatus *status,
-            int options)
+record_wait_1 (struct target_ops *ops,
+              ptid_t ptid, struct target_waitstatus *status,
+              int options)
 {
   struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
 
   if (record_debug)
     fprintf_unfiltered (gdb_stdlog,
                        "Process record: record_wait "
-                       "record_resume_step = %d\n",
-                       record_resume_step);
+                       "record_resume_step = %d, record_resumed = %d, direction=%s\n",
+                       record_resume_step, record_resumed,
+                       record_execution_dir == EXEC_FORWARD ? "forward" : "reverse");
+
+  if (!record_resumed)
+    {
+      gdb_assert ((options & TARGET_WNOHANG) != 0);
+
+      /* No interesting event.  */
+      status->kind = TARGET_WAITKIND_IGNORE;
+      return minus_one_ptid;
+    }
 
   record_get_sig = 0;
   signal (SIGINT, record_sig_handler);
@@ -1134,12 +1202,20 @@ record_wait (struct target_ops *ops,
            {
              ret = record_beneath_to_wait (record_beneath_to_wait_ops,
                                            ptid, status, options);
+             if (status->kind == TARGET_WAITKIND_IGNORE)
+               {
+                 if (record_debug)
+                   fprintf_unfiltered (gdb_stdlog,
+                                       "Process record: record_wait "
+                                       "target beneath not done yet\n");
+                 return ret;
+               }
 
               if (single_step_breakpoints_inserted ())
                 remove_single_step_breakpoints ();
 
              if (record_resume_step)
-               return ret;
+               return ret;
 
              /* Is this a SIGTRAP?  */
              if (status->kind == TARGET_WAITKIND_STOPPED
@@ -1204,6 +1280,10 @@ record_wait (struct target_ops *ops,
                          set_executing (inferior_ptid, 1);
                        }
 
+                     if (record_debug)
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: record_wait "
+                                           "issuing one more step in the target beneath\n");
                      record_beneath_to_resume (record_beneath_to_resume_ops,
                                                ptid, step,
                                                TARGET_SIGNAL_0);
@@ -1385,6 +1465,24 @@ replay_out:
   return inferior_ptid;
 }
 
+static ptid_t
+record_wait (struct target_ops *ops,
+            ptid_t ptid, struct target_waitstatus *status,
+            int options)
+{
+  ptid_t return_ptid;
+
+  return_ptid = record_wait_1 (ops, ptid, status, options);
+  if (status->kind != TARGET_WAITKIND_IGNORE)
+    {
+      /* We're reporting a stop.  Make sure any spurious
+        target_wait(WNOHANG) doesn't advance the target until the
+        core wants us resumed again.  */
+      record_resumed = 0;
+    }
+  return return_ptid;
+}
+
 static int
 record_stopped_by_watchpoint (void)
 {
@@ -1719,6 +1817,58 @@ record_goto_bookmark (gdb_byte *bookmark, int from_tty)
   return;
 }
 
+static int record_async_mask_value = 1;
+
+static void
+record_async (void (*callback) (enum inferior_event_type event_type,
+                               void *context), void *context)
+{
+  if (record_async_mask_value == 0)
+    internal_error (__FILE__, __LINE__,
+                   _("Calling record_async when async is masked"));
+
+  /* If we're on top of a line target (e.g., linux-nat, remote), then
+     set it to async mode as well.  Will be NULL if we're sitting on
+     top of the core target, for "record restore".  */
+  if (record_beneath_to_async != NULL)
+    record_beneath_to_async (callback, context);
+}
+
+static int
+record_async_mask (int new_mask)
+{
+  int curr_mask = record_async_mask_value;
+
+  record_async_mask_value = new_mask;
+  return curr_mask;
+}
+
+static int
+record_can_async_p (void)
+{
+  /* We only enable async when the user specifically asks for it.  */
+  if (!target_async_permitted)
+    return 0;
+
+  return record_async_mask_value;
+}
+
+static int
+record_is_async_p (void)
+{
+  /* We only enable async when the user specifically asks for it.  */
+  if (!target_async_permitted)
+    return 0;
+
+  return record_async_mask_value;
+}
+
+static enum exec_direction_kind
+record_execution_direction (void)
+{
+  return record_execution_dir;
+}
+
 static void
 init_record_ops (void)
 {
@@ -1746,6 +1896,11 @@ init_record_ops (void)
   /* Add bookmark target methods.  */
   record_ops.to_get_bookmark = record_get_bookmark;
   record_ops.to_goto_bookmark = record_goto_bookmark;
+  record_ops.to_async = record_async;
+  record_ops.to_can_async_p = record_can_async_p;
+  record_ops.to_is_async_p = record_is_async_p;
+  record_ops.to_async_mask = record_async_mask;
+  record_ops.to_execution_direction = record_execution_direction;
   record_ops.to_magic = OPS_MAGIC;
 }
 
@@ -1756,6 +1911,18 @@ record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
                     enum target_signal signal)
 {
   record_resume_step = step;
+  record_resumed = 1;
+  record_execution_dir = execution_direction;
+
+  /* We are about to start executing the inferior (or simulate it),
+     let's register it with the event loop.  */
+  if (target_can_async_p ())
+    {
+      target_async (inferior_event_handler, 0);
+
+      /* Notify the event loop there's an event to wait for.  */
+      mark_async_event_handler (record_async_inferior_event_token);
+    }
 }
 
 /* "to_kill" method for prec over corefile.  */
@@ -1955,6 +2122,11 @@ init_record_core_ops (void)
   /* Add bookmark target methods.  */
   record_core_ops.to_get_bookmark = record_get_bookmark;
   record_core_ops.to_goto_bookmark = record_goto_bookmark;
+  record_core_ops.to_async = record_async;
+  record_core_ops.to_can_async_p = record_can_async_p;
+  record_core_ops.to_is_async_p = record_is_async_p;
+  record_core_ops.to_async_mask = record_async_mask;
+  record_core_ops.to_execution_direction = record_execution_direction;
   record_core_ops.to_magic = OPS_MAGIC;
 }
 
index ed2da34744cc534c74afede90930ca9a0dfb7986..0b7e61e04c80416993b96cdb95716d94f097a35d 100644 (file)
@@ -544,6 +544,18 @@ default_get_ada_task_ptid (long lwp, long tid)
   return ptid_build (ptid_get_pid (inferior_ptid), lwp, tid);
 }
 
+static enum exec_direction_kind
+default_execution_direction (void)
+{
+  if (!target_can_execute_reverse)
+    return EXEC_FORWARD;
+  else if (!target_can_async_p ())
+    return EXEC_FORWARD;
+  else
+    gdb_assert_not_reached ("\
+to_execution_direction must be implemented for reverse async");
+}
+
 /* Go through the target stack from top to bottom, copying over zero
    entries in current_target, then filling in still empty entries.  In
    effect, we are doing class inheritance through the pushed target
@@ -654,6 +666,7 @@ update_current_target (void)
       INHERIT (to_goto_bookmark, t);
       /* Do not inherit to_get_thread_local_address.  */
       INHERIT (to_can_execute_reverse, t);
+      INHERIT (to_execution_direction, t);
       INHERIT (to_thread_architecture, t);
       /* Do not inherit to_read_description.  */
       INHERIT (to_get_ada_task_ptid, t);
@@ -897,6 +910,8 @@ update_current_target (void)
   de_fault (to_traceframe_info,
            (struct traceframe_info * (*) (void))
            tcomplain);
+  de_fault (to_execution_direction, default_execution_direction);
+
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
index fd58bd95c98d9d5e1138b45caabfb744b64d0eff..21e14501eb86a09d4d5b12586549e79b69a52f1a 100644 (file)
@@ -641,6 +641,11 @@ struct target_ops
     /* Can target execute in reverse?  */
     int (*to_can_execute_reverse) (void);
 
+    /* The direction the target is currently executing.  Must be
+       implemented on targets that support reverse execution and async
+       mode.  The default simply returns forward execution.  */
+    enum exec_direction_kind (*to_execution_direction) (void);
+
     /* Does this target support debugging multiple processes
        simultaneously?  */
     int (*to_supports_multi_process) (void);
@@ -1271,6 +1276,9 @@ int target_supports_non_stop (void);
 #define target_async_mask(MASK)        \
   (current_target.to_async_mask (MASK))
 
+#define target_execution_direction() \
+  (current_target.to_execution_direction ())
+
 /* Converts a process id to a string.  Usually, the string just contains
    `process xyz', but on some systems it may contain
    `process xyz thread abc'.  */