[2/7] New regs_info for aarch32

Message ID 86614ve5z5.fsf@gmail.com
State New, archived
Headers

Commit Message

Yao Qi Aug. 4, 2015, 9:51 a.m. UTC
  Pedro Alves <palves@redhat.com> writes:

> Let me try putting it another way then.
>
> Why are some init_registers_arm_XXX calls done in
> linux-aarch32-low.c:initialize_low_arch_aarch32 but others
> in linux-arm-low.c:initialize_low_arch?
>
> If we already end up with __aarch64__ #ifdefs, shouldn't the resulting
> code end like this?
>
>   void
>   initialize_low_arch_aarch32 (void)
>   {
> #ifndef __aarch64__
>     init_registers_arm ();
>     init_registers_arm_with_iwmmxt ();
>     init_registers_arm_with_vfpv2 ();
>     init_registers_arm_with_vfpv3 ();
> #endif
>     init_registers_arm_with_neon ();
>   }
>
> Isn't aarch32 the term used for all 32-bit execution state,
> including pre-ARMv8?  Otherwise, going forward, what is the
> guideline to know where to put a new
> init_registers_arm_xxx call?

aarch32 means armv7+neon, so ideally we only need call
init_registers_arm_with_neon for aarch32.  However, arm_store_vfpregset
and arm_fill_vfpregset need to check tdesc_arm_with_vfpv3 and
tdesc_arm_with_vfpv2, so we need to call init_registers_arm_with_vfpv2
and init_registers_arm_with_vfpv3 to init them.  That is the reason I
call them inside initialize_low_arch_aarch32.

I agree the "#ifndef __aarch64__" is confusing, and let me remove that
block out of initialize_low_arch_aarch32.  The patch below is updated to
initialize arm_with_neon target description in
linux-aarch32-low.c:initialize_low_arch_aarch32, and leave vfpv2 and
vfpv3 target descriptions inside linux-arm-low.c.  This is cleaner than
the previous version.    As a result, patch 3/7 is cleaner too, because
"#ifndef __aarch64__" is not needed anymore.

The guideline of adding new arm targets in my mind is if new arm target
can be run on aarch32 (32-bit mode on aarch64), it should be initialized
in initialize_low_arch_aarch32.  If new arm target can't be run on
32-bit mode on aarch64, it should be initialized in
linux-arm-low.c:initialize_low_arch.
  

Comments

Pedro Alves Aug. 4, 2015, 10:11 a.m. UTC | #1
On 08/04/2015 10:51 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> Let me try putting it another way then.
>>
>> Why are some init_registers_arm_XXX calls done in
>> linux-aarch32-low.c:initialize_low_arch_aarch32 but others
>> in linux-arm-low.c:initialize_low_arch?
>>
>> If we already end up with __aarch64__ #ifdefs, shouldn't the resulting
>> code end like this?
>>
>>   void
>>   initialize_low_arch_aarch32 (void)
>>   {
>> #ifndef __aarch64__
>>     init_registers_arm ();
>>     init_registers_arm_with_iwmmxt ();
>>     init_registers_arm_with_vfpv2 ();
>>     init_registers_arm_with_vfpv3 ();
>> #endif
>>     init_registers_arm_with_neon ();
>>   }
>>
>> Isn't aarch32 the term used for all 32-bit execution state,
>> including pre-ARMv8?  Otherwise, going forward, what is the
>> guideline to know where to put a new
>> init_registers_arm_xxx call?
> 
> aarch32 means armv7+neon, 

Ah.

