Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / ravenscar-thread.c
index 7fca51da2a79f9271449d5462af6279351871717..490af3a0bb47becc0d0e83d6432e2a6d29cd9608 100644 (file)
@@ -1,6 +1,6 @@
 /* Ada Ravenscar thread support.
 
-   Copyright (C) 2004-2020 Free Software Foundation, Inc.
+   Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -30,6 +30,7 @@
 #include "top.h"
 #include "regcache.h"
 #include "objfiles.h"
+#include <unordered_map>
 
 /* This module provides support for "Ravenscar" tasks (Ada) when
    debugging on bare-metal targets.
@@ -86,7 +87,7 @@ struct ravenscar_thread_target final : public target_ops
 
   strata stratum () const override { return thread_stratum; }
 
-  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+  ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
   void resume (ptid_t, int, enum gdb_signal) override;
 
   void fetch_registers (struct regcache *, int) override;
@@ -102,18 +103,31 @@ struct ravenscar_thread_target final : public target_ops
 
   bool stopped_data_address (CORE_ADDR *) override;
 
+  enum target_xfer_status xfer_partial (enum target_object object,
+                                       const char *annex,
+                                       gdb_byte *readbuf,
+                                       const gdb_byte *writebuf,
+                                       ULONGEST offset, ULONGEST len,
+                                       ULONGEST *xfered_len) override;
+
   bool thread_alive (ptid_t ptid) override;
 
   int core_of_thread (ptid_t ptid) override;
 
   void update_thread_list () override;
 
-  const char *extra_thread_info (struct thread_info *) override;
-
   std::string pid_to_str (ptid_t) override;
 
   ptid_t get_ada_task_ptid (long lwp, long thread) override;
 
+  struct btrace_target_info *enable_btrace (ptid_t ptid,
+                                           const struct btrace_config *conf)
+    override
+  {
+    ptid = get_base_thread_from_ravenscar_task (ptid);
+    return beneath ()->enable_btrace (ptid, conf);
+  }
+
   void mourn_inferior () override;
 
   void close () override
@@ -133,6 +147,24 @@ private:
   ptid_t active_task (int cpu);
   bool task_is_currently_active (ptid_t ptid);
   bool runtime_initialized ();
+  int get_thread_base_cpu (ptid_t ptid);
+  ptid_t get_base_thread_from_ravenscar_task (ptid_t ptid);
+  void add_thread (struct ada_task_info *task);
+
+  /* Like switch_to_thread, but uses the base ptid for the thread.  */
+  void set_base_thread_from_ravenscar_task (ptid_t ptid)
+  {
+    process_stratum_target *proc_target
+      = as_process_stratum_target (this->beneath ());
+    ptid_t underlying = get_base_thread_from_ravenscar_task (ptid);
+    switch_to_thread (find_thread_ptid (proc_target, underlying));
+  }
+
+  /* This maps a TID to the CPU on which it was running.  This is
+     needed because sometimes the runtime will report an active task
+     that hasn't yet been put on the list of tasks that is read by
+     ada-tasks.c.  */
+  std::unordered_map<long, int> m_cpu_map;
 };
 
 /* Return true iff PTID corresponds to a ravenscar task.  */
@@ -156,17 +188,26 @@ is_ravenscar_task (ptid_t ptid)
    This assume that PTID is a valid ptid_t.  Otherwise, a gdb_assert
    will be triggered.  */
 
