gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / xtensa-linux-nat.c
index 2d506f7fcac6d420ddcfe868a698f6e67bb158df..57ad8a69722404533e85f6ab7f688f50d5d90571 100644 (file)
@@ -1,6 +1,6 @@
 /* Xtensa GNU/Linux native support.
 
-   Copyright (C) 2007-2014 Free Software Foundation, Inc.
+   Copyright (C) 2007-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "regcache.h"
 #include "target.h"
 #include "linux-nat.h"
-
-#include <stdint.h>
 #include <sys/types.h>
 #include <signal.h>
 #include <sys/user.h>
 #include <sys/ioctl.h>
-#include "gdb_wait.h"
+#include "gdbsupport/gdb_wait.h"
 #include <fcntl.h>
 #include <sys/procfs.h>
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
 #include <asm/ptrace.h>
 
 #include "gregset.h"
 #include "xtensa-tdep.h"
 
+/* Defines ps_err_e, struct ps_prochandle.  */
+#include "gdb_proc_service.h"
+
 /* Extended register set depends on hardware configs.
    Keeping these definitions separately allows to introduce
    hardware-specific overlays.  */
 #include "xtensa-xtregs.c"
 
-static int
-get_thread_id (ptid_t ptid)
+class xtensa_linux_nat_target final : public linux_nat_target
 {
-  int tid = ptid_get_lwp (ptid);
-  if (0 == tid)
-    tid = ptid_get_pid (ptid);
-  return tid;
-}
-#define GET_THREAD_ID(PTID)    get_thread_id (PTID)
+public:
+  /* Add our register access methods.  */
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+};
+
+static xtensa_linux_nat_target the_xtensa_linux_nat_target;
 
 void
 fill_gregset (const struct regcache *regcache,
@@ -60,101 +61,119 @@ fill_gregset (const struct regcache *regcache,
 {
   int i;
   xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp;
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
 
   if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
-    regcache_raw_collect (regcache, gdbarch_pc_regnum (gdbarch), &regs->pc);
+    regcache->raw_collect (gdbarch_pc_regnum (gdbarch), &regs->pc);
   if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1)
-    regcache_raw_collect (regcache, gdbarch_ps_regnum (gdbarch), &regs->ps);
+    regcache->raw_collect (gdbarch_ps_regnum (gdbarch), &regs->ps);
 
   if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1)
-    regcache_raw_collect (regcache,
-                         gdbarch_tdep (gdbarch)->wb_regnum,
-                         &regs->windowbase);
+    regcache->raw_collect (gdbarch_tdep (gdbarch)->wb_regnum,
+                          &regs->windowbase);
   if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1)
-    regcache_raw_collect (regcache,
-                         gdbarch_tdep (gdbarch)->ws_regnum,
-                         &regs->windowstart);
+    regcache->raw_collect (gdbarch_tdep (gdbarch)->ws_regnum,
+                          &regs->windowstart);
   if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1)
-    regcache_raw_collect (regcache,
-                         gdbarch_tdep (gdbarch)->lbeg_regnum,
-                         &regs->lbeg);
+    regcache->raw_collect (gdbarch_tdep (gdbarch)->lbeg_regnum,
+                          &regs->lbeg);
   if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1)
-    regcache_raw_collect (regcache,
-                         gdbarch_tdep (gdbarch)->lend_regnum,
-                         &regs->lend);
+    regcache->raw_collect (gdbarch_tdep (gdbarch)->lend_regnum,
+                          &regs->lend);
   if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1)
-    regcache_raw_collect (regcache,
-                         gdbarch_tdep (gdbarch)->lcount_regnum,
-                         &regs->lcount);
+    regcache->raw_collect (gdbarch_tdep (gdbarch)->lcount_regnum,
+                          &regs->lcount);
   if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1)
-    regcache_raw_collect (regcache,
-                         gdbarch_tdep (gdbarch)->sar_regnum,
-                         &regs->sar);
+    regcache->raw_collect (gdbarch_tdep (gdbarch)->sar_regnum,
+                          &regs->sar);
+  if (regnum == gdbarch_tdep (gdbarch)->threadptr_regnum || regnum == -1)
+    regcache->raw_collect (gdbarch_tdep (gdbarch)->threadptr_regnum,
+                          &regs->threadptr);
   if (regnum >=gdbarch_tdep (gdbarch)->ar_base
       && regnum < gdbarch_tdep (gdbarch)->ar_base
                    + gdbarch_tdep (gdbarch)->num_aregs)
-    regcache_raw_collect (regcache,regnum,
-                         &regs->ar[regnum - gdbarch_tdep (gdbarch)->ar_base]);
+    regcache->raw_collect (regnum,
+                          &regs->ar[regnum - gdbarch_tdep (gdbarch)->ar_base]);
   else if (regnum == -1)
     {
       for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i)
