This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[rfc][2/3] gdbserver bi-arch support: core s390x part


Hello,

this patch makes gdbserver on s390x bi-arch capabable: it will now detect
whether the target is 31-bit or 64-bit and select the appropriate register
format definition.

The basic idea is to simply link gdbserver with both reg-s390.o and
reg-s390x.o (which no longer conflict), and change the compile-time
selection of the linux-s390-low version of the_low_target.arch_setup
into a run-time selection.

However, this isn't really sufficient: at the time the arch_setup routine
is currently called, there is no target attached, and thus there is no
way of detecting whether to use the 31-bit or 64-bit register set.
Thus the patch also changes the call location of arch_setup in linux-low.c
to just after the inferior is attached (but before any register access).
This point happens to be in linux_wait_for_process (when called for the
first time).

This exposes another problem: at this time, common code has already set up
a register cache for the initial thread, which may now turn out to be of
the wrong size.  To fix this, the set_register_cache routine (which is 
called by the generated init_register_... routine) now goes through all
register caches that may already have been allocated and re-sizes them
to the new size.  (As a nice side-effect, this now also allows to call
init_register_... multiple times.)

Finally, the patch adapted s390_get_pc and s390_set_pc to properly work
in the bi-arch configuration.  (Note that even so there are a couple of
problems that need to be fixed in a follow-on patch.)

Tested (together with the follow-on patch) on s390-linux and s390x-linux.

Bye,
Ulrich

ChangeLog:

	* configure.srv [s390x-*-linux*]: Set srv_regobj to include both
	reg-s390.o and reg-s390x.o.

	* linux-low.c (linux_wait_for_process): Call the_low_target.arch_setup
	after the target has stopped for the first time.
	(initialize_low): Do not call the_low_target.arch_setup.

	* linux-s390-low.c (s390_get_pc): Support bi-arch operation.
	(s390_set_pc): Likewise.
	(s390_arch_setup): New function.
	(the_low_target): Use s390_arch_setup as arch_setup routine.

	* regcache.c (realloc_register_cache): New function.
	(set_register_cache): Call it for each existing regcache.


diff -urNp gdb-orig/gdb/gdbserver/configure.srv gdb-head/gdb/gdbserver/configure.srv
--- gdb-orig/gdb/gdbserver/configure.srv	2008-01-18 00:57:40.000000000 +0100
+++ gdb-head/gdb/gdbserver/configure.srv	2008-01-17 22:29:26.000000000 +0100
@@ -138,7 +138,7 @@ case "${target}" in
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
 			;;