-static int
-ravenscar_get_thread_base_cpu (ptid_t ptid)
+int
+ravenscar_thread_target::get_thread_base_cpu (ptid_t ptid)
 {
   int base_cpu;
 
   if (is_ravenscar_task (ptid))
     {
-      struct ada_task_info *task_info = ada_get_task_info_from_ptid (ptid);
-
-      gdb_assert (task_info != NULL);
-      base_cpu = task_info->base_cpu;
+      /* Prefer to not read inferior memory if possible, to avoid
+        reentrancy problems with xfer_partial.  */
+      auto iter = m_cpu_map.find (ptid.tid ());
+
+      if (iter != m_cpu_map.end ())
+       base_cpu = iter->second;
+      else
+       {
+         struct ada_task_info *task_info = ada_get_task_info_from_ptid (ptid);
+
+         gdb_assert (task_info != NULL);
+         base_cpu = task_info->base_cpu;
+       }
     }
   else
     {
@@ -190,8 +231,7 @@ ravenscar_get_thread_base_cpu (ptid_t ptid)
 bool
 ravenscar_thread_target::task_is_currently_active (ptid_t ptid)
 {
-  ptid_t active_task_ptid
-    = active_task (ravenscar_get_thread_base_cpu (ptid));
+  ptid_t active_task_ptid = active_task (get_thread_base_cpu (ptid));
 
   return ptid == active_task_ptid;
 }
@@ -202,15 +242,15 @@ ravenscar_thread_target::task_is_currently_active (ptid_t ptid)
    This is the thread that corresponds to the CPU on which the task
    is running.  */
 
-static ptid_t
-get_base_thread_from_ravenscar_task (ptid_t ptid)
+ptid_t
+ravenscar_thread_target::get_base_thread_from_ravenscar_task (ptid_t ptid)
 {
   int base_cpu;
 
   if (!is_ravenscar_task (ptid))
     return ptid;
 
-  base_cpu = ravenscar_get_thread_base_cpu (ptid);
+  base_cpu = get_thread_base_cpu (ptid);
   return ptid_t (ptid.pid (), base_cpu, 0);
 }
 
@@ -227,7 +267,7 @@ ravenscar_thread_target::add_active_thread ()
   int base_cpu;
 
   gdb_assert (!is_ravenscar_task (m_base_ptid));
-  base_cpu = ravenscar_get_thread_base_cpu (m_base_ptid);
+  base_cpu = get_thread_base_cpu (m_base_ptid);
 
   if (!runtime_initialized ())
     return nullptr;
@@ -242,7 +282,10 @@ ravenscar_thread_target::add_active_thread ()
      may not always add it to the thread list.  Add it here.  */
   thread_info *active_thr = find_thread_ptid (proc_target, active_ptid);
   if (active_thr == nullptr)
-    active_thr = add_thread (proc_target, active_ptid);
+    {
+      active_thr = ::add_thread (proc_target, active_ptid);
+      m_cpu_map[active_ptid.tid ()] = base_cpu;
+    }
   return active_thr;
 }
 
@@ -329,7 +372,12 @@ ravenscar_thread_target::resume (ptid_t ptid, int step,
   /* If we see a wildcard resume, we simply pass that on.  Otherwise,
      arrange to resume the base ptid.  */
   inferior_ptid = m_base_ptid;
-  if (ptid != minus_one_ptid)
+  if (ptid.is_pid ())
+    {
+      /* We only have one process, so resume all threads of it.  */
+      ptid = minus_one_ptid;
+    }
+  else if (ptid != minus_one_ptid)
     ptid = m_base_ptid;
   beneath ()->resume (ptid, step, siggnal);
 }
@@ -337,7 +385,7 @@ ravenscar_thread_target::resume (ptid_t ptid, int step,
 ptid_t
 ravenscar_thread_target::wait (ptid_t ptid,
                               struct target_waitstatus *status,
-                              int options)
+                              target_wait_flags options)
 {
   process_stratum_target *beneath
     = as_process_stratum_target (this->beneath ());
@@ -354,34 +402,47 @@ ravenscar_thread_target::wait (ptid_t ptid,
      because we might try switching threads (and thus sending packets)
      after the remote has disconnected.  */
   if (status->kind != TARGET_WAITKIND_EXITED
-      && status->kind != TARGET_WAITKIND_SIGNALLED)
+      && status->kind != TARGET_WAITKIND_SIGNALLED
+      && runtime_initialized ())
     {
       m_base_ptid = event_ptid;
       this->update_thread_list ();
       return this->add_active_thread ()->ptid;
     }
-  return m_base_ptid;
+  return event_ptid;
 }
 
 /* Add the thread associated to the given TASK to the thread list
    (if the thread has already been added, this is a no-op).  */
 
-static void
-ravenscar_add_thread (struct ada_task_info *task)
+void
+ravenscar_thread_target::add_thread (struct ada_task_info *task)
 {
   if (find_thread_ptid (current_inferior (), task->ptid) == NULL)
-    add_thread (current_inferior ()->process_target (), task->ptid);
+    {
+      ::add_thread (current_inferior ()->process_target (), task->ptid);
+      m_cpu_map[task->ptid.tid ()] = task->base_cpu;
+    }
 }
 
 void
 ravenscar_thread_target::update_thread_list ()
 {
+  /* iterate_over_live_ada_tasks requires that inferior_ptid be set,
+     but this isn't always the case in target methods.  So, we ensure
+     it here.  */
+  scoped_restore save_ptid = make_scoped_restore (&inferior_ptid,
+                                                 m_base_ptid);
+
   /* Do not clear the thread list before adding the Ada task, to keep
      the thread that the process stratum has included into it
      (m_base_ptid) and the running thread, that may not have been included
      to system.tasking.debug's list yet.  */
 
-  iterate_over_live_ada_tasks (ravenscar_add_thread);
+  iterate_over_live_ada_tasks ([=] (struct ada_task_info *task)
+                              {
+                                this->add_thread (task);
+                              });
 }
 
 ptid_t
@@ -395,12 +456,6 @@ ravenscar_thread_target::active_task (int cpu)
     return ptid_t (m_base_ptid.pid (), 0, tid);
 }
 