-       regcache_raw_collect (regcache,
-                             gdbarch_tdep (gdbarch)->ar_base + i,
-                             &regs->ar[i]);
+       regcache->raw_collect (gdbarch_tdep (gdbarch)->ar_base + i,
+                              &regs->ar[i]);
+    }
+  if (regnum >= gdbarch_tdep (gdbarch)->a0_base
+      && regnum < gdbarch_tdep (gdbarch)->a0_base + C0_NREGS)
+    regcache->raw_collect (regnum,
+                          &regs->ar[(4 * regs->windowbase + regnum
+                                     - gdbarch_tdep (gdbarch)->a0_base)
+                         % gdbarch_tdep (gdbarch)->num_aregs]);
+  else if (regnum == -1)
+    {
+      for (i = 0; i < C0_NREGS; ++i)
+       regcache->raw_collect (gdbarch_tdep (gdbarch)->a0_base + i,
+                              (&regs->ar[(4 * regs->windowbase + i)
+                               % gdbarch_tdep (gdbarch)->num_aregs]));
     }
 }
 
-void
+static void
 supply_gregset_reg (struct regcache *regcache,
                    const gdb_gregset_t *gregsetp, int regnum)
 {
   int i;
   xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp;
 
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = regcache->arch ();
 
   if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
-    regcache_raw_supply (regcache, gdbarch_pc_regnum (gdbarch), &regs->pc);
+    regcache->raw_supply (gdbarch_pc_regnum (gdbarch), &regs->pc);
   if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1)
-    regcache_raw_supply (regcache, gdbarch_ps_regnum (gdbarch), &regs->ps);
+    regcache->raw_supply (gdbarch_ps_regnum (gdbarch), &regs->ps);
 
   if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1)
-    regcache_raw_supply (regcache,
-                         gdbarch_tdep (gdbarch)->wb_regnum,
+    regcache->raw_supply (gdbarch_tdep (gdbarch)->wb_regnum,
                          &regs->windowbase);
   if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1)
-    regcache_raw_supply (regcache,
-                         gdbarch_tdep (gdbarch)->ws_regnum,
+    regcache->raw_supply (gdbarch_tdep (gdbarch)->ws_regnum,
                          &regs->windowstart);
   if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1)
-    regcache_raw_supply (regcache,
-                         gdbarch_tdep (gdbarch)->lbeg_regnum,
+    regcache->raw_supply (gdbarch_tdep (gdbarch)->lbeg_regnum,
                          &regs->lbeg);
   if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1)
-    regcache_raw_supply (regcache,
-                         gdbarch_tdep (gdbarch)->lend_regnum,
+    regcache->raw_supply (gdbarch_tdep (gdbarch)->lend_regnum,
                          &regs->lend);
   if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1)
-    regcache_raw_supply (regcache,
-                         gdbarch_tdep (gdbarch)->lcount_regnum,
+    regcache->raw_supply (gdbarch_tdep (gdbarch)->lcount_regnum,
                          &regs->lcount);
   if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1)