-  s390x-*-linux*)	srv_regobj=reg-s390x.o
+  s390x-*-linux*)	srv_regobj="reg-s390.o reg-s390x.o"
 			srv_tgtobj="linux-low.o linux-s390-low.o"
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
diff -urNp gdb-orig/gdb/gdbserver/linux-low.c gdb-head/gdb/gdbserver/linux-low.c
--- gdb-orig/gdb/gdbserver/linux-low.c	2008-01-18 00:57:40.000000000 +0100
+++ gdb-head/gdb/gdbserver/linux-low.c	2008-01-18 00:57:34.000000000 +0100
@@ -548,6 +548,7 @@ status_pending_p (struct inferior_list_e
 static void
 linux_wait_for_process (struct process_info **childp, int *wstatp)
 {
+  static int arch_setup_done = 0;
   int ret;
   int to_wait_for = -1;
 
@@ -606,6 +607,16 @@ retry:
 
   (*childp)->last_status = *wstatp;
 
+  /* Architecture-specific setup after inferior is running.
+     This needs to happen after we have attached to the inferior
+     and it is stopped for the first time, but before we access
+     any inferior registers.  */
+  if (!arch_setup_done)
+    {
+      the_low_target.arch_setup ();
+      arch_setup_done = 1;
+    }
+
   if (debug_threads
       && WIFSTOPPED (*wstatp))
     {
@@ -2060,7 +2071,6 @@ initialize_low (void)
   set_target_ops (&linux_target_ops);
   set_breakpoint_data (the_low_target.breakpoint,
 		       the_low_target.breakpoint_len);
-  the_low_target.arch_setup ();
   linux_init_signals ();
   linux_test_for_tracefork ();
 }
diff -urNp gdb-orig/gdb/gdbserver/linux-s390-low.c gdb-head/gdb/gdbserver/linux-s390-low.c
--- gdb-orig/gdb/gdbserver/linux-s390-low.c	2008-01-18 00:57:40.000000000 +0100
+++ gdb-head/gdb/gdbserver/linux-s390-low.c	2008-01-18 01:00:18.000000000 +0100
@@ -102,24 +102,61 @@ static const unsigned char s390_breakpoi
 static CORE_ADDR
 s390_get_pc ()
 {
-  unsigned long pc;
-  collect_register_by_name ("pswa", &pc);
+  if (register_size (0) == 4)
+    {
+      unsigned int pc;
+      collect_register_by_name ("pswa", &pc);
 #ifndef __s390x__
-  pc &= 0x7fffffff;
+      pc &= 0x7fffffff;
 #endif
-  return pc;
+      return pc;
+    }
+  else
+    {
+      unsigned long pc;
+      collect_register_by_name ("pswa", &pc);
+      return pc;
+    }
 }
 
 static void
 s390_set_pc (CORE_ADDR newpc)
 {
-  unsigned long pc = newpc;
+  if (register_size (0) == 4)
+    {
+      unsigned int pc = newpc;
 #ifndef __s390x__
-  pc |= 0x80000000;
+      pc |= 0x80000000;
 #endif
-  supply_register_by_name ("pswa", &pc);
+      supply_register_by_name ("pswa", &pc);
+    }
+  else
+    {
+      unsigned long pc = newpc;
+      supply_register_by_name ("pswa", &pc);
+    }
 }
 
+
+static void
+s390_arch_setup (void)
+{
+  /* Assume 31-bit inferior process.  */
+  init_registers_s390 ();
+
+  /* On a 64-bit host, check the low bit of the (31-bit) PSWM
+     -- if this is one, we actually have a 64-bit inferior.  */
+#ifdef __s390x__
+  {
+    unsigned int pswm;
+    collect_register_by_name ("pswm", &pswm);
+    if (pswm & 1)
+      init_registers_s390x ();
+  }
+#endif
+}
+
+
 static int
 s390_breakpoint_at (CORE_ADDR pc)
 {
@@ -130,11 +167,7 @@ s390_breakpoint_at (CORE_ADDR pc)
 
 
 struct linux_target_ops the_low_target = {
-#ifndef __s390x__
-  init_registers_s390,
-#else
-  init_registers_s390x,
-#endif
+  s390_arch_setup,
   s390_num_regs,
   s390_regmap,
   s390_cannot_fetch_register,
diff -urNp gdb-orig/gdb/gdbserver/regcache.c gdb-head/gdb/gdbserver/regcache.c
--- gdb-orig/gdb/gdbserver/regcache.c	2008-01-18 00:57:40.000000000 +0100
+++ gdb-head/gdb/gdbserver/regcache.c	2008-01-17 22:29:26.000000000 +0100
@@ -121,6 +121,15 @@ free_register_cache (void *regcache_p)
   free (regcache);
 }
 
+static void
+realloc_register_cache (struct inferior_list_entry *thread_p)
+{
+  struct thread_info *thread = (struct thread_info *) thread_p;
+
+  free_register_cache (inferior_regcache_data (thread));
+  set_inferior_regcache_data (thread, new_register_cache ());
+}
+
 void
 set_register_cache (struct reg *regs, int n)
 {
@@ -137,6 +146,9 @@ set_register_cache (struct reg *regs, in
     }
 
   register_bytes = offset / 8;
+
+  /* Re-allocate all pre-existing register caches.  */
+  for_each_inferior (&all_threads, realloc_register_cache);
 }
 
 void
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]