> so ideally we only need call
> init_registers_arm_with_neon for aarch32.  However, arm_store_vfpregset
> and arm_fill_vfpregset need to check tdesc_arm_with_vfpv3 and
> tdesc_arm_with_vfpv2, so we need to call init_registers_arm_with_vfpv2
> and init_registers_arm_with_vfpv3 to init them.  That is the reason I
> call them inside initialize_low_arch_aarch32.
> 
> I agree the "#ifndef __aarch64__" is confusing, and let me remove that
> block out of initialize_low_arch_aarch32.  The patch below is updated to
> initialize arm_with_neon target description in
> linux-aarch32-low.c:initialize_low_arch_aarch32, and leave vfpv2 and
> vfpv3 target descriptions inside linux-arm-low.c.  This is cleaner than
> the previous version.    As a result, patch 3/7 is cleaner too, because
> "#ifndef __aarch64__" is not needed anymore.
> 

Nice.

> The guideline of adding new arm targets in my mind is if new arm target
> can be run on aarch32 (32-bit mode on aarch64), it should be initialized
> in initialize_low_arch_aarch32.  If new arm target can't be run on
> 32-bit mode on aarch64, it should be initialized in
> linux-arm-low.c:initialize_low_arch.
> 

OK, that makes sense.  This version looks good to me.  Thanks!
  

Patch

diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 9a04aac..1a8361a 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -62,6 +62,7 @@  case "${target}" in
 			srv_regobj="${srv_regobj} arm-with-vfpv3.o"
 			srv_regobj="${srv_regobj} arm-with-neon.o"
 			srv_tgtobj="$srv_linux_obj linux-arm-low.o"
+			srv_tgtobj="$srv_tgtobj linux-aarch32-low.o"
 			srv_xmlfiles="arm-with-iwmmxt.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml"