-    regcache_raw_supply (regcache,
-                         gdbarch_tdep (gdbarch)->sar_regnum,
+    regcache->raw_supply (gdbarch_tdep (gdbarch)->sar_regnum,
                          &regs->sar);
+  if (regnum == gdbarch_tdep (gdbarch)->threadptr_regnum || regnum == -1)
+    regcache->raw_supply (gdbarch_tdep (gdbarch)->threadptr_regnum,
+                         &regs->threadptr);
   if (regnum >=gdbarch_tdep (gdbarch)->ar_base
       && regnum < gdbarch_tdep (gdbarch)->ar_base
                    + gdbarch_tdep (gdbarch)->num_aregs)
-    regcache_raw_supply (regcache,regnum,
+    regcache->raw_supply (regnum,
                          &regs->ar[regnum - gdbarch_tdep (gdbarch)->ar_base]);
   else if (regnum == -1)
     {
       for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i)
-       regcache_raw_supply (regcache,
-                             gdbarch_tdep (gdbarch)->ar_base + i,
+       regcache->raw_supply (gdbarch_tdep (gdbarch)->ar_base + i,
                              &regs->ar[i]);
     }
+  if (regnum >= gdbarch_tdep (gdbarch)->a0_base
+      && regnum < gdbarch_tdep (gdbarch)->a0_base + C0_NREGS)
+    regcache->raw_supply (regnum,
+                         &regs->ar[(4 * regs->windowbase + regnum
+                                    - gdbarch_tdep (gdbarch)->a0_base)
+                        % gdbarch_tdep (gdbarch)->num_aregs]);
+  else if (regnum == -1)
+    {
+      for (i = 0; i < C0_NREGS; ++i)
+       regcache->raw_supply (gdbarch_tdep (gdbarch)->a0_base + i,
+                             &regs->ar[(4 * regs->windowbase + i)
+                                       % gdbarch_tdep (gdbarch)->num_aregs]);
+    }
 }
 
 void
@@ -183,8 +202,8 @@ supply_fpregset (struct regcache *regcache,
 static void
 fetch_gregs (struct regcache *regcache, int regnum)
 {
-  int tid = GET_THREAD_ID (inferior_ptid);
-  const gdb_gregset_t regs;
+  int tid = regcache->ptid ().lwp ();
+  gdb_gregset_t regs;
   int areg;
   
   if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
@@ -202,7 +221,7 @@ fetch_gregs (struct regcache *regcache, int regnum)
 static void
 store_gregs (struct regcache *regcache, int regnum)
 {
-  int tid = GET_THREAD_ID (inferior_ptid);
+  int tid = regcache->ptid ().lwp ();
   gdb_gregset_t regs;
   int areg;
 
@@ -230,7 +249,7 @@ static int xtreg_high;
 static void
 fetch_xtregs (struct regcache *regcache, int regnum)
 {
-  int tid = GET_THREAD_ID (inferior_ptid);
+  int tid = regcache->ptid ().lwp ();
   const xtensa_regtable_t *ptr;
   char xtregs [XTENSA_ELF_XTREG_SIZE];
 
@@ -239,14 +258,13 @@ fetch_xtregs (struct regcache *regcache, int regnum)
 
   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
     if (regnum == ptr->gdb_regnum || regnum == -1)
-      regcache_raw_supply (regcache, ptr->gdb_regnum,
-                          xtregs + ptr->ptrace_offset);
+      regcache->raw_supply (ptr->gdb_regnum, xtregs + ptr->ptrace_offset);
 }
 
 static void
 store_xtregs (struct regcache *regcache, int regnum)
 {
-  int tid = GET_THREAD_ID (inferior_ptid);
+  int tid = regcache->ptid ().lwp ();
   const xtensa_regtable_t *ptr;
   char xtregs [XTENSA_ELF_XTREG_SIZE];
 
@@ -255,16 +273,15 @@ store_xtregs (struct regcache *regcache, int regnum)
 
   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
     if (regnum == ptr->gdb_regnum || regnum == -1)
-      regcache_raw_collect (regcache, ptr->gdb_regnum,
-                           xtregs + ptr->ptrace_offset);
+      regcache->raw_collect (ptr->gdb_regnum, xtregs + ptr->ptrace_offset);
 
   if (ptrace (PTRACE_SETXTREGS, tid, 0, (long)&xtregs) < 0)
     perror_with_name (_("Couldn't write extended registers"));
 }
 
 void
-xtensa_linux_fetch_inferior_registers (struct target_ops *ops,
-                                      struct regcache *regcache, int regnum)
+xtensa_linux_nat_target::fetch_registers (struct regcache *regcache,
+                                         int regnum)
 {
   if (regnum == -1)
     {
@@ -278,8 +295,8 @@ xtensa_linux_fetch_inferior_registers (struct target_ops *ops,
 }
 
 void
-xtensa_linux_store_inferior_registers (struct target_ops *ops,
-                                      struct regcache *regcache, int regnum)
+xtensa_linux_nat_target::store_registers (struct regcache *regcache,
+                                         int regnum)
 {
   if (regnum == -1)
     {
@@ -292,12 +309,29 @@ xtensa_linux_store_inferior_registers (struct target_ops *ops,
     store_xtregs (regcache, regnum);
 }
 
-void _initialize_xtensa_linux_nat (void);
+/* Called by libthread_db.  */
+
+ps_err_e
+ps_get_thread_area (struct ps_prochandle *ph,
+                    lwpid_t lwpid, int idx, void **base)
+{
+  xtensa_elf_gregset_t regs;
 
+  if (ptrace (PTRACE_GETREGS, lwpid, NULL, &regs) != 0)
+    return PS_ERR;
+
+  /* IDX is the bias from the thread pointer to the beginning of the
+     thread descriptor.  It has to be subtracted due to implementation
+     quirks in libthread_db.  */
+  *base = (void *) ((char *) regs.threadptr - idx);
+
+  return PS_OK;
+}
+
+void _initialize_xtensa_linux_nat ();
 void
-_initialize_xtensa_linux_nat (void)
+_initialize_xtensa_linux_nat ()
 {
-  struct target_ops *t;
   const xtensa_regtable_t *ptr;
 
   /* Calculate the number range for extended registers.  */
@@ -311,12 +345,6 @@ _initialize_xtensa_linux_nat (void)
        xtreg_high = ptr->gdb_regnum;
     }
 
-  /* Fill in the generic GNU/Linux methods.  */
-  t = linux_target ();
-
-  /* Add our register access methods.  */
-  t->to_fetch_registers = xtensa_linux_fetch_inferior_registers;
-  t->to_store_registers = xtensa_linux_store_inferior_registers;
-
-  linux_nat_add_target (t);
+  linux_target = &the_xtensa_linux_nat_target;
+  add_inf_child_target (&the_xtensa_linux_nat_target);
 }
This page took 0.030299 seconds and 4 git commands to generate.