]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/record-btrace.c
Push pruning old threads down to the target
[thirdparty/binutils-gdb.git] / gdb / record-btrace.c
index 166e78edace1bc4d96bd8a8b0944b4cc251eb005..65d28e39c9bff0eb2d38b182aa423712b481c544 100644 (file)
@@ -26,7 +26,6 @@
 #include "gdbcmd.h"
 #include "disasm.h"
 #include "observer.h"
-#include "exceptions.h"
 #include "cli/cli-utils.h"
 #include "source.h"
 #include "ui-out.h"
@@ -36,6 +35,8 @@
 #include "frame-unwind.h"
 #include "hashtab.h"
 #include "infrun.h"
+#include "event-loop.h"
+#include "inf-loop.h"
 
 /* The target_ops of record-btrace.  */
 static struct target_ops record_btrace_ops;
@@ -60,6 +61,15 @@ static const char *replay_memory_access = replay_memory_access_read_only;
 static struct cmd_list_element *set_record_btrace_cmdlist;
 static struct cmd_list_element *show_record_btrace_cmdlist;
 
+/* The execution direction of the last resume we got.  See record-full.c.  */
+static enum exec_direction_kind record_btrace_resume_exec_dir = EXEC_FORWARD;
+
+/* The async event handler for reverse/replay execution.  */
+static struct async_event_handler *record_btrace_async_inferior_event_handler;
+
+/* A flag indicating that we are currently generating a core file.  */
+static int record_btrace_generating_corefile;
+
 /* Print a record-btrace debug message.  Use do ... while (0) to avoid
    ambiguities when used in if statements.  */
 
@@ -166,10 +176,18 @@ record_btrace_auto_disable (void)
   record_btrace_thread_observer = NULL;
 }
 
+/* The record-btrace async event handler function.  */
+
+static void
+record_btrace_handle_async_inferior_event (gdb_client_data data)
+{
+  inferior_event_handler (INF_REG_EVENT, NULL);
+}
+
 /* The to_open method of target record-btrace.  */
 
 static void
-record_btrace_open (char *args, int from_tty)
+record_btrace_open (const char *args, int from_tty)
 {
   struct cleanup *disable_chain;
   struct thread_info *tp;
@@ -190,7 +208,7 @@ record_btrace_open (char *args, int from_tty)
   gdb_assert (record_btrace_thread_observer == NULL);
 
   disable_chain = make_cleanup (null_cleanup, NULL);
-  ALL_THREADS (tp)
+  ALL_NON_EXITED_THREADS (tp)
     if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
       {
        btrace_enable (tp);
@@ -202,6 +220,11 @@ record_btrace_open (char *args, int from_tty)
 
   push_target (&record_btrace_ops);
 
+  record_btrace_async_inferior_event_handler
+    = create_async_event_handler (record_btrace_handle_async_inferior_event,
+                                 NULL);
+  record_btrace_generating_corefile = 0;
+
   observer_notify_record_changed (current_inferior (),  1);
 
   discard_cleanups (disable_chain);
@@ -218,7 +241,7 @@ record_btrace_stop_recording (struct target_ops *self)
 
   record_btrace_auto_disable ();
 
-  ALL_THREADS (tp)
+  ALL_NON_EXITED_THREADS (tp)
     if (tp->btrace.target != NULL)
       btrace_disable (tp);
 }
@@ -230,13 +253,16 @@ record_btrace_close (struct target_ops *self)
 {
   struct thread_info *tp;
 
+  if (record_btrace_async_inferior_event_handler != NULL)
+    delete_async_event_handler (&record_btrace_async_inferior_event_handler);
+
   /* Make sure automatic recording gets disabled even if we did not stop
      recording before closing the record-btrace target.  */
   record_btrace_auto_disable ();
 
   /* We should have already stopped recording.
      Tear down btrace in case we have not.  */
-  ALL_THREADS (tp)
+  ALL_NON_EXITED_THREADS (tp)
     btrace_teardown (tp);
 }
 
@@ -812,7 +838,7 @@ record_btrace_is_replaying (struct target_ops *self)
 {
   struct thread_info *tp;
 
-  ALL_THREADS (tp)
+  ALL_NON_EXITED_THREADS (tp)
     if (btrace_is_replaying (tp))
       return 1;
 
@@ -831,6 +857,7 @@ record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
 
   /* Filter out requests that don't make sense during replay.  */
   if (replay_memory_access == replay_memory_access_read_only
+      && !record_btrace_generating_corefile
       && record_btrace_is_replaying (ops))
     {
       switch (object)
@@ -868,13 +895,9 @@ record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
     }
 
   /* Forward the request.  */
-  for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
-    if (ops->to_xfer_partial != NULL)
-      return ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
-                                  offset, len, xfered_len);
-
-  *xfered_len = len;
-  return TARGET_XFER_UNAVAILABLE;
+  ops = ops->beneath;
+  return ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
+                              offset, len, xfered_len);
 }
 
 /* The to_insert_breakpoint method of target record-btrace.  */