diff --git a/gdb/gdbserver/linux-aarch32-low.c b/gdb/gdbserver/linux-aarch32-low.c
new file mode 100644
index 0000000..7f3b985
--- /dev/null
+++ b/gdb/gdbserver/linux-aarch32-low.c
@@ -0,0 +1,140 @@ 
+/* Copyright (C) 1995-2015 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 "server.h"
+#include "arch/arm.h"
+#include "linux-low.h"
+#include "linux-aarch32-low.h"
+
+#include <sys/ptrace.h>
+/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h.
+   On Bionic elf.h and linux/elf.h have conflicting definitions.  */
+#ifndef ELFMAG0
+#include <elf.h>
+#endif
+
+/* Collect GP registers from REGCACHE to buffer BUF.  */
+
+void
+arm_fill_gregset (struct regcache *regcache, void *buf)
+{
+  int i;
+  uint32_t *regs = buf;
+
+  for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++)
+    collect_register (regcache, i, &regs[i]);
+
+  collect_register (regcache, ARM_PS_REGNUM, &regs[16]);
+}
+
+/* Supply GP registers contents, stored in BUF, to REGCACHE.  */
+
+void
+arm_store_gregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+  char zerobuf[8];
+  const uint32_t *regs = buf;
+
+  memset (zerobuf, 0, 8);
+  for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++)
+    supply_register (regcache, i, &regs[i]);
+
+  for (; i < ARM_PS_REGNUM; i++)
+    supply_register (regcache, i, zerobuf);
+
+  supply_register (regcache, ARM_PS_REGNUM, &regs[16]);
+}
+
+/* Collect NUM number of VFP registers from REGCACHE to buffer BUF.  */
+
+void
+arm_fill_vfpregset_num (struct regcache *regcache, void *buf, int num)
+{
+  int i, base;
+
+  gdb_assert (num == 16 || num == 32);
+
+  base = find_regno (regcache->tdesc, "d0");
+  for (i = 0; i < num; i++)
+    collect_register (regcache, base + i, (char *) buf + i * 8);
+
+  collect_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
+}
+
+/* Supply NUM number of VFP registers contents, stored in BUF, to
+   REGCACHE.  */
+
+void
+arm_store_vfpregset_num (struct regcache *regcache, const void *buf, int num)
+{
+  int i, base;
+
+  gdb_assert (num == 16 || num == 32);
+
+  base = find_regno (regcache->tdesc, "d0");
+  for (i = 0; i < num; i++)
+    supply_register (regcache, base + i, (char *) buf + i * 8);
+
+  supply_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
+}
+
+static void
+arm_fill_vfpregset (struct regcache *regcache, void *buf)
+{
+  arm_fill_vfpregset_num (regcache, buf, 32);
+}
+
+static void
+arm_store_vfpregset (struct regcache *regcache, const void *buf)
+{
+  arm_store_vfpregset_num (regcache, buf, 32);
+}
+
+/* Register sets with using PTRACE_GETREGSET.  */
+
+static struct regset_info aarch32_regsets[] = {
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, 18 * 4,
+    GENERAL_REGS,
+    arm_fill_gregset, arm_store_gregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_VFP, 32 * 8 + 4,
+    EXTENDED_REGS,
+    arm_fill_vfpregset, arm_store_vfpregset },
+  { 0, 0, 0, -1, -1, NULL, NULL }
+};
+
+static struct regsets_info aarch32_regsets_info =
+  {
+    aarch32_regsets, /* regsets */
+    0, /* num_regsets */
+    NULL, /* disabled_regsets */
+  };
+
+struct regs_info regs_info_aarch32 =
+  {
+    NULL, /* regset_bitmap */
+    NULL, /* usrregs */
+    &aarch32_regsets_info
+  };
+
+void
+initialize_low_arch_aarch32 (void)
+{
+  init_registers_arm_with_neon ();
+
+  initialize_regsets_info (&aarch32_regsets_info);
+}
diff --git a/gdb/gdbserver/linux-aarch32-low.h b/gdb/gdbserver/linux-aarch32-low.h
new file mode 100644
index 0000000..6682f0a
--- /dev/null
+++ b/gdb/gdbserver/linux-aarch32-low.h
@@ -0,0 +1,29 @@ 
+/* Copyright (C) 1995-2015 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/>.  */
+
+extern struct regs_info regs_info_aarch32;
+
+void arm_fill_gregset (struct regcache *regcache, void *buf);
+void arm_store_gregset (struct regcache *regcache, const void *buf);
+void arm_fill_vfpregset_num (struct regcache *regcache, void *buf, int num);
+void arm_store_vfpregset_num (struct regcache *regcache, const void *buf,
+			      int num);
+
+void initialize_low_arch_aarch32 (void);
+
+void init_registers_arm_with_neon (void);
+extern const struct target_desc *tdesc_arm_with_neon;
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 3c5956b..6a27e6e 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -19,7 +19,9 @@ 
 #include "server.h"
 #include "linux-low.h"
 #include "arch/arm.h"
+#include "linux-aarch32-low.h"
 
+#include <sys/uio.h>
 /* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h.
    On Bionic elf.h and linux/elf.h have conflicting definitions.  */
 #ifndef ELFMAG0
@@ -41,9 +43,6 @@  extern const struct target_desc *tdesc_arm_with_vfpv2;
 void init_registers_arm_with_vfpv3 (void);
 extern const struct target_desc *tdesc_arm_with_vfpv3;
 
-void init_registers_arm_with_neon (void);
-extern const struct target_desc *tdesc_arm_with_neon;
-
 #ifndef PTRACE_GET_THREAD_AREA
 #define PTRACE_GET_THREAD_AREA 22
 #endif
@@ -150,35 +149,6 @@  arm_cannot_fetch_register (int regno)
 }
 
 static void
