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] [01/18] Cell multi-arch: Per-thread architecture infrastructure


Hello,

the first piece of infrastructure is support for per-thread architecture.
To be more specific, this is about the architecture of the per-thread
register cache.  Now, register caches today already are architecture-
specific, but they are all initialized to current_gdbarch on creation.

This patch adds two features:

- A new get_thread_arch_regcache function

  This allows to explicitly specify an architecture to use when creating
  the per-thread register cache.  It is up to the caller to ensure that
  the target is able to handle that request.

  Note that it is possible to create multiple different register caches
  for the same thread using different architectures.  This is used on
  Cell: Every thread has a PowerPC architecture register set.  *Some*
  threads *in addition* have a SPU register set -- for those threads,
  the PowerPC register set points to the location of the spu_run system
  call that has started SPU execution.

  In order to not continually throw away the register cache in this case,
  the patch also changes regcache.c to not only keep a single regcache as
  cache, but cache all results from get_thread_arch_regcache until the
  next registers_changed call.  This allows caching multiple architecture
  views, and as a nice side effect allows caching register sets for multiple
  threads at the same time as well.

- A new target_ops member to_thread_architecture

  This is used to determine the "main" architecture to use for a given
  thread.  It is used to implement the existing get_thread_regcache 
  and get_current_regcache routines (on top of get_thread_arch_regcache).

  The target is supposed to determine the architecture of the code where
  the target is currently stopped at (on Cell, if a target is in spu_run,
  to_thread_architecture would return SPU, otherwise PowerPC).  This is
  architecture used to perform decr_pc_after_break adjustment, and also
  determines the frame architecture of the innermost frame.

  The default implementation always returns target_gdbarch.


In addition, the patch makes two related changes:

- Switch current_gdbarch in switch_to_thread

  As long as we still have current_gdbarch, this patch makes sure that when
  the user switches to a different thread, current_gdbarch is reset to refer
  to that thread's main architecture (as returned by to_thread_architecture).

- Use get_thread_arch_regcache where appropriate

  The proc-service callbacks used by thread debugging libraries need to provide
  register sets of the architecture expected by that library, no matter what
  the "current architecture" of the given thread is.

  Similarly, there are other places where we have to operate on a specific
  architecture: when storing "expedited" registers in remote_wait, and when
  generating a core file in linux_nat_do_thread_registers.

  This patch switches those places to use get_thread_arch_regcache to retrieve
  a register cache in target_gdbarch to operate on.  (On targets without a
  specific to_thread_architecture, this change is a no-op.)


Bye,
Ulrich