@@ -946,7 +969,7 @@ record_btrace_fetch_registers (struct target_ops *ops,
   gdb_assert (tp != NULL);
 
   replay = tp->btrace.replay;
-  if (replay != NULL)
+  if (replay != NULL && !record_btrace_generating_corefile)
     {
       const struct btrace_insn *insn;
       struct gdbarch *gdbarch;
@@ -968,14 +991,9 @@ record_btrace_fetch_registers (struct target_ops *ops,
     }
   else
     {
-      struct target_ops *t;
+      struct target_ops *t = ops->beneath;
 
-      for (t = ops->beneath; t != NULL; t = t->beneath)
-       if (t->to_fetch_registers != NULL)
-         {
-           t->to_fetch_registers (t, regcache, regno);
-           break;
-         }
+      t->to_fetch_registers (t, regcache, regno);
     }
 }
 
@@ -987,19 +1005,13 @@ record_btrace_store_registers (struct target_ops *ops,
 {
   struct target_ops *t;
 
-  if (record_btrace_is_replaying (ops))
+  if (!record_btrace_generating_corefile && record_btrace_is_replaying (ops))
     error (_("This record target does not allow writing registers."));
 
   gdb_assert (may_write_registers != 0);
 
-  for (t = ops->beneath; t != NULL; t = t->beneath)
-    if (t->to_store_registers != NULL)
-      {
-       t->to_store_registers (t, regcache, regno);
-       return;
-      }
-
-  noprocess ();
+  t = ops->beneath;
+  t->to_store_registers (t, regcache, regno);
 }
 
 /* The to_prepare_to_store method of target record-btrace.  */
@@ -1010,15 +1022,11 @@ record_btrace_prepare_to_store (struct target_ops *ops,
 {
   struct target_ops *t;
 
-  if (record_btrace_is_replaying (ops))
+  if (!record_btrace_generating_corefile && record_btrace_is_replaying (ops))
     return;
 
-  for (t = ops->beneath; t != NULL; t = t->beneath)
-    if (t->to_prepare_to_store != NULL)
-      {
-       t->to_prepare_to_store (t, regcache);
-       return;
-      }
+  t = ops->beneath;
+  t->to_prepare_to_store (t, regcache);
 }
 
 /* The branch trace frame cache.  */
@@ -1490,23 +1498,23 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
 
   DEBUG ("resume %s: %s", target_pid_to_str (ptid), step ? "step" : "cont");
 
+  /* Store the execution direction of the last resume.  */
+  record_btrace_resume_exec_dir = execution_direction;
+
   tp = record_btrace_find_resume_thread (ptid);
   if (tp == NULL)
     error (_("Cannot find thread to resume."));
 
   /* Stop replaying other threads if the thread to resume is not replaying.  */
   if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE)
-    ALL_THREADS (other)
+    ALL_NON_EXITED_THREADS (other)
       record_btrace_stop_replaying (other);
 
   /* As long as we're not replaying, just forward the request.  */
   if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
     {
-      for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
-       if (ops->to_resume != NULL)
-         return ops->to_resume (ops, ptid, step, signal);
-
-      error (_("Cannot find target for stepping."));
+      ops = ops->beneath;
+      return ops->to_resume (ops, ptid, step, signal);
     }
 
   /* Compute the btrace thread flag for the requested move.  */
@@ -1524,6 +1532,13 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
 
   /* We just indicate the resume intent here.  The actual stepping happens in
      record_btrace_wait below.  */
+
+  /* Async support.  */
+  if (target_can_async_p ())
+    {
+      target_async (inferior_event_handler, 0);
+      mark_async_event_handler (record_btrace_async_inferior_event_handler);
+    }
 }
 
 /* Find a thread to move.  */
@@ -1539,7 +1554,7 @@ record_btrace_find_thread_to_move (ptid_t ptid)
     return tp;
 
   /* Otherwise, find one other thread that has been resumed.  */
-  ALL_THREADS (tp)
+  ALL_NON_EXITED_THREADS (tp)
     if ((tp->btrace.flags & BTHR_MOVE) != 0)
       return tp;
 
@@ -1722,11 +1737,8 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
   /* As long as we're not replaying, just forward the request.  */
   if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
     {
-      for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
-       if (ops->to_wait != NULL)
-         return ops->to_wait (ops, ptid, status, options);
-
-      error (_("Cannot find target for waiting."));
+      ops = ops->beneath;
+      return ops->to_wait (ops, ptid, status, options);
     }
 
   /* Let's find a thread to move.  */
@@ -1744,7 +1756,7 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
 
   /* Stop all other threads. */
   if (!non_stop)
-    ALL_THREADS (other)
+    ALL_NON_EXITED_THREADS (other)
       other->btrace.flags &= ~BTHR_MOVE;
 
   /* Start record histories anew from the current position.  */
@@ -1778,22 +1790,18 @@ record_btrace_decr_pc_after_break (struct target_ops *ops,
   return ops->beneath->to_decr_pc_after_break (ops->beneath, gdbarch);
 }
 
-/* The to_find_new_threads method of target record-btrace.  */
+/* The to_update_thread_list method of target record-btrace.  */
 
 static void
-record_btrace_find_new_threads (struct target_ops *ops)
+record_btrace_update_thread_list (struct target_ops *ops)
 {
-  /* Don't expect new threads if we're replaying.  */
+  /* We don't add or remove threads during replay.  */
   if (record_btrace_is_replaying (ops))
     return;
 
   /* Forward the request.  */
-  for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
-    if (ops->to_find_new_threads != NULL)
-      {
-       ops->to_find_new_threads (ops);
-       break;
-      }
+  ops = ops->beneath;
+  ops->to_update_thread_list (ops);
 }
 
 /* The to_thread_alive method of target record-btrace.  */
@@ -1806,11 +1814,8 @@ record_btrace_thread_alive (struct target_ops *ops, ptid_t ptid)
     return find_thread_ptid (ptid) != NULL;
 
   /* Forward the request.  */
-  for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
-    if (ops->to_thread_alive != NULL)
-      return ops->to_thread_alive (ops, ptid);
-
-  return 0;
+  ops = ops->beneath;
+  return ops->to_thread_alive (ops, ptid);
 }
 
 /* Set the replay branch trace instruction iterator.  If IT is NULL, replay
@@ -1898,6 +1903,30 @@ record_btrace_goto (struct target_ops *self, ULONGEST insn)
   print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
 }
 
+/* The to_execution_direction target method.  */
+
+static enum exec_direction_kind
+record_btrace_execution_direction (struct target_ops *self)
+{
+  return record_btrace_resume_exec_dir;
+}
+
+/* The to_prepare_to_generate_core target method.  */
+
+static void
+record_btrace_prepare_to_generate_core (struct target_ops *self)
+{
+  record_btrace_generating_corefile = 1;
+}
+
+/* The to_done_generating_core target method.  */
+
+static void
+record_btrace_done_generating_core (struct target_ops *self)
+{
+  record_btrace_generating_corefile = 0;
+}
+
 /* Initialize the record-btrace target ops.  */
 
 static void
@@ -1934,13 +1963,16 @@ init_record_btrace_ops (void)
   ops->to_get_tailcall_unwinder = &record_btrace_to_get_tailcall_unwinder;
   ops->to_resume = record_btrace_resume;
   ops->to_wait = record_btrace_wait;
-  ops->to_find_new_threads = record_btrace_find_new_threads;
+  ops->to_update_thread_list = record_btrace_update_thread_list;
   ops->to_thread_alive = record_btrace_thread_alive;
   ops->to_goto_record_begin = record_btrace_goto_begin;
   ops->to_goto_record_end = record_btrace_goto_end;
   ops->to_goto_record = record_btrace_goto;
   ops->to_can_execute_reverse = record_btrace_can_execute_reverse;
   ops->to_decr_pc_after_break = record_btrace_decr_pc_after_break;
+  ops->to_execution_direction = record_btrace_execution_direction;
+  ops->to_prepare_to_generate_core = record_btrace_prepare_to_generate_core;
+  ops->to_done_generating_core = record_btrace_done_generating_core;
   ops->to_stratum = record_stratum;
   ops->to_magic = OPS_MAGIC;
 }