-const char *
-ravenscar_thread_target::extra_thread_info (thread_info *tp)
-{
-  return "Ravenscar task";
-}
-
 bool
 ravenscar_thread_target::thread_alive (ptid_t ptid)
 {
@@ -411,23 +466,61 @@ ravenscar_thread_target::thread_alive (ptid_t ptid)
 std::string
 ravenscar_thread_target::pid_to_str (ptid_t ptid)
 {
-  return string_printf ("Thread %#x", (int) ptid.tid ());
+  if (!is_ravenscar_task (ptid))
+    return beneath ()->pid_to_str (ptid);
+
+  return string_printf ("Ravenscar Thread %#x", (int) ptid.tid ());
 }
 
+/* Temporarily set the ptid of a regcache to some other value.  When
+   this object is destroyed, the regcache's original ptid is
+   restored.  */
+
+class temporarily_change_regcache_ptid
+{
+public:
+
+  temporarily_change_regcache_ptid (struct regcache *regcache, ptid_t new_ptid)
+    : m_regcache (regcache),
+      m_save_ptid (regcache->ptid ())
+  {
+    m_regcache->set_ptid (new_ptid);
+  }
+
+  ~temporarily_change_regcache_ptid ()
+  {
+    m_regcache->set_ptid (m_save_ptid);
+  }
+
+private:
+
+  /* The regcache.  */
+  struct regcache *m_regcache;
+  /* The saved ptid.  */
+  ptid_t m_save_ptid;
+};
+
 void
 ravenscar_thread_target::fetch_registers (struct regcache *regcache, int regnum)
 {
   ptid_t ptid = regcache->ptid ();
 
-  if (runtime_initialized ()
-      && is_ravenscar_task (ptid)
-      && !task_is_currently_active (ptid))
+  if (runtime_initialized () && is_ravenscar_task (ptid))
     {
-      struct gdbarch *gdbarch = regcache->arch ();
-      struct ravenscar_arch_ops *arch_ops
-       = gdbarch_ravenscar_ops (gdbarch);
-
-      arch_ops->fetch_registers (regcache, regnum);
+      if (task_is_currently_active (ptid))
+       {
+         ptid_t base = get_base_thread_from_ravenscar_task (ptid);
+         temporarily_change_regcache_ptid changer (regcache, base);
+         beneath ()->fetch_registers (regcache, regnum);
+       }
+      else
+       {
+         struct gdbarch *gdbarch = regcache->arch ();
+         struct ravenscar_arch_ops *arch_ops
+           = gdbarch_ravenscar_ops (gdbarch);
+
+         arch_ops->fetch_registers (regcache, regnum);
+       }
     }
   else
     beneath ()->fetch_registers (regcache, regnum);
@@ -439,15 +532,22 @@ ravenscar_thread_target::store_registers (struct regcache *regcache,
 {
   ptid_t ptid = regcache->ptid ();
 
-  if (runtime_initialized ()
-      && is_ravenscar_task (ptid)
-      && !task_is_currently_active (ptid))
+  if (runtime_initialized () && is_ravenscar_task (ptid))
     {
-      struct gdbarch *gdbarch = regcache->arch ();
-      struct ravenscar_arch_ops *arch_ops
-       = gdbarch_ravenscar_ops (gdbarch);
-
-      arch_ops->store_registers (regcache, regnum);
+      if (task_is_currently_active (ptid))
+       {
+         ptid_t base = get_base_thread_from_ravenscar_task (ptid);
+         temporarily_change_regcache_ptid changer (regcache, base);
+         beneath ()->store_registers (regcache, regnum);
+       }
+      else
+       {
+         struct gdbarch *gdbarch = regcache->arch ();
+         struct ravenscar_arch_ops *arch_ops
+           = gdbarch_ravenscar_ops (gdbarch);
+
+         arch_ops->store_registers (regcache, regnum);
+       }
     }
   else
     beneath ()->store_registers (regcache, regnum);
@@ -458,11 +558,18 @@ ravenscar_thread_target::prepare_to_store (struct regcache *regcache)
 {
   ptid_t ptid = regcache->ptid ();
 
-  if (runtime_initialized ()
-      && is_ravenscar_task (ptid)
-      && !task_is_currently_active (ptid))
+  if (runtime_initialized () && is_ravenscar_task (ptid))
     {
-      /* Nothing.  */
+      if (task_is_currently_active (ptid))
+       {
+         ptid_t base = get_base_thread_from_ravenscar_task (ptid);
+         temporarily_change_regcache_ptid changer (regcache, base);
+         beneath ()->prepare_to_store (regcache);
+       }
+      else
+       {
+         /* Nothing.  */
+       }
     }
   else
     beneath ()->prepare_to_store (regcache);
@@ -473,8 +580,8 @@ ravenscar_thread_target::prepare_to_store (struct regcache *regcache)
 bool
 ravenscar_thread_target::stopped_by_sw_breakpoint ()
 {
-  scoped_restore save_ptid = make_scoped_restore (&inferior_ptid);
-  inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid);
+  scoped_restore_current_thread saver;
+  set_base_thread_from_ravenscar_task (inferior_ptid);
   return beneath ()->stopped_by_sw_breakpoint ();
 }
 
@@ -483,8 +590,8 @@ ravenscar_thread_target::stopped_by_sw_breakpoint ()
 bool
 ravenscar_thread_target::stopped_by_hw_breakpoint ()
 {
-  scoped_restore save_ptid = make_scoped_restore (&inferior_ptid);
-  inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid);
+  scoped_restore_current_thread saver;
+  set_base_thread_from_ravenscar_task (inferior_ptid);
   return beneath ()->stopped_by_hw_breakpoint ();
 }
 
@@ -493,8 +600,8 @@ ravenscar_thread_target::stopped_by_hw_breakpoint ()
 bool
 ravenscar_thread_target::stopped_by_watchpoint ()
 {
-  scoped_restore save_ptid = make_scoped_restore (&inferior_ptid);
-  inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid);
+  scoped_restore_current_thread saver;
+  set_base_thread_from_ravenscar_task (inferior_ptid);
   return beneath ()->stopped_by_watchpoint ();
 }
 
@@ -503,8 +610,8 @@ ravenscar_thread_target::stopped_by_watchpoint ()
 bool
 ravenscar_thread_target::stopped_data_address (CORE_ADDR *addr_p)
 {
-  scoped_restore save_ptid = make_scoped_restore (&inferior_ptid);
-  inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid);
+  scoped_restore_current_thread saver;
+  set_base_thread_from_ravenscar_task (inferior_ptid);
   return beneath ()->stopped_data_address (addr_p);
 }
 
@@ -513,7 +620,7 @@ ravenscar_thread_target::mourn_inferior ()
 {
   m_base_ptid = null_ptid;
   target_ops *beneath = this->beneath ();
-  unpush_target (this);
+  current_inferior ()->unpush_target (this);
   beneath->mourn_inferior ();
 }
 
@@ -521,16 +628,36 @@ ravenscar_thread_target::mourn_inferior ()
 
 int
 ravenscar_thread_target::core_of_thread (ptid_t ptid)
+{
+  scoped_restore_current_thread saver;
+  set_base_thread_from_ravenscar_task (inferior_ptid);
+  return beneath ()->core_of_thread (inferior_ptid);
+}
+
+/* Implement the target xfer_partial method.  */
+
+enum target_xfer_status
+ravenscar_thread_target::xfer_partial (enum target_object object,
+                                      const char *annex,
+                                      gdb_byte *readbuf,
+                                      const gdb_byte *writebuf,
+                                      ULONGEST offset, ULONGEST len,
+                                      ULONGEST *xfered_len)
 {
   scoped_restore save_ptid = make_scoped_restore (&inferior_ptid);
+  /* Calling get_base_thread_from_ravenscar_task can read memory from
+     the inferior.  However, that function is written to prefer our
+     internal map, so it should not result in recursive calls in
+     practice.  */
   inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid);
-  return beneath ()->core_of_thread (inferior_ptid);
+  return beneath ()->xfer_partial (object, annex, readbuf, writebuf,
+                                  offset, len, xfered_len);
 }
 
 /* Observer on inferior_created: push ravenscar thread stratum if needed.  */
 
 static void