ChangeLog:

	* target.h (struct target_ops): New member to_thread_architecture.
	(target_thread_architecture): New macro.
	* target.c (update_current_target): Inherit to_thread_architecture.
	(default_thread_architecture): New function.
	(debug_to_thread_architecture): New function.
	(setup_target_debug): Handle to_thread_architecture.

	* regcache.h (get_thread_arch_regcache): New.
	* regcache.c (struct regcache_list): New data type.
	(current_regcache): Hold regcache list instead of single regcache.
	(current_thread_ptid, current_thread_arch): New static variables.
	(get_thread_arch_regcache): New function.
	(get_thread_regcache): Use it.  Call target_thread_architecture.
	(regcache_thread_ptid_changed): Update to current_regcache changes.
	(registers_changed): Likewise.  Reset current_thread_arch and
	current_thread_ptid.

	* thread.c (switch_to_thread): Reset current_gdbarch.

	* remote.c (remote_wait): Access target registers in target_gdbarch.
	* linux-nat.c (linux_nat_do_thread_registers): Likewise.
	* proc-service.c (ps_lgetregs, ps_lsetregs): Likewise.
	(ps_lgetfpregs, ps_lsetfpregs): Likewise.
	* sol-thread.c (ps_lgetregs, ps_lsetregs): Likewise.
	(ps_lgetfpregs, ps_lsetfpregs): Likewise.


Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c
+++ src/gdb/linux-nat.c
@@ -3334,8 +3334,8 @@ linux_nat_do_thread_registers (bfd *obfd
   gdb_gregset_t gregs;
   gdb_fpregset_t fpregs;
   unsigned long lwp = ptid_get_lwp (ptid);
-  struct regcache *regcache = get_thread_regcache (ptid);
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch *gdbarch = target_gdbarch;
+  struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
   const struct regset *regset;
   int core_regset_p;
   struct cleanup *old_chain;
Index: src/gdb/proc-service.c
===================================================================
--- src.orig/gdb/proc-service.c
+++ src/gdb/proc-service.c
@@ -257,7 +257,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwp
   struct regcache *regcache;
 
   inferior_ptid = BUILD_LWP (lwpid, ph->pid);
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   target_fetch_registers (regcache, -1);
   fill_gregset (regcache, (gdb_gregset_t *) gregset, -1);
@@ -276,7 +276,7 @@ ps_lsetregs (gdb_ps_prochandle_t ph, lwp
   struct regcache *regcache;
 
   inferior_ptid = BUILD_LWP (lwpid, ph->pid);
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   supply_gregset (regcache, (const gdb_gregset_t *) gregset);
   target_store_registers (regcache, -1);
@@ -296,7 +296,7 @@ ps_lgetfpregs (gdb_ps_prochandle_t ph, l
   struct regcache *regcache;
 
   inferior_ptid = BUILD_LWP (lwpid, ph->pid);
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   target_fetch_registers (regcache, -1);
   fill_fpregset (regcache, (gdb_fpregset_t *) fpregset, -1);
@@ -316,7 +316,7 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, l
   struct regcache *regcache;
 
   inferior_ptid = BUILD_LWP (lwpid, ph->pid);
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset);
   target_store_registers (regcache, -1);
Index: src/gdb/regcache.c
===================================================================
--- src.orig/gdb/regcache.c
+++ src/gdb/regcache.c
@@ -410,36 +410,60 @@ regcache_invalidate (struct regcache *re
 
 
 /* Global structure containing the current regcache.  */
-/* FIXME: cagney/2002-05-11: The two global arrays registers[] and
-   deprecated_register_valid[] currently point into this structure.  */
-static struct regcache *current_regcache;
 
 /* NOTE: this is a write-through cache.  There is no "dirty" bit for
    recording if the register values have been changed (eg. by the
    user).  Therefore all registers must be written back to the
    target when appropriate.  */
 
-struct regcache *get_thread_regcache (ptid_t ptid)
+struct regcache_list
 {
-  /* NOTE: uweigand/2007-05-05:  We need to detect the thread's
-     current architecture at this point.  */
-  struct gdbarch *thread_gdbarch = current_gdbarch;
+  struct regcache *regcache;
+  struct regcache_list *next;
+};
+
+static struct regcache_list *current_regcache;
 
-  if (current_regcache && ptid_equal (current_regcache->ptid, ptid)
-      && get_regcache_arch (current_regcache) == thread_gdbarch)
-    return current_regcache;
+struct regcache *
+get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+{
+  struct regcache_list *list;
+  struct regcache *new_regcache;
 
-  if (current_regcache)
-    regcache_xfree (current_regcache);
+  for (list = current_regcache; list; list = list->next)
+    if (ptid_equal (list->regcache->ptid, ptid)
+	&& get_regcache_arch (list->regcache) == gdbarch)
+      return list->regcache;
 
-  current_regcache = regcache_xmalloc (thread_gdbarch);
-  current_regcache->readonly_p = 0;
-  current_regcache->ptid = ptid;
+  new_regcache = regcache_xmalloc (gdbarch);
+  new_regcache->readonly_p = 0;
+  new_regcache->ptid = ptid;
 
-  return current_regcache;
+  list = xmalloc (sizeof (struct regcache_list));
+  list->regcache = new_regcache;
+  list->next = current_regcache;
+  current_regcache = list;
+
+  return new_regcache;
 }
 
-struct regcache *get_current_regcache (void)
+static ptid_t current_thread_ptid;
+static struct gdbarch *current_thread_arch;
+
+struct regcache *
+get_thread_regcache (ptid_t ptid)
+{
+  if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid))
+    {
+      current_thread_ptid = ptid;
+      current_thread_arch = target_thread_architecture (ptid);
+    }
+
+  return get_thread_arch_regcache (ptid, current_thread_arch);
+}
+
+struct regcache *
+get_current_regcache (void)
 {
   return get_thread_regcache (inferior_ptid);
 }
@@ -458,9 +482,11 @@ regcache_observer_target_changed (struct
 static void
 regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
 {
-  if (current_regcache != NULL
-      && ptid_equal (current_regcache->ptid, old_ptid))
-    current_regcache->ptid = new_ptid;
+  struct regcache_list *list;
+
+  for (list = current_regcache; list; list = list->next)
+    if (ptid_equal (list->regcache->ptid, old_ptid))
+      list->regcache->ptid = new_ptid;
 }
 
 /* Low level examining and depositing of registers.
@@ -477,11 +503,20 @@ regcache_thread_ptid_changed (ptid_t old
 void
 registers_changed (void)
 {
-  int i;
+  struct regcache_list *list, *next;
+
+  for (list = current_regcache; list; list = next)
+    {
+      next = list->next;
+      regcache_xfree (list->regcache);
+      xfree (list);
+    }
 
-  regcache_xfree (current_regcache);
   current_regcache = NULL;
 
+  current_thread_ptid = null_ptid;
+  current_thread_arch = NULL;
+
   /* Need to forget about any frames we have cached, too. */
   reinit_frame_cache ();
 
Index: src/gdb/regcache.h
===================================================================
--- src.orig/gdb/regcache.h
+++ src/gdb/regcache.h
@@ -26,6 +26,7 @@ struct gdbarch;
 
 extern struct regcache *get_current_regcache (void);
 extern struct regcache *get_thread_regcache (ptid_t ptid);
+extern struct regcache *get_thread_arch_regcache (ptid_t, struct gdbarch *);
 
 void regcache_xfree (struct regcache *regcache);
 struct cleanup *make_cleanup_regcache_xfree (struct regcache *regcache);
Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c
+++ src/gdb/remote.c
@@ -3576,6 +3576,7 @@ Packet: '%s'\n"),
 		else
 		  {
 		    struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
+		    struct regcache *regcache;
 		    p = p1;
 
 		    if (*p != ':')
@@ -3596,8 +3597,10 @@ Packet: '%s'\n"),
 		    if (fieldsize < register_size (target_gdbarch,
 						   reg->regnum))
 		      warning (_("Remote reply is too short: %s"), buf);
-		    regcache_raw_supply (get_current_regcache (),
-					 reg->regnum, regs);
+
+		    regcache = get_thread_arch_regcache
+				(inferior_ptid, target_gdbarch);
+		    regcache_raw_supply (regcache, reg->regnum, regs);
 		  }
 
 		if (*p != ';')
Index: src/gdb/sol-thread.c
===================================================================
--- src.orig/gdb/sol-thread.c
+++ src/gdb/sol-thread.c
@@ -1090,7 +1090,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwp
   old_chain = save_inferior_ptid ();
 
   inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   if (target_has_execution)
     procfs_ops.to_fetch_registers (regcache, -1);
@@ -1115,7 +1115,7 @@ ps_lsetregs (gdb_ps_prochandle_t ph, lwp
   old_chain = save_inferior_ptid ();
 
   inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   supply_gregset (regcache, (const gdb_gregset_t *) gregset);
   if (target_has_execution)
@@ -1226,7 +1226,7 @@ ps_lgetfpregs (gdb_ps_prochandle_t ph, l
   old_chain = save_inferior_ptid ();
 
   inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   if (target_has_execution)
     procfs_ops.to_fetch_registers (regcache, -1);
@@ -1251,7 +1251,7 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, l
   old_chain = save_inferior_ptid ();
 
   inferior_ptid = BUILD_LWP (lwpid, PIDGET (inferior_ptid));
-  regcache = get_thread_regcache (inferior_ptid);
+  regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch);
 
   supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset);
   if (target_has_execution)
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c
+++ src/gdb/target.c
@@ -91,6 +91,9 @@ static LONGEST target_xfer_partial (stru
 				    void *readbuf, const void *writebuf,
 				    ULONGEST offset, LONGEST len);
 
+static struct gdbarch *default_thread_architecture (struct target_ops *ops,
+						    ptid_t ptid);
+
 static void init_dummy_target (void);
 
 static struct target_ops debug_target;
@@ -460,6 +463,7 @@ update_current_target (void)
       INHERIT (to_find_memory_regions, t);
       INHERIT (to_make_corefile_notes, t);
       INHERIT (to_get_thread_local_address, t);
+      INHERIT (to_thread_architecture, t);
       /* Do not inherit to_read_description.  */
       /* Do not inherit to_search_memory.  */
       INHERIT (to_magic, t);
@@ -625,6 +629,8 @@ update_current_target (void)
   de_fault (to_async_mask,
 	    (int (*) (int))
 	    return_one);
+  de_fault (to_thread_architecture,
+	    default_thread_architecture);
   current_target.to_read_description = NULL;
 #undef de_fault
 
@@ -2164,6 +2170,12 @@ default_watchpoint_addr_within_range (st
   return addr >= start && addr < start + length;
 }
 
+static struct gdbarch *
+default_thread_architecture (struct target_ops *ops, ptid_t ptid)
+{
+  return target_gdbarch;
+}
+
 static int
 return_zero (void)
 {
@@ -3036,6 +3048,19 @@ debug_to_find_new_threads (void)
   fputs_unfiltered ("target_find_new_threads ()\n", gdb_stdlog);
 }
 
+static struct gdbarch *
+debug_to_thread_architecture (struct target_ops *ops, ptid_t ptid)
+{
+  struct gdbarch *retval;
+
+  retval = debug_target.to_thread_architecture (ops, ptid);
+
+  fprintf_unfiltered (gdb_stdlog, "target_thread_architecture (%s) = %p [%s]\n",
+		      target_pid_to_str (ptid), retval,
+		      gdbarch_bfd_arch_info (retval)->printable_name);
+  return retval;
+}
+
 static void
 debug_to_stop (ptid_t ptid)
 {
@@ -3121,6 +3146,7 @@ setup_target_debug (void)
   current_target.to_stop = debug_to_stop;
   current_target.to_rcmd = debug_to_rcmd;
   current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
+  current_target.to_thread_architecture = debug_to_thread_architecture;
 }
 
 
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h
+++ src/gdb/target.h
@@ -523,6 +523,9 @@ struct target_ops
 			     const gdb_byte *pattern, ULONGEST pattern_len,
 			     CORE_ADDR *found_addrp);
 
+    /* Determine current architecture of thread PTID.  */
+    struct gdbarch *(*to_thread_architecture) (struct target_ops *, ptid_t);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1025,6 +1028,11 @@ extern char *normal_pid_to_str (ptid_t p
 #define target_pid_to_exec_file(pid) \
      (current_target.to_pid_to_exec_file) (pid)
 
+/* Determine current architecture of thread PTID.  */
+
+#define target_thread_architecture(ptid) \
+     (current_target.to_thread_architecture (&current_target, ptid))
+
 /*
  * Iterator function for target memory regions.
  * Calls a callback function once for each memory region 'mapped'
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c
+++ src/gdb/thread.c
@@ -886,6 +886,7 @@ switch_to_thread (ptid_t ptid)
   inferior_ptid = ptid;
   reinit_frame_cache ();
   registers_changed ();
+  current_gdbarch = get_regcache_arch (get_current_regcache ());
 
   /* We don't check for is_stopped, because we're called at times
      while in the TARGET_RUNNING state, e.g., while handling an
-- 
  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]