-arm_fill_gregset (struct regcache *regcache, void *buf)
-{
-  int i;
-  uint32_t *regs = buf;
-
-  for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++)
-    collect_register (regcache, i, &regs[i]);
-
-  collect_register (regcache, ARM_PS_REGNUM, &regs[16]);
-}
-
-static void
-arm_store_gregset (struct regcache *regcache, const void *buf)
-{
-  int i;
-  char zerobuf[8];
-  const uint32_t *regs = buf;
-
-  memset (zerobuf, 0, 8);
-  for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++)
-    supply_register (regcache, i, &regs[i]);
-
-  for (; i < ARM_PS_REGNUM; i++)
-    supply_register (regcache, i, zerobuf);
-
-  supply_register (regcache, ARM_PS_REGNUM, &regs[16]);
-}
-
-static void
 arm_fill_wmmxregset (struct regcache *regcache, void *buf)
 {
   int i;
@@ -215,7 +185,7 @@  arm_store_wmmxregset (struct regcache *regcache, const void *buf)
 static void
 arm_fill_vfpregset (struct regcache *regcache, void *buf)
 {
-  int i, num, base;
+  int num;
 
   if (regcache->tdesc == tdesc_arm_with_neon
       || regcache->tdesc == tdesc_arm_with_vfpv3)
@@ -225,17 +195,13 @@  arm_fill_vfpregset (struct regcache *regcache, void *buf)
   else
     return;
 
-  base = find_regno (regcache->tdesc, "d0");
-  for (i = 0; i < num; i++)
-    collect_register (regcache, base + i, (char *) buf + i * 8);
-
-  collect_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
+  arm_fill_vfpregset_num (regcache, buf, num);
 }
 
 static void
 arm_store_vfpregset (struct regcache *regcache, const void *buf)
 {
-  int i, num, base;
+  int num;
 
   if (regcache->tdesc == tdesc_arm_with_neon
       || regcache->tdesc == tdesc_arm_with_vfpv3)
@@ -245,11 +211,7 @@  arm_store_vfpregset (struct regcache *regcache, const void *buf)
   else
     return;
 
-  base = find_regno (regcache->tdesc, "d0");
-  for (i = 0; i < num; i++)
-    supply_register (regcache, base + i, (char *) buf + i * 8);
-
-  supply_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
+  arm_store_vfpregset_num (regcache, buf, num);
 }
 
 extern int debug_threads;
@@ -888,9 +850,24 @@  arm_read_description (void)
 static void
 arm_arch_setup (void)
 {
+  int tid = lwpid_of (current_thread);
+  int gpregs[18];
+  struct iovec iov;
+
   current_process ()->tdesc = arm_read_description ();
+
+  iov.iov_base = gpregs;
+  iov.iov_len = sizeof (gpregs);
+
+  /* Check if PTRACE_GETREGSET works.  */
+  if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov) == 0)
+    have_ptrace_getregset = 1;
+  else
+    have_ptrace_getregset = 0;
 }
 
+/* Register sets without using PTRACE_GETREGSET.  */
+
 static struct regset_info arm_regsets[] = {
   { PTRACE_GETREGS, PTRACE_SETREGS, 0, 18 * 4,
     GENERAL_REGS,
@@ -917,7 +894,7 @@  static struct usrregs_info arm_usrregs_info =
     arm_regmap,
   };
 
-static struct regs_info regs_info =
+static struct regs_info regs_info_arm =
   {
     NULL, /* regset_bitmap */
     &arm_usrregs_info,
@@ -927,7 +904,13 @@  static struct regs_info regs_info =
 static const struct regs_info *
 arm_regs_info (void)
 {
-  return &regs_info;
+  const struct target_desc *tdesc = current_process ()->tdesc;
+
+  if (have_ptrace_getregset == 1
+      && (tdesc == tdesc_arm_with_neon || tdesc == tdesc_arm_with_vfpv3))
+    return &regs_info_aarch32;
+  else
+    return &regs_info_arm;
 }
 
 struct linux_target_ops the_low_target = {
@@ -975,7 +958,8 @@  initialize_low_arch (void)
   init_registers_arm_with_iwmmxt ();
   init_registers_arm_with_vfpv2 ();
   init_registers_arm_with_vfpv3 ();
-  init_registers_arm_with_neon ();
+
+  initialize_low_arch_aarch32 ();
 
   initialize_regsets_info (&arm_regsets_info);
 }