-ravenscar_inferior_created (struct target_ops *target, int from_tty)
+ravenscar_inferior_created (inferior *inf)
 {
   const char *err_msg;
 
@@ -547,7 +674,7 @@ ravenscar_inferior_created (struct target_ops *target, int from_tty)
     }
 
   ravenscar_thread_target *rtarget = new ravenscar_thread_target ();
-  push_target (target_ops_up (rtarget));
+  inf->push_target (target_ops_up (rtarget));
   thread_info *thr = rtarget->add_active_thread ();
   if (thr != nullptr)
     switch_to_thread (thr);
@@ -587,21 +714,22 @@ _initialize_ravenscar ()
 {
   /* Notice when the inferior is created in order to push the
      ravenscar ops if needed.  */
-  gdb::observers::inferior_created.attach (ravenscar_inferior_created);
+  gdb::observers::inferior_created.attach (ravenscar_inferior_created,
+                                          "ravenscar-thread");
 
   add_basic_prefix_cmd ("ravenscar", no_class,
                        _("Prefix command for changing Ravenscar-specific settings."),
-                       &set_ravenscar_list, "set ravenscar ", 0, &setlist);
+                       &set_ravenscar_list, 0, &setlist);
 
   add_show_prefix_cmd ("ravenscar", no_class,
                       _("Prefix command for showing Ravenscar-specific settings."),
-                      &show_ravenscar_list, "show ravenscar ", 0, &showlist);
+                      &show_ravenscar_list, 0, &showlist);
 
   add_setshow_boolean_cmd ("task-switching", class_obscure,
-                           &ravenscar_task_support, _("\
+                          &ravenscar_task_support, _("\
 Enable or disable support for GNAT Ravenscar tasks."), _("\
 Show whether support for GNAT Ravenscar tasks is enabled."),
-                           _("\
+                          _("\
 Enable or disable support for task/thread switching with the GNAT\n\
 Ravenscar run-time library for bareboard configuration."),
                           NULL, show_ravenscar_task_switching_command,
This page took 0.03475 seconds and 4 git commands